From 32aebafb040f3774f65ee1ae663dc85e030af49d Mon Sep 17 00:00:00 2001 From: Richard Hanna Date: Fri, 30 Aug 2024 11:21:44 -0400 Subject: [PATCH 1/7] Update convert_mixed_structure support and test cases --- R/clean_redcap_long.R | 39 ++++++++++++++++++------- tests/testthat/test-clean_redcap_long.R | 29 +++++++++++------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/R/clean_redcap_long.R b/R/clean_redcap_long.R index 8080ffed..d9ae6b22 100644 --- a/R/clean_redcap_long.R +++ b/R/clean_redcap_long.R @@ -80,7 +80,6 @@ clean_redcap_long <- function(db_data_long, has_mixed_structure_forms <- FALSE # nolint: object_usage_linter mixed_structure_ref <- data.frame() - if (allow_mixed_structure) { # Retrieve mixed structure fields and forms in reference df mixed_structure_ref <- get_mixed_structure_fields(db_data_long) %>% @@ -399,17 +398,37 @@ distill_repeat_table_long <- function(form_name, convert_mixed_instrument <- function(db_data_long, mixed_structure_ref) { for (i in seq_len(nrow(mixed_structure_ref))) { - field <- mixed_structure_ref$field_name[i] - form <- mixed_structure_ref$form_name[i] - - # Create a logical mask for rows needing update - update_mask <- is.na(db_data_long$redcap_repeat_instance) & !is.na(db_data_long[[field]]) + field <- mixed_structure_ref$field_name[i] # nolint: object_usage_linter + form <- mixed_structure_ref$form_name[i] # nolint: object_usage_linter - # Update redcap_repeat_instance - db_data_long$redcap_repeat_instance <- if_else(update_mask, 1, db_data_long$redcap_repeat_instance) + # Create an update mask column to identify which mixed structure rows need updates + db_data_long <- db_data_long %>% + mutate( + update_mask = case_when( + # repeat separately instances + !is.na({{ field }}) & is.na(.data$redcap_repeat_instance) ~ TRUE, + # repeat together instances + !is.na({{ field }}) & !is.na(.data$redcap_repeat_instance) & is.na(.data$redcap_repeat_instrument) ~ TRUE, + .default = FALSE + ) + ) - # Update redcap_repeat_instrument - db_data_long$redcap_repeat_instrument <- if_else(update_mask, form, db_data_long$redcap_repeat_instrument) + # Assign update data based on rules below + db_data_long <- db_data_long %>% + mutate( + redcap_repeat_instance = case_when( + # Add single instance repeat event instance vals when none exist + update_mask & is.na(redcap_repeat_instance) ~ 1, + # Keep repeat event instance vals when they already exist + update_mask & !is.na(redcap_repeat_instance) ~ redcap_repeat_instance, + .default = .data$redcap_repeat_instance + ), + redcap_repeat_instrument = case_when( + update_mask ~ form, + .default = .data$redcap_repeat_instrument + ) + ) %>% + select(-.data$update_mask) } db_data_long diff --git a/tests/testthat/test-clean_redcap_long.R b/tests/testthat/test-clean_redcap_long.R index 04f479f0..3a68e780 100644 --- a/tests/testthat/test-clean_redcap_long.R +++ b/tests/testthat/test-clean_redcap_long.R @@ -290,24 +290,31 @@ test_that("get_mixed_structure_fields works", { test_that("convert_mixed_instrument works", { mixed_structure_db <- tibble::tribble( - ~record_id, ~redcap_repeat_instrument, ~redcap_repeat_instance, ~mixed_structure_variable, ~repeat_form_variable, - 1, NA, NA, "A", NA, - 2, "mixed_structure_form", 1, "B", NA, - 3, "repeat_form", 1, NA, "C", - 4, "repeat_form", 2, NA, "D" + ~record_id, ~redcap_repeat_instrument, ~redcap_repeat_instance, ~mixed_structure_variable, + ~repeat_form_variable, ~mixed_repeat_var, + 1, NA, NA, "A", NA, NA, + 2, "mixed_structure_form", 1, "B", NA, NA, + 3, "repeat_form", 1, NA, "C", NA, + 4, "repeat_form", 2, NA, "D", NA, + 5, "mixed_repeat_together", 1, NA, NA, "E", + 5, "mixed_repeat_together", 2, NA, NA, "F" ) mixed_structure_ref <- tibble::tribble( ~field_name, ~rep_and_nonrep, ~form_name, - "mixed_structure_variable", TRUE, "mixed_structure_form" + "mixed_structure_variable", TRUE, "mixed_structure_form", + "mixed_repeat_var", TRUE, "mixed_repeat_together" ) expected_out <- tibble::tribble( - ~record_id, ~redcap_repeat_instrument, ~redcap_repeat_instance, ~mixed_structure_variable, ~repeat_form_variable, - 1, "mixed_structure_form", 1, "A", NA, - 2, "mixed_structure_form", 1, "B", NA, - 3, "repeat_form", 1, NA, "C", - 4, "repeat_form", 2, NA, "D" + ~record_id, ~redcap_repeat_instrument, ~redcap_repeat_instance, ~mixed_structure_variable, + ~repeat_form_variable, ~mixed_repeat_var, + 1, "mixed_structure_form", 1, "A", NA, NA, + 2, "mixed_structure_form", 1, "B", NA, NA, + 3, "repeat_form", 1, NA, "C", NA, + 4, "repeat_form", 2, NA, "D", NA, + 5, "mixed_repeat_together", 1, NA, NA, "E", + 5, "mixed_repeat_together", 2, NA, NA, "F" ) out <- convert_mixed_instrument(mixed_structure_db, mixed_structure_ref) From 557030a899c7e39d248cc7e53b4bee3f41f90a93 Mon Sep 17 00:00:00 2001 From: Richard Hanna Date: Fri, 30 Aug 2024 11:55:28 -0400 Subject: [PATCH 2/7] Update news --- NEWS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 6211fda9..68630808 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,9 @@ # REDCapTidieR 1.2.0 +- Added `combine_checkboxes()` analytics function + - Use `combine_checkboxes()` to consolidate multiple checkbox fields in a REDCap data tibble under a single column +- Fixed bug for mixed structure databases resulting in data loss when some fields had dual repeating-separately/repeating-together behavior + # REDCapTidieR 1.1.1 (development version) Version 1.1.1 From e154fecc81322d98d7e86019ddae090f04f114a4 Mon Sep 17 00:00:00 2001 From: Richard Hanna Date: Fri, 30 Aug 2024 11:56:32 -0400 Subject: [PATCH 3/7] Update NEWS.md --- NEWS.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 68630808..96ede72c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,12 @@ -# REDCapTidieR 1.2.0 +# REDCapTidieR 1.2.0 (development version) - Added `combine_checkboxes()` analytics function - Use `combine_checkboxes()` to consolidate multiple checkbox fields in a REDCap data tibble under a single column -- Fixed bug for mixed structure databases resulting in data loss when some fields had dual repeating-separately/repeating-together behavior +- Fixed a bug for mixed structure databases resulting in data loss when some fields had dual repeating-separately/repeating-together behavior -# REDCapTidieR 1.1.1 (development version) +# REDCapTidieR 1.1.1 -Version 1.1.1 +Version 1.1.1 (Released 2024-04-18) ========================================================== - `read_redcap(raw_or_label = "haven")` now correctly casts categorical data values to character when their type is not character or numeric. From 7a02e5cf5e09b02e711a36a9f6e2fe55bcf6d574 Mon Sep 17 00:00:00 2001 From: Rich Hanna <38384694+rsh52@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:02:35 -0400 Subject: [PATCH 4/7] Update R/clean_redcap_long.R Co-authored-by: Ezra Porter <60618324+ezraporter@users.noreply.github.com> --- R/clean_redcap_long.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/clean_redcap_long.R b/R/clean_redcap_long.R index d9ae6b22..b03321a4 100644 --- a/R/clean_redcap_long.R +++ b/R/clean_redcap_long.R @@ -409,7 +409,7 @@ convert_mixed_instrument <- function(db_data_long, mixed_structure_ref) { !is.na({{ field }}) & is.na(.data$redcap_repeat_instance) ~ TRUE, # repeat together instances !is.na({{ field }}) & !is.na(.data$redcap_repeat_instance) & is.na(.data$redcap_repeat_instrument) ~ TRUE, - .default = FALSE + TRUE ~ FALSE ) ) From 6e21801b295e5c3b7fbcf8bc76c7e9b1df23ade5 Mon Sep 17 00:00:00 2001 From: Rich Hanna <38384694+rsh52@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:02:41 -0400 Subject: [PATCH 5/7] Update R/clean_redcap_long.R Co-authored-by: Ezra Porter <60618324+ezraporter@users.noreply.github.com> --- R/clean_redcap_long.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/clean_redcap_long.R b/R/clean_redcap_long.R index b03321a4..3c08dd8c 100644 --- a/R/clean_redcap_long.R +++ b/R/clean_redcap_long.R @@ -425,7 +425,7 @@ convert_mixed_instrument <- function(db_data_long, mixed_structure_ref) { ), redcap_repeat_instrument = case_when( update_mask ~ form, - .default = .data$redcap_repeat_instrument + TRUE ~ .data$redcap_repeat_instrument ) ) %>% select(-.data$update_mask) From 7c93fe7b4f7a245ff8c028e0f5b3c18c03260c90 Mon Sep 17 00:00:00 2001 From: Rich Hanna <38384694+rsh52@users.noreply.github.com> Date: Fri, 30 Aug 2024 15:04:17 -0400 Subject: [PATCH 6/7] Update R/clean_redcap_long.R Co-authored-by: Ezra Porter <60618324+ezraporter@users.noreply.github.com> --- R/clean_redcap_long.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/clean_redcap_long.R b/R/clean_redcap_long.R index 3c08dd8c..f6408017 100644 --- a/R/clean_redcap_long.R +++ b/R/clean_redcap_long.R @@ -421,7 +421,7 @@ convert_mixed_instrument <- function(db_data_long, mixed_structure_ref) { update_mask & is.na(redcap_repeat_instance) ~ 1, # Keep repeat event instance vals when they already exist update_mask & !is.na(redcap_repeat_instance) ~ redcap_repeat_instance, - .default = .data$redcap_repeat_instance + TRUE ~ .data$redcap_repeat_instance ), redcap_repeat_instrument = case_when( update_mask ~ form, From 98f6cd2c892c31ed1d7fb542994c70831dfb4329 Mon Sep 17 00:00:00 2001 From: Richard Hanna Date: Fri, 30 Aug 2024 15:06:27 -0400 Subject: [PATCH 7/7] Fix convert_mixed_structure NSE --- R/clean_redcap_long.R | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/R/clean_redcap_long.R b/R/clean_redcap_long.R index 3c08dd8c..f335e5e0 100644 --- a/R/clean_redcap_long.R +++ b/R/clean_redcap_long.R @@ -406,9 +406,12 @@ convert_mixed_instrument <- function(db_data_long, mixed_structure_ref) { mutate( update_mask = case_when( # repeat separately instances - !is.na({{ field }}) & is.na(.data$redcap_repeat_instance) ~ TRUE, + !is.na(!!as.symbol(field)) & + is.na(.data$redcap_repeat_instance) ~ TRUE, # repeat together instances - !is.na({{ field }}) & !is.na(.data$redcap_repeat_instance) & is.na(.data$redcap_repeat_instrument) ~ TRUE, + !is.na(!!as.symbol(field)) & + !is.na(.data$redcap_repeat_instance) & + is.na(.data$redcap_repeat_instrument) ~ TRUE, TRUE ~ FALSE ) )