Skip to contents

If any of the data-masked named expressions in ... are not of the same type, then the object attempts to be cast to the type specified in the expression. .names and .size arguments can be used to check for given names and size of the data.frame/list. The checking of type and the type conversion are from the vctrs package (using vctrs::vec_is and vctrs::vec_cast) and thus stick to the vctrs type conversion rules. The checking of size is also from vctrs (using vctrs::vec_size) and thus applies vctrs size rules.

Usage

schema_cast(.data, ...)

# S3 method for class 'data.frame'
schema_cast(
  .data,
  ...,
  .lossy = FALSE,
  .names = NULL,
  .size = NULL,
  .class = NULL,
  .error_call = caller_env()
)

# S3 method for class 'list'
schema_cast(
  .data,
  ...,
  .lossy = FALSE,
  .names = NULL,
  .size = NULL,
  .class = NULL,
  .error_call = caller_env()
)

Arguments

.data

a data.frame or list to check the types schema of.

...

any number of data-masking name-value pairs to be evaluated using .data as a data-mask. Should follow the format of name = expected_type(), e.g, var_x = integer() or var_x = var_y.

.lossy

logical, if TRUE allow lossy casts.

.names

optional character vector of names which must be present in the data.frame/list.

.size

optional scalar integerish value for the size that the data.frame/list must have.

.class

class to assign to the error (passed to rlang::abort).

.error_call

the call environment to use for the error (passed to rlang::abort).

Details

See also schema and schema_recycle, as well as cast_if_not for a non-data-masked version of casting.

Examples

# NB: Some of these examples are expected to produce an error. To
#     prevent them from terminating a run with example() they are
#     piped into a call to try().

li <- list(x = 1.1, y = "hi", z = 1L:2L)
# input remains the same if types match
li |>
  schema_cast(x = double(), y = character(), z = integer()) |>
  lapply(class)
#> $x
#> [1] "numeric"
#> 
#> $y
#> [1] "character"
#> 
#> $z
#> [1] "integer"
#> 

li |>
  schema_cast(y = numeric()) |>
  try()
#> Error in eval(expr, envir) : Error in `schema_cast()`
#>  Can't convert `y` <character> to <double>.
# => Error: Can't convert `y` <character> to <double>.

li |>
  schema_cast(x = z) |>
  try()
#> Error in eval(expr, envir) : Error in `schema_cast()`
#>  Can't convert from `x` <double> to <integer> due to loss of precision. 
#>   Locations: 1
# => Error: Can't convert from `x` <double> to <integer> due to loss of precision.

# with lossy casting
li |>
  schema_cast(x = z, .lossy = TRUE) |>
  lapply(class)
#> $x
#> [1] "integer"
#> 
#> $y
#> [1] "character"
#> 
#> $z
#> [1] "integer"
#> 

# schema_cast works sequentially with quosures, so references to objects will be
# after they have been evaluated:
li$a <- 1L
li |>
  schema_cast(z = x, a = z) |>
  lapply(class)
#> $x
#> [1] "numeric"
#> 
#> $y
#> [1] "character"
#> 
#> $z
#> [1] "numeric"
#> 
#> $a
#> [1] "numeric"
#> 

li |>
  schema_cast(x = numeric(), .size = 5) |>
  try()
#> Error in eval(expr, envir) : Error in `schema_cast()`
#>  Object `li` must have vctrs size `5`, not `4`.
# => Error: Object `li` must have vctrs size `5`, not `4`.

li |>
  schema_cast(x = numeric(), .names = c("x", "p")) |>
  try()
#> Error in eval(expr, envir) : Error in `schema_cast()`
#>  Objects `p` not found in `li`.
# => Error: Names `p` not found in `li`.

# injection and glue can be used to supply expressions, names, and messages:
li <- list(x = 1L, z = 5.5)
x_name <- "x"
schema_cast(li, !!x_name := z) |>
  lapply(class)
#> $x
#> [1] "numeric"
#> 
#> $z
#> [1] "numeric"
#> 
xg_name <- "{x_name}"
schema_cast(li, {{ xg_name }} := character()) |> try()
#> Error in eval(expr, envir) : Error in `schema_cast()`
#>  Can't convert `x` <integer> to <character>.
# => Error: Can't convert `x` <integer> to <character>.