From 332dcc86b4e4064559411e6fda1e2464eb06132e Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:54:55 -0500 Subject: [PATCH 01/11] Add function to create trigger to log deletions --- R/fct_SQLite.R | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index c3cd8715..0a286b3b 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -220,6 +220,29 @@ db_add_log <- function(con, key_cols = c("id", key_columns)) { DBI::dbClearResult(rs) } +create_delete_log_trigger <- function(con) { + rs <- DBI::dbSendStatement(con, paste( + "CREATE TRIGGER all_review_data_delete_log_trigger", + "AFTER DELETE ON all_review_data FOR EACH ROW", + "BEGIN", + "INSERT INTO all_review_data_log (", + "review_id, edit_date_time, reviewed, comment, reviewer, timestamp, status, dml_type", + ")", + "VALUES(", + "OLD.id,", + "OLD.edit_date_time,", + "OLD.reviewed,", + "OLD.comment,", + "OLD.reviewer,", + "OLD.timestamp,", + "OLD.status,", + "'DELETE'", + ");", + "END" + )) + DBI::dbClearResult(rs) +} + #' Update app database #' #' Compares the latest edit date-times in the review database and in the data From 949c29ea9445a7d91b330768315ecb890095ce45 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:59:46 -0500 Subject: [PATCH 02/11] Incorporate into DB creation process --- R/fct_SQLite.R | 1 + R/sysdata.rda | Bin 799 -> 819 bytes data-raw/internal_data.R | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index 0a286b3b..2729625e 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -218,6 +218,7 @@ db_add_log <- function(con, key_cols = c("id", key_columns)) { "END" )) DBI::dbClearResult(rs) + create_delete_log_trigger(con) } create_delete_log_trigger <- function(con) { diff --git a/R/sysdata.rda b/R/sysdata.rda index 2fab1dcfa8951ddee8f81f4d6ed23df4cb1da319..40696f6a2721ba518a74ec99e90636362fbf5d3d 100644 GIT binary patch literal 819 zcmV-31I+wFT4*^jL0KkKS%!EB`~U;9f589$_&`dBf8YfG7C^uM|KLCX00GbgetIg{ zm1=?#N@|~}q&y_`Jw}fSl+XYTGHCTO8UQ(?CMEzTBLXzQgAsycz#|T5$%%joh`^07 zAjDvqFbKgEf+~6m`kDrVKmY&$000ssA)+-s382aV+D}jb01Y%7Qkh<3sSEr~28LV1 zD+}nb7&gGZgpyXI7upg;<_dx&L)FjmWnUjc~}B+;RZI;|19>UrE7;Tj+0%l27RVjy5P0!doI13KT=xoM!KU6UTB zamAZ_$J1GHae1?cE(Vv@G@Nj)b{v*Sz>9J!LZhO%f->ZpONot)0R;%BrEnr*LL;uA zu!x1`BtVcb1S+u%XlxoA0iaW4pb$xs-WT0$}qkrEfYo_bVjSH3<_zMxl8 zLH(aUmJdAFU554vo<&vCx!N@I`q{_$=mR-k-W*h%!Z$9GlSC6D2q-k-gy3ev3uaB+ zO^oW}q06cZa03q_URH1>ZVP6ny1>S`kQa#Q2bTqTLm%SY4H*9b=j%R_Uw?5QG?c*6 zt5P47l@kEK1b{VFz>VBx@Ei2VINKU{RU6D&&@o8oDoTqc)(VSZ1Mxy6oNzNhK|$Qi z6+9N5lO}@srEnb+Unba6RLN*ojI%g%7|A|JRwU9=u!bn_D(gP@Vm^$8nhD94}9nAz-Xpb6K4&1H1R||}7K{BOQMaDyOAww*rVO7lo zN!i)aD)a2(H2KVfIAy-geH-l!i6_X!G66u;0jSNa7`(;3U4(6@4DjHM4_n!^kqKrw zO+(f`YsysB0OP{9$S@hks$jfONW_7-WtJ6uUpw-cTr%PiR0&3MxVi}}D3qz<%&2fs x!l6Aj9A{3_6pae=1QKd(K6jsz!jNe<9bc3W=B&%&5Hl(KF64@Ep&<%>06Bn7FbR;r z08A4A00AOGXi1F;lT1;x0YJ?|)Y_Tl6M0h$%$g9tB+zDOJSbf?c)_*>)FhI3q!-jC zi2|ZAG)Q6w!6=-GB#sx(a{{-X_6ZeZ8+1UpA0{6^SV~nf^CmpGMJxr+10{}7r_k1B5yNf`4kC7ul z`f9doX7>!*N=s?D?9VXVZ>S%YQ6(d_xFccl=nIbOoTg0$^GeV>CcT?sNmB)xRArdM zS=?m%luSj%u-pPFlngMBc+@=!1`1*27Ybt$fGu7D(6W#0QR2mP{OfO4IG=|%q zRL>p9qZ>XpC6~2U?*%TT`jL}O48lp4Igl{T-qnhtO2Ug|mVlWB$60#p2F8X(8*Ck| z1XyN&?CHD8D|Hs-(0H;%3MB?p1(iUMbd!6MOHdikT)ZWBUd*O{;J`749+qkF^r&n} zJxoI&6b(Qc4viqi`<3I!jkf^K{7B67y_-o8mqFBM9+B(3rN)Q{9qZCTh-XT;#Ju2< zkb$^mmKQv~OYoRlGSU!S1fv;tM?ocuiAtV*3WqfeE(zzb={&ZOq-Ix`kV&bu`rbWO d6oWb9ao~Y+-y<-AibVhMcO+AV2@J-o@!&;BTY&%o diff --git a/data-raw/internal_data.R b/data-raw/internal_data.R index 4e650643..611bc724 100644 --- a/data-raw/internal_data.R +++ b/data-raw/internal_data.R @@ -58,7 +58,7 @@ required_meta_cols <- c( "item_type" ) -db_version <- "1.1" +db_version <- "1.2" # Used in get_form_level_data(). Set a default if ClinSight needs the columns # to function properly. From e153c2ed5929d3789ce370cfe00e754167e6706f Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:00:07 -0500 Subject: [PATCH 03/11] Add function to upgrade DB version --- R/fct_SQLite.R | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index 2729625e..07f96920 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -244,6 +244,24 @@ create_delete_log_trigger <- function(con) { DBI::dbClearResult(rs) } +db_upgrade <- function(db_path){ + stopifnot(file.exists(db_path)) + + current_db_version <- db_get_version(db_path) + if (identical(current_db_version, db_version)) + return(paste("Upgraded to version", db_version)) + + switch( + current_db_version, + "1.1" = db_temp_connect(db_path, { + create_delete_log_trigger(con) + DBI::dbWriteTable(con, "db_version", data.frame(version = "1.2"), overwrite = TRUE) + }), + stop("No upgrade available for version ", current_db_version) + ) + db_upgrade(db_path) +} + #' Update app database #' #' Compares the latest edit date-times in the review database and in the data From 926e7809ad99a85220ab17a53e5478737638881a Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:01:10 -0500 Subject: [PATCH 04/11] Add function to delete records from `all_review_data` --- R/fct_SQLite.R | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index 07f96920..d2076c43 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -262,6 +262,20 @@ db_upgrade <- function(db_path){ db_upgrade(db_path) } +db_delete <- function(con, data, key_cols = "id") { + dplyr::copy_to(con, data, "row_deletes") + rs <- DBI::dbSendStatement(con, paste( + "DELETE FROM", + "all_review_data", + "WHERE EXISTS (", + "SELECT 1", + "FROM row_deletes", + "WHERE", paste(sprintf("row_deletes.%1$s = all_review_data.%1$s", key_cols), collapse = " AND "), + ")" + )) + DBI::dbClearResult(rs) +} + #' Update app database #' #' Compares the latest edit date-times in the review database and in the data From ca29d5ecdf0e01c6f884066bb36f028c0edef055 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:04:12 -0500 Subject: [PATCH 05/11] Separate handling of record deletions from `update_review_data()` --- R/fct_SQLite.R | 37 ++++++++++++++++++++------------- R/mod_review_data_fct_helpers.R | 34 +++++++++++++++++------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index d2076c43..ba25e863 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -262,20 +262,6 @@ db_upgrade <- function(db_path){ db_upgrade(db_path) } -db_delete <- function(con, data, key_cols = "id") { - dplyr::copy_to(con, data, "row_deletes") - rs <- DBI::dbSendStatement(con, paste( - "DELETE FROM", - "all_review_data", - "WHERE EXISTS (", - "SELECT 1", - "FROM row_deletes", - "WHERE", paste(sprintf("row_deletes.%1$s = all_review_data.%1$s", key_cols), collapse = " AND "), - ")" - )) - DBI::dbClearResult(rs) -} - #' Update app database #' #' Compares the latest edit date-times in the review database and in the data @@ -298,6 +284,7 @@ db_update <- function( edit_time_var = "edit_date_time" ){ stopifnot(file.exists(db_path)) + stopifnot(identical(db_version, db_get_version(db_path))) con <- get_db_connection(db_path) data_synch_time <- attr(data, "synch_time") %||% "" @@ -316,6 +303,14 @@ db_update <- function( # Continue in the case data_synch_time is missing and if data_synch_time is # more recent than db_synch_time review_data <- DBI::dbGetQuery(con, "SELECT * FROM all_review_data") + cat("Check for deleted rows\n") + deleted_review_data <- delete_review_data( + review_df = review_data, + latest_review_data = data, + key_cols = key_cols + ) + cat("logging deleted review data to database...\n") + db_delete(con, deleted_review_data) cat("Start adding new rows to database\n") updated_review_data <- update_review_data( review_df = review_data, @@ -335,6 +330,20 @@ db_update <- function( cat("Finished updating review data\n") } +db_delete <- function(con, data, key_cols = "id") { + dplyr::copy_to(con, data, "row_deletes") + rs <- DBI::dbSendStatement(con, paste( + "DELETE FROM", + "all_review_data", + "WHERE EXISTS (", + "SELECT 1", + "FROM row_deletes", + "WHERE", paste(sprintf("row_deletes.%1$s = all_review_data.%1$s", key_cols), collapse = " AND "), + ")" + )) + DBI::dbClearResult(rs) +} + #' UPSERT to all_review_data #' #' Performs an UPSERT on all_review_data. New records will be appended to the diff --git a/R/mod_review_data_fct_helpers.R b/R/mod_review_data_fct_helpers.R index 2ded1835..b6d1b318 100644 --- a/R/mod_review_data_fct_helpers.R +++ b/R/mod_review_data_fct_helpers.R @@ -39,6 +39,26 @@ get_review_data <- function( all_review_data } +delete_review_data <- function( + review_df, + latest_review_data, + key_cols = key_columns +){ + stopifnot(is.data.frame(latest_review_data), nrow(latest_review_data) > 0 ) + stopifnot(is.data.frame(review_df), nrow(review_df) > 0 ) + stopifnot(is.character(key_cols)) + + deleted_data <- dplyr::anti_join(review_df, latest_review_data, by = key_cols) + n_deleted <- nrow(deleted_data) + if(n_deleted != 0){ + warning(n_deleted, " items were not found in the updated dataset") + cat("Missing items in the dataset:\n") + print(deleted_data) + } + + deleted_data +} + #' Update review data #' #' @@ -67,20 +87,6 @@ update_review_data <- function( stopifnot(is.character(key_cols)) stopifnot(is.character(edit_time_var)) - deleted_data <- dplyr::anti_join(review_df, latest_review_data, by = key_cols) - n_deleted <- nrow(deleted_data) - if(n_deleted != 0){ - warning(n_deleted, " items were not found in the updated dataset") - cat("Missing items in the dataset:\n") - print(deleted_data) - } - - # If data is reviewed and later in an update deleted, then it is okay if the - # deletion does not show up in the updated data set, and the deleted data point shows - # up as reviewed. One reason why this is okay is because missing data is checked - # by the data managers. - # a more practical reason is that missing data does not show up in the application. - # when do we have the same edit_date_time but different timestamps? # For example: # - we have a new data point. It is not yet reviewed (status new or updated). From bb2b65f036e883dc9bb7d2372929262e9830bb03 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:24:56 -0500 Subject: [PATCH 06/11] Repair `test-fct_SQLite.R` --- tests/testthat/test-fct_SQLite.R | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-fct_SQLite.R b/tests/testthat/test-fct_SQLite.R index cf2fbb34..3a462469 100644 --- a/tests/testthat/test-fct_SQLite.R +++ b/tests/testthat/test-fct_SQLite.R @@ -53,7 +53,7 @@ describe( ) expect_equal( dplyr::collect(dplyr::tbl(con, "db_version")), - dplyr::tibble(version = "1.1") + dplyr::tibble(version = "1.2") ) expect_equal( dplyr::collect(dplyr::tbl(con, "query_data")), @@ -128,6 +128,7 @@ describe( db_add_primary_key(con, "all_review_data", cbind(old_data, review_cols), comvars) db_add_log(con, c("id", comvars)) DBI::dbWriteTable(con, "db_synch_time", data.frame("synch_time" = "2024-01-01 01:01:01 UTC")) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) df_old <- cbind(id = 1, old_data, review_cols) log_old <- DBI::dbGetQuery(con, "SELECT * FROM all_review_data_log") @@ -155,6 +156,7 @@ describe( db_add_primary_key(con, "all_review_data", cbind(old_data, review_cols), comvars) db_add_log(con, c("id", comvars)) DBI::dbWriteTable(con, "db_synch_time", data.frame("synch_time" = "2024-01-01 01:01:01 UTC")) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) log_old <- DBI::dbGetQuery(con, "SELECT * FROM all_review_data_log") @@ -175,6 +177,7 @@ describe( temp_path <- withr::local_tempfile(fileext = ".sqlite") con <- get_db_connection(temp_path) db_add_primary_key(con, "all_review_data", cbind(old_data, review_cols), comvars) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) rev_data <- rbind(old_data, new_data) # no synch_time attribute added db_update(rev_data, db_path = temp_path, key_cols = comvars) @@ -193,6 +196,7 @@ describe( db_add_primary_key(con, "all_review_data", cbind(old_data, review_cols), comvars) db_add_log(con, c("id", comvars)) DBI::dbWriteTable(con, "db_synch_time", data.frame("synch_time" = "2024-01-01 01:01:01 UTC")) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) rev_data <- old_data |> dplyr::mutate(edit_date_time = "2023-11-13 01:01:01") @@ -214,6 +218,7 @@ describe( db_add_primary_key(con, "all_review_data", rev_data, comvars) db_add_log(con, c("id", comvars)) DBI::dbWriteTable(con, "db_synch_time", data.frame("synch_time" = synch_time)) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) log_old <- DBI::dbGetQuery(con, "SELECT * FROM all_review_data_log") @@ -241,6 +246,7 @@ describe( db_add_primary_key(con, "all_review_data", rev_data, comvars) db_add_log(con, c("id", comvars)) DBI::dbWriteTable(con, "db_synch_time", data.frame("synch_time" = synch_time)) + DBI::dbWriteTable(con, "db_version", data.frame(version = db_version)) expect_warning( db_update(rev_data, db_path = temp_path, key_cols = comvars), "DB synch time is more recent than data synch time. Aborting synchronization" From 7b9cba8a37fc1b931f6d2e8a34b429cfe93ca8fa Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:28:32 -0500 Subject: [PATCH 07/11] Remove defunct check on `update_review_data()` --- tests/testthat/test-update_review_data.R | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/testthat/test-update_review_data.R b/tests/testthat/test-update_review_data.R index f2725381..644c5169 100644 --- a/tests/testthat/test-update_review_data.R +++ b/tests/testthat/test-update_review_data.R @@ -60,15 +60,5 @@ describe( key_cols = c("key_col1", "item_group")))) == 0 ) }) - it("warns if rows are not found in the updated dataset but still returns a - valid data frame; might happen if entries are deleted from the source", { - missing_row_data <- updated_review_data |> dplyr::filter(key_col1 != 9999) - expect_warning(update_review_data(old_review_data, missing_row_data, - key_cols = c("key_col1", "item_group"))) - expect_true(is.data.frame(suppressWarnings( - update_review_data(old_review_data, missing_row_data, - key_cols = c("key_col1", "item_group")) - ))) - }) } ) From a8accda71114ebbcc73b88a3509ed4b9ae73a3ad Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:36:37 -0500 Subject: [PATCH 08/11] Upgrade `testdb.sqlite` --- tests/testthat/fixtures/testdb.sqlite | Bin 1081344 -> 1081344 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/testthat/fixtures/testdb.sqlite b/tests/testthat/fixtures/testdb.sqlite index 0e06c7214477bd93bc6f25579c6072a3fb1f145a..a0bd7975799687b76a9b21d87e61eb5f9f2b6df7 100644 GIT binary patch delta 209 zcmZo@aB669njkI6!@$7E!GHj~6LpLgc^LG%1bKmiT&&9&_@?kV@y_Hi=aS~Q#BRfV zi**@y=k~+}ENZOG&BEN1?b+p6Qc`nLCnvJoKo|?zMOj>2eOxE+VqeMZ@8dE#jU$c^ zBoN}NuAphH;OghH*@oSZg^{PZo4dW6n-PeafS4JGS%8=oh}nRc9f&!Am=lP(fEc8f Z2Z(urm=B2gw|8?3l%y~kEpreM005R7G*DK+FQftU$~L#Oy%K0mPg@%mu_CwLCz~ W3&eat%)h;xTc9L`(QuiAfB*ns!Xy3w From 0ba9cb9a2b6b98a030d7434c6e4328c27e47ae65 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:05:02 -0500 Subject: [PATCH 09/11] Update docs --- NAMESPACE | 1 + R/fct_SQLite.R | 36 ++++++++++++++++++++++++++++++-- R/mod_review_data_fct_helpers.R | 14 +++++++++++++ man/create_delete_log_trigger.Rd | 15 +++++++++++++ man/db_add_log.Rd | 2 +- man/db_delete.Rd | 25 ++++++++++++++++++++++ man/db_upgrade.Rd | 19 +++++++++++++++++ man/db_upsert.Rd | 2 +- man/delete_review_data.Rd | 25 ++++++++++++++++++++++ 9 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 man/create_delete_log_trigger.Rd create mode 100644 man/db_delete.Rd create mode 100644 man/db_upgrade.Rd create mode 100644 man/delete_review_data.Rd diff --git a/NAMESPACE b/NAMESPACE index 5d3f1f26..d208949d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,6 +16,7 @@ export(create_table) export(db_create) export(db_get_query) export(db_update) +export(db_upgrade) export(get_appdata) export(get_base_value) export(get_db_connection) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index ba25e863..fea65e57 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -158,7 +158,7 @@ db_add_primary_key <- function(con, name, value, keys = NULL) { #' Add Logging Table #' -#' Both creates the logging table and the trigger to update it for +#' Creates the logging table and the triggers on updates and deletions for #' all_review_data. #' #' @param con A DBI Connection to the SQLite DB @@ -221,6 +221,13 @@ db_add_log <- function(con, key_cols = c("id", key_columns)) { create_delete_log_trigger(con) } +#' Create Delete Logging Trigger +#' +#' Logs record deletions on all_review_data into all_review_data_log. +#' +#' @param con A DBI Connection to the SQLite DB +#' +#' @keywords internal create_delete_log_trigger <- function(con) { rs <- DBI::dbSendStatement(con, paste( "CREATE TRIGGER all_review_data_delete_log_trigger", @@ -244,6 +251,17 @@ create_delete_log_trigger <- function(con) { DBI::dbClearResult(rs) } +#' Upgrade app database +#' +#' Helper function to upgrade the database when migrating to a newer version of +#' ClinSight that impacts the database. +#' +#' @param db_path Character vector. Path to the database +#' +#' @return A character vector indicating the version the DB was upgraded to. Run +#' for side effects on the database. +#' +#' @export db_upgrade <- function(db_path){ stopifnot(file.exists(db_path)) @@ -330,6 +348,20 @@ db_update <- function( cat("Finished updating review data\n") } +#' DELETE FROM all_review_data +#' +#' Performs a DELETE FROM on all_review_data based on a data set containing the +#' records to delete. +#' +#' @param con A DBI Connection to the SQLite DB +#' @param data A data frame containing the records to DELETE FROM +#' all_review_data +#' @param key_cols A character vectory specifying which columns define a unique +#' index for a row. Defaults to "id" +#' +#' @return invisible returns TRUE. Is run for its side effects on the DB. +#' +#' @keywords internal db_delete <- function(con, data, key_cols = "id") { dplyr::copy_to(con, data, "row_deletes") rs <- DBI::dbSendStatement(con, paste( @@ -355,7 +387,7 @@ db_delete <- function(con, data, key_cols = "id") { #' @param key_cols A character vector specifying which columns define a unique #' index for a row. Defaults to `ClinSight` [key_columns()]. #' -#' @return invisibly returns TRUE. Is run for it's side effects on the DB. +#' @return invisibly returns TRUE. Is run for its side effects on the DB. #' #' @keywords internal db_upsert <- function(con, data, key_cols = key_columns) { diff --git a/R/mod_review_data_fct_helpers.R b/R/mod_review_data_fct_helpers.R index b6d1b318..a90345d4 100644 --- a/R/mod_review_data_fct_helpers.R +++ b/R/mod_review_data_fct_helpers.R @@ -39,6 +39,20 @@ get_review_data <- function( all_review_data } +#' Delete review data +#' +#' Identifies the records no longer in the dataset to be removed from +#' all_review_data. +#' +#' @param review_df Data frame containing old review data that need to be +#' updated. +#' @param latest_review_data Data frame containing latest review data. +#' @param key_cols A character vector containing the common key variables. +#' Defaults to `ClinSight` [key_columns()]. +#' +#' @return A data frame containing only the rows to remove from the review data. +#' +#' @keywords internal delete_review_data <- function( review_df, latest_review_data, diff --git a/man/create_delete_log_trigger.Rd b/man/create_delete_log_trigger.Rd new file mode 100644 index 00000000..19b4f6c5 --- /dev/null +++ b/man/create_delete_log_trigger.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fct_SQLite.R +\name{create_delete_log_trigger} +\alias{create_delete_log_trigger} +\title{Create Delete Logging Trigger} +\usage{ +create_delete_log_trigger(con) +} +\arguments{ +\item{con}{A DBI Connection to the SQLite DB} +} +\description{ +Logs record deletions on all_review_data into all_review_data_log. +} +\keyword{internal} diff --git a/man/db_add_log.Rd b/man/db_add_log.Rd index 9f0d2c0d..e63541c4 100644 --- a/man/db_add_log.Rd +++ b/man/db_add_log.Rd @@ -14,7 +14,7 @@ not be updated in a table. If unset, defaults to 'id' and the package-defined \code{\link[=key_columns]{key_columns()}}.} } \description{ -Both creates the logging table and the trigger to update it for +Creates the logging table and the triggers on updates and deletions for all_review_data. } \keyword{internal} diff --git a/man/db_delete.Rd b/man/db_delete.Rd new file mode 100644 index 00000000..24138c43 --- /dev/null +++ b/man/db_delete.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fct_SQLite.R +\name{db_delete} +\alias{db_delete} +\title{DELETE FROM all_review_data} +\usage{ +db_delete(con, data, key_cols = "id") +} +\arguments{ +\item{con}{A DBI Connection to the SQLite DB} + +\item{data}{A data frame containing the records to DELETE FROM +all_review_data} + +\item{key_cols}{A character vectory specifying which columns define a unique +index for a row. Defaults to "id"} +} +\value{ +invisible returns TRUE. Is run for its side effects on the DB. +} +\description{ +Performs a DELETE FROM on all_review_data based on a data set containing the +records to delete. +} +\keyword{internal} diff --git a/man/db_upgrade.Rd b/man/db_upgrade.Rd new file mode 100644 index 00000000..5dbe6dbe --- /dev/null +++ b/man/db_upgrade.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fct_SQLite.R +\name{db_upgrade} +\alias{db_upgrade} +\title{Upgrade app database} +\usage{ +db_upgrade(db_path) +} +\arguments{ +\item{db_path}{Character vector. Path to the database} +} +\value{ +A character vector indicating the version the DB was upgraded to. Run +for side effects on the database. +} +\description{ +Helper function to upgrade the database when migrating to a newer version of +ClinSight that impacts the database. +} diff --git a/man/db_upsert.Rd b/man/db_upsert.Rd index fd5699a1..be99b1fd 100644 --- a/man/db_upsert.Rd +++ b/man/db_upsert.Rd @@ -15,7 +15,7 @@ db_upsert(con, data, key_cols = key_columns) index for a row. Defaults to \code{ClinSight} \code{\link[=key_columns]{key_columns()}}.} } \value{ -invisibly returns TRUE. Is run for it's side effects on the DB. +invisibly returns TRUE. Is run for its side effects on the DB. } \description{ Performs an UPSERT on all_review_data. New records will be appended to the diff --git a/man/delete_review_data.Rd b/man/delete_review_data.Rd new file mode 100644 index 00000000..663590f2 --- /dev/null +++ b/man/delete_review_data.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/mod_review_data_fct_helpers.R +\name{delete_review_data} +\alias{delete_review_data} +\title{Delete review data} +\usage{ +delete_review_data(review_df, latest_review_data, key_cols = key_columns) +} +\arguments{ +\item{review_df}{Data frame containing old review data that need to be +updated.} + +\item{latest_review_data}{Data frame containing latest review data.} + +\item{key_cols}{A character vector containing the common key variables. +Defaults to \code{ClinSight} \code{\link[=key_columns]{key_columns()}}.} +} +\value{ +A data frame containing only the rows to remove from the review data. +} +\description{ +Identifies the records no longer in the dataset to be removed from +all_review_data. +} +\keyword{internal} From dc2670321651ff0c14c55bc3309badbb537eae9c Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Fri, 9 Jan 2026 14:35:32 -0500 Subject: [PATCH 10/11] Update `_pkgdown.yml` --- inst/_pkgdown.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/inst/_pkgdown.yml b/inst/_pkgdown.yml index 48811d67..45a60f21 100644 --- a/inst/_pkgdown.yml +++ b/inst/_pkgdown.yml @@ -76,6 +76,7 @@ reference: - contents: - get_db_connection - db_create + - db_upgrade - db_update - db_get_review - db_get_query From d24e8c4befd1b02938bf390c4e258f640cb59765 Mon Sep 17 00:00:00 2001 From: Jeff Thompson <160783290+jthompson-arcus@users.noreply.github.com> Date: Wed, 14 Jan 2026 08:58:41 -0500 Subject: [PATCH 11/11] Add upgrade menu requiring user opt-in --- R/fct_SQLite.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/R/fct_SQLite.R b/R/fct_SQLite.R index fea65e57..99b9415d 100644 --- a/R/fct_SQLite.R +++ b/R/fct_SQLite.R @@ -272,6 +272,8 @@ db_upgrade <- function(db_path){ switch( current_db_version, "1.1" = db_temp_connect(db_path, { + if (!identical(db_upgrade_menu("1.2"), 1L)) + return(paste("Abandoning DB upgrading. DB version is", current_db_version)) create_delete_log_trigger(con) DBI::dbWriteTable(con, "db_version", data.frame(version = "1.2"), overwrite = TRUE) }), @@ -280,6 +282,16 @@ db_upgrade <- function(db_path){ db_upgrade(db_path) } +db_upgrade_menu <- function(upgrade_version) { + utils::menu( + c("Yes", "No"), + title = sprintf( + "Attempting to update to v%s. Do you want to proceed?", + upgrade_version + ) + ) +} + #' Update app database #' #' Compares the latest edit date-times in the review database and in the data