check_define.RdCompares the metadata with the datasets it claims to describe and returns
every disagreement as one row. This is the check that catches the drift a
spreadsheet-driven define always accumulates: a Length that no longer
covers the longest value actually present, a codelist term used in the data
but never declared, a variable dropped from the data but left in the
metadata.
check_define(spec, data)A tibble of class define21_check with columns dataset,
variable, value (the value level key, NA for a variable-level
finding), check, severity ("error" or "warning") and message.
Zero rows means the metadata and the data agree.
Findings reported:
dataset_missing - described in the metadata, not present in data.
dataset_undocumented - present in data, absent from the metadata.
variable_missing - declared for a dataset, not a column of it.
variable_undocumented - a column of the dataset, not declared.
type_mismatch - declared DataType disagrees with the observed R type.
A character column behind a date/time declaration is accepted, because
that is how SDTM ships ISO 8601 values; float covering integer data is
accepted; integer covering non-whole numbers is not.
length_too_short - the longest observed value is wider than Length.
codelist_value_missing - a value in the data is not a term of the
declared codelist.
codelist_external - warning: the codelist is an ExternalCodeList, so
its terms are not in the document and the data could not be compared with
them. The dictionary is not shipped with this package.
where_clause_not_evaluable - warning: a value level condition tests a
variable outside the dataset being checked (a cross-domain where clause),
so that value could not be checked.
value_absent - warning: value level metadata describes a value whose
where clause selects no record in the data.
empty_dataset / all_missing - warnings noting checks that could not
run because there was nothing to look at.
Every value in spec$value_levels is checked the same way as a variable,
on the subset of rows its def:WhereClauseDef selects. That is the point of
value level metadata: a Length declared for VSSTRESN where
VSTESTCD = "SYSBP" is checked against the systolic rows only.
ex <- define21_example()
check_define(ex$spec, ex$data)
#>
#> ── Define-XML consistency check ────────────────────────────────────────────────
#> ✔ 0 errors
#> ! 2 warning(s)
#> ℹ codelist_external: 2
#> # A tibble: 2 × 6
#> dataset variable value check severity message
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 AE AEDECOD NA codelist_external warning Variable 'AE.AEDECOD' uses …
#> 2 AE AEBODSYS NA codelist_external warning Variable 'AE.AEBODSYS' uses…
# Introduce real drift and watch it surface.
bad <- ex$data
bad$DM$USUBJID[1] <- "STUDY01-A-VERY-LONG-SUBJECT-IDENTIFIER"
bad$DM$SEX[2] <- "U"
check_define(ex$spec, bad)[, c("variable", "check", "severity")]
#>
#> ── Define-XML consistency check ────────────────────────────────────────────────
#> ✖ 2 error(s)
#> ! 2 warning(s)
#> ℹ length_too_short: 1
#> ℹ codelist_value_missing: 1
#> ℹ codelist_external: 2
#> # A tibble: 4 × 3
#> variable check severity
#> <chr> <chr> <chr>
#> 1 USUBJID length_too_short error
#> 2 SEX codelist_value_missing error
#> 3 AEDECOD codelist_external warning
#> 4 AEBODSYS codelist_external warning
# Drift inside one value of a value list, invisible at variable level.
vsbad <- ex$data
vsbad$VS$VSSTRESU[vsbad$VS$VSTESTCD == "PULSE"] <- "mmHg"
subset(check_define(ex$spec, vsbad), !is.na(value))[, c("variable", "value", "check")]
#> # A tibble: 1 × 3
#> variable value check
#> <chr> <chr> <chr>
#> 1 VSSTRESU PULSE codelist_value_missing