diff --git a/NEWS.md b/NEWS.md index 8cb31910..6222ec9f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,7 @@ These features are not yet on CRAN. Install with `remotes::install_github("Ouhs * New parameter `blank_for_gray_form_status` in the functions `redcap_read()`, `redcap_read_oneshot()`, and `redcap_read_oneshot_eav()`. (@greg-botwin, #386, #389) * A `httr::handle` value is accepted by functions that contact the server. This will accommodate some institutions with unconventional environments. (Suggested by @brandonpotvin, #429) * `sanitized_token()` now accepts an alternative regex pattern. (Suggested by @maeon & @michalkouril, #370) +* `redcap_read_eav_oneshot()` is an UNexported function that returns data in an EAV format (#437) ### Minor Enhancements diff --git a/R/redcap-read-eav-oneshot.R b/R/redcap-read-eav-oneshot.R new file mode 100644 index 00000000..95cd21d0 --- /dev/null +++ b/R/redcap-read-eav-oneshot.R @@ -0,0 +1,371 @@ +#' @title +#' Read/Export records from a REDCap project, returned as eav +#' +#' @description +#' This function uses REDCap's API to select and return data in an +#' [eav] +#' (https://en.wikipedia.org/wiki/Entity%E2%80%93attribute%E2%80%93value_model) +#' +#' @param redcap_uri The +#' [uri](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)/url +#' of the REDCap server +#' typically formatted as "https://server.org/apps/redcap/api/". +#' Required. +#' @param token The user-specific string that serves as the password for a +#' project. Required. +#' @param records An array, where each element corresponds to the ID of a +#' desired record. Optional. +#' @param records_collapsed A single string, where the desired ID values +#' are separated by commas. Optional. +#' @param fields An array, where each element corresponds to a desired project +#' field. Optional. +#' @param fields_collapsed A single string, where the desired field names are +#' separated by commas. Optional. +#' @param forms An array, where each element corresponds to a desired project +#' form. Optional. +#' @param forms_collapsed A single string, where the desired form names are +#' separated by commas. Optional. +#' @param events An array, where each element corresponds to a desired project +#' event. Optional. +#' @param events_collapsed A single string, where the desired event names are +#' separated by commas. Optional. +# @param raw_or_label A string (either `'raw'` or `'label'`) that specifies +# whether to export the raw coded values or the labels for the options of +# multiple choice fields. Default is `'raw'`. +# @param raw_or_label_headers A string (either `'raw'` or `'label'` that +# specifies for the CSV headers whether to export the variable/field names +# (raw) or the field labels (label). Default is `'raw'`. +# @param export_checkbox_label specifies the format of checkbox field values +# specifically when exporting the data as labels. If `raw_or_label` is +# `'label'` and `export_checkbox_label` is TRUE, the values will be the text +# displayed to the users. Otherwise, the values will be 0/1. +# placeholder: returnFormat +#' @param export_survey_fields A boolean that specifies whether to export the +#' survey identifier field (e.g., 'redcap_survey_identifier') or survey +#' timestamp fields (e.g., instrument+'_timestamp'). +#' The timestamp outputs reflect the survey's *completion* time +#' (according to the time and timezone of the REDCap server.) +#' @param export_data_access_groups A boolean value that specifies whether or +#' not to export the `redcap_data_access_group` field when data access groups +#' are utilized in the project. Default is `FALSE`. See the details below. +#' @param filter_logic String of logic text (e.g., `[gender] = 'male'`) for +#' filtering the data to be returned by this API method, in which the API will +#' only return the records (or record-events, if a longitudinal project) where +#' the logic evaluates as TRUE. An blank/empty string returns all records. +#' @param datetime_range_begin To return only records that have been created or +#' modified *after* a given datetime, provide a +#' [POSIXct](https://stat.ethz.ch/R-manual/R-devel/library/base/html/as.POSIXlt.html) +#' value. +#' If not specified, REDCap will assume no begin time. +#' @param datetime_range_end To return only records that have been created or +#' modified *before* a given datetime, provide a +#' [POSIXct](https://stat.ethz.ch/R-manual/R-devel/library/base/html/as.POSIXlt.html) +#' value. +#' If not specified, REDCap will assume no end time. +#' @param blank_for_gray_form_status A boolean value that specifies whether +#' or not to export blank values for instrument complete status fields that have +#' a gray status icon. All instrument complete status fields having a gray icon +#' can be exported either as a blank value or as "0" (Incomplete). Blank values +#' are recommended in a data export if the data will be re-imported into a +#' REDCap project. Default is `FALSE`. +# @param col_types A [readr::cols()] object passed internally to +# [readr::read_csv()]. Optional. +# @param guess_type A boolean value indicating if all columns should be +# returned as character. If true, [readr::read_csv()] guesses the intended +# data type for each column. Ignored if `col_types` is not null. +# @param guess_max A positive [base::numeric] value +# passed to [readr::read_csv()] that +# specifies the maximum number of records to use for guessing column types. +#' @param http_response_encoding The encoding value passed to +#' [httr::content()]. Defaults to 'UTF-8'. +#' @param locale a [readr::locale()] object to specify preferences like +#' number, date, and time formats. This object is passed to +#' [readr::read_csv()]. Defaults to [readr::default_locale()]. +#' @param verbose A boolean value indicating if `message`s should be printed +#' to the R console during the operation. The verbose output might contain +#' sensitive information (*e.g.* PHI), so turn this off if the output might +#' be visible somewhere public. Optional. +#' @param config_options A list of options passed to [httr::POST()]. +#' See details at [httr::httr_options()]. Optional. +#' @param handle_httr The value passed to the `handle` parameter of +#' [httr::POST()]. +#' This is useful for only unconventional authentication approaches. It +#' should be `NULL` for most institutions. Optional. +# @param encode_httr The value passed to the `encode` parameter of +# [httr::POST()]. +# This is useful for only unconventional authentication approaches. +# Defaults to `"multipart"`, which is appropriate for most institutions. +#' +#' @return +#' Currently, a list is returned with the following elements: +#' * `data`: A [tibble::tibble()] of the desired records and columns. +#' * `success`: A boolean value indicating if the operation was apparently +#' successful. +#' * `status_code`: The +#' [http status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) +#' of the operation. +#' * `outcome_message`: A human readable string indicating the operation's +#' outcome. +#' * `records_collapsed`: The desired records IDs, collapsed into a single +#' string, separated by commas. +#' * `fields_collapsed`: The desired field names, collapsed into a single +#' string, separated by commas. +#' * `filter_logic`: The filter statement passed as an argument. +#' * `elapsed_seconds`: The duration of the function. +#' * `raw_text`: If an operation is NOT successful, the text returned by +#' REDCap. If an operation is successful, the `raw_text` is returned as an +#' empty string to save RAM. +#' +#' @details +#' If you do not pass an `export_data_access_groups` value, it will default +#' to `FALSE`. The following is from the API help page for version 10.5.1: +#' *This flag is only viable if the user whose token is being used to make the +#' API request is **not** in a data access group. If the user is in a group, +#' then this flag will revert to its default value*. +#' +#' @author +#' Will Beasley +#' +#' @references +#' The official documentation can be found on the 'API Help Page' +#' and 'API Examples' pages on the REDCap wiki (*i.e.*, +#' https://community.projectredcap.org/articles/456/api-documentation.html and +#' https://community.projectredcap.org/articles/462/api-examples.html). +#' If you do not have an account for the wiki, please ask your campus REDCap +#' administrator to send you the static material. +#' +#' @examples +#' \dontrun{ +#' uri <- "https://bbmc.ouhsc.edu/redcap/api/" +#' token <- "9A81268476645C4E5F03428B8AC3AA7B" +#' +#' # Return all records and all variables. +#' ds <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=uri, token=token)$data +#' +#' # Return only records with IDs of 1 and 3 +#' desired_records_v1 <- c(1, 3) +#' ds_some_rows_v1 <- REDCapR:::redcap_read_eav_oneshot( +#' redcap_uri = uri, +#' token = token, +#' records = desired_records_v1 +#' )$data +#' +#' # Return only the fields record_id, name_first, and age +#' desired_fields_v1 <- c("record_id", "name_first", "age") +#' ds_some_fields_v1 <- REDCapR:::redcap_read_eav_oneshot( +#' redcap_uri = uri, +#' token = token, +#' fields = desired_fields_v1 +#' )$data +#' +# # Specify the column types. +# col_types <- readr::cols( +# record_id = readr::col_integer(), +# race___1 = readr::col_logical(), +# race___2 = readr::col_logical(), +# race___3 = readr::col_logical(), +# race___4 = readr::col_logical(), +# race___5 = readr::col_logical(), +# race___6 = readr::col_logical() +# ) +# ds_col_types <- REDCapR:::redcap_read_eav_oneshot( +# redcap_uri = uri, +# token = token, +# col_types = col_types +# )$data +#' } + +#' @importFrom magrittr %>% +# Intentionally NOT exporting for now: @export +redcap_read_eav_oneshot <- function( + redcap_uri, + token, + records = NULL, + records_collapsed = "", + fields = NULL, + fields_collapsed = "", + forms = NULL, + forms_collapsed = "", + events = NULL, + events_collapsed = "", + # raw_or_label = "raw", + # raw_or_label_headers = "raw", + # export_checkbox_label = FALSE, + # placeholder returnFormat + export_survey_fields = FALSE, + export_data_access_groups = FALSE, + filter_logic = "", + datetime_range_begin = as.POSIXct(NA), + datetime_range_end = as.POSIXct(NA), + blank_for_gray_form_status = FALSE, + # col_types = NULL, + # guess_type = TRUE, + # guess_max = 1000, + http_response_encoding = "UTF-8", + locale = readr::default_locale(), + verbose = TRUE, + config_options = NULL, + handle_httr = NULL + # encode_httr = "multipart" +) { + + checkmate::assert_character(redcap_uri , any.missing=FALSE, len=1, pattern="^.{1,}$") + checkmate::assert_character(token , any.missing=FALSE, len=1, pattern="^.{1,}$") + checkmate::assert_atomic(records , any.missing=TRUE , min.len=0) + checkmate::assert_character(records_collapsed , any.missing=TRUE , len=1, pattern="^.{0,}$", null.ok=TRUE) + checkmate::assert_character(fields , any.missing=TRUE , min.len=1, pattern="^.{1,}$", null.ok=TRUE) + checkmate::assert_character(fields_collapsed , any.missing=TRUE , len=1, pattern="^.{0,}$", null.ok=TRUE) + checkmate::assert_character(forms , any.missing=TRUE , min.len=1, pattern="^.{1,}$", null.ok=TRUE) + checkmate::assert_character(forms_collapsed , any.missing=TRUE , len=1, pattern="^.{0,}$", null.ok=TRUE) + checkmate::assert_character(events , any.missing=TRUE , min.len=1, pattern="^.{1,}$", null.ok=TRUE) + checkmate::assert_character(events_collapsed , any.missing=TRUE , len=1, pattern="^.{0,}$", null.ok=TRUE) +# checkmate::assert_character(raw_or_label , any.missing=FALSE, len=1) +# checkmate::assert_subset( raw_or_label , c("raw", "label")) +# checkmate::assert_character(raw_or_label_headers , any.missing=FALSE, len=1) +# checkmate::assert_subset( raw_or_label_headers , c("raw", "label")) +# checkmate::assert_logical( export_checkbox_label , any.missing=FALSE, len=1) + # placeholder: returnFormat + checkmate::assert_logical( export_survey_fields , any.missing=FALSE, len=1) + checkmate::assert_logical( export_data_access_groups , any.missing=FALSE, len=1) + checkmate::assert_character(filter_logic , any.missing=FALSE, len=1, pattern="^.{0,}$") + checkmate::assert_posixct( datetime_range_begin , any.missing=TRUE , len=1, null.ok=TRUE) + checkmate::assert_posixct( datetime_range_end , any.missing=TRUE , len=1, null.ok=TRUE) + checkmate::assert_logical( blank_for_gray_form_status , any.missing=FALSE, len=1) + +# checkmate::assert_logical( guess_type , any.missing=FALSE, len=1) +# checkmate::assert_numeric( guess_max , any.missing=FALSE, len=1, lower=1) + + checkmate::assert_character(http_response_encoding , any.missing=FALSE, len=1) + checkmate::assert_class( locale, "locale" , null.ok = FALSE) + checkmate::assert_logical( verbose , any.missing=FALSE, len=1, null.ok=TRUE) + checkmate::assert_list( config_options , any.missing=TRUE , null.ok=TRUE) + # checkmate::assert_character(encode_httr , any.missing=FALSE, len=1, null.ok = FALSE) + + validate_field_names(fields, stop_on_error = TRUE) + + token <- sanitize_token(token) + records_collapsed <- collapse_vector(records , records_collapsed) + fields_collapsed <- collapse_vector(fields , fields_collapsed) + forms_collapsed <- collapse_vector(forms , forms_collapsed) + events_collapsed <- collapse_vector(events , events_collapsed) + filter_logic <- filter_logic_prepare(filter_logic) + datetime_range_begin<- dplyr::coalesce(strftime(datetime_range_begin, "%Y-%m-%d %H:%M:%S"), "") + datetime_range_end <- dplyr::coalesce(strftime(datetime_range_end , "%Y-%m-%d %H:%M:%S"), "") + verbose <- verbose_prepare(verbose) + + if (1L <= nchar(fields_collapsed) ) + validate_field_names_collapsed(fields_collapsed, stop_on_error = TRUE) + + post_body <- list( + token = token, + content = "record", + format = "csv", + type = "eav", + # rawOrLabel = raw_or_label, + # rawOrLabelHeaders = raw_or_label_headers, + # exportCheckboxLabel = tolower(as.character(export_checkbox_label)), + # placeholder: returnFormat + exportSurveyFields = tolower(as.character(export_survey_fields)), + exportDataAccessGroups = tolower(as.character(export_data_access_groups)), + filterLogic = filter_logic, + dateRangeBegin = datetime_range_begin, + dateRangeEnd = datetime_range_end, + exportBlankForGrayFormStatus = blank_for_gray_form_status + # record, fields, forms & events are specified below + ) + + if (0L < nchar(records_collapsed)) post_body$records <- records_collapsed + if (0L < nchar(fields_collapsed )) post_body$fields <- fields_collapsed + if (0L < nchar(forms_collapsed )) post_body$forms <- forms_collapsed + if (0L < nchar(events_collapsed )) post_body$events <- events_collapsed + + # This is the important call that communicates with the REDCap server. + kernel <- kernel_api( + redcap_uri = redcap_uri, + post_body = post_body, + config_options = config_options, + encoding = http_response_encoding, + handle_httr = handle_httr + # encode_httr = encode_httr + ) + + if (kernel$success) { + # col_types <- + # if (!is.null(col_types)) col_types + # else if (guess_type) NULL + # else readr::cols(.default = readr::col_character()) + + try( + # Convert the raw text to a dataset. + ds <- + readr::read_csv( + file = I(kernel$raw_text), + col_types = readr::cols(.default = readr::col_character()), + # guess_max = guess_max, + locale = locale, + show_col_types = FALSE + ), + + # Don't print the warning in the try block. Print it below, + # where it's under the control of the caller. + silent = TRUE + ) + + if (exists("ds") && inherits(ds, "data.frame")) { + outcome_message <- sprintf( + "%s records and %s columns were read from REDCap in %0.1f seconds. The http status code was %i.", + format( nrow(ds), big.mark = ",", scientific = FALSE, trim = TRUE), + format(length(ds), big.mark = ",", scientific = FALSE, trim = TRUE), + kernel$elapsed_seconds, + kernel$status_code + ) + + # If an operation is successful, the `raw_text` is no longer returned to + # save RAM. The content is not really necessary with httr's status + # message exposed. + kernel$raw_text <- "" + } else { # ds doesn't exist as a data.frame. + # nocov start + # Override the 'success' determination from the http status code. + # and return an empty data.frame. + kernel$success <- FALSE + ds <- tibble::tibble() + outcome_message <- sprintf( + "The REDCap read failed. The http status code was %i. The 'raw_text' returned was '%s'.", + kernel$status_code, + kernel$raw_text + ) + # nocov end + } + } else { # kernel fails + ds <- tibble::tibble() # Return an empty data.frame + outcome_message <- + if (any(grepl(kernel$regex_empty, kernel$raw_text))) { + "The REDCapR read/export operation was not successful. The returned dataset was empty." # nocov + } else { + sprintf( + "The REDCapR read/export operation was not successful. The error message was:\n%s", + kernel$raw_text + ) + } + } + + if (verbose) + message(outcome_message) + + list( + data = ds, + success = kernel$success, + status_code = kernel$status_code, + outcome_message = outcome_message, + records_collapsed = records_collapsed, + fields_collapsed = fields_collapsed, + forms_collapsed = forms_collapsed, + events_collapsed = events_collapsed, + filter_logic = filter_logic, + datetime_range_begin = datetime_range_begin, + datetime_range_end = datetime_range_end, + elapsed_seconds = kernel$elapsed_seconds, + raw_text = kernel$raw_text + ) +} diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-false.R b/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-false.R new file mode 100644 index 00000000..d25725e7 --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-false.R @@ -0,0 +1,52 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5", "6", "6", "6", "6"), field_name = c("address", +"age", "bmi", "comments", "demographics_complete", "dob", "email", +"ethnicity", "health_complete", "height", "interpreter_needed", +"mugshot", "name_first", "name_last", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "interpreter_needed", "mugshot", +"name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "interpreter_needed", "mugshot", +"name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "mugshot", "name_first", "name_last", +"race", "race", "race_and_ethnicity_complete", "record_id", "sex", +"telephone", "weight", "address", "age", "bmi", "comments", "demographics_complete", +"dob", "email", "ethnicity", "health_complete", "height", "interpreter_needed", +"mugshot", "name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "name_first", "name_last", +"demographics_complete", "record_id"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"11", "204.1", "Character in a book, with some guessing", "2", +"2003-08-30", "nutty@mouse.com", "1", "1", "7", "0", "324901", +"Nutmeg", "Nutmouse", "5", "2", "1", "0", "(405) 321-1111", "1", +"14 Rose Cottage Blvd.\nKenning UK 34243", "11", "277.8", "A mouse character from a good book", +"2", "2003-03-10", "tummy@mouse.comm", "1", "0", "6", "0", "324902", +"Tumtum", "Nutmouse", "3", "5", "0", "2", "1", "(405) 321-2222", +"1", "243 Hill St.\nGuthrie OK 73402", "80", "24.7", "completely made up", +"2", "1934-04-09", "mw@mwood.net", "0", "2", "180", "1", "324903", +"Marcus", "Wood", "4", "5", "2", "3", "1", "(405) 321-3333", +"80", "342 Elm\nDuncanville TX, 75116", "61", "19.8", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"2", "1952-11-02", "peroxide@blonde.com", "1", "2", "165", "324904", +"Trudy", "DAG", "2", "5", "2", "4", "0", "(405) 321-4444", "54", +"Hotel Suite\nNew Orleans LA, 70115", "59", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"2", "1955-04-15", "left@hippocket.com", "2", "0", "193.04", +"0", "324905", "John Lee", "Walker", "1", "6", "2", "5", "1", +"(405) 321-5555", "104", "blank-for-gray", "blank-for-gray", +"0", "6")), row.names = c(NA, -107L), spec = structure(list(cols = list( + record = structure(list(), class = c("collector_character", + "collector")), field_name = structure(list(), class = c("collector_character", + "collector")), value = structure(list(), class = c("collector_character", + "collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-true.R b/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-true.R new file mode 100644 index 00000000..d25725e7 --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-true.R @@ -0,0 +1,52 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5", "6", "6", "6", "6"), field_name = c("address", +"age", "bmi", "comments", "demographics_complete", "dob", "email", +"ethnicity", "health_complete", "height", "interpreter_needed", +"mugshot", "name_first", "name_last", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "interpreter_needed", "mugshot", +"name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "interpreter_needed", "mugshot", +"name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "address", "age", +"bmi", "comments", "demographics_complete", "dob", "email", "ethnicity", +"health_complete", "height", "mugshot", "name_first", "name_last", +"race", "race", "race_and_ethnicity_complete", "record_id", "sex", +"telephone", "weight", "address", "age", "bmi", "comments", "demographics_complete", +"dob", "email", "ethnicity", "health_complete", "height", "interpreter_needed", +"mugshot", "name_first", "name_last", "race", "race", "race_and_ethnicity_complete", +"record_id", "sex", "telephone", "weight", "name_first", "name_last", +"demographics_complete", "record_id"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"11", "204.1", "Character in a book, with some guessing", "2", +"2003-08-30", "nutty@mouse.com", "1", "1", "7", "0", "324901", +"Nutmeg", "Nutmouse", "5", "2", "1", "0", "(405) 321-1111", "1", +"14 Rose Cottage Blvd.\nKenning UK 34243", "11", "277.8", "A mouse character from a good book", +"2", "2003-03-10", "tummy@mouse.comm", "1", "0", "6", "0", "324902", +"Tumtum", "Nutmouse", "3", "5", "0", "2", "1", "(405) 321-2222", +"1", "243 Hill St.\nGuthrie OK 73402", "80", "24.7", "completely made up", +"2", "1934-04-09", "mw@mwood.net", "0", "2", "180", "1", "324903", +"Marcus", "Wood", "4", "5", "2", "3", "1", "(405) 321-3333", +"80", "342 Elm\nDuncanville TX, 75116", "61", "19.8", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"2", "1952-11-02", "peroxide@blonde.com", "1", "2", "165", "324904", +"Trudy", "DAG", "2", "5", "2", "4", "0", "(405) 321-4444", "54", +"Hotel Suite\nNew Orleans LA, 70115", "59", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"2", "1955-04-15", "left@hippocket.com", "2", "0", "193.04", +"0", "324905", "John Lee", "Walker", "1", "6", "2", "5", "1", +"(405) 321-5555", "104", "blank-for-gray", "blank-for-gray", +"0", "6")), row.names = c(NA, -107L), spec = structure(list(cols = list( + record = structure(list(), class = c("collector_character", + "collector")), field_name = structure(list(), class = c("collector_character", + "collector")), value = structure(list(), class = c("collector_character", + "collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/default.R b/inst/test-data/specific-redcapr/read-eav-oneshot/default.R new file mode 100644 index 00000000..880c3b5f --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/default.R @@ -0,0 +1,51 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5"), field_name = c("address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "race", "sex", "height", +"weight", "bmi", "comments", "demographics_complete", "record_id", +"name_first", "name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "ethnicity", "sex", "height", "weight", "bmi", +"demographics_complete", "record_id", "comments", "age", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "address", "demographics_complete", +"record_id", "telephone", "email", "dob", "age", "ethnicity", +"sex", "height", "weight", "bmi", "comments", "name_first", "name_last", +"health_complete", "race_and_ethnicity_complete", "race", "race", +"mugshot", "interpreter_needed"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"(405) 321-1111", "nutty@mouse.com", "2003-08-30", "11", "1", +"0", "7", "1", "204.1", "Character in a book, with some guessing", +"2", "1", "Nutmeg", "Nutmouse", "1", "2", "5", "197977", "0", +"14 Rose Cottage Blvd.\nKenning UK 34243", "(405) 321-2222", +"tummy@mouse.comm", "2003-03-10", "11", "1", "1", "6", "1", "277.8", +"A mouse character from a good book", "2", "2", "Tumtum", "Nutmouse", +"0", "0", "3", "5", "197978", "0", "243 Hill St.\nGuthrie OK 73402", +"(405) 321-3333", "mw@mwood.net", "1934-04-09", "80", "0", "4", +"1", "180", "80", "24.7", "completely made up", "2", "3", "Marcus", +"Wood", "2", "2", "5", "197979", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"165", "54", "19.8", "2", "4", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"61", "Trudy", "DAG", "2", "2", "2", "5", "198002", "Hotel Suite\nNew Orleans LA, 70115", +"2", "5", "(405) 321-5555", "left@hippocket.com", "1955-04-15", +"59", "2", "1", "193.04", "104", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"John Lee", "Walker", "0", "2", "1", "6", "198021", "0")), row.names = c(NA, +-103L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/filter-character.R b/inst/test-data/specific-redcapr/read-eav-oneshot/filter-character.R new file mode 100644 index 00000000..53153083 --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/filter-character.R @@ -0,0 +1,16 @@ +structure(list(record = c("5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5"), field_name = c("address", "demographics_complete", "record_id", +"telephone", "email", "dob", "age", "ethnicity", "sex", "height", +"weight", "bmi", "comments", "name_first", "name_last", "health_complete", +"race_and_ethnicity_complete", "race", "race", "mugshot", "interpreter_needed" +), value = c("Hotel Suite\nNew Orleans LA, 70115", "2", "5", +"(405) 321-5555", "left@hippocket.com", "1955-04-15", "59", "2", +"1", "193.04", "104", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"John Lee", "Walker", "0", "2", "1", "6", "198021", "0")), row.names = c(NA, +-21L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/filter-numeric.R b/inst/test-data/specific-redcapr/read-eav-oneshot/filter-numeric.R new file mode 100644 index 00000000..7979a924 --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/filter-numeric.R @@ -0,0 +1,24 @@ +structure(list(record = c("3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4"), field_name = c("address", +"telephone", "email", "dob", "age", "ethnicity", "race", "sex", +"height", "weight", "bmi", "comments", "demographics_complete", +"record_id", "name_first", "name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "ethnicity", "sex", "height", "weight", "bmi", +"demographics_complete", "record_id", "comments", "age", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot"), value = c("243 Hill St.\nGuthrie OK 73402", +"(405) 321-3333", "mw@mwood.net", "1934-04-09", "80", "0", "4", +"1", "180", "80", "24.7", "completely made up", "2", "3", "Marcus", +"Wood", "2", "2", "5", "197979", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"165", "54", "19.8", "2", "4", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"61", "Trudy", "DAG", "2", "2", "2", "5", "198002")), row.names = c(NA, +-41L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields-zero-length.R b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields-zero-length.R new file mode 100644 index 00000000..880c3b5f --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields-zero-length.R @@ -0,0 +1,51 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5"), field_name = c("address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "race", "sex", "height", +"weight", "bmi", "comments", "demographics_complete", "record_id", +"name_first", "name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "ethnicity", "sex", "height", "weight", "bmi", +"demographics_complete", "record_id", "comments", "age", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "address", "demographics_complete", +"record_id", "telephone", "email", "dob", "age", "ethnicity", +"sex", "height", "weight", "bmi", "comments", "name_first", "name_last", +"health_complete", "race_and_ethnicity_complete", "race", "race", +"mugshot", "interpreter_needed"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"(405) 321-1111", "nutty@mouse.com", "2003-08-30", "11", "1", +"0", "7", "1", "204.1", "Character in a book, with some guessing", +"2", "1", "Nutmeg", "Nutmouse", "1", "2", "5", "197977", "0", +"14 Rose Cottage Blvd.\nKenning UK 34243", "(405) 321-2222", +"tummy@mouse.comm", "2003-03-10", "11", "1", "1", "6", "1", "277.8", +"A mouse character from a good book", "2", "2", "Tumtum", "Nutmouse", +"0", "0", "3", "5", "197978", "0", "243 Hill St.\nGuthrie OK 73402", +"(405) 321-3333", "mw@mwood.net", "1934-04-09", "80", "0", "4", +"1", "180", "80", "24.7", "completely made up", "2", "3", "Marcus", +"Wood", "2", "2", "5", "197979", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"165", "54", "19.8", "2", "4", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"61", "Trudy", "DAG", "2", "2", "2", "5", "198002", "Hotel Suite\nNew Orleans LA, 70115", +"2", "5", "(405) 321-5555", "left@hippocket.com", "1955-04-15", +"59", "2", "1", "193.04", "104", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"John Lee", "Walker", "0", "2", "1", "6", "198021", "0")), row.names = c(NA, +-103L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields.R b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields.R new file mode 100644 index 00000000..27d7ded0 --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-fields.R @@ -0,0 +1,15 @@ +structure(list(record = c("1", "1", "1", "1", "2", "2", "2", +"2", "3", "3", "3", "3", "4", "4", "4", "4", "5", "5", "5", "5" +), field_name = c("age", "record_id", "name_first", "name_last", +"age", "record_id", "name_first", "name_last", "age", "record_id", +"name_first", "name_last", "record_id", "age", "name_first", +"name_last", "record_id", "age", "name_first", "name_last"), + value = c("11", "1", "Nutmeg", "Nutmouse", "11", "2", "Tumtum", + "Nutmouse", "80", "3", "Marcus", "Wood", "4", "61", "Trudy", + "DAG", "5", "59", "John Lee", "Walker")), row.names = c(NA, +-20L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/specify-forms.R b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-forms.R new file mode 100644 index 00000000..7209eb0b --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-forms.R @@ -0,0 +1,38 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5"), field_name = c("address", "telephone", "email", "dob", +"age", "ethnicity", "sex", "demographics_complete", "record_id", +"name_first", "name_last", "race_and_ethnicity_complete", "race", +"interpreter_needed", "address", "telephone", "email", "dob", +"age", "ethnicity", "sex", "demographics_complete", "record_id", +"name_first", "name_last", "race_and_ethnicity_complete", "race", +"race", "interpreter_needed", "address", "telephone", "email", +"dob", "age", "ethnicity", "race", "sex", "demographics_complete", +"record_id", "name_first", "name_last", "race_and_ethnicity_complete", +"race", "interpreter_needed", "address", "telephone", "email", +"dob", "ethnicity", "sex", "demographics_complete", "record_id", +"age", "name_first", "name_last", "race_and_ethnicity_complete", +"race", "race", "address", "demographics_complete", "record_id", +"telephone", "email", "dob", "age", "ethnicity", "sex", "name_first", +"name_last", "race_and_ethnicity_complete", "race", "race", "interpreter_needed" +), value = c("14 Rose Cottage St.\nKenning UK, 323232", "(405) 321-1111", +"nutty@mouse.com", "2003-08-30", "11", "1", "0", "2", "1", "Nutmeg", +"Nutmouse", "2", "5", "0", "14 Rose Cottage Blvd.\nKenning UK 34243", +"(405) 321-2222", "tummy@mouse.comm", "2003-03-10", "11", "1", +"1", "2", "2", "Tumtum", "Nutmouse", "0", "3", "5", "0", "243 Hill St.\nGuthrie OK 73402", +"(405) 321-3333", "mw@mwood.net", "1934-04-09", "80", "0", "4", +"1", "2", "3", "Marcus", "Wood", "2", "5", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"2", "4", "61", "Trudy", "DAG", "2", "2", "5", "Hotel Suite\nNew Orleans LA, 70115", +"2", "5", "(405) 321-5555", "left@hippocket.com", "1955-04-15", +"59", "2", "1", "John Lee", "Walker", "2", "1", "6", "0")), row.names = c(NA, +-73L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records-zero-length.R b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records-zero-length.R new file mode 100644 index 00000000..880c3b5f --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records-zero-length.R @@ -0,0 +1,51 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", +"2", "2", "2", "2", "2", "2", "2", "2", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "5", "5", "5", +"5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", "5", +"5", "5", "5", "5", "5"), field_name = c("address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "sex", "height", "weight", +"bmi", "comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "age", "ethnicity", "race", "sex", "height", +"weight", "bmi", "comments", "demographics_complete", "record_id", +"name_first", "name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "ethnicity", "sex", "height", "weight", "bmi", +"demographics_complete", "record_id", "comments", "age", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot", "address", "demographics_complete", +"record_id", "telephone", "email", "dob", "age", "ethnicity", +"sex", "height", "weight", "bmi", "comments", "name_first", "name_last", +"health_complete", "race_and_ethnicity_complete", "race", "race", +"mugshot", "interpreter_needed"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"(405) 321-1111", "nutty@mouse.com", "2003-08-30", "11", "1", +"0", "7", "1", "204.1", "Character in a book, with some guessing", +"2", "1", "Nutmeg", "Nutmouse", "1", "2", "5", "197977", "0", +"14 Rose Cottage Blvd.\nKenning UK 34243", "(405) 321-2222", +"tummy@mouse.comm", "2003-03-10", "11", "1", "1", "6", "1", "277.8", +"A mouse character from a good book", "2", "2", "Tumtum", "Nutmouse", +"0", "0", "3", "5", "197978", "0", "243 Hill St.\nGuthrie OK 73402", +"(405) 321-3333", "mw@mwood.net", "1934-04-09", "80", "0", "4", +"1", "180", "80", "24.7", "completely made up", "2", "3", "Marcus", +"Wood", "2", "2", "5", "197979", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"165", "54", "19.8", "2", "4", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"61", "Trudy", "DAG", "2", "2", "2", "5", "198002", "Hotel Suite\nNew Orleans LA, 70115", +"2", "5", "(405) 321-5555", "left@hippocket.com", "1955-04-15", +"59", "2", "1", "193.04", "104", "27.9", "Had a hand for trouble and a eye for cash\n\nHe had a gold watch chain and a black mustache", +"John Lee", "Walker", "0", "2", "1", "6", "198021", "0")), row.names = c(NA, +-103L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records.R b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records.R new file mode 100644 index 00000000..12c3f92b --- /dev/null +++ b/inst/test-data/specific-redcapr/read-eav-oneshot/specify-records.R @@ -0,0 +1,33 @@ +structure(list(record = c("1", "1", "1", "1", "1", "1", "1", +"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", +"3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", "3", +"3", "3", "3", "3", "3", "3", "3", "3", "4", "4", "4", "4", "4", +"4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4", +"4", "4"), field_name = c("address", "telephone", "email", "dob", +"age", "ethnicity", "sex", "height", "weight", "bmi", "comments", +"demographics_complete", "record_id", "name_first", "name_last", +"health_complete", "race_and_ethnicity_complete", "race", "mugshot", +"interpreter_needed", "address", "telephone", "email", "dob", +"age", "ethnicity", "race", "sex", "height", "weight", "bmi", +"comments", "demographics_complete", "record_id", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "mugshot", "interpreter_needed", "address", "telephone", +"email", "dob", "ethnicity", "sex", "height", "weight", "bmi", +"demographics_complete", "record_id", "comments", "age", "name_first", +"name_last", "health_complete", "race_and_ethnicity_complete", +"race", "race", "mugshot"), value = c("14 Rose Cottage St.\nKenning UK, 323232", +"(405) 321-1111", "nutty@mouse.com", "2003-08-30", "11", "1", +"0", "7", "1", "204.1", "Character in a book, with some guessing", +"2", "1", "Nutmeg", "Nutmouse", "1", "2", "5", "197977", "0", +"243 Hill St.\nGuthrie OK 73402", "(405) 321-3333", "mw@mwood.net", +"1934-04-09", "80", "0", "4", "1", "180", "80", "24.7", "completely made up", +"2", "3", "Marcus", "Wood", "2", "2", "5", "197979", "1", "342 Elm\nDuncanville TX, 75116", +"(405) 321-4444", "peroxide@blonde.com", "1952-11-02", "1", "0", +"165", "54", "19.8", "2", "4", "This record doesn't have a DAG assigned\n\nSo call up Trudy on the telephone\nSend her a letter in the mail", +"61", "Trudy", "DAG", "2", "2", "2", "5", "198002")), row.names = c(NA, +-61L), spec = structure(list(cols = list(record = structure(list(), class = c("collector_character", +"collector")), field_name = structure(list(), class = c("collector_character", +"collector")), value = structure(list(), class = c("collector_character", +"collector"))), default = structure(list(), class = c("collector_character", +"collector")), delim = ","), class = "col_spec"), class = c("spec_tbl_df", +"tbl_df", "tbl", "data.frame")) diff --git a/man/redcap_metadata_coltypes.Rd b/man/redcap_metadata_coltypes.Rd index 576daafc..f602be47 100644 --- a/man/redcap_metadata_coltypes.Rd +++ b/man/redcap_metadata_coltypes.Rd @@ -147,7 +147,7 @@ col_types <- redcap_metadata_coltypes(uri, token) redcap_read_oneshot(uri, token, col_types = col_types)$data # A project with every field type and validation type. -# Notice It throws a warning that some fields use a comma for a decimal, +# Notice it throws a warning that some fields use a comma for a decimal, # while other fields use a period/dot as a decimal token <- "8F5313CAA266789F560D79EFCEE2E2F1" # 2634 - Validation Types col_types <- redcap_metadata_coltypes(uri, token) diff --git a/man/redcap_read_eav_oneshot.Rd b/man/redcap_read_eav_oneshot.Rd new file mode 100644 index 00000000..97dfc31b --- /dev/null +++ b/man/redcap_read_eav_oneshot.Rd @@ -0,0 +1,189 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/redcap-read-eav-oneshot.R +\name{redcap_read_eav_oneshot} +\alias{redcap_read_eav_oneshot} +\title{Read/Export records from a REDCap project, returned as eav} +\usage{ +redcap_read_eav_oneshot( + redcap_uri, + token, + records = NULL, + records_collapsed = "", + fields = NULL, + fields_collapsed = "", + forms = NULL, + forms_collapsed = "", + events = NULL, + events_collapsed = "", + export_survey_fields = FALSE, + export_data_access_groups = FALSE, + filter_logic = "", + datetime_range_begin = as.POSIXct(NA), + datetime_range_end = as.POSIXct(NA), + blank_for_gray_form_status = FALSE, + http_response_encoding = "UTF-8", + locale = readr::default_locale(), + verbose = TRUE, + config_options = NULL, + handle_httr = NULL +) +} +\arguments{ +\item{redcap_uri}{The +\href{https://en.wikipedia.org/wiki/Uniform_Resource_Identifier}{uri}/url +of the REDCap server +typically formatted as "https://server.org/apps/redcap/api/". +Required.} + +\item{token}{The user-specific string that serves as the password for a +project. Required.} + +\item{records}{An array, where each element corresponds to the ID of a +desired record. Optional.} + +\item{records_collapsed}{A single string, where the desired ID values +are separated by commas. Optional.} + +\item{fields}{An array, where each element corresponds to a desired project +field. Optional.} + +\item{fields_collapsed}{A single string, where the desired field names are +separated by commas. Optional.} + +\item{forms}{An array, where each element corresponds to a desired project +form. Optional.} + +\item{forms_collapsed}{A single string, where the desired form names are +separated by commas. Optional.} + +\item{events}{An array, where each element corresponds to a desired project +event. Optional.} + +\item{events_collapsed}{A single string, where the desired event names are +separated by commas. Optional.} + +\item{export_survey_fields}{A boolean that specifies whether to export the +survey identifier field (e.g., 'redcap_survey_identifier') or survey +timestamp fields (e.g., instrument+'_timestamp'). +The timestamp outputs reflect the survey's \emph{completion} time +(according to the time and timezone of the REDCap server.)} + +\item{export_data_access_groups}{A boolean value that specifies whether or +not to export the \code{redcap_data_access_group} field when data access groups +are utilized in the project. Default is \code{FALSE}. See the details below.} + +\item{filter_logic}{String of logic text (e.g., \verb{[gender] = 'male'}) for +filtering the data to be returned by this API method, in which the API will +only return the records (or record-events, if a longitudinal project) where +the logic evaluates as TRUE. An blank/empty string returns all records.} + +\item{datetime_range_begin}{To return only records that have been created or +modified \emph{after} a given datetime, provide a +\href{https://stat.ethz.ch/R-manual/R-devel/library/base/html/as.POSIXlt.html}{POSIXct} +value. +If not specified, REDCap will assume no begin time.} + +\item{datetime_range_end}{To return only records that have been created or +modified \emph{before} a given datetime, provide a +\href{https://stat.ethz.ch/R-manual/R-devel/library/base/html/as.POSIXlt.html}{POSIXct} +value. +If not specified, REDCap will assume no end time.} + +\item{blank_for_gray_form_status}{A boolean value that specifies whether +or not to export blank values for instrument complete status fields that have +a gray status icon. All instrument complete status fields having a gray icon +can be exported either as a blank value or as "0" (Incomplete). Blank values +are recommended in a data export if the data will be re-imported into a +REDCap project. Default is \code{FALSE}.} + +\item{http_response_encoding}{The encoding value passed to +\code{\link[httr:content]{httr::content()}}. Defaults to 'UTF-8'.} + +\item{locale}{a \code{\link[readr:locale]{readr::locale()}} object to specify preferences like +number, date, and time formats. This object is passed to +\code{\link[readr:read_delim]{readr::read_csv()}}. Defaults to \code{\link[readr:locale]{readr::default_locale()}}.} + +\item{verbose}{A boolean value indicating if \code{message}s should be printed +to the R console during the operation. The verbose output might contain +sensitive information (\emph{e.g.} PHI), so turn this off if the output might +be visible somewhere public. Optional.} + +\item{config_options}{A list of options passed to \code{\link[httr:POST]{httr::POST()}}. +See details at \code{\link[httr:httr_options]{httr::httr_options()}}. Optional.} + +\item{handle_httr}{The value passed to the \code{handle} parameter of +\code{\link[httr:POST]{httr::POST()}}. +This is useful for only unconventional authentication approaches. It +should be \code{NULL} for most institutions. Optional.} +} +\value{ +Currently, a list is returned with the following elements: +\itemize{ +\item \code{data}: A \code{\link[tibble:tibble]{tibble::tibble()}} of the desired records and columns. +\item \code{success}: A boolean value indicating if the operation was apparently +successful. +\item \code{status_code}: The +\href{https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}{http status code} +of the operation. +\item \code{outcome_message}: A human readable string indicating the operation's +outcome. +\item \code{records_collapsed}: The desired records IDs, collapsed into a single +string, separated by commas. +\item \code{fields_collapsed}: The desired field names, collapsed into a single +string, separated by commas. +\item \code{filter_logic}: The filter statement passed as an argument. +\item \code{elapsed_seconds}: The duration of the function. +\item \code{raw_text}: If an operation is NOT successful, the text returned by +REDCap. If an operation is successful, the \code{raw_text} is returned as an +empty string to save RAM. +} +} +\description{ +This function uses REDCap's API to select and return data in an +\link{eav} +(https://en.wikipedia.org/wiki/Entity\%E2\%80\%93attribute\%E2\%80\%93value_model) +} +\details{ +If you do not pass an \code{export_data_access_groups} value, it will default +to \code{FALSE}. The following is from the API help page for version 10.5.1: +\emph{This flag is only viable if the user whose token is being used to make the +API request is \strong{not} in a data access group. If the user is in a group, +then this flag will revert to its default value}. +} +\examples{ +\dontrun{ +uri <- "https://bbmc.ouhsc.edu/redcap/api/" +token <- "9A81268476645C4E5F03428B8AC3AA7B" + +# Return all records and all variables. +ds <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=uri, token=token)$data + +# Return only records with IDs of 1 and 3 +desired_records_v1 <- c(1, 3) +ds_some_rows_v1 <- REDCapR:::redcap_read_eav_oneshot( + redcap_uri = uri, + token = token, + records = desired_records_v1 +)$data + +# Return only the fields record_id, name_first, and age +desired_fields_v1 <- c("record_id", "name_first", "age") +ds_some_fields_v1 <- REDCapR:::redcap_read_eav_oneshot( + redcap_uri = uri, + token = token, + fields = desired_fields_v1 +)$data + +} +} +\references{ +The official documentation can be found on the 'API Help Page' +and 'API Examples' pages on the REDCap wiki (\emph{i.e.}, +https://community.projectredcap.org/articles/456/api-documentation.html and +https://community.projectredcap.org/articles/462/api-examples.html). +If you do not have an account for the wiki, please ask your campus REDCap +administrator to send you the static material. +} +\author{ +Will Beasley +} diff --git a/tests/testthat/test-read-eav-oneshot.R b/tests/testthat/test-read-eav-oneshot.R new file mode 100644 index 00000000..84d51342 --- /dev/null +++ b/tests/testthat/test-read-eav-oneshot.R @@ -0,0 +1,328 @@ +library(testthat) + +credential <- retrieve_credential_testing() +update_expectation <- FALSE +path_expected_default <- "test-data/specific-redcapr/read-eav-oneshot/default.R" + +test_that("smoke test", { + testthat::skip_on_cran() + expect_message( + returned_object <- + REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential$redcap_uri, + token = credential$token + ) + ) +}) +test_that("default", { + testthat::skip_on_cran() + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential$redcap_uri, + token = credential$token + ) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected_default) + expected_data_frame <- retrieve_expected(path_expected_default) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) + + +test_that("specify-records", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/specify-records.R" + desired_records <- c(1L, 3L, 4L) + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, records=desired_records) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed==paste(desired_records, collapse=",")) + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("specify-records-zero-length", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/specify-records-zero-length.R" + desired_records <- c() + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, records=desired_records) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed==paste(desired_records, collapse=",")) + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("specify-fields", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/specify-fields.R" + desired_fields <- c("record_id", "name_first", "name_last", "age") + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, fields=desired_fields) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed==paste(desired_fields, collapse=",")) + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("specify-fields-zero-length", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/specify-fields-zero-length.R" + desired_fields <- c() + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, fields=desired_fields) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed==paste(desired_fields, collapse=",")) + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) + +test_that("specify-forms", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/specify-forms.R" + desired_forms <- c("demographics", "race_and_ethnicity") + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, forms=desired_forms) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("filter-numeric", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/filter-numeric.R" + + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + filter <- "[age] >= 61" + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, filter_logic=filter) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_equal(returned_object$filter_logic, filter) + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("filter-character", { + testthat::skip_on_cran() + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/filter-character.R" + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + filter <- "[name_first] = 'John Lee'" + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot(redcap_uri=credential$redcap_uri, token=credential$token, filter_logic=filter) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_equal(returned_object$filter_logic, filter) + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("blank-for-gray-status-true", { + testthat::skip_on_cran() + credential_blank_for_gray <- retrieve_credential_testing(3003L) + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-true.R" + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential_blank_for_gray$redcap_uri, + token = credential_blank_for_gray$token, + blank_for_gray_form_status = TRUE + ) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) +test_that("blank-for-gray-status-false", { + testthat::skip_on_cran() + credential_blank_for_gray <- retrieve_credential_testing(3003L) + path_expected <- "test-data/specific-redcapr/read-eav-oneshot/blank-for-gray-false.R" + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + expect_message( + regexp = expected_outcome_message, + returned_object <- REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential_blank_for_gray$redcap_uri, + token = credential_blank_for_gray$token, + blank_for_gray_form_status = FALSE + ) + ) + + if (update_expectation) save_expected(returned_object$data, path_expected) + expected_data_frame <- retrieve_expected(path_expected) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_true(returned_object$filter_logic=="", "A filter was not specified.") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) + +test_that("date-range", { + testthat::skip_on_cran() + expected_outcome_message <- "\\d+ records and \\d+ columns were read from REDCap in \\d+(\\.\\d+\\W|\\W)seconds\\." + + start <- as.POSIXct(strptime("2018-08-01 03:00", "%Y-%m-%d %H:%M")) + stop <- Sys.time() + expect_message( + regexp = expected_outcome_message, + returned_object <- + REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential$redcap_uri, + token = credential$token, + datetime_range_begin = start, + datetime_range_end = stop + ) + ) + + expected_data_frame <- retrieve_expected(path_expected_default) + + expect_equal(returned_object$data, expected=expected_data_frame, label="The returned data.frame should be correct", ignore_attr = TRUE) # dput(returned_object$data) + expect_equal(returned_object$status_code, expected=200L) + expect_equal(returned_object$raw_text, expected="", ignore_attr = TRUE) # dput(returned_object$raw_text) + expect_true(returned_object$records_collapsed=="", "A subset of records was not requested.") + expect_true(returned_object$fields_collapsed=="", "A subset of fields was not requested.") + expect_equal(returned_object$filter_logic, "") + expect_match(returned_object$outcome_message, regexp=expected_outcome_message, perl=TRUE) + expect_true(returned_object$success) + + expect_s3_class(returned_object$data, "tbl") +}) + +test_that("bad token -Error", { + testthat::skip_on_cran() + expected_outcome_message <- "The REDCapR read/export operation was not successful\\." + + expect_message( + returned_object <- + REDCapR:::redcap_read_eav_oneshot( + redcap_uri = credential$redcap_uri, + token = "BAD00000000000000000000000000000" + ), + expected_outcome_message + ) + testthat::expect_false(returned_object$success) + testthat::expect_equal(returned_object$status_code, 403L) + testthat::expect_equal(returned_object$raw_text, "ERROR: You do not have permissions to use the API") +}) +rm(credential)