diff --git a/.github/workflows/rhub.yaml b/.github/workflows/rhub.yaml new file mode 100644 index 00000000..74ec7b05 --- /dev/null +++ b/.github/workflows/rhub.yaml @@ -0,0 +1,95 @@ +# R-hub's generic GitHub Actions workflow file. It's canonical location is at +# https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml +# You can update this file to a newer version using the rhub2 package: +# +# rhub::rhub_setup() +# +# It is unlikely that you need to modify this file manually. + +name: R-hub +run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" + +on: + workflow_dispatch: + inputs: + config: + description: 'A comma separated list of R-hub platforms to use.' + type: string + default: 'linux,windows,macos' + name: + description: 'Run name. You can leave this empty now.' + type: string + id: + description: 'Unique ID. You can leave this empty now.' + type: string + +jobs: + + setup: + runs-on: ubuntu-latest + outputs: + containers: ${{ steps.rhub-setup.outputs.containers }} + platforms: ${{ steps.rhub-setup.outputs.platforms }} + + steps: + # NO NEED TO CHECKOUT HERE + - uses: r-hub/actions/setup@v1 + with: + config: ${{ github.event.inputs.config }} + id: rhub-setup + + linux-containers: + needs: setup + if: ${{ needs.setup.outputs.containers != '[]' }} + runs-on: ubuntu-latest + name: ${{ matrix.config.label }} + strategy: + fail-fast: false + matrix: + config: ${{ fromJson(needs.setup.outputs.containers) }} + container: + image: ${{ matrix.config.container }} + + steps: + - uses: r-hub/actions/checkout@v1 + - uses: r-hub/actions/platform-info@v1 + with: + token: ${{ secrets.RHUB_TOKEN }} + job-config: ${{ matrix.config.job-config }} + - uses: r-hub/actions/setup-deps@v1 + with: + token: ${{ secrets.RHUB_TOKEN }} + job-config: ${{ matrix.config.job-config }} + - uses: r-hub/actions/run-check@v1 + with: + token: ${{ secrets.RHUB_TOKEN }} + job-config: ${{ matrix.config.job-config }} + + other-platforms: + needs: setup + if: ${{ needs.setup.outputs.platforms != '[]' }} + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.label }} + strategy: + fail-fast: false + matrix: + config: ${{ fromJson(needs.setup.outputs.platforms) }} + + steps: + - uses: r-hub/actions/checkout@v1 + - uses: r-hub/actions/setup-r@v1 + with: + job-config: ${{ matrix.config.job-config }} + token: ${{ secrets.RHUB_TOKEN }} + - uses: r-hub/actions/platform-info@v1 + with: + token: ${{ secrets.RHUB_TOKEN }} + job-config: ${{ matrix.config.job-config }} + - uses: r-hub/actions/setup-deps@v1 + with: + job-config: ${{ matrix.config.job-config }} + token: ${{ secrets.RHUB_TOKEN }} + - uses: r-hub/actions/run-check@v1 + with: + job-config: ${{ matrix.config.job-config }} + token: ${{ secrets.RHUB_TOKEN }} diff --git a/NEWS.md b/NEWS.md index f6ee917e..fb1435a0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,7 +13,7 @@ Version 1.1.0 (Released 2024-03-28) - `read_redcap()` now supports instruments that follow a mixed repeating/non-repeating structure with the `allow_mixed_structure` parameter - Mixed structure instruments (those with both repeating and nonrepeating elements) can be supported by setting `allow_mixed_structure` to `TRUE` or `getOption("redcaptidier.allow.mixed.structure", FALSE)`. - - When allowed, nonrepeating elements of mixed structure insturments will be treated as repeating elements with a single instance. + - When allowed, nonrepeating elements of mixed structure instruments will be treated as repeating elements with a single instance. - Missing data codes from REDCap additional customization settings are now handled. Non-logical values are converted to `NA` in `yesno`, `truefalse`, and `checkbox` fields with a warning. - Warnings for MDCs can be silenced with `options(redcaptidier.allow.mdc = TRUE)`. - `raw_or_label` now accepts `"haven"` as an option, converting categorical fields to `haven_labelled` vectors instead of factors. diff --git a/R/checks.R b/R/checks.R index 8a73f0d8..09c39a7c 100644 --- a/R/checks.R +++ b/R/checks.R @@ -624,7 +624,7 @@ check_field_is_logical <- function(x) { #' #' @keywords internal check_extra_field_values <- function(x, values) { - extra_vals <- setdiff(as.character(x), values) |> na.omit() + extra_vals <- setdiff(as.character(x), values) %>% na.omit() if (length(extra_vals) == 0) { return(NULL) } @@ -632,7 +632,7 @@ check_extra_field_values <- function(x, values) { } check_extra_field_values_message <- function(extra_field_values, call = caller_env()) { - extra_field_values <- extra_field_values |> + extra_field_values <- extra_field_values %>% discard(is.null) if (length(extra_field_values) == 0) { @@ -640,7 +640,7 @@ check_extra_field_values_message <- function(extra_field_values, call = caller_e } fields <- names(extra_field_values) - values <- flatten_chr(extra_field_values) |> unique() + values <- flatten_chr(extra_field_values) %>% unique() msg <- c( `!` = "{.code {fields}} contain{?s/} values with no labels: {values}", diff --git a/R/utils.R b/R/utils.R index 2729f8ee..f6a04763 100644 --- a/R/utils.R +++ b/R/utils.R @@ -514,13 +514,13 @@ parse_logical_cols <- function(db_data, db_metadata, call = caller_env()) { out[logical_cols$field_name_updated] <- map(parsed, "parsed") if (!getOption("redcaptidier.allow.mdc", FALSE)) { - problems <- parsed |> - map("problems") |> + problems <- parsed %>% + map("problems") %>% discard(is.null) if (length(problems) > 0) { fields <- names(problems) - values <- flatten_chr(problems) |> unique() + values <- flatten_chr(problems) %>% unique() msg <- c( `!` = "{.code {fields}} {?is/are} logical but contain{?s/} non-logical values: {values}", diff --git a/utility/cli_message_examples_reprex.R b/utility/cli_message_examples_reprex.R deleted file mode 100644 index 21234377..00000000 --- a/utility/cli_message_examples_reprex.R +++ /dev/null @@ -1,157 +0,0 @@ -#' --- -#' output: reprex::reprex_document -#' --- - -devtools::load_all() - -options(rlang_backtrace_on_error_report = "none") - -# read_redcap - -classic_token <- Sys.getenv("REDCAPTIDIER_CLASSIC_API") -longitudinal_token <- Sys.getenv("REDCAPTIDIER_LONGITUDINAL_API") -redcap_uri <- Sys.getenv("REDCAP_URI") - -## args missing - -# read_redcap() - -# read_redcap(redcap_uri) - -# read_redcap(token = classic_token) - -## redcap_uri - -read_redcap(123, classic_token) - -read_redcap(letters[1:3], classic_token) - -read_redcap("https://www.google.com", classic_token) - -read_redcap("https://www.google.comm", classic_token) - -## token - -read_redcap(redcap_uri, 123) - -read_redcap(redcap_uri, letters[1:3]) - -read_redcap(redcap_uri, "") - -read_redcap(redcap_uri, "CC0CE44238EF65C5DA26A55DD749AF7") # 31 hex characters - -read_redcap(redcap_uri, "CC0CE44238EF65C5DA26A55DD749AF7A") # will be rejected by server - -## unexpected REDCapR error - -try_redcapr(list(success = FALSE, status_code = "", outcome_message = "This is an error message from REDCapR!")) - -## raw_or_label - -read_redcap(redcap_uri, classic_token, raw_or_label = "bad option") - -## forms - -read_redcap(redcap_uri, classic_token, forms = 123) - -## export_survey_fields - -read_redcap(redcap_uri, classic_token, export_survey_fields = 123) - -read_redcap(redcap_uri, classic_token, export_survey_fields = c(TRUE, TRUE)) - -## suppress_redcapr_messages - -read_redcap(redcap_uri, classic_token, suppress_redcapr_messages = 123) - -read_redcap(redcap_uri, classic_token, suppress_redcapr_messages = c(TRUE, TRUE)) - -# data access groups - -read_redcap(redcap_uri, classic_token, export_data_access_groups = TRUE) - -# surveys - -read_redcap(redcap_uri, longitudinal_token, export_survey_fields = TRUE) - -# bind_tibbles - -bind_tibbles(123) - -supertbl <- tibble(redcap_data = list()) -bind_tibbles(supertbl, environment = "abc") - -bind_tibbles(supertbl, tbls = 123) - -# extract_tibbles - -extract_tibbles(letters[1:10]) - -# extract_tibble - -extract_tibble(123, "my_tibble") - -supertbl <- tibble(redcap_data = list()) %>% - as_supertbl() -extract_tibble(supertbl, tbl = 123) - -extract_tibble(supertbl, tbl = letters[1:3]) - -# make_labelled - -make_labelled(123) - -missing_col_supertbl <- tibble(redcap_data = list()) %>% - as_supertbl() -make_labelled(missing_col_supertbl) - -missing_list_col_supertbl <- tibble(redcap_data = list(), redcap_metadata = 123) %>% - as_supertbl() -make_labelled(missing_list_col_supertbl) - -# add_skimr_metadata - -mtcars %>% add_skimr_metadata() - -# write_redcap_xlsx - -withr::with_tempdir({ - dir <- getwd() - filepath <- paste0(dir, "/temp.csv") - REDCapTidieR:::check_file_exists(file = filepath, overwrite = FALSE) -}) - -withr::with_tempdir({ - dir <- getwd() - tempfile <- write.csv(x = mtcars, file = "temp.csv") - filepath <- paste0(dir, "/temp.csv") - REDCapTidieR:::check_file_exists(file = filepath, overwrite = FALSE) -}) - -write_redcap_xlsx(mtcars, file = "temp.xlsx") - -read_redcap(redcap_uri, classic_token) %>% - write_redcap_xlsx(file = "temp.xlsx", add_labelled_column_headers = TRUE) - -withr::with_tempdir({ - dir <- getwd() - filepath <- paste0(dir, "/temp.pdf") - read_redcap(redcap_uri, longitudinal_token) %>% - write_redcap_xlsx(file = filepath) -}) - -withr::with_tempdir({ - dir <- getwd() - filepath <- paste0(dir, "/temp") - read_redcap(redcap_uri, longitudinal_token) %>% - write_redcap_xlsx(file = filepath) -}) - -# Printed supertibble - -read_redcap(Sys.getenv("REDCAP_URI"), Sys.getenv("REDCAPTIDIER_CLASSIC_API")) %>% - suppressWarnings() - -# missing data codes - -read_redcap(redcap_uri, Sys.getenv("REDCAPTIDIER_MDC_API")) diff --git a/utility/cli_message_examples_reprex.md b/utility/cli_message_examples_reprex.md index 0a54bf0a..4234a231 100644 --- a/utility/cli_message_examples_reprex.md +++ b/utility/cli_message_examples_reprex.md @@ -34,9 +34,13 @@ read_redcap(letters[1:3], classic_token) read_redcap("https://www.google.com", classic_token) #> Error in `read_redcap()`: #> ✖ The REDCapR export operation was not successful. -#> ! The URL returned the HTTP error code 405 (POST Method not allowed). -#> ℹ Are you sure the URI points to an active REDCap API endpoint? -#> ℹ URI: `https://www.google.com` +#> ! An unexpected error occured. +#> ℹ This means that you probably discovered a bug! +#> ℹ Please consider submitting a bug report here: +#> . +#> Caused by error in `redcap_metadata_read()`: +#> ! The REDCapR metadata export operation was not successful. The error message was: +#>

404 Not Found

read_redcap("https://www.google.comm", classic_token) #> Error in `read_redcap()`: @@ -255,7 +259,7 @@ withr::with_tempdir({ }) #> Error: #> ✖ File -#> ''/private/var/folders/qc/mmjjyjq50530z9r_7mfqcqfhxkkk67/T/RtmpQi1Xne/file52d750f31b3f/temp.csv'' +#> ''/private/var/folders/9c/k1m0bzys7gb1v32g86hfn5sn5k86h1/T/Rtmp1QPC0p/file5c744dd73619/temp.csv'' #> already exists. #> ℹ Overwriting files is disabled by default. Set `overwrite = TRUE` to overwrite #> existing file. @@ -296,7 +300,7 @@ withr::with_tempdir({ write_redcap_xlsx(file = filepath) }) #> Warning in write_redcap_xlsx(., file = filepath): ! No extension provided for `file`: -#> '/private/var/folders/qc/mmjjyjq50530z9r_7mfqcqfhxkkk67/T/RtmpQi1Xne/file52d72e91eb7b/temp' +#> '/private/var/folders/9c/k1m0bzys7gb1v32g86hfn5sn5k86h1/T/Rtmp1QPC0p/file5c7456597c2b/temp' #> ℹ The extension '.xlsx' will be appended to the file name. # Printed supertibble @@ -339,4 +343,4 @@ read_redcap(redcap_uri, Sys.getenv("REDCAPTIDIER_MDC_API")) #> # data_na_pct , form_complete_pct ``` -Created on 2024-03-27 with [reprex v2.1.0](https://reprex.tidyverse.org) +Created on 2024-04-10 with [reprex v2.1.0](https://reprex.tidyverse.org) diff --git a/utility/microbenchmark_results.csv b/utility/microbenchmark_results.csv index 63ee9ebd..a7186b18 100644 --- a/utility/microbenchmark_results.csv +++ b/utility/microbenchmark_results.csv @@ -1,42 +1,42 @@ min,lq,mean,median,uq,max,neval,description,source -1.16,1.16,1.16,1.16,1.16,1.16,1,simple static (read-only) test project,ouhsc -1.18,1.18,1.18,1.18,1.18,1.18,1,longitudinal (read-only) ARM test project,ouhsc -0.6,0.6,0.6,0.6,0.6,0.6,1,simple write data,ouhsc +1.15,1.15,1.15,1.15,1.15,1.15,1,simple static (read-only) test project,ouhsc +1.7,1.7,1.7,1.7,1.7,1.7,1,longitudinal (read-only) ARM test project,ouhsc +0.83,0.83,0.83,0.83,0.83,0.83,1,simple write data,ouhsc 1.79,1.79,1.79,1.79,1.79,1.79,1,Russian Characters,ouhsc -3.2,3.2,3.2,3.2,3.2,3.2,1,"super-wide --3,000 columns",ouhsc -0.68,0.68,0.68,0.68,0.68,0.68,1,static (not longitudinal) survey test project,ouhsc -0.68,0.68,0.68,0.68,0.68,0.68,1,"Clinical Trial (Fake) --Read-only, contributed by @higgi13425",ouhsc -0.58,0.58,0.58,0.58,0.58,0.58,1,nonnumeric record_id,ouhsc -0.6,0.6,0.6,0.6,0.6,0.6,1,DAG Read,ouhsc -0.58,0.58,0.58,0.58,0.58,0.58,1,potentially problematic values,ouhsc -0.68,0.68,0.68,0.68,0.68,0.68,1,Repeating Instruments,ouhsc -0.56,0.56,0.56,0.56,0.56,0.56,1,simple write metadata,ouhsc -0.65,0.65,0.65,0.65,0.65,0.65,1,DAG Write -admin,ouhsc -0.56,0.56,0.56,0.56,0.56,0.56,1,DAG Write -group A,ouhsc -130.23,130.23,130.23,130.23,130.23,130.23,1,"super-wide #3--35,000 columns",ouhsc -0.66,0.66,0.66,0.66,0.66,0.66,1,Repeating Instruments --Sparse,ouhsc -0.65,0.65,0.65,0.65,0.65,0.65,1,Delete Single Arm,ouhsc -1.04,1.04,1.04,1.04,1.04,1.04,1,Delete Multiple Arm,ouhsc -1.14,1.14,1.14,1.14,1.14,1.14,1,longitudinal single arm,ouhsc -0.62,0.62,0.62,0.62,0.62,0.62,1,decimal comma and dot,ouhsc -0.67,0.67,0.67,0.67,0.67,0.67,1,decimal comma,ouhsc -0.6,0.6,0.6,0.6,0.6,0.6,1,decimal dot,ouhsc -0.66,0.66,0.66,0.66,0.66,0.66,1,Validation Types,ouhsc -0.69,0.69,0.69,0.69,0.69,0.69,1,Blank for Gray Status,ouhsc -0.68,0.68,0.68,0.68,0.68,0.68,1,Checkboxes 1,ouhsc -0.67,0.67,0.67,0.67,0.67,0.67,1,Vignette: Longitudinal & Repeating Measures,ouhsc -0.9,0.9,0.9,0.9,0.9,0.9,1,classic,redcaptidier -0.82,0.82,0.82,0.82,0.82,0.82,1,classic no repeat,redcaptidier -1.27,1.27,1.27,1.27,1.27,1.27,1,longitudinal,redcaptidier -1.22,1.22,1.22,1.22,1.22,1.22,1,longitudinal no arms,redcaptidier -1.26,1.26,1.26,1.26,1.26,1.26,1,longitudinal no repeat,redcaptidier -1.62,1.62,1.62,1.62,1.62,1.62,1,deep dive vignette,redcaptidier -0.74,0.74,0.74,0.74,0.74,0.74,1,repeat first instrument,redcaptidier -1.23,1.23,1.23,1.23,1.23,1.23,1,repeat event,redcaptidier +3.37,3.37,3.37,3.37,3.37,3.37,1,"super-wide --3,000 columns",ouhsc +1,1,1,1,1,1,1,static (not longitudinal) survey test project,ouhsc +0.82,0.82,0.82,0.82,0.82,0.82,1,"Clinical Trial (Fake) --Read-only, contributed by @higgi13425",ouhsc +0.77,0.77,0.77,0.77,0.77,0.77,1,nonnumeric record_id,ouhsc +0.94,0.94,0.94,0.94,0.94,0.94,1,DAG Read,ouhsc +0.82,0.82,0.82,0.82,0.82,0.82,1,potentially problematic values,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,Repeating Instruments,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,simple write metadata,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,DAG Write -admin,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,DAG Write -group A,ouhsc +129.61,129.61,129.61,129.61,129.61,129.61,1,"super-wide #3--35,000 columns",ouhsc +0.82,0.82,0.82,0.82,0.82,0.82,1,Repeating Instruments --Sparse,ouhsc +0.8,0.8,0.8,0.8,0.8,0.8,1,Delete Single Arm,ouhsc +1.29,1.29,1.29,1.29,1.29,1.29,1,Delete Multiple Arm,ouhsc +1.55,1.55,1.55,1.55,1.55,1.55,1,longitudinal single arm,ouhsc +0.78,0.78,0.78,0.78,0.78,0.78,1,decimal comma and dot,ouhsc +0.82,0.82,0.82,0.82,0.82,0.82,1,decimal comma,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,decimal dot,ouhsc +0.87,0.87,0.87,0.87,0.87,0.87,1,Validation Types,ouhsc +0.81,0.81,0.81,0.81,0.81,0.81,1,Blank for Gray Status,ouhsc +0.97,0.97,0.97,0.97,0.97,0.97,1,Checkboxes 1,ouhsc +0.83,0.83,0.83,0.83,0.83,0.83,1,Vignette: Longitudinal & Repeating Measures,ouhsc +1.11,1.11,1.11,1.11,1.11,1.11,1,classic,redcaptidier +0.98,0.98,0.98,0.98,0.98,0.98,1,classic no repeat,redcaptidier +1.7,1.7,1.7,1.7,1.7,1.7,1,longitudinal,redcaptidier +1.67,1.67,1.67,1.67,1.67,1.67,1,longitudinal no arms,redcaptidier +1.51,1.51,1.51,1.51,1.51,1.51,1,longitudinal no repeat,redcaptidier +1.96,1.96,1.96,1.96,1.96,1.96,1,deep dive vignette,redcaptidier +0.99,0.99,0.99,0.99,0.99,0.99,1,repeat first instrument,redcaptidier +1.51,1.51,1.51,1.51,1.51,1.51,1,repeat event,redcaptidier 1.04,1.04,1.04,1.04,1.04,1.04,1,restricted access,redcaptidier -1.06,1.06,1.06,1.06,1.06,1.06,1,large sparse db,redcaptidier -0.74,0.74,0.74,0.74,0.74,0.74,1,data access groups,redcaptidier -1.35,1.35,1.35,1.35,1.35,1.35,1,longitudinal data access groups,redcaptidier -1.42,1.42,1.42,1.42,1.42,1.42,1,mixed structure repeat no repeat,redcaptidier -5.33,5.33,5.33,5.33,5.33,5.33,1,prodigy db,redcaptidier -8.95,8.95,8.95,8.95,8.95,8.95,1,cart comprehensive db,redcaptidier +0.97,0.97,0.97,0.97,0.97,0.97,1,large sparse db,redcaptidier +1.13,1.13,1.13,1.13,1.13,1.13,1,data access groups,redcaptidier +1.78,1.78,1.78,1.78,1.78,1.78,1,longitudinal data access groups,redcaptidier +2.06,2.06,2.06,2.06,2.06,2.06,1,mixed structure repeat no repeat,redcaptidier +4.62,4.62,4.62,4.62,4.62,4.62,1,prodigy db,redcaptidier +5.26,5.26,5.26,5.26,5.26,5.26,1,cart comprehensive db,redcaptidier diff --git a/utility/refresh.R b/utility/refresh.R index ca39131c..e17e061d 100644 --- a/utility/refresh.R +++ b/utility/refresh.R @@ -4,12 +4,12 @@ options(device = deviceType) #https://support.rstudio.org/help/discussions/probl spelling::spell_check_package() # spelling::update_wordlist() -lintr::lint_package() urlchecker::url_check(); urlchecker::url_update() styler::style_pkg() devtools::document() +lintr::lint_package() devtools::check_man() #Should return NULL # Run as not CRAN to build full vignettes @@ -63,8 +63,8 @@ devtools::check( # Equivalent of R-hub remote = TRUE, incoming = TRUE ) -# devtools::check_rhub(email="richardshanna91@gmail.com") -# devtools::check_win_devel(email = "richardshanna91@gmail.com") # CRAN submission policies encourage the development version +devtools::check_rhub(email="porterej@chop.edu") +devtools::check_win_devel(email = "porterej@chop.edu") # CRAN submission policies encourage the development version # Note: Must be off of VPN revdepcheck::revdep_check(num_workers = 4) # Careful, the last question ultimately uploads it to CRAN, where you can't delete/reverse your decision. diff --git a/utility/test_creds.R b/utility/test_creds.R index 0f263611..4f8fbf1b 100644 --- a/utility/test_creds.R +++ b/utility/test_creds.R @@ -5,7 +5,7 @@ library(dplyr) library(microbenchmark) # Load REDCapR creds -ouhsc_creds <- readr::read_csv(file = "utility/redcapr.example.credentials", skip = 5) %>% +ouhsc_creds <- readr::read_csv(file = "utility/redcapr.example.credentials", skip = 5, show_col_types = FALSE) %>% select(redcap_uri, token, comment) # Remove identified APIs that don't work @@ -38,11 +38,12 @@ redcaptidier_creds <- tibble::tribble( ) # Combine Credentials -creds <- rbind(ouhsc_creds %>% mutate(source = "ouhsc"), redcaptidier_creds %>% mutate(source = "redcaptidier")) +creds <- rbind(ouhsc_creds %>% mutate(source = "ouhsc"), redcaptidier_creds %>% mutate(source = "redcaptidier")) %>% + filter(token != "") microbenchmark_fx <- function(redcap_uri, token, name, times = 1){ microbenchmark( - name = read_redcap(redcap_uri = redcap_uri, token = token, allow_mixed_structure = TRUE), + name = suppressWarnings(read_redcap(redcap_uri = redcap_uri, token = token, allow_mixed_structure = TRUE)), times = times, unit = "seconds" )