OuhscBbmc / REDCapR
Showing 17 of 69 files from the diff.
Other files ignored by Codecov
inst/WORDLIST has changed.
NAMESPACE has changed.
_pkgdown.yml has changed.
utility/refresh.R has changed.
NEWS.md has changed.

@@ -13,7 +13,7 @@
Loading
13 13
#' @param perl Indicates if perl-compatible regexps should be used.
14 14
#'   Default is `TRUE`. Optional.
15 15
#'
16 -
#' @return Currently, a [base::data.frame()] is returned a row for each match,
16 +
#' @return Currently, a [tibble::tibble()] is returned a row for each match,
17 17
#' and a column for each *named* group within a match.  For the
18 18
#' `retrieve_checkbox_choices()` function, the columns will be.
19 19
#' * `id`: The numeric value assigned to each choice (in the data dictionary).
@@ -22,13 +22,17 @@
Loading
22 22
#' @details
23 23
#' The [regex_named_captures()] function is general, and not specific to
24 24
#' REDCap; it accepts any arbitrary regular expression.
25 -
#' It returns a [base::data.frame()] with as many columns as named matches.
25 +
#' It returns a [tibble::tibble()] with as many columns as named matches.
26 26
#'
27 27
#' The [checkbox_choices()] function is specialized, and accommodates the
28 28
#' "select choices" for a *single* REDCap checkbox group (where multiple boxes
29 -
#' can be selected).  It returns a [base::data.frame()] with two columns, one
29 +
#' can be selected).  It returns a [tibble::tibble()] with two columns, one
30 30
#' for the numeric id and one for the text label.
31 31
#'
32 +
#' The parse will probably fail if a label contains a pipe (*i.e.*, `|`),
33 +
#' since that the delimiter REDCap uses to separate choices
34 +
#' presented to the user.
35 +
#'
32 36
#' @author Will Beasley
33 37
#' @references See the official documentation for permissible characters in a
34 38
#' checkbox label.
@@ -59,7 +63,7 @@
Loading
59 63
#' token       <- "9A81268476645C4E5F03428B8AC3AA7B"
60 64
#'
61 65
#' ds_metadata <- redcap_metadata_read(redcap_uri=uri, token=token)$data
62 -
#' choices_2   <- ds_metadata[ds_metadata$field_name=="race", "select_choices_or_calculations"]
66 +
#' choices_2   <- ds_metadata[ds_metadata$field_name=="race", ]$select_choices_or_calculations
63 67
#'
64 68
#' REDCapR::regex_named_captures(pattern=pattern_boxes, text=choices_2)
65 69
#' }
@@ -70,15 +74,14 @@
Loading
70 74
#' REDCapR::regex_named_captures(pattern=pattern_boxes, text=choices_3)
71 75
72 76
#' @export
73 -
regex_named_captures <- function(pattern, text, perl=TRUE) {
74 -
77 +
regex_named_captures <- function(pattern, text, perl = TRUE) {
75 78
  checkmate::assert_character(pattern, any.missing=FALSE, min.chars=0L, len=1)
76 79
  checkmate::assert_character(text   , any.missing=FALSE, min.chars=0L, len=1)
77 80
  checkmate::assert_logical(  perl   , any.missing=FALSE)
78 81
79 82
  match <- gregexpr(pattern, text, perl = perl)[[1]]
80 83
  capture_names <- attr(match, "capture.names")
81 -
  d <- as.data.frame(matrix(
84 +
  d <- base::data.frame(matrix(
82 85
    data  = NA_character_,
83 86
    nrow  = length(attr(match, "match.length")),
84 87
    ncol  = length(capture_names)
@@ -95,7 +98,7 @@
Loading
95 98
      attr(match, "capture.length")[, column_name]
96 99
    )
97 100
  }
98 -
  d
101 +
  tibble::as_tibble(d)
99 102
}
100 103
101 104
#' @rdname metadata_utilities

@@ -10,7 +10,7 @@
Loading
10 10
# This function isn't used during testing itself.  Just to create the expected file.
11 11
save_expected <- function(o, path) {
12 12
  # nocov start
13 -
  attr(returned_object$data, which = "problems") <- NULL
13 +
  attr(o, which = "problems") <- NULL
14 14
  path <- file.path("inst", path)
15 15
  if (!dir.exists(dirname(path))) dir.create(dirname(path), recursive = FALSE)
16 16

@@ -32,7 +32,7 @@
Loading
32 32
#' @author Will Beasley
33 33
#'
34 34
#' @seealso
35 -
#' See [redcap_read()] for a function that uses `create_batch_gloassary`.
35 +
#' See [redcap_read()] for a function that uses `create_batch_glossary`.
36 36
#'
37 37
#' @examples
38 38
#' REDCapR::create_batch_glossary(100, 50)

@@ -22,7 +22,7 @@
Loading
22 22
#' `httr` package.  See the details below. Optional.
23 23
#'
24 24
#' @return Currently, a list is returned with the following elements,
25 -
#' * `data`: An R [base::data.frame()] where each row represents one column
25 +
#' * `data`: A [tibble::tibble()] where each row represents one column
26 26
#' in the REDCap dataset.
27 27
#' * `success`: A boolean value indicating if the operation was apparently
28 28
#' successful.
@@ -119,7 +119,7 @@
Loading
119 119
    } else {
120 120
      # nocov start
121 121
      kernel$success  <- FALSE # Override the 'success' http status code.
122 -
      ds              <- data.frame() #Return an empty data.frame
122 +
      ds              <- tibble::tibble() # Return an empty data.frame
123 123
124 124
      outcome_message <- sprintf(
125 125
        "The REDCap variable retrieval failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
@@ -129,7 +129,7 @@
Loading
129 129
      # nocov end
130 130
    }
131 131
  } else {
132 -
    ds              <- data.frame() #Return an empty data.frame
132 +
    ds              <- tibble::tibble() # Return an empty data.frame
133 133
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
134 134
      "The REDCapR read/export operation was not successful.  The returned dataset (of instrument-events) was empty."
135 135
    } else {
136 136
imilarity index 100%
137 137
ename from R/redcap-download-instrument.R
138 138
ename to R/redcap-instrument-download.R

@@ -4,7 +4,7 @@
Loading
4 4
#' @description From an external perspective, this function is similar to
5 5
#' [redcap_read_oneshot()].  The internals differ in that `redcap_read`
6 6
#' retrieves subsets of the data, and then combines them before returning
7 -
#' (among other objects) a single [base::data.frame()].  This function can
7 +
#' (among other objects) a single [tibble::tibble()].  This function can
8 8
#' be more appropriate than [redcap_read_oneshot()] when returning large
9 9
#' datasets that could tie up the server.
10 10
#'
@@ -100,7 +100,7 @@
Loading
100 100
#' This defaults to the first variable in the dataset.
101 101
#'
102 102
#' @return Currently, a list is returned with the following elements:
103 -
#' * `data`: An R [base::data.frame()] of the desired records and columns.
103 +
#' * `data`: A [tibble::tibble()] of the desired records and columns.
104 104
#' * `success`: A boolean value indicating if the operation was apparently
105 105
#' successful.
106 106
#' * `status_codes`: A collection of
@@ -122,7 +122,7 @@
Loading
122 122
#' through the REDCap API.  The long list is then subsetted into batches,
123 123
#' whose sizes are determined by the `batch_size` parameter.  REDCap is then
124 124
#' queried for all variables of the subset's subjects.  This is repeated for
125 -
#' each subset, before returning a unified [base::data.frame()].
125 +
#' each subset, before returning a unified [tibble::tibble()].
126 126
#'
127 127
#' The function allows a delay between calls, which allows the server to
128 128
#' attend to other users' requests (such as the users entering data in a
@@ -300,7 +300,7 @@
Loading
300 300
    outcome_messages  <- paste0("The initial call failed with the code: ", initial_call$status_code, ".")
301 301
    elapsed_seconds   <- as.numeric(difftime(Sys.time(), start_time, units="secs"))
302 302
    return(list(
303 -
      data                  = data.frame(),
303 +
      data                  = tibble::tibble(),
304 304
      records_collapsed     = "failed in initial batch call",
305 305
      fields_collapsed      = "failed in initial batch call",
306 306
      forms_collapsed       = "failed in initial batch call",
@@ -402,7 +402,7 @@
Loading
402 402
    rm(read_result) #Admittedly overkill defensiveness.
403 403
  }
404 404
405 -
  ds_stacked               <- as.data.frame(dplyr::bind_rows(lst_batch))
405 +
  ds_stacked               <- dplyr::bind_rows(lst_batch)
406 406
407 407
  if (is.null(col_types) && guess_type) {
408 408
    ds_stacked <-

@@ -0,0 +1,309 @@
Loading
1 +
#' @title Read/Export records from a REDCap project
2 +
#'
3 +
#' @description This function uses REDCap's API to select and return data.
4 +
#'
5 +
#' @param redcap_uri The
6 +
#' [uri](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)/url
7 +
#' of the REDCap server
8 +
#' typically formatted as "https://server.org/apps/redcap/api/".
9 +
#' Required.
10 +
#' @param token The user-specific string that serves as the password for a
11 +
#' project.  Required.
12 +
#' @param http_response_encoding  The encoding value passed to
13 +
#' [httr::content()].  Defaults to 'UTF-8'.
14 +
#' @param locale a [readr::locale()] object to specify preferences like
15 +
#' number, date, and time formats.  This object is passed to
16 +
#' [`readr::read_csv()`].  Defaults to [readr::default_locale()].
17 +
#' @param verbose A boolean value indicating if `message`s should be printed
18 +
#' to the R console during the operation.  The verbose output might contain
19 +
#' sensitive information (*e.g.* PHI), so turn this off if the output might
20 +
#' be visible somewhere public. Optional.
21 +
#' @param config_options  A list of options to pass to `POST` method in the
22 +
#' `httr` package.  See the details below. Optional.
23 +
#'
24 +
#' @return Currently, a list is returned with the following elements:
25 +
#' * `data`: A [tibble::tibble()] of the desired records and columns.
26 +
#' * `success`: A boolean value indicating if the operation was apparently
27 +
#' successful.
28 +
#' * `status_code`: The
29 +
#' [http status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
30 +
#' of the operation.
31 +
#' * `outcome_message`: A human readable string indicating the operation's
32 +
#' outcome.
33 +
#' * `elapsed_seconds`: The duration of the function.
34 +
#' * `raw_text`: If an operation is NOT successful, the text returned by
35 +
#' REDCap.  If an operation is successful, the `raw_text` is returned as an
36 +
#' empty string to save RAM.
37 +
#'
38 +
#' @details
39 +
#' The full list of configuration options accepted by the `httr` package is
40 +
#' viewable by executing [httr::httr_options()].  The `httr` package and
41 +
#' documentation is available at https://cran.r-project.org/package=httr.
42 +
#'
43 +
#' @author Will Beasley
44 +
#'
45 +
#' @references The official documentation can be found on the 'API Help Page'
46 +
#' and 'API Examples' pages on the REDCap wiki (*i.e.*,
47 +
#' https://community.projectredcap.org/articles/456/api-documentation.html and
48 +
#' https://community.projectredcap.org/articles/462/api-examples.html).
49 +
#' If you do not have an account for the wiki, please ask your campus REDCap
50 +
#' administrator to send you the static material.
51 +
#'
52 +
#' @examples
53 +
#' \dontrun{
54 +
#' uri      <- "https://bbmc.ouhsc.edu/redcap/api/"
55 +
#'
56 +
#' # A simple project with a variety of types
57 +
#' token    <- "9A81268476645C4E5F03428B8AC3AA7B" # 153 - Simple
58 +
#' redcap_metadata_coltypes(uri, token)
59 +
#'
60 +
#' # This project includes every field type and validation type.
61 +
#' #   It throws a warning that some fields use a comma for a decimal,
62 +
#' #   while other fields use a period/dot as a decimal
63 +
#' token    <- "8F5313CAA266789F560D79EFCEE2E2F1" # 2634 - Validation Types
64 +
#' redcap_metadata_coltypes(uri, token)
65 +
#' }
66 +
67 +
#' @importFrom magrittr %>%
68 +
#' @export
69 +
redcap_metadata_coltypes <- function(
70 +
    redcap_uri,
71 +
    token,
72 +
73 +
    http_response_encoding        = "UTF-8",
74 +
    locale                        = readr::default_locale(),
75 +
    verbose                       = FALSE,
76 +
    config_options                = NULL
77 +
) {
78 +
79 +
  checkmate::assert_character(redcap_uri                , any.missing=FALSE, len=1, pattern="^.{1,}$")
80 +
  checkmate::assert_character(token                     , any.missing=FALSE, len=1, pattern="^.{1,}$")
81 +
82 +
  checkmate::assert_character(http_response_encoding    , any.missing=FALSE,     len=1)
83 +
  checkmate::assert_class(    locale, "locale"          , null.ok = FALSE)
84 +
  checkmate::assert_logical(  verbose                   , any.missing=FALSE, len=1, null.ok=TRUE)
85 +
  checkmate::assert_list(     config_options            , any.missing=TRUE ,        null.ok=TRUE)
86 +
87 +
  token               <- sanitize_token(token)
88 +
  verbose             <- verbose_prepare(verbose)
89 +
90 +
  # Retrieve the info necessary to infer the likely data types
91 +
  d_var  <- REDCapR::redcap_variables(        redcap_uri, token, verbose = verbose)$data
92 +
  d_meta <- REDCapR::redcap_metadata_read(    redcap_uri, token, verbose = verbose)$data
93 +
  d_inst <- REDCapR::redcap_instruments(      redcap_uri, token, verbose = verbose)$data
94 +
  d_proj <- REDCapR::redcap_project_info_read(redcap_uri, token, verbose = verbose)$data
95 +
96 +
  # Determine status of autonumbering, instrument complete status, and decimal mark
97 +
  .record_field         <- d_var$original_field_name[1]
98 +
  .autonumber           <- d_proj$record_autonumbering_enabled[1]
99 +
  .form_complete_boxes  <- paste0(d_inst$instrument_name, "_complete")
100 +
  decimal_period        <- (locale$decimal_mark == ".")
101 +
  decimal_comma         <- (locale$decimal_mark == ",")
102 +
103 +
  # Prepare metadata to be joined
104 +
  d_var <-
105 +
    d_var %>%
106 +
    dplyr::select(
107 +
      field_name            = .data$export_field_name,
108 +
      field_name_original   = .data$original_field_name
109 +
    )
110 +
111 +
  d_complete <-
112 +
    tibble::tibble(
113 +
      field_name  = .form_complete_boxes,
114 +
      field_type  = "complete",
115 +
      vt          = NA_character_,
116 +
    )
117 +
118 +
  d_again <-
119 +
    tibble::tibble(
120 +
      field_name  = character(0),
121 +
      field_type  = character(0),
122 +
      vt          = character(0),
123 +
    )
124 +
125 +
  if (d_proj$is_longitudinal[1]) {
126 +
    d_again <-
127 +
      d_again %>%
128 +
      dplyr::union_all(
129 +
        tibble::tibble(
130 +
          field_name  = "redcap_event_name",
131 +
          field_type  = "event_name",
132 +
          vt          = NA_character_,
133 +
        )
134 +
      )
135 +
  }
136 +
  if (d_proj$has_repeating_instruments_or_events[1]) {
137 +
    d_again <-
138 +
      d_again %>%
139 +
      dplyr::union_all(
140 +
        tibble::tibble(
141 +
          field_name  = c("redcap_repeat_instrument", "redcap_repeat_instance"),
142 +
          field_type  = c("repeat_instrument"       , "repeat_instance"),
143 +
          vt          = NA_character_,
144 +
        )
145 +
      )
146 +
  }
147 +
148 +
  # Prepare metadata to be joined
149 +
  d_meta <-
150 +
    d_meta %>%
151 +
    dplyr::select(
152 +
      field_name_original  = .data$field_name,
153 +
      .data$field_type,
154 +
      .data$text_validation_type_or_show_slider_number,
155 +
    ) %>%
156 +
    dplyr::filter(.data$field_type != "descriptive") %>%
157 +
    dplyr::left_join(d_var, by = "field_name_original") %>%
158 +
    dplyr::mutate(
159 +
      field_name = dplyr::coalesce(.data$field_name, .data$field_name_original),
160 +
    ) %>%
161 +
    dplyr::select(
162 +
      .data$field_name,
163 +
      .data$field_type,
164 +
      vt            = .data$text_validation_type_or_show_slider_number,
165 +
    ) %>%
166 +
    tibble::add_row(d_again, .after = 1) %>%
167 +
    dplyr::union_all(d_complete)
168 +
169 +
  # setdiff(d_meta$field_name_original, d_var$original_field_name)
170 +
  # [1] "signature"   "file_upload" "descriptive"
171 +
172 +
  # Translate the four datasets into a single `readr:cols()` string printed to the console
173 +
  meat <-
174 +
    d_meta %>%
175 +
    dplyr::mutate(
176 +
      # vt          = dplyr::if_else(.data$field_name %in% .form_complete_boxes, "complete", vt),
177 +
      autonumber  = (.autonumber & (.data$field_name == .record_field)),
178 +
    ) %>%
179 +
    dplyr::mutate(
180 +
      response =
181 +
        dplyr::case_when(
182 +
          autonumber                                          ~ paste0("col_integer()"                        , "~~record_autonumbering is enabled for the project"),
183 +
          field_type == "event_name"                          ~ paste0("col_character()"                      , "~~longitudinal event_name"),
184 +
          field_type == "repeat_instrument"                   ~ paste0("col_character()"                      , "~~repeat_instrument"),
185 +
          field_type == "repeat_instance"                     ~ paste0("col_integer()"                        , "~~repeat_instance"),
186 +
          field_type == "truefalse"                           ~ paste0("col_logical()"                        , "~~field_type is truefalse"),
187 +
          field_type == "yesno"                               ~ paste0("col_logical()"                        , "~~field_type is yesno"),
188 +
          field_type == "checkbox"                            ~ paste0("col_logical()"                        , "~~field_type is checkbox"),
189 +
          field_type == "radio"                               ~ paste0("col_character()"                      , "~~field_type is radio"),
190 +
          field_type == "dropdown"                            ~ paste0("col_character()"                      , "~~field_type is dropdown"),
191 +
          field_type == "file"                                ~ paste0("col_character()"                      , "~~field_type is file"),
192 +
          field_type == "notes"                               ~ paste0("col_character()"                      , "~~field_type is note"),
193 +
          field_type == "slider"                              ~ paste0("col_integer()"                        , "~~field_type is slider"),
194 +
          field_type == "calc"                                ~ paste0("col_character()"                      , "~~field_type is calc"),
195 +
          field_type == "descriptive"                         ~ paste0("col_character()"                      , "~~field_type is descriptive"),
196 +
          field_type == "sql"                                 ~ paste0("col_character()"                      , "~~field_type is sql"),
197 +
          field_type == "text" & is.na(vt)                    ~ paste0("col_character()"                      , "~~field_type is text and validation isn't set"),
198 +
          field_type == "text" & vt == ""                     ~ paste0("col_character()"                      , "~~field_type is text and validation isn't set"),
199 +
          is.na(field_type) & vt == "complete"                ~ paste0("col_integer()"                        , "~~indicates completion status of form/instrument"),
200 +
          vt == "alpha_only"                                  ~ paste0("col_character()"                      , "~~validation is 'alpha_only'"),
201 +
          vt == "date_dmy"                                    ~ paste0("col_date()"                           , "~~validation is 'date_dmy'"),
202 +
          vt == "date_mdy"                                    ~ paste0("col_date()"                           , "~~validation is 'date_mdy'"),
203 +
          vt == "date_ymd"                                    ~ paste0("col_date()"                           , "~~validation is 'date_ymd'"),
204 +
          vt == "datetime_dmy"                                ~ paste0("col_datetime(\"%Y-%m-%d %H:%M\")"     , "~~validation is 'datetime_dmy'"),
205 +
          vt == "datetime_mdy"                                ~ paste0("col_datetime(\"%Y-%m-%d %H:%M\")"     , "~~validation is 'datetime_mdy'"),
206 +
          vt == "datetime_seconds_dmy"                        ~ paste0("col_datetime(\"%Y-%m-%d %H:%M:%S\")"  , "~~validation is 'datetime_seconds_dmy'"),
207 +
          vt == "datetime_seconds_mdy"                        ~ paste0("col_datetime(\"%Y-%m-%d %H:%M:%S\")"  , "~~validation is 'datetime_seconds_mdy'"),
208 +
          vt == "datetime_seconds_ymd"                        ~ paste0("col_datetime(\"%Y-%m-%d %H:%M:%S\")"  , "~~validation is 'datetime_seconds_ymd'"),
209 +
          vt == "datetime_ymd"                                ~ paste0("col_datetime(\"%Y-%m-%d %H:%M\")"     , "~~validation is 'datetime_ymd'"),
210 +
          vt == "email"                                       ~ paste0("col_character()"                      , "~~validation is 'email'"),
211 +
          vt == "integer"                                     ~ paste0("col_integer()"                        , "~~validation is 'integer'"),
212 +
          vt == "mrn_10d"                                     ~ paste0("col_character()"                      , "~~validation is 'mrn_10d'"),
213 +
          vt == "mrn_generic"                                 ~ paste0("col_character()"                      , "~~validation is 'mrn_generic'"),
214 +
          vt == "number"                    &  decimal_period ~ paste0("col_double()"                         , "~~validation is 'number'"),
215 +
          vt == "number_1dp"                &  decimal_period ~ paste0("col_double()"                         , "~~validation is 'number_1dp'"),
216 +
          vt == "number_2dp"                &  decimal_period ~ paste0("col_double()"                         , "~~validation is 'number_2dp'"),
217 +
          vt == "number_3dp"                &  decimal_period ~ paste0("col_double()"                         , "~~validation is 'number_3dp'"),
218 +
          vt == "number_4dp"                &  decimal_period ~ paste0("col_double()"                         , "~~validation is 'number_4dp'"),
219 +
          vt == "number"                    & !decimal_period ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a period, yet validation is 'number'"),
220 +
          vt == "number_1dp"                & !decimal_period ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a period, yet validation is 'number_1dp'"),
221 +
          vt == "number_2dp"                & !decimal_period ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a period, yet validation is 'number_2dp'"),
222 +
          vt == "number_3dp"                & !decimal_period ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a period, yet validation is 'number_3dp'"),
223 +
          vt == "number_4dp"                & !decimal_period ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a period, yet validation is 'number_4dp'"),
224 +
          vt == "number_comma_decimal"      &  decimal_comma  ~ paste0("col_double()"                         , "~~validation is 'number_comma_decimal'"),
225 +
          vt == "number_1dp_comma_decimal"  &  decimal_comma  ~ paste0("col_double()"                         , "~~validation is 'number_1dp_comma_decimal'"),
226 +
          vt == "number_2dp_comma_decimal"  &  decimal_comma  ~ paste0("col_double()"                         , "~~validation is 'number_2dp_comma_decimal'"),
227 +
          vt == "number_3dp_comma_decimal"  &  decimal_comma  ~ paste0("col_double()"                         , "~~validation is 'number_3dp_comma_decimal'"),
228 +
          vt == "number_4dp_comma_decimal"  &  decimal_comma  ~ paste0("col_double()"                         , "~~validation is 'number_4dp_comma_decimal'"),
229 +
          vt == "number_comma_decimal"      & !decimal_comma  ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a comma, yet validation is 'number_comma_decimal'"),
230 +
          vt == "number_1dp_comma_decimal"  & !decimal_comma  ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a comma, yet validation is 'number_1dp_comma_decimal'"),
231 +
          vt == "number_2dp_comma_decimal"  & !decimal_comma  ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a comma, yet validation is 'number_2dp_comma_decimal'"),
232 +
          vt == "number_3dp_comma_decimal"  & !decimal_comma  ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a comma, yet validation is 'number_3dp_comma_decimal'"),
233 +
          vt == "number_4dp_comma_decimal"  & !decimal_comma  ~ paste0("col_character()"                      , "~~locale's decimal mark isn't a comma, yet validation is 'number_4dp_comma_decimal'"),
234 +
          vt == "phone"                                       ~ paste0("col_character()"                      , "~~validation is 'phone'"),
235 +
          vt == "phone_australia"                             ~ paste0("col_character()"                      , "~~validation is 'phone_australia'"),
236 +
          vt == "postalcode_australia"                        ~ paste0("col_character()"                      , "~~validation is 'postalcode_australia'"),
237 +
          vt == "postalcode_canada"                           ~ paste0("col_character()"                      , "~~validation is 'postalcode_canada'"),
238 +
          vt == "postalcode_french"                           ~ paste0("col_character()"                      , "~~validation is 'postalcode_french'"),
239 +
          vt == "postalcode_germany"                          ~ paste0("col_character()"                      , "~~validation is 'postalcode_germany'"),
240 +
          vt == "ssn"                                         ~ paste0("col_character()"                      , "~~validation is 'ssn'"),
241 +
          vt == "time"                                        ~ paste0("col_time(\"%H:%M\")"                  , "~~validation is 'time'"),
242 +
          vt == "time_hh_mm_ss"                               ~ paste0("col_time(\"%H:%M:%S\")"               , "~~validation is 'time_hh_mm_ss'"),
243 +
          vt == "time_mm_ss"                                  ~ paste0("col_time(\"%M:%S\")"                  , "~~validation is 'time_mm_ss'"),
244 +
          vt == "vmrn"                                        ~ paste0("col_character()"                      , "~~validation is 'vmrn'"),
245 +
          vt == "zipcode"                                     ~ paste0("col_character()"                      , "~~validation is 'zipcode'"),
246 +
          TRUE                                                ~ paste0("col_character()"                      , "~~validation doesn't have an associated col_type.  Tell us in a new REDCapR issue. "),
247 +
        )
248 +
    ) %>%
249 +
    dplyr::mutate(
250 +
      # Retrieve the col_type and the explanation
251 +
      readr_col_type  = sub("^(col_.+)~~(.+)$", "\\1", .data$response),
252 +
      explanation     = sub("^(col_.+)~~(.+)$", "\\2", .data$response),
253 +
254 +
      # Calculate the odd number of spaces -just beyond the longest variable name.
255 +
      padding1  = nchar(.data$field_name),
256 +
      padding1  = max(.data$padding1) %/% 2 * 2 + 3,
257 +
      padding2  = nchar(.data$readr_col_type),
258 +
      padding2  = max(.data$padding2) %/% 2 * 2 + 3,
259 +
260 +
      # Pad the left side before appending the right side.
261 +
      aligned = sprintf("  %-*s = readr::%-*s, # %s", .data$padding1, .data$field_name, .data$padding2, .data$readr_col_type, .data$explanation)
262 +
    ) %>%
263 +
    # View()
264 +
    # tibble::add_row(aligned = sprintf("  %-*s = readr::%-*s, # b/c %s", .data$padding1, .data$field_name, .data$padding2, .data$readr_col_type, .data$explanation)) %>%
265 +
    dplyr::pull(.data$aligned)
266 +
267 +
  # Construct an explanation header that's aligned with the col_types output
268 +
  gaps <- unlist(gregexpr("[=#]", meat[1]))
269 +
  header <- sprintf(
270 +
    "  # %-*s %-*s %s\n",
271 +
    gaps[1] - 4,
272 +
    "[field]",
273 +
    gaps[2] - gaps[1] - 1,
274 +
    "[readr col_type]",
275 +
    "[explanation for col_type]"
276 +
  )
277 +
278 +
  # Sandwich the col_types output in between the opening+header and the closing
279 +
  sandwich <-
280 +
    # I'd prefer this approach, but the `.` is causing problems with R CMD check.
281 +
    paste0(
282 +
      "# col_types <- readr::cols_only( # Use `readr::cols_only()` to restrict the retrieval to only these columns\n",
283 +
      "col_types <- readr::cols( # Use `readr::cols()` to include unspecified columns\n",
284 +
      header,
285 +
      paste(meat, collapse = "\n") ,
286 +
      "\n)\n"
287 +
    )
288 +
289 +
  sandwich %>%
290 +
    message()
291 +
292 +
  decimal_period_any <- any(d_meta$vt %in% c("number", "number_1dp", "number_2dp", "number_3dp", "number_4dp" ))
293 +
  decimal_comma_any  <- any(d_meta$vt %in% c("number_comma_decimal", "number_1dp_comma_decimal", "number_2dp_comma_decimal", "number_3dp_comma_decimal", "number_4dp_comma_decimal"))
294 +
295 +
  if (decimal_period_any && decimal_comma_any) {
296 +
    warning(
297 +
      "The metadata for the REDCap project has validation types ",
298 +
      "for at least one field that specifies a comma for a decimal ",
299 +
      "for at least one field that specifies a period for a decimal.  ",
300 +
      "Mixing these two formats in the same proejct can cause confusion and problems.  ",
301 +
      "Consider passing `readr::col_character()` for this field ",
302 +
      "(to REDCapR's `col_types` parameter) and then convert the ",
303 +
      "desired fields to R's numeric type.  ",
304 +
      "The function `readr::parse_double()` is useful for this."
305 +
    )
306 +
  }
307 +
308 +
  eval(str2expression(sandwich))
309 +
}

@@ -1,7 +1,7 @@
Loading
1 1
#' @title Get the logging of a project.
2 2
#'
3 3
#' @description This function reads the available logging messages from
4 -
#'   REDCap an returns them as a [base::data.frame()].
4 +
#'   REDCap as a [tibble::tibble()].
5 5
#'
6 6
#' @param redcap_uri The
7 7
#' [uri](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)/url
@@ -39,7 +39,7 @@
Loading
39 39
#' `httr` package.
40 40
#'
41 41
#' @return Currently, a list is returned with the following elements:
42 -
#' * `data`: An R [base::data.frame()] of all data access groups of the project.
42 +
#' * `data`: An R [tibble::tibble()] of all data access groups of the project.
43 43
#' * `success`: A boolean value indicating if the operation was apparently
44 44
#' successful.
45 45
#' * `status_codes`: A collection of
@@ -144,8 +144,7 @@
Loading
144 144
          file            = I(kernel$raw_text),
145 145
          locale          = locale,
146 146
          show_col_types  = FALSE
147 -
        ) %>%
148 -
        as.data.frame(),
147 +
        ),
149 148
150 149
      # Don't print the warning in the try block.  Print it below,
151 150
      #   where it's under the control of the caller.
@@ -169,7 +168,7 @@
Loading
169 168
      # Override the 'success' determination from the http status code.
170 169
      #   and return an empty data.frame.
171 170
      kernel$success   <- FALSE
172 -
      ds               <- data.frame()
171 +
      ds               <- tibble::tibble()
173 172
      outcome_message  <- sprintf(
174 173
        "The REDCap log export failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
175 174
        kernel$status_code,
@@ -178,7 +177,7 @@
Loading
178 177
      # nocov end
179 178
    }
180 179
  } else { # kernel fails
181 -
    ds              <- data.frame() #Return an empty data.frame
180 +
    ds              <- tibble::tibble() # Return an empty data.frame
182 181
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
183 182
      "The REDCapR log export operation was not successful.  The returned dataset was empty."  # nocov
184 183
    } else {

@@ -70,7 +70,7 @@
Loading
70 70
#' `httr` package.  See the details below. Optional.
71 71
#'
72 72
#' @return Currently, a list is returned with the following elements:
73 -
#' * `data`: An R [base::data.frame()] of the desired records and columns.
73 +
#' * `data`: A [tibble::tibble()] of the desired records and columns.
74 74
#' * `success`: A boolean value indicating if the operation was apparently
75 75
#' successful.
76 76
#' * `status_code`: The
@@ -351,7 +351,7 @@
Loading
351 351
    } else {
352 352
      # nocov start
353 353
      kernel$success    <- FALSE #Override the 'success' determination from the http status code.
354 -
      ds_2              <- tibble::tibble() #Return an empty data.frame
354 +
      ds_2              <- tibble::tibble() # Return an empty data.frame
355 355
      outcome_message   <- sprintf(
356 356
        "The REDCap read failed.  The http status code was %s.  The 'raw_text' returned was '%s'.",
357 357
        kernel$status_code,
@@ -361,7 +361,7 @@
Loading
361 361
    }
362 362
  } else {
363 363
    # nocov start
364 -
    ds_2            <- tibble::tibble() #Return an empty data.frame
364 +
    ds_2            <- tibble::tibble() # Return an empty data.frame
365 365
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
366 366
      "The REDCapR read/export operation was not successful.  The returned dataset was empty."
367 367
    } else {

@@ -24,7 +24,7 @@
Loading
24 24
#' `httr` package.  See the details below. Optional.
25 25
#'
26 26
#' @return Currently, a list is returned with the following elements,
27 -
#' * `data`: An R [base::data.frame()] where each row represents one column
27 +
#' * `data`: A [tibble::tibble()] where each row represents one column
28 28
#' in the REDCap dataset.
29 29
#' * `success`: A boolean value indicating if the operation was apparently
30 30
#' successful.
@@ -118,7 +118,7 @@
Loading
118 118
    } else {
119 119
      # nocov start
120 120
      kernel$success  <- FALSE # Override the 'success' http status code.
121 -
      ds              <- data.frame() #Return an empty data.frame
121 +
      ds              <- tibble::tibble() # Return an empty data.frame
122 122
123 123
      outcome_message <- sprintf(
124 124
        "The REDCap variable retrieval failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
@@ -128,7 +128,7 @@
Loading
128 128
      # nocov end
129 129
    }
130 130
  } else {
131 -
    ds              <- data.frame() #Return an empty data.frame
131 +
    ds              <- tibble::tibble() # Return an empty data.frame
132 132
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
133 133
      "The REDCapR read/export operation was not successful.  The returned dataset (of instruments) was empty."
134 134
    } else {

@@ -1,7 +1,7 @@
Loading
1 1
#' @title Export the metadata of a REDCap project
2 2
#'
3 3
#' @description Export the metadata (as a data dictionary) of a REDCap project
4 -
#' as a [base::data.frame()]. Each row in the data dictionary corresponds to
4 +
#' as a [tibble::tibble()]. Each row in the data dictionary corresponds to
5 5
#' one field in the project's dataset.
6 6
#'
7 7
#' @param redcap_uri The
@@ -28,7 +28,7 @@
Loading
28 28
#'
29 29
#' @return Currently, a list is returned with the following elements:
30 30
#'
31 -
#' * `data`: An R [base::data.frame()] of the desired records and columns.
31 +
#' * `data`: An R [tibble::tibble()] of the desired fields (as rows).
32 32
#' * `success`: A boolean value indicating if the operation was apparently
33 33
#' successful.
34 34
#' * `status_codes`: A collection of
@@ -43,17 +43,6 @@
Loading
43 43
#' string, separated by commas.
44 44
#' * `elapsed_seconds`: The duration of the function.
45 45
#'
46 -
#' @details
47 -
#' Specifically, it internally uses multiple calls to [redcap_read_oneshot()]
48 -
#' to select and return data.  Initially, only primary key is queried through
49 -
#' the REDCap API.  The long list is then subsetted into partitions, whose
50 -
#' sizes are determined by the `batch_size` parameter.  REDCap is then queried
51 -
#' for all variables of the subset's subjects.  This is repeated for each
52 -
#' subset, before returning a unified [base::data.frame()].
53 -
#'
54 -
#' The function allows a delay between calls, which allows the server to
55 -
#' attend to other users' requests.
56 -
#'
57 46
#' @author Will Beasley
58 47
#'
59 48
#' @references The official documentation can be found on the 'API Help Page'
@@ -142,7 +131,7 @@
Loading
142 131
      # Override the 'success' determination from the http status code
143 132
      #   and return an empty data.frame.
144 133
      kernel$success    <- FALSE
145 -
      ds                <- data.frame()
134 +
      ds                <- tibble::tibble()
146 135
      outcome_message   <- sprintf(
147 136
        "The REDCap metadata export failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
148 137
        kernel$status_code,
@@ -150,7 +139,7 @@
Loading
150 139
      )
151 140
    }       # nocov end
152 141
  } else {
153 -
    ds                  <- data.frame() #Return an empty data.frame
142 +
    ds                  <- tibble::tibble() # Return an empty data.frame
154 143
    outcome_message     <- sprintf(
155 144
      "The REDCapR metadata export operation was not successful.  The error message was:\n%s",
156 145
      kernel$raw_text

@@ -39,7 +39,7 @@
Loading
39 39
#' `httr` package.  See the details below. Optional.
40 40
#'
41 41
#' @return Currently, a list is returned with the following elements:
42 -
#' * `data`: An R [base::data.frame()] of the desired records and columns.
42 +
#' * `data`: A [tibble::tibble()] of the desired records and columns.
43 43
#' * `success`: A boolean value indicating if the operation was apparently
44 44
#' successful.
45 45
#' * `status_code`: The
@@ -177,8 +177,7 @@
Loading
177 177
          col_types       = col_types,
178 178
          guess_max       = guess_max,
179 179
          show_col_types  = FALSE
180 -
        ) %>%
181 -
        as.data.frame(),
180 +
        ),
182 181
183 182
      # Don't print the warning in the try block.  Print it below,
184 183
      #   where it's under the control of the caller.
@@ -203,7 +202,7 @@
Loading
203 202
      # Override the 'success' determination from the http status code.
204 203
      #   and return an empty data.frame.
205 204
      kernel$success   <- FALSE
206 -
      ds               <- data.frame()
205 +
      ds               <- tibble::tibble() # Return an empty data.frame
207 206
      outcome_message  <- sprintf(
208 207
        "The REDCap report failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
209 208
        kernel$status_code,
@@ -212,7 +211,7 @@
Loading
212 211
      # nocov end
213 212
    }
214 213
  } else { # kernel fails
215 -
    ds              <- data.frame() #Return an empty data.frame
214 +
    ds              <- tibble::tibble() # Return an empty data.frame
216 215
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
217 216
      "The REDCapR report operation was not successful.  The returned dataset was empty."  # nocov
218 217
    } else {

@@ -86,7 +86,7 @@
Loading
86 86
#' `httr` package.  See the details below. Optional.
87 87
#'
88 88
#' @return Currently, a list is returned with the following elements:
89 -
#' * `data`: An R [base::data.frame()] of the desired records and columns.
89 +
#' * `data`: A [tibble::tibble()] of the desired records and columns.
90 90
#' * `success`: A boolean value indicating if the operation was apparently
91 91
#' successful.
92 92
#' * `status_code`: The
@@ -292,8 +292,7 @@
Loading
292 292
          guess_max       = guess_max,
293 293
          locale          = locale,
294 294
          show_col_types  = FALSE
295 -
        ) %>%
296 -
        as.data.frame(),
295 +
        ),
297 296
298 297
      # Don't print the warning in the try block.  Print it below,
299 298
      #   where it's under the control of the caller.
@@ -337,7 +336,7 @@
Loading
337 336
      # Override the 'success' determination from the http status code.
338 337
      #   and return an empty data.frame.
339 338
      kernel$success   <- FALSE
340 -
      ds               <- data.frame()
339 +
      ds               <- tibble::tibble()
341 340
      outcome_message  <- sprintf(
342 341
        "The REDCap read failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
343 342
        kernel$status_code,
@@ -346,7 +345,7 @@
Loading
346 345
      # nocov end
347 346
    }
348 347
  } else { # kernel fails
349 -
    ds              <- data.frame() #Return an empty data.frame
348 +
    ds              <- tibble::tibble() # Return an empty data.frame
350 349
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
351 350
      "The REDCapR read/export operation was not successful.  The returned dataset was empty."  # nocov
352 351
    } else {

@@ -16,7 +16,20 @@
Loading
16 16
#' @param config_options  A list of options to pass to `POST` method in the
17 17
#' `httr` package.  See the details below.  Optional.
18 18
#'
19 -
#' @return a [utils::packageDescription].
19 +
#' @return Currently, a list is returned with the following elements:
20 +
#' * `data_user`: A [tibble::tibble()] of all users associated with the project.
21 +
#' One row represents one user.
22 +
#' * `data_user_form`: A [tibble::tibble()] of permissions for users and forms.
23 +
#' One row represents a unique user-by-form combination.
24 +
#' * `success`: A boolean value indicating if the operation was apparently
25 +
#' successful.
26 +
#' * `status_codes`: A collection of
27 +
#' [http status codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes),
28 +
#' separated by semicolons.  There is one code for each batch attempted.
29 +
#' * `outcome_messages`: A collection of human readable strings indicating the
30 +
#' operations' semicolons.  There is one code for each batch attempted.  In an
31 +
#' unsuccessful operation, it should contain diagnostic information.
32 +
#' * `elapsed_seconds`: The duration of the function.
20 33
#'
21 34
#' @note
22 35
#' **Documentation in REDCap 8.4.0**
@@ -31,11 +44,13 @@
Loading
31 44
#' ```
32 45
#'
33 46
#' @examples
47 +
#' \dontrun{
34 48
#' uri      <- "https://bbmc.ouhsc.edu/redcap/api/"
35 49
#' token    <- "06DEFB601F9B46847DAA9DF0CFA951B4"
36 50
#' result   <- REDCapR::redcap_users_export(redcap_uri=uri, token=token)
37 51
#' result$data_user
38 52
#' result$data_user_form
53 +
#' }
39 54
40 55
#' @export
41 56
redcap_users_export <- function(
@@ -159,8 +174,8 @@
Loading
159 174
    } else {
160 175
      # nocov start
161 176
      kernel$success   <- FALSE # Override the 'success' http status code.
162 -
      ds_user          <- data.frame() # Return an empty data.frame
163 -
      ds_user_form     <- data.frame() # Return an empty data.frame
177 +
      ds_user          <- tibble::tibble() # Return an empty data.frame
178 +
      ds_user_form     <- tibble::tibble() # Return an empty data.frame
164 179
      outcome_message  <- sprintf(
165 180
        "The REDCap user export failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
166 181
        kernel$status_code,
@@ -169,8 +184,8 @@
Loading
169 184
      # nocov end
170 185
    }
171 186
  } else {
172 -
    ds_user          <- data.frame() # Return an empty data.frame
173 -
    ds_user_form     <- data.frame() # Return an empty data.frame
187 +
    ds_user          <- tibble::tibble() # Return an empty data.frame
188 +
    ds_user_form     <- tibble::tibble() # Return an empty data.frame
174 189
    outcome_message  <- sprintf(
175 190
      "The REDCap user export failed.  The error message was:\n%s",
176 191
      kernel$raw_text

@@ -140,6 +140,7 @@
Loading
140 140
    )
141 141
  }
142 142
}
143 +
143 144
#' @export
144 145
validate_field_names_collapsed <- function(field_names_collapsed, stop_on_error = FALSE) {
145 146
  field_names <- trimws(unlist(strsplit(field_names_collapsed, ",")))
@@ -156,7 +157,5 @@
Loading
156 157
  )
157 158
158 159
  # Vertically stack all the data.frames into a single data.frame
159 -
  ds_concern <- dplyr::bind_rows(lst_concerns)
160 -
161 -
 ds_concern
160 +
  dplyr::bind_rows(lst_concerns)
162 161
}

@@ -1,7 +1,7 @@
Loading
1 1
#' @title Read data access groups from a REDCap project
2 2
#'
3 3
#' @description This function reads all available data access groups from
4 -
#'   REDCap an returns them as a [base::data.frame()].
4 +
#'   REDCap an returns them as a [tibble::tibble()].
5 5
#'
6 6
#' @param redcap_uri The
7 7
#' [uri](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier)/url
@@ -23,7 +23,7 @@
Loading
23 23
#' `httr` package.
24 24
#'
25 25
#' @return Currently, a list is returned with the following elements:
26 -
#' * `data`: An R [base::data.frame()] of all data access groups of the project.
26 +
#' * `data`: A [tibble::tibble()] of all data access groups of the project.
27 27
#' * `success`: A boolean value indicating if the operation was apparently
28 28
#' successful.
29 29
#' * `status_codes`: A collection of
@@ -93,8 +93,7 @@
Loading
93 93
          file            = I(kernel$raw_text),
94 94
          locale          = locale,
95 95
          show_col_types  = FALSE
96 -
        ) %>%
97 -
        as.data.frame(),
96 +
        ),
98 97
99 98
      # Don't print the warning in the try block.  Print it below,
100 99
      #   where it's under the control of the caller.
@@ -118,7 +117,7 @@
Loading
118 117
      # Override the 'success' determination from the http status code.
119 118
      #   and return an empty data.frame.
120 119
      kernel$success   <- FALSE
121 -
      ds               <- data.frame()
120 +
      ds               <- tibble::tibble()
122 121
      outcome_message  <- sprintf(
123 122
        "The REDCap read failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
124 123
        kernel$status_code,
@@ -127,7 +126,7 @@
Loading
127 126
      # nocov end
128 127
    }
129 128
  } else { # kernel fails
130 -
    ds              <- data.frame() #Return an empty data.frame
129 +
    ds              <- tibble::tibble() # Return an empty data.frame
131 130
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
132 131
      "The REDCapR read/export operation was not successful.  The returned dataset was empty."  # nocov
133 132
    } else {

@@ -18,7 +18,7 @@
Loading
18 18
#' `httr` package.  See the details below. Optional.
19 19
#'
20 20
#' @return Currently, a list is returned with the following elements,
21 -
#' * `data`: An R [base::data.frame()] where each row represents one column
21 +
#' * `data`: A [tibble::tibble()] where each row represents one column
22 22
#' in the REDCap dataset.
23 23
#' * `success`: A boolean value indicating if the operation was apparently
24 24
#' successful.
@@ -109,7 +109,7 @@
Loading
109 109
    } else {
110 110
      # nocov start
111 111
      kernel$success  <- FALSE # Override the 'success' http status code.
112 -
      ds              <- data.frame() #Return an empty data.frame
112 +
      ds              <- tibble::tibble() # Return an empty data.frame
113 113
114 114
      outcome_message <- sprintf(
115 115
        "The REDCap variable retrieval failed.  The http status code was %i.  The 'raw_text' returned was '%s'.",
@@ -119,7 +119,7 @@
Loading
119 119
      # nocov end
120 120
    }
121 121
  } else {
122 -
    ds              <- data.frame() #Return an empty data.frame
122 +
    ds              <- tibble::tibble() # Return an empty data.frame
123 123
    outcome_message <- if (any(grepl(kernel$regex_empty, kernel$raw_text))) {
124 124
      "The REDCapR read/export operation was not successful.  The returned dataset (of variables) was empty."
125 125
    } else {
Files Coverage
R 95.99%
Project Totals (40 files) 95.99%
1
comment: false
2

3
coverage:
4
  status:
5
    project:
6
      default:
7
        target: auto
8
        threshold: 3%
9
    patch:
10
      default:
11
        target: auto
12
        threshold: 3%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading