diff --git a/NAMESPACE b/NAMESPACE index cb9c595..b4b4460 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,6 +12,7 @@ export(assert_character) export(assert_character_vector) export(assert_character_vector_or_glue) export(assert_class) +export(assert_connection) export(assert_create) export(assert_create_chain) export(assert_dataframe) diff --git a/R/assert.R b/R/assert.R index 511b391..dbe0b55 100644 --- a/R/assert.R +++ b/R/assert.R @@ -1,7 +1,8 @@ #' Assert that conditions are met #' #' @param ... a list of conditions to check -#' @param msg A character string containing the error message to display if any of the conditions are not met. The string can include the placeholder {failed_expressions} to insert a list of the failed expressions. The string can also include {?s} and {?is/are} to insert the correct pluralization for the list of failed expressions. +#' @param msg A character string containing the error message to display if any of the conditions are not met. +#' The string can include the placeholder \{failed_expressions\} to insert a list of the failed expressions. The string can also include \{?s\} and \{?is/are\} to insert the correct pluralization for the list of failed expressions. #' @inheritParams common_roxygen_params #' #' @return invisible(TRUE) if all conditions are met, otherwise aborts with the error message specified by msg diff --git a/R/assert_set.R b/R/assert_set.R index 00b2476..57f751b 100644 --- a/R/assert_set.R +++ b/R/assert_set.R @@ -59,12 +59,18 @@ assert_one_of <- assert_create_chain( #' #' @return Returns `invisible(TRUE)` if `x` and `y` contain all the same elements (ignoring order and duplicates), otherwise throws an error. #' @examples -#' assert_set_equal(c(1, 2, 3), c(3, 2, 1)) # Passes because elements are the same, order doesn't matter -#' assert_set_equal(c("A", "B", "C"), c("C", "A", "B")) # Passes because elements are identical +#' # Passes because elements are the same, order doesn't matter +#' assert_set_equal(c(1, 2, 3), c(3, 2, 1)) +#' +#' # Passes because elements are identical +#' assert_set_equal(c("A", "B", "C"), c("C", "A", "B")) #' #' try({ -#' assert_set_equal(c(1, 2, 3), c(1, 2)) # Throws error because elements are not identical -#' assert_set_equal(c("A", "B"), c("A", "B", "C")) # Throws error because elements differ +#' # Throws error because elements are not identical +#' assert_set_equal(c(1, 2, 3), c(1, 2)) +#' +#' # Throws error because elements differ +#' assert_set_equal(c("A", "B"), c("A", "B", "C")) #' }) #' @export assert_set_equal <- assert_create( diff --git a/R/assert_type.R b/R/assert_type.R index cdc3d63..fcff512 100644 --- a/R/assert_type.R +++ b/R/assert_type.R @@ -565,3 +565,36 @@ assert_scalar <- assert_create( default_error_msg = msg_helper_assert_type("scalar") ) +# Connections ----------------------------------------------------------------- + +#' Assert input is a database connection +#' +#' Assert the input object is a database connection, specifically of the "DBIConnection" class, +#' which is the standard virtual class used by the DBI package for database connections. +#' Note this assertion does not test if the database connection is valid and/or active. +#' +#' @param x An object to assert is a database connection +#' @param msg A custom error message displayed if `x` is not a valid database connection. +#' @inheritParams common_roxygen_params +#' +#' @return `invisible(TRUE)` if `x` is a valid database connection, otherwise aborts with an error message. +#' +#' @examples +#' try({ +#' # Assuming a valid DBI connection `conn`: +#' assert_connection(conn) # Passes if `conn` is a DBI connection +#' +#' assert_connection(42) # Fails with error message +#' }) +#' +#' @details +#' This function is designed for use with objects inheriting from the "DBIConnection" class, which is used widely across database connection implementations in R. +#' As other database interface packages are introduced, additional checks may be added to support other connection classes. +#' +#' @concept assert_type +#' @export +assert_connection <- assert_create( + func = is_connection, + default_error_msg = msg_helper_assert_type("database connection") +) + diff --git a/R/is_functions.R b/R/is_functions.R index 6e8e406..53eba2f 100644 --- a/R/is_functions.R +++ b/R/is_functions.R @@ -150,6 +150,11 @@ is_reactive <- function(x){ is_whole_number <- function(x){ return(x%%1==0) } + +is_connection <- function(x){ + inherits(x, "DBIConnection") +} + # Advanced ---------------------------------------------------------------- # assert_create_advanced functions ----------------------------------------- # These functions are for feeding into assert_create_advanced diff --git a/man/assert.Rd b/man/assert.Rd index 337e2b5..22e8870 100644 --- a/man/assert.Rd +++ b/man/assert.Rd @@ -9,7 +9,8 @@ assert(..., msg = NULL, call = rlang::caller_env()) \arguments{ \item{...}{a list of conditions to check} -\item{msg}{A character string containing the error message to display if any of the conditions are not met. The string can include the placeholder {failed_expressions} to insert a list of the failed expressions. The string can also include {?s} and {?is/are} to insert the correct pluralization for the list of failed expressions.} +\item{msg}{A character string containing the error message to display if any of the conditions are not met. +The string can include the placeholder \{failed_expressions\} to insert a list of the failed expressions. The string can also include \{?s\} and \{?is/are\} to insert the correct pluralization for the list of failed expressions.} \item{call}{Only relevant when pooling assertions into multi-assertion helper functions. See \link[cli]{cli_abort} for details.} } diff --git a/man/assert_connection.Rd b/man/assert_connection.Rd new file mode 100644 index 0000000..d4ef627 --- /dev/null +++ b/man/assert_connection.Rd @@ -0,0 +1,39 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/assert_type.R +\name{assert_connection} +\alias{assert_connection} +\title{Assert input is a database connection} +\usage{ +assert_connection(x, msg = NULL, call = rlang::caller_env(), arg_name = NULL) +} +\arguments{ +\item{x}{An object to assert is a database connection} + +\item{msg}{A custom error message displayed if \code{x} is not a valid database connection.} + +\item{call}{Only relevant when pooling assertions into multi-assertion helper functions. See \link[cli]{cli_abort} for details.} + +\item{arg_name}{Advanced use only. Name of the argument passed (default: NULL, will automatically extract arg_name).} +} +\value{ +\code{invisible(TRUE)} if \code{x} is a valid database connection, otherwise aborts with an error message. +} +\description{ +Assert the input object is a database connection, specifically of the "DBIConnection" class, +which is the standard virtual class used by the DBI package for database connections. +Note this assertion does not test if the database connection is valid and/or active. +} +\details{ +This function is designed for use with objects inheriting from the "DBIConnection" class, which is used widely across database connection implementations in R. +As other database interface packages are introduced, additional checks may be added to support other connection classes. +} +\examples{ +try({ + # Assuming a valid DBI connection `conn`: + assert_connection(conn) # Passes if `conn` is a DBI connection + + assert_connection(42) # Fails with error message +}) + +} +\concept{assert_type} diff --git a/man/assert_set_equal.Rd b/man/assert_set_equal.Rd index 2a5b83b..ea1c9b2 100644 --- a/man/assert_set_equal.Rd +++ b/man/assert_set_equal.Rd @@ -24,11 +24,17 @@ Returns \code{invisible(TRUE)} if \code{x} and \code{y} contain all the same ele This function checks that \code{x} and \code{y} contain exactly the same elements, ignoring order and duplicates. } \examples{ -assert_set_equal(c(1, 2, 3), c(3, 2, 1)) # Passes because elements are the same, order doesn't matter -assert_set_equal(c("A", "B", "C"), c("C", "A", "B")) # Passes because elements are identical +# Passes because elements are the same, order doesn't matter +assert_set_equal(c(1, 2, 3), c(3, 2, 1)) + +# Passes because elements are identical +assert_set_equal(c("A", "B", "C"), c("C", "A", "B")) try({ - assert_set_equal(c(1, 2, 3), c(1, 2)) # Throws error because elements are not identical - assert_set_equal(c("A", "B"), c("A", "B", "C")) # Throws error because elements differ + # Throws error because elements are not identical + assert_set_equal(c(1, 2, 3), c(1, 2)) + + # Throws error because elements differ + assert_set_equal(c("A", "B"), c("A", "B", "C")) }) } diff --git a/tests/testthat/test-assert_type.R b/tests/testthat/test-assert_type.R index 4fdc54f..b616f5e 100644 --- a/tests/testthat/test-assert_type.R +++ b/tests/testthat/test-assert_type.R @@ -523,3 +523,31 @@ cli::test_that_cli("assert_scalar() works", configs = "plain", { # Custom error messages work expect_error(assert_scalar(c(1, 2), msg = "Custom error message"), "Custom error message") }) + + +# Assert Connection --------------------------------------------------------- +cli::test_that_cli("assert_connection() works", configs = "plain", { + + # Works for valid database connection objects + # conn <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") # We use a mock connection instead since a real one would require more dependencies + conn <- structure(list(), class = c("SQLiteConnection", "DBIConnection")) + + expect_true(assert_connection(conn)) + + # Aborts for non-connection objects + expect_error(assert_connection(42), "'42' must be a database connection, not a numeric", fixed = TRUE) + expect_error(assert_connection('not_a_connection'), "'\"not_a_connection\"' must be a database connection, not a character", fixed = TRUE) + expect_error(assert_connection(list()), "'list()' must be a database connection, not a list", fixed = TRUE) + expect_error(assert_connection(data.frame(a = 1)), "'data.frame(a = 1)' must be a database connection, not a data.frame", fixed = TRUE) + + + # Error messages use variable name of passed arguments + x <- list() + expect_error(assert_connection(x), "'x' must be a database connection, not a list", fixed = TRUE) + + # Custom error messages work + expect_error(assert_connection(42, msg = "Custom error message"), "Custom error message") +}) + + +