Skip to content

Commit

Permalink
validate_repeat_instance()
Browse files Browse the repository at this point in the history
ref #485
  • Loading branch information
wibeasley committed Jun 3, 2023
1 parent 2e1cab0 commit 4d40306
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 1 deletion.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export(validate_data_frame_inherits)
export(validate_field_names)
export(validate_for_write)
export(validate_no_logical)
export(validate_repeat_instance)
importFrom(magrittr,"%>%")
importFrom(methods,new)
importFrom(rlang,.data)
Expand Down
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ This will help extract forms from longitudinal & repeating projects.
* `redcap_log_read()` now returns a new column reflecting the affected record id value (ref #478)
* `redcap_read()` and `redcap_read_oneshot()` now remove "pseudofields" (e.g., `redcap_event_name`, `redcap_repeat_instrument`, & `redcap_repeat_instance`) from the `fields` parameter. Starting with REDCap v13.4.10, an error is thrown by the server. REDCap will return a message if a common pseudofield is requested explicitly by the user. (#477)
* `redcap_event_instruments()` now can return mappings for all arms, instead of one arm per call.(Suggested by @januz, #482)
* `validate_for_write()` contains a few more checks, such as `validate_repeat_instance()` and `validate_data_frame_inherits()` (#485)

Version 1.1.0 (released 2022-08-10)
==========================================================
Expand Down
47 changes: 46 additions & 1 deletion R/validate.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#'
#' @aliases
#' validate_for_write
#' validate_data_frame_inherits
#' validate_no_logical
#' validate_field_names
#' validate_repeat_instance
#'
#' @usage
#' validate_for_write( d, convert_logical_to_integer )
Expand All @@ -15,6 +17,8 @@
#'
#' validate_field_names( field_names, stop_on_error = FALSE )
#'
#' validate_repeat_instance( d, stop_on_error )
#'
#' @title
#' Inspect a dataset to anticipate problems before
#' writing to a REDCap project
Expand Down Expand Up @@ -54,13 +58,15 @@
#' with one call.
#'
#' Currently it verifies that the dataset
#' * inherits from [data.table::data.table()].
#' * does not contain
#' [logical](https://stat.ethz.ch/R-manual/R-devel/library/base/html/logical.html)
#' values (because REDCap typically wants `0`/`1` values instead of
#' `FALSE`/`TRUE`).
#' * starts with a lowercase letter, and subsequent optional characters are a
#' sequence of (a) lowercase letters, (b) digits 0-9, and/or (c) underscores.
#' (The exact regex is `^[a-z][0-9a-z_]*$`.)
#' * has an integer for `redcap_repeat_instance`, if the column is present.
#'
#' If you encounter additional types of problems when attempting to write to
#' REDCap, please tell us by creating a
Expand Down Expand Up @@ -169,6 +175,44 @@ validate_field_names <- function(field_names, stop_on_error = FALSE) {
}
}

#' @export
validate_repeat_instance <- function(d, stop_on_error = FALSE) {
checkmate::assert_data_frame(d)
checkmate::assert_logical(stop_on_error, any.missing = FALSE, len = 1)

column_name <- "redcap_repeat_instance"
if(!any(colnames(d) == column_name)) {
tibble::tibble(
field_name = character(0),
field_index = integer(0),
concern = character(0),
suggestion = character(0)
)
} else if (inherits(d[[column_name]], "integer")) {
tibble::tibble(
field_name = character(0),
field_index = integer(0),
concern = character(0),
suggestion = character(0)
)
} else if (stop_on_error) {
stop(
"The `redcap_repeat_instance` column should be an integer. ",
"Use `as.integer()` to cast it. ",
"Make sure no 'NAs introduced by coercion' warnings appears."
)
} else {
indices <- grep(column_name, x = colnames(d), perl = TRUE)

tibble::tibble(
field_name = column_name,
field_index = indices,
concern = "The `redcap_repeat_instance` column should be an integer.",
suggestion = "Use `as.integer()` to cast it. Make sure no 'NAs introduced by coercion' warnings appears."
)
}
}

# #' @export
# validate_field_names_collapsed <- function(field_names_collapsed, stop_on_error = FALSE) {
# field_names <- trimws(unlist(strsplit(field_names_collapsed, ",")))
Expand All @@ -185,7 +229,8 @@ validate_for_write <- function(

lst_concerns <- list(
validate_data_frame_inherits(d),
validate_field_names(colnames(d))
validate_field_names(colnames(d)),
validate_repeat_instance(d)
)

if (!convert_logical_to_integer) {
Expand Down
5 changes: 5 additions & 0 deletions man/validate.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 54 additions & 0 deletions tests/testthat/test-validate.R
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,57 @@ test_that("validate_field_names -concern dataset", {
expect_equal(object=ds$field_name, expected="bad_Uppercase")
expect_equal(object=ds$field_index, expected=3)
})


# ---- redcap-repeat-instance --------------------------------------------------
# credential <- REDCapR::retrieve_credential_local(
# path_credential = system.file("misc/example.credentials", package = "REDCapR"),
# project_id = 1400
# )

test_that("repeat-instance: no column", {
ds <- validate_repeat_instance(mtcars)
expect_equal(object = nrow(ds), expected = 0)
})
test_that("repeat-instance: good integer", {
d <-
"test-data/vignette-repeating-write/data-block-matrix.csv" |>
system.file(package = "REDCapR") |>
readr::read_csv(show_col_types = FALSE) |>
dplyr::mutate(
redcap_repeat_instance = as.integer(redcap_repeat_instance),
)

ds <- validate_repeat_instance(d)
expect_equal(object = nrow(ds), expected = 0)
})
test_that("repeat-instance: bad double", {
d <-
"test-data/vignette-repeating-write/data-block-matrix.csv" |>
system.file(package = "REDCapR") |>
readr::read_csv(show_col_types = FALSE)

ds_1 <- validate_repeat_instance(d)

expect_equal(object=nrow(ds_1), expected=1, info="One uppercase field should be flagged")
expect_equal(object=ds_1$field_name, expected="redcap_repeat_instance")
expect_equal(object=ds_1$field_index, expected=3)

ds_2 <- validate_for_write(d, convert_logical_to_integer = TRUE)

expect_equal(object=nrow(ds_2), expected=1, info="One uppercase field should be flagged")
expect_equal(object=ds_2$field_name, expected="redcap_repeat_instance")
expect_equal(object=ds_2$field_index, expected=3)
})

test_that("repeat-instance: bad double -stop on error", {
d <-
"test-data/vignette-repeating-write/data-block-matrix.csv" |>
system.file(package = "REDCapR") |>
readr::read_csv(show_col_types = FALSE)

expect_error(
validate_repeat_instance(d, stop_on_error = TRUE),
"The `redcap_repeat_instance` column should be an integer\\."
)
})

0 comments on commit 4d40306

Please sign in to comment.