diff --git a/NAMESPACE b/NAMESPACE index 51ae8f93df..242ffaf984 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,7 +2,6 @@ S3method(c,teal_slices) S3method(get_code,tdata) -S3method(get_join_keys,default) S3method(get_join_keys,tdata) S3method(get_metadata,default) S3method(get_metadata,tdata) @@ -21,7 +20,6 @@ export(TealReportCard) export(as.teal_slices) export(example_module) export(get_code_tdata) -export(get_join_keys) export(get_metadata) export(init) export(landing_popup_module) diff --git a/R/dummy_functions.R b/R/dummy_functions.R index cf0c0116d4..1fdaea0d8e 100644 --- a/R/dummy_functions.R +++ b/R/dummy_functions.R @@ -23,14 +23,9 @@ example_cdisc_data <- function() { # nolint ADSL$logical_test <- sample(c(TRUE, FALSE, NA), size = nrow(ADSL), replace = TRUE) # nolint ADSL$SEX[c(2, 5)] <- NA # nolint - cdisc_data_obj <- teal.data::cdisc_data( - cdisc_dataset(dataname = "ADSL", x = ADSL), - cdisc_dataset(dataname = "ADTTE", x = ADTTE) - ) - res <- teal.data::cdisc_data( - teal.data::cdisc_dataset(dataname = "ADSL", x = ADSL), - teal.data::cdisc_dataset(dataname = "ADTTE", x = ADTTE), + ADSL = ADSL, + ADTTE = ADTTE, code = ' ADSL <- data.frame( STUDYID = "study", @@ -62,7 +57,7 @@ example_cdisc_data <- function() { # nolint #' @keywords internal example_datasets <- function() { # nolint dummy_cdisc_data <- example_cdisc_data() - datasets <- teal.slice::init_filtered_data(dummy_cdisc_data) + datasets <- teal_data_to_filtered_data(dummy_cdisc_data) list( "d2" = list( "d3" = list( diff --git a/R/init.R b/R/init.R index 56b6812083..b697e2829b 100644 --- a/R/init.R +++ b/R/init.R @@ -15,7 +15,7 @@ #' an end-user, don't use this function, but instead this module. #' #' @param data (`TealData` or `TealDataset` or `TealDatasetConnector` or `list` or `data.frame` -#' or `MultiAssayExperiment`)\cr +#' or `MultiAssayExperiment`, `teal_data`)\cr #' `R6` object as returned by [teal.data::cdisc_data()], [teal.data::teal_data()], #' [teal.data::cdisc_dataset()], [teal.data::dataset()], [teal.data::dataset_connector()] or #' [teal.data::cdisc_dataset_connector()] or a single `data.frame` or a `MultiAssayExperiment` @@ -114,9 +114,11 @@ init <- function(data, footer = tags$p(), id = character(0)) { logger::log_trace("init initializing teal app with: data ({ class(data)[1] }).") - data <- teal.data::to_relational_data(data = data) - checkmate::assert_class(data, "TealData") + if (!inherits(data, c("TealData", "teal_data"))) { + data <- teal.data::to_relational_data(data = data) + } + checkmate::assert_multi_class(data, c("TealData", "teal_data")) checkmate::assert_multi_class(modules, c("teal_module", "list", "teal_modules")) checkmate::assert_string(title, null.ok = TRUE) checkmate::assert( @@ -142,22 +144,8 @@ init <- function(data, # resolve modules datanames datanames <- teal.data::get_dataname(data) - join_keys <- data$get_join_keys() - resolve_modules_datanames <- function(modules) { - if (inherits(modules, "teal_modules")) { - modules$children <- sapply(modules$children, resolve_modules_datanames, simplify = FALSE) - modules - } else { - modules$datanames <- if (identical(modules$datanames, "all")) { - datanames - } else if (is.character(modules$datanames)) { - datanames_adjusted <- intersect(modules$datanames, datanames) - include_parent_datanames(dataname = datanames_adjusted, join_keys = join_keys) - } - modules - } - } - modules <- resolve_modules_datanames(modules = modules) + join_keys <- teal.data::get_join_keys(data) + modules <- resolve_modules_datanames(modules = modules, datanames = datanames, join_keys = join_keys) if (!inherits(filter, "teal_slices")) { checkmate::assert_subset(names(filter), choices = datanames) @@ -170,13 +158,18 @@ init <- function(data, # Calculate app hash to ensure snapshot compatibility. See ?snapshot. Raw data must be extracted from environments. hashables <- mget(c("data", "modules")) - hashables$data <- sapply(hashables$data$get_datanames(), function(dn) { - if (hashables$data$is_pulled()) { + hashables$data <- if (inherits(hashables$data, "teal_data")) { + as.list(hashables$data@env) + } else if (inherits(hashables$data, "ddl")) { + attr(hashables$data, "code") + } else if (hashables$data$is_pulled()) { + sapply(get_dataname(hashables$data), simplify = FALSE, function(dn) { hashables$data$get_dataset(dn)$get_raw_data() - } else { - hashables$data$get_code(dn) - } - }, simplify = FALSE) + }) + } else { + hashables$data$get_code() + } + attr(filter, "app_id") <- rlang::hash(hashables) # check teal_slices @@ -231,8 +224,10 @@ init <- function(data, landing_module <- landing[[1L]] do.call(landing_module$server, c(list(id = "landing_module_shiny_id"), landing_module$server_args)) } - # copy object so that load won't be shared between the session - data <- data$copy(deep = TRUE) + if (inherits(data, "TealDataAbstract")) { + # copy TealData so that load won't be shared between the session + data <- data$copy(deep = TRUE) + } filter <- deep_copy_filter(filter) srv_teal_with_splash(id = id, data = data, modules = modules, filter = filter) } diff --git a/R/module_nested_tabs.R b/R/module_nested_tabs.R index 443587b07e..0a012f32dd 100644 --- a/R/module_nested_tabs.R +++ b/R/module_nested_tabs.R @@ -314,12 +314,14 @@ srv_nested_tabs.teal_module <- function(id, datasets, modules, is_module_specifi data, eventReactive( trigger_data(), - c( - get_rcode_str_install(), - get_rcode_libraries(), - get_datasets_code(datanames, datasets, hashes), - teal.slice::get_filter_expr(datasets, datanames) - ) + { + c( + get_rcode_str_install(), + get_rcode_libraries(), + get_datasets_code(datanames, datasets, hashes), + teal.slice::get_filter_expr(datasets, datanames) + ) + } ), datasets$get_join_keys(), metadata diff --git a/R/module_teal.R b/R/module_teal.R index e5d3b399e4..413e47d349 100644 --- a/R/module_teal.R +++ b/R/module_teal.R @@ -34,7 +34,7 @@ #' [init()] about how to call the corresponding server function. #' #' @param raw_data (`reactive`)\cr -#' returns the `TealData`, only evaluated once, `NULL` value is ignored +#' returns the `teal_data`, only evaluated once, `NULL` value is ignored #' #' @return #' `ui_teal` returns `HTML` for Shiny module UI. @@ -160,18 +160,14 @@ srv_teal <- function(id, modules, raw_data, filter = teal_slices()) { } ) - # loading the data ----- env <- environment() - datasets_reactive <- reactive({ - if (is.null(raw_data())) { - return(NULL) - } + datasets_reactive <- eventReactive(raw_data(), { env$progress <- shiny::Progress$new(session) env$progress$set(0.25, message = "Setting data") # create a list of data following structure of the nested modules list structure. # Because it's easier to unpack modules and datasets when they follow the same nested structure. - datasets_singleton <- teal.slice::init_filtered_data(raw_data()) + datasets_singleton <- teal_data_to_filtered_data(raw_data()) # Singleton starts with only global filters active. filter_global <- Filter(function(x) x$id %in% attr(filter, "mapping")$global_filters, filter) datasets_singleton$set_filter_state(filter_global) @@ -184,25 +180,9 @@ srv_teal <- function(id, modules, raw_data, filter = teal_slices()) { } else if (isTRUE(attr(filter, "module_specific"))) { # we should create FilteredData even if modules$datanames is null # null controls a display of filter panel but data should be still passed - datanames <- if (is.null(modules$datanames)) raw_data()$get_datanames() else modules$datanames - data_objects <- sapply( - datanames, - function(dataname) { - dataset <- raw_data()$get_dataset(dataname) - list( - dataset = dataset$get_raw_data(), - metadata = dataset$get_metadata(), - label = dataset$get_dataset_label() - ) - }, - simplify = FALSE - ) - datasets_module <- teal.slice::init_filtered_data( - data_objects, - join_keys = raw_data()$get_join_keys(), - code = raw_data()$get_code_class(), - check = raw_data()$get_check() - ) + datanames <- if (is.null(modules$datanames)) teal.data::get_dataname(raw_data()) else modules$datanames + # todo: subset tdata object to datanames + datasets_module <- teal_data_to_filtered_data(raw_data()) # set initial filters slices <- Filter(x = filter, f = function(x) { diff --git a/R/module_teal_with_splash.R b/R/module_teal_with_splash.R index 2a4b19e3e9..01348381b2 100644 --- a/R/module_teal_with_splash.R +++ b/R/module_teal_with_splash.R @@ -22,16 +22,16 @@ ui_teal_with_splash <- function(id, title, header = tags$p("Add Title Here"), footer = tags$p("Add Footer Here")) { - checkmate::assert_class(data, "TealDataAbstract") - is_pulled_data <- teal.data::is_pulled(data) + checkmate::assert_multi_class(data, c("TealDataAbstract", "teal_data")) ns <- NS(id) # Startup splash screen for delayed loading # We use delayed loading in all cases, even when the data does not need to be fetched. # This has the benefit that when filtering the data takes a lot of time initially, the # Shiny app does not time out. - splash_ui <- if (is_pulled_data) { - # blank ui if data is already pulled + splash_ui <- if (inherits(data, "teal_data")) { + div() + } else if (inherits(data, "TealDataAbstract") && teal.data::is_pulled(data)) { div() } else { message("App was initialized with delayed data loading.") @@ -52,36 +52,58 @@ ui_teal_with_splash <- function(id, #' will be displayed in the teal application. See [modules()] and [module()] for #' more details. #' @inheritParams shiny::moduleServer -#' @return `reactive`, return value of [srv_teal()] +#' @return `reactive` containing `teal_data` object when data is loaded. +#' If data is not loaded yet, `reactive` returns `NULL`. #' @export srv_teal_with_splash <- function(id, data, modules, filter = teal_slices()) { - checkmate::assert_class(data, "TealDataAbstract") + checkmate::assert_multi_class(data, c("TealDataAbstract", "teal_data")) moduleServer(id, function(input, output, session) { - logger::log_trace( - "srv_teal_with_splash initializing module with data { paste(data$get_datanames(), collapse = ' ')}." - ) + logger::log_trace("srv_teal_with_splash initializing module with data { toString(get_dataname(data))}.") if (getOption("teal.show_js_log", default = FALSE)) { shinyjs::showLog() } - is_pulled_data <- teal.data::is_pulled(data) - # raw_data contains TealDataAbstract, i.e. R6 object and container for data - # reactive to get data through delayed loading - # we must leave it inside the server because of callModule which needs to pick up the right session - if (is_pulled_data) { - raw_data <- reactiveVal(data) # will trigger by setting it + # raw_data contains teal_data object + # either passed to teal::init or returned from ddl + raw_data <- if (inherits(data, "teal_data")) { + reactiveVal(data) + } else if (inherits(data, "TealDataAbstract") && teal.data::is_pulled(data)) { + new_data <- do.call( + teal.data::teal_data, + c( + lapply(data$get_datasets(), function(x) x$get_raw_data()), + code = data$get_code(), + join_keys = data$get_join_keys() + ) + ) + reactiveVal(new_data) # will trigger by setting it } else { - raw_data <- data$get_server()(id = "startapp_module") + raw_data_old <- data$get_server()(id = "startapp_module") + raw_data <- reactive({ + data <- raw_data_old() + if (!is.null(data)) { + # raw_data is a reactive which returns data only when submit button clicked + # otherwise it returns NULL + do.call( + teal.data::teal_data, + c( + lapply(data$get_datasets(), function(x) x$get_raw_data()), + code = data$get_code(), + join_keys = data$get_join_keys() + ) + ) + } + }) + if (!is.reactive(raw_data)) { stop("The delayed loading module has to return a reactive object.") } + raw_data } res <- srv_teal(id = "teal", modules = modules, raw_data = raw_data, filter = filter) - logger::log_trace( - "srv_teal_with_splash initialized the module with data { paste(data$get_datanames(), collapse = ' ') }." - ) + logger::log_trace("srv_teal_with_splash initialized module with data { toString(get_dataname(data))}.") return(res) }) } diff --git a/R/tdata.R b/R/tdata.R index 25fc845d38..d3fe151b95 100644 --- a/R/tdata.R +++ b/R/tdata.R @@ -123,29 +123,15 @@ get_code_tdata <- function(data) { get_code(data) } - -#' Function to get join keys from a `tdata` object -#' @param data `tdata` - object to extract the join keys -#' @return Either `JoinKeys` object or `NULL` if no join keys -#' @export -get_join_keys <- function(data) { - UseMethod("get_join_keys", data) -} - - +#' Extract `JoinKeys` from `tdata` #' @rdname get_join_keys +#' @param data (`tdata`) object +#' @keywords internal #' @export get_join_keys.tdata <- function(data) { attr(data, "join_keys") } - -#' @rdname get_join_keys -#' @export -get_join_keys.default <- function(data) { - stop("get_join_keys function not implemented for this object") -} - #' Function to get metadata from a `tdata` object #' @param data `tdata` - object to extract the data from #' @param dataname `character(1)` the dataset name whose metadata is requested diff --git a/R/utils.R b/R/utils.R index dffa06364a..a4a31f2a5d 100644 --- a/R/utils.R +++ b/R/utils.R @@ -47,6 +47,29 @@ include_parent_datanames <- function(dataname, join_keys) { return(unique(c(parents, dataname))) } + + +#' Create a `FilteredData` +#' +#' Create a `FilteredData` object from a `teal_data` object +#' @param x (`teal_data`) object +#' @return (`FilteredData`) object +#' @keywords internal +teal_data_to_filtered_data <- function(x) { + checkmate::assert_class(x, "teal_data") + datanames <- x@datanames + + teal.slice::init_filtered_data( + x = as.list(x@env)[datanames], + join_keys = x@join_keys, + code = teal.data:::CodeClass$new( + code = paste(teal.code::get_code(x), collapse = "\n"), + dataname = teal.data::get_dataname(x) + ), + check = FALSE + ) +} + #' Template Function for `TealReportCard` Creation and Customization #' #' This function generates a report card with a title, @@ -77,3 +100,43 @@ report_card_template <- function(title, label, description = NULL, with_filter, if (with_filter) card$append_fs(filter_panel_api$get_filter_state()) card } +#' Resolve `datanames` for the modules +#' +#' Modifies `module$datanames` to include names of the parent dataset (taken from `join_keys`). +#' When `datanames` is set to `"all"` it is replaced with all available datasets names. +#' @param modules (`teal_modules`) object +#' @param datanames (`character`) names of datasets available in the `data` object +#' @param join_keys (`JoinKeys`) object +#' @return `teal_modules` with resolved `datanames` +#' @keywords internal +resolve_modules_datanames <- function(modules, datanames, join_keys) { + if (inherits(modules, "teal_modules")) { + modules$children <- sapply( + modules$children, + resolve_modules_datanames, + simplify = FALSE, + datanames = datanames, + join_keys = join_keys + ) + modules + } else { + modules$datanames <- if (identical(modules$datanames, "all")) { + datanames + } else if (is.character(modules$datanames)) { + extra_datanames <- setdiff(modules$datanames, datanames) + if (length(extra_datanames)) { + stop( + sprintf( + "Module %s has datanames that are not available in a 'data':\n %s not in %s", + modules$label, + toString(extra_datanames), + toString(datanames) + ) + ) + } + datanames_adjusted <- intersect(modules$datanames, datanames) + include_parent_datanames(dataname = datanames_adjusted, join_keys = join_keys) + } + modules + } +} diff --git a/_pkgdown.yml b/_pkgdown.yml index c75a61786d..01209c9ae4 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -114,7 +114,6 @@ reference: contents: - tdata - get_code_tdata - - get_join_keys - get_metadata - tdata2env - show_rcode_modal diff --git a/man/get_join_keys.Rd b/man/get_join_keys.Rd index d69ef17f9c..977a4b3145 100644 --- a/man/get_join_keys.Rd +++ b/man/get_join_keys.Rd @@ -1,23 +1,15 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/tdata.R -\name{get_join_keys} -\alias{get_join_keys} +\name{get_join_keys.tdata} \alias{get_join_keys.tdata} -\alias{get_join_keys.default} -\title{Function to get join keys from a \code{tdata} object} +\title{Extract \code{JoinKeys} from \code{tdata}} \usage{ -get_join_keys(data) - \method{get_join_keys}{tdata}(data) - -\method{get_join_keys}{default}(data) } \arguments{ -\item{data}{\code{tdata} - object to extract the join keys} -} -\value{ -Either \code{JoinKeys} object or \code{NULL} if no join keys +\item{data}{(\code{tdata}) object} } \description{ -Function to get join keys from a \code{tdata} object +Extract \code{JoinKeys} from \code{tdata} } +\keyword{internal} diff --git a/man/init.Rd b/man/init.Rd index 234f60697f..07bbec2deb 100644 --- a/man/init.Rd +++ b/man/init.Rd @@ -16,7 +16,7 @@ init( } \arguments{ \item{data}{(\code{TealData} or \code{TealDataset} or \code{TealDatasetConnector} or \code{list} or \code{data.frame} -or \code{MultiAssayExperiment})\cr +or \code{MultiAssayExperiment}, \code{teal_data})\cr \code{R6} object as returned by \code{\link[teal.data:cdisc_data]{teal.data::cdisc_data()}}, \code{\link[teal.data:teal_data]{teal.data::teal_data()}}, \code{\link[teal.data:cdisc_dataset]{teal.data::cdisc_dataset()}}, \code{\link[teal.data:dataset]{teal.data::dataset()}}, \code{\link[teal.data:dataset_connector]{teal.data::dataset_connector()}} or \code{\link[teal.data:cdisc_dataset_connector]{teal.data::cdisc_dataset_connector()}} or a single \code{data.frame} or a \code{MultiAssayExperiment} diff --git a/man/module_teal.Rd b/man/module_teal.Rd index a9a7f7f0ea..10c1c8654c 100644 --- a/man/module_teal.Rd +++ b/man/module_teal.Rd @@ -36,7 +36,7 @@ argument) will be placed in the app's \code{ui} function so code which needs to the footer of the app} \item{raw_data}{(\code{reactive})\cr -returns the \code{TealData}, only evaluated once, \code{NULL} value is ignored} +returns the \code{teal_data}, only evaluated once, \code{NULL} value is ignored} } \value{ \code{ui_teal} returns \code{HTML} for Shiny module UI. diff --git a/man/resolve_modules_datanames.Rd b/man/resolve_modules_datanames.Rd new file mode 100644 index 0000000000..0509844daf --- /dev/null +++ b/man/resolve_modules_datanames.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{resolve_modules_datanames} +\alias{resolve_modules_datanames} +\title{Resolve \code{datanames} for the modules} +\usage{ +resolve_modules_datanames(modules, datanames, join_keys) +} +\arguments{ +\item{modules}{(\code{teal_modules}) object} + +\item{datanames}{(\code{character}) names of datasets available in the \code{data} object} + +\item{join_keys}{(\code{JoinKeys}) object} +} +\value{ +\code{teal_modules} with resolved \code{datanames} +} +\description{ +Modifies \code{module$datanames} to include names of the parent dataset (taken from \code{join_keys}). +When \code{datanames} is set to \code{"all"} it is replaced with all available datasets names. +} +\keyword{internal} diff --git a/man/srv_teal_with_splash.Rd b/man/srv_teal_with_splash.Rd index abee79b6d1..7ab0c6efea 100644 --- a/man/srv_teal_with_splash.Rd +++ b/man/srv_teal_with_splash.Rd @@ -15,7 +15,7 @@ See the vignette for an example. However, \code{\link[=ui_teal_with_splash]{ui_t is then preferred to this function.} \item{data}{(\code{TealData} or \code{TealDataset} or \code{TealDatasetConnector} or \code{list} or \code{data.frame} -or \code{MultiAssayExperiment})\cr +or \code{MultiAssayExperiment}, \code{teal_data})\cr \code{R6} object as returned by \code{\link[teal.data:cdisc_data]{teal.data::cdisc_data()}}, \code{\link[teal.data:teal_data]{teal.data::teal_data()}}, \code{\link[teal.data:cdisc_dataset]{teal.data::cdisc_dataset()}}, \code{\link[teal.data:dataset]{teal.data::dataset()}}, \code{\link[teal.data:dataset_connector]{teal.data::dataset_connector()}} or \code{\link[teal.data:cdisc_dataset_connector]{teal.data::cdisc_dataset_connector()}} or a single \code{data.frame} or a \code{MultiAssayExperiment} @@ -34,7 +34,8 @@ Old way of specifying filters through a list is deprecated and will be removed i next release. Please fix your applications to use \code{\link[=teal_slices]{teal_slices()}}.} } \value{ -\code{reactive}, return value of \code{\link[=srv_teal]{srv_teal()}} +\code{reactive} containing \code{teal_data} object when data is loaded. +If data is not loaded yet, \code{reactive} returns \code{NULL}. } \description{ \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} diff --git a/man/teal_data_to_filtered_data.Rd b/man/teal_data_to_filtered_data.Rd new file mode 100644 index 0000000000..7ab5828072 --- /dev/null +++ b/man/teal_data_to_filtered_data.Rd @@ -0,0 +1,18 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/utils.R +\name{teal_data_to_filtered_data} +\alias{teal_data_to_filtered_data} +\title{Create a \code{FilteredData}} +\usage{ +teal_data_to_filtered_data(x) +} +\arguments{ +\item{x}{(\code{teal_data}) object} +} +\value{ +(\code{FilteredData}) object +} +\description{ +Create a \code{FilteredData} object from a \code{teal_data} object +} +\keyword{internal} diff --git a/man/ui_teal_with_splash.Rd b/man/ui_teal_with_splash.Rd index 7536afe2a7..0ece4d3027 100644 --- a/man/ui_teal_with_splash.Rd +++ b/man/ui_teal_with_splash.Rd @@ -17,7 +17,7 @@ ui_teal_with_splash( module id} \item{data}{(\code{TealData} or \code{TealDataset} or \code{TealDatasetConnector} or \code{list} or \code{data.frame} -or \code{MultiAssayExperiment})\cr +or \code{MultiAssayExperiment}, \code{teal_data})\cr \code{R6} object as returned by \code{\link[teal.data:cdisc_data]{teal.data::cdisc_data()}}, \code{\link[teal.data:teal_data]{teal.data::teal_data()}}, \code{\link[teal.data:cdisc_dataset]{teal.data::cdisc_dataset()}}, \code{\link[teal.data:dataset]{teal.data::dataset()}}, \code{\link[teal.data:dataset_connector]{teal.data::dataset_connector()}} or \code{\link[teal.data:cdisc_dataset_connector]{teal.data::cdisc_dataset_connector()}} or a single \code{data.frame} or a \code{MultiAssayExperiment} diff --git a/tests/testthat/test-init.R b/tests/testthat/test-init.R index e3c0fbbc33..a34e460472 100644 --- a/tests/testthat/test-init.R +++ b/tests/testthat/test-init.R @@ -1,140 +1,143 @@ -dataset_1 <- teal.data::dataset("iris", head(iris)) -adsl_df <- as.data.frame(as.list(setNames(nm = teal.data::get_cdisc_keys("ADSL")))) -adsl_dataset <- teal.data::cdisc_dataset( - "ADSL", adsl_df, - parent = character(0), keys = teal.data::get_cdisc_keys("ADSL") -) -mods <- teal:::example_modules() - -testthat::test_that("init data accepts TealData objects", { - teal_data_object <- teal.data::teal_data(dataset_1) - cdisc_data_object <- teal.data::cdisc_data(adsl_dataset) - testthat::expect_no_error(init(data = teal_data_object, modules = mods)) - testthat::expect_no_error(init(data = cdisc_data_object, modules = mods)) -}) - -testthat::test_that("init data throws an error with input other than accepted input", { +testthat::test_that("init data accepts TealData object", { + testthat::expect_no_error( + init( + data = teal.data::cdisc_data( + teal.data::cdisc_dataset( + "ADSL", + as.data.frame(as.list(setNames(nm = teal.data::get_cdisc_keys("ADSL")))), + parent = character(0), + keys = teal.data::get_cdisc_keys("ADSL") + ) + ), + modules = teal:::example_modules(datanames = "ADSL") + ) + ) +}) + +testthat::test_that("init data accepts teal_data object", { + testthat::expect_no_error( + init( + data = teal.data::teal_data(iris = iris), + modules = modules(teal:::example_module()) + ) + ) +}) + +testthat::test_that("init data throws an error with input other than TealData, teal_data and ddl", { character_vector <- c("a", "b", "c") numeric_vector <- c(1, 2, 3) matrix_d <- as.matrix(c(1, 2, 3)) - teal_data_list <- list(teal.data::teal_data(dataset_1)) - mods <- teal:::example_modules() - testthat::expect_error(init(data = character_vector, modules = mods)) - testthat::expect_error(init(data = numeric_vector, modules = mods)) - testthat::expect_error(init(data = numeric_vector, modules = mods)) - testthat::expect_error(init(data = matrix_d, modules = mods)) - testthat::expect_error(init(data = teal_data_list, modules = mods)) + teal_data_list <- list(teal.data::teal_data(teal.data::dataset("iris", iris))) + testthat::expect_error(init(data = character_vector, modules = modules(example_module()))) + testthat::expect_error(init(data = numeric_vector, modules = modules(example_module()))) + testthat::expect_error(init(data = numeric_vector, modules = modules(example_module()))) + testthat::expect_error(init(data = matrix_d, modules = modules(example_module()))) + testthat::expect_error(init(data = teal_data_list, modules = modules(example_module()))) }) -testthat::test_that("init data accepts a single TealDataset/CDISCTealDataset", { - testthat::expect_no_error(init(data = teal.data::dataset("iris", head(iris)), modules = mods)) +testthat::test_that("init data accepts a single TealDataset", { testthat::expect_no_error( init( - data = teal.data::cdisc_dataset("ADSL", adsl_df, parent = character(0), keys = teal.data::get_cdisc_keys("ADSL")), - modules = mods + data = teal.data::dataset("ADSL", head(iris)), + modules = teal:::example_modules(datanames = "ADSL") ) ) - testthat::expect_no_error(init(data = dataset_1, modules = mods)) - testthat::expect_no_error(init(data = adsl_dataset, modules = mods)) }) -testthat::test_that("init data accepts a list of single TealDataset/CDISCTealDataset without renaming", { - dataset_list <- list(teal.data::dataset("iris", head(iris))) - cdisc_dataset_list <- list( - teal.data::cdisc_dataset("ADSL", adsl_df, parent = character(0), keys = teal.data::get_cdisc_keys("ADSL")) - ) - - testthat::expect_no_error(init(data = list(teal.data::dataset("iris", head(iris))), modules = mods)) +testthat::test_that("init data accepts a list of single TealDataset without renaming", { testthat::expect_no_error( init( data = list( - teal.data::cdisc_dataset("ADSL", adsl_df, parent = character(0), keys = teal.data::get_cdisc_keys("ADSL")) + teal.data::dataset("ADSL", head(iris)), + teal.data::dataset("ADTTE", head(iris)) ), - modules = mods + modules = teal:::example_modules() ) ) - testthat::expect_no_error(init(data = dataset_list, modules = mods)) - testthat::expect_no_error(init(data = cdisc_dataset_list, modules = mods)) }) testthat::test_that("init data accepts a single dataframe", { - testthat::expect_no_error(init(data = adsl_df, modules = mods)) + testthat::expect_no_error( + init(data = list(iris = iris), modules = modules(example_module())) + ) }) testthat::test_that("init data accepts a list of single dataframe without renaming", { - testthat::expect_no_error(init(data = list(adsl_df), modules = mods)) + testthat::expect_no_error( + init(data = list(iris, mtcars), modules = modules(example_module())) + ) }) testthat::test_that("init data accepts a list of single dataframe with renaming", { - adsl_list <- list(data1 = adsl_df) - testthat::expect_no_error(init(data = list(data1 = adsl_df), modules = mods)) - testthat::expect_no_error(init(data = adsl_list, modules = mods)) + testthat::expect_no_error( + init( + data = list(iris2 = iris), + modules = modules(example_module()) + ) + ) }) testthat::test_that("init data accepts a list of a TealDataset and a dataframe without renaming", { - testthat::expect_no_error(init(data = list(dataset_1, adsl_df), modules = mods)) + testthat::expect_no_error( + init( + data = list(teal.data::dataset("ADSL", head(iris)), iris), + modules = modules(example_module()) + ) + ) }) testthat::test_that("init data accepts a single MultiAssayExperiment object", { utils::data(miniACC, package = "MultiAssayExperiment") - testthat::expect_no_error(init(data = miniACC, modules = mods)) + testthat::expect_no_error( + init(data = list(MAE = miniACC), modules = modules(example_module())) + ) }) testthat::test_that("init data accepts a list of a single MultiAssayExperiment object without renaming", { utils::data(miniACC, package = "MultiAssayExperiment") - testthat::expect_no_error(init(data = list(miniACC), modules = mods)) + testthat::expect_no_error(init(data = list(miniACC), modules = modules(example_module()))) }) testthat::test_that("init data accepts a list of a single MultiAssayExperiment object with renaming", { utils::data(miniACC, package = "MultiAssayExperiment") - testthat::expect_no_error(init(data = list(x = miniACC), modules = mods)) + testthat::expect_no_error(init(data = list(x = miniACC), modules = modules(example_module()))) }) testthat::test_that("init data acceptsa mixed list of MultiAssayExperiment object and data.frame", { utils::data(miniACC, package = "MultiAssayExperiment") - testthat::expect_no_error(init(data = list(x = miniACC, y = head(iris)), modules = mods)) + testthat::expect_no_error(init(data = list(x = miniACC, y = head(iris)), modules = modules(example_module()))) }) testthat::test_that("init data accepts a list of a TealDataset and a dataframe with renaming", { + testthat::expect_no_error(init( + data = list( + data1 = teal.data::dataset("iris", head(iris)), + data2 = as.data.frame(as.list(setNames(nm = teal.data::get_cdisc_keys("ADSL")))) + ), + modules = modules(example_module()) + )) +}) + +testthat::test_that("init data accepts a list of mixed TealDataset and dataframe with mixed renaming", { testthat::expect_no_error( init( data = list( data1 = teal.data::dataset("iris", head(iris)), - data2 = as.data.frame(as.list(setNames(nm = teal.data::get_cdisc_keys("ADSL")))) + iris2 = iris ), - modules = mods + modules = modules(example_module()) ) ) - testthat::expect_no_error(init(data = list(data1 = dataset_1, data2 = adsl_df), modules = mods)) -}) - -testthat::test_that("init data accepts a list of mixed TealDataset and dataframe with mixed renaming", { - testthat::expect_no_error(init(data = list(data1 = teal.data::dataset("iris", head(iris)), adsl_df), modules = mods)) - testthat::expect_no_error(init(data = list(dataset_1, data2 = adsl_df), modules = mods)) }) testthat::test_that("init data accepts TealDatasetConnector object", { dsc1 <- teal.data::dataset_connector("iris", teal.data::callable_function(function() head(iris))) - testthat::expect_no_error(init(data = dsc1, modules = mods)) - testthat::expect_no_error( - init( - data = teal.data::dataset_connector("iris", teal.data::callable_function(function() head(iris))), - modules = mods - ) - ) + testthat::expect_no_error(init(data = dsc1, modules = modules(example_module()))) }) testthat::test_that("init data accepts a list of TealDatasetConnector object", { dsc1 <- list(teal.data::dataset_connector("iris", teal.data::callable_function(function() head(iris)))) - testthat::expect_no_error(init(data = dsc1, modules = mods)) - testthat::expect_no_error( - init( - data = list( - teal.data::dataset_connector("iris", teal.data::callable_function(function() head(iris))) - ), - modules = mods - ) - ) + testthat::expect_no_error(init(data = dsc1, modules = modules(example_module()))) }) testthat::test_that("init modules accepts a teal_modules object", { @@ -161,7 +164,10 @@ testthat::test_that("init filter accepts named list or `teal_slices`", { fs <- teal.slice::teal_slices( teal.slice::teal_slice(dataname = "iris", varname = "species", selected = "setosa") ) - testthat::expect_no_error(init(data = dataset_1, modules = mods, filter = fl)) - testthat::expect_no_error(init(data = dataset_1, modules = mods, filter = fs)) - testthat::expect_error(init(data = dataset_1, modules = mods, filter = unclass(fs)), "Assertion failed") + testthat::expect_no_error(init(data = list(iris), modules = modules(example_module()), filter = fl)) + testthat::expect_no_error(init(data = list(iris), modules = modules(example_module()), filter = fs)) + testthat::expect_error( + init(data = list(iris), modules = modules(example_module()), filter = unclass(fs)), + "Assertion failed" + ) }) diff --git a/tests/testthat/test-module_teal.R b/tests/testthat/test-module_teal.R index fddc04b2c7..ca3cc28d8f 100644 --- a/tests/testthat/test-module_teal.R +++ b/tests/testthat/test-module_teal.R @@ -1,14 +1,12 @@ -iris_ds <- teal.data::dataset(dataname = "iris", x = iris) -mtcars_ds <- teal.data::dataset(dataname = "mtcars", x = mtcars) -data <- teal_data(iris_ds, mtcars_ds) +data <- teal_data(iris1 = iris, mtcars1 = mtcars, code = "iris1 <- iris; mtcars1 <- mtcars") -test_module1 <- module( +test_module1 <- example_module( label = "iris_tab", - datanames = "iris" + datanames = "iris1" ) -test_module2 <- module( +test_module2 <- example_module( label = "mtcars_tab", - datanames = "mtcars" + datanames = "mtcars1" ) testthat::test_that("srv_teal fails when raw_data is not reactive", { @@ -35,7 +33,6 @@ testthat::test_that("srv_teal initializes the data when raw_data changes", { modules = modules(test_module1) ), expr = { - testthat::expect_null(datasets_reactive()) raw_data(data) testthat::expect_named(datasets_reactive(), "iris_tab") } diff --git a/tests/testthat/test-module_teal_with_splash.R b/tests/testthat/test-module_teal_with_splash.R index f96d13633a..039ea01011 100644 --- a/tests/testthat/test-module_teal_with_splash.R +++ b/tests/testthat/test-module_teal_with_splash.R @@ -2,12 +2,12 @@ iris_ds <- teal.data::dataset(dataname = "iris", x = head(iris)) mtcars_ds <- teal.data::dataset(dataname = "mtcars", x = head(mtcars)) data <- teal_data(iris_ds, mtcars_ds) -test_module1 <- module( +test_module1 <- example_module( label = "iris_tab", datanames = "iris" ) -testthat::test_that("srv_teal_with_splash creates reactiveVal returning data input", { +testthat::test_that("srv_teal_with_splash creates reactiveVal returning teal_data", { shiny::testServer( app = srv_teal_with_splash, args = list( @@ -17,7 +17,7 @@ testthat::test_that("srv_teal_with_splash creates reactiveVal returning data inp ), expr = { testthat::expect_is(raw_data, "reactiveVal") - testthat::expect_identical(raw_data(), data) + testthat::expect_s4_class(raw_data(), "teal_data") } ) }) @@ -50,8 +50,8 @@ testthat::test_that("srv_teal_with_splash creates raw_data based on DDL returns expr = { testthat::expect_null(raw_data()) session$setInputs(`startapp_module-submit` = TRUE) # DDL has independent session id (without ns) - testthat::expect_is(raw_data(), "TealData") - testthat::expect_identical(raw_data()$get_dataset("iris")$get_raw_data(), iris) + testthat::expect_is(raw_data(), "teal_data") + testthat::expect_identical(raw_data()[["iris"]], iris) } ) }) diff --git a/vignettes/adding-support-for-reporting.Rmd b/vignettes/adding-support-for-reporting.Rmd index 70a9c69579..b28fbd32f4 100644 --- a/vignettes/adding-support-for-reporting.Rmd +++ b/vignettes/adding-support-for-reporting.Rmd @@ -54,10 +54,7 @@ Using `teal`, you can launch this example module with the following: ```{r, eval = FALSE} app <- init( - data = teal_data( - dataset("IRIS", iris), - dataset("MTCARS", mtcars) - ), + data = teal_data(IRIS = iris, MTCARS = mtcars), modules = teal_example_module() ) @@ -97,10 +94,7 @@ With these modifications, the module is now ready to be launched with `teal`: ```{r} app <- init( - data = teal_data( - dataset("IRIS", iris), - dataset("MTCARS", mtcars) - ), + data = teal_data(IRIS = iris, MTCARS = mtcars), modules = example_module_with_reporting() ) @@ -148,10 +142,7 @@ This updated module is now ready to be launched: ```{r} app <- init( - data = teal_data( - dataset("IRIS", iris), - dataset("MTCARS", mtcars) - ), + data = teal_data(IRIS = iris, MTCARS = mtcars), modules = example_module_with_reporting() ) @@ -201,10 +192,7 @@ example_module_with_reporting <- function(label = "example teal module") { ```{r} app <- init( - data = teal_data( - dataset("IRIS", iris), - dataset("MTCARS", mtcars) - ), + data = teal_data(IRIS = iris, MTCARS = mtcars), modules = example_module_with_reporting() ) @@ -323,9 +311,12 @@ example_reporter_module <- function(label = "Example") { app <- init( data = teal_data( - dataset("AIR", airquality, code = "data(airquality); AIR <- airquality"), - dataset("IRIS", iris, code = "data(iris); IRIS <- iris"), - check = FALSE + AIR = airquality, + IRI = iris, + code = "data(airquality) + AIR <- airquality + data(iris) + IRIS <- iris" ), modules = list( example_reporter_module(label = "with Reporter"), diff --git a/vignettes/creating-custom-modules.Rmd b/vignettes/creating-custom-modules.Rmd index 5a51551080..9e68150c0e 100644 --- a/vignettes/creating-custom-modules.Rmd +++ b/vignettes/creating-custom-modules.Rmd @@ -177,8 +177,8 @@ library(teal) app <- init( data = teal_data( - dataset("IRIS", iris, code = "IRIS <- iris"), - check = TRUE + IRIS = iris, + code = "IRIS <- iris" ), modules = tm_histogram_example( label = "Simple Module", diff --git a/vignettes/filter-panel.Rmd b/vignettes/filter-panel.Rmd index 544e67546e..009b7f5aae 100644 --- a/vignettes/filter-panel.Rmd +++ b/vignettes/filter-panel.Rmd @@ -19,8 +19,9 @@ library(teal) app <- init( data = teal_data( - dataset("IRIS", iris, code = "IRIS <- iris"), - dataset("CARS", mtcars, code = "CARS <- mtcars") + IRIS = iris, CARS = mtcars, + code = "IRIS <- iris + CARS <- mtcars" ), modules = example_module(), filter = teal_slices( @@ -47,8 +48,9 @@ library(teal) app <- init( data = teal_data( - dataset("IRIS", iris, code = "IRIS <- iris"), - dataset("CARS", mtcars, code = "CARS <- mtcars") + IRIS = iris, CARS = mtcars, + code = "IRIS <- iris + CARS <- mtcars" ), modules = modules( example_module(label = "all datasets"), diff --git a/vignettes/including-adam-data-in-teal.Rmd b/vignettes/including-adam-data-in-teal.Rmd index 0197e923c9..428bff9f88 100644 --- a/vignettes/including-adam-data-in-teal.Rmd +++ b/vignettes/including-adam-data-in-teal.Rmd @@ -57,29 +57,21 @@ adtte$AVAL <- c( ) cdisc_data_obj <- cdisc_data( - cdisc_dataset( - dataname = "ADSL", - x = adsl, - code = ' + ADSL = adsl, ADTTE = adtte, + code = ' adsl <- data.frame( STUDYID = "study", USUBJID = 1:10, SEX = sample(c("F", "M"), 10, replace = TRUE), AGE = rpois(10, 40) - )' - ), - cdisc_dataset( - dataname = "ADTTE", - x = adtte, - code = ' + ) adtte <- rbind(adsl, adsl, adsl) adtte$PARAMCD <- rep(c("OS", "EFS", "PFS"), each = 10) adtte$AVAL <- c( - rnorm(10, mean = 700, sd = 200), - rnorm(10, mean = 400, sd = 100), - rnorm(10, mean = 450, sd = 200) + rnorm(10, mean = 700, sd = 200), # dummy OS level + rnorm(10, mean = 400, sd = 100), # dummy EFS level + rnorm(10, mean = 450, sd = 200) # dummy PFS level )' - ) ) class(cdisc_data_obj) ``` @@ -87,36 +79,21 @@ class(cdisc_data_obj) which is equivalent to: ```{r, message=FALSE} example_data <- cdisc_data( - cdisc_dataset( - dataname = "ADSL", - x = adsl, - code = ' + ADSL = adsl, ADTTE = adtte, + code = ' adsl <- data.frame( STUDYID = "study", USUBJID = 1:10, SEX = sample(c("F", "M"), 10, replace = TRUE), AGE = rpois(10, 40) - )', - keys = c("STUDYID", "USUBJID") - ), - cdisc_dataset( - dataname = "ADTTE", - x = adtte, - code = ' + ) adtte <- rbind(adsl, adsl, adsl) adtte$PARAMCD <- rep(c("OS", "EFS", "PFS"), each = 10) adtte$AVAL <- c( rnorm(10, mean = 700, sd = 200), rnorm(10, mean = 400, sd = 100), rnorm(10, mean = 450, sd = 200) - )', - keys = c("STUDYID", "USUBJID", "PARAMCD") - ), - join_keys = join_keys( - join_key("ADSL", "ADSL", c("STUDYID", "USUBJID")), - join_key("ADTTE", "ADTTE", c("USUBJID", "STUDYID", "PARAMCD")), - join_key("ADSL", "ADTTE", c("STUDYID", "USUBJID")) - ) + )' ) class(cdisc_data_obj) ``` diff --git a/vignettes/including-general-data-in-teal.Rmd b/vignettes/including-general-data-in-teal.Rmd index 30251d6aaa..75c14cbd80 100644 --- a/vignettes/including-general-data-in-teal.Rmd +++ b/vignettes/including-general-data-in-teal.Rmd @@ -19,8 +19,9 @@ library(teal) app <- init( data = teal_data( - dataset("IRIS", iris, code = "IRIS <- iris"), - dataset("CARS", mtcars, code = "CARS <- mtcars") + IRIS = iris, CARS = mtcars, + code = "IRIS <- iris + CARS <- mtcars" ), modules = example_module() ) diff --git a/vignettes/including-mae-data-in-teal.Rmd b/vignettes/including-mae-data-in-teal.Rmd index bb4f5501ef..c614dc7a1f 100644 --- a/vignettes/including-mae-data-in-teal.Rmd +++ b/vignettes/including-mae-data-in-teal.Rmd @@ -21,10 +21,8 @@ The example below represents an application including `MultiAssayExperiment` dat library(teal) utils::data(miniACC, package = "MultiAssayExperiment") -mae_d <- dataset("MAE", miniACC, metadata = list(type = "example")) - app <- init( - data = teal_data(mae_d), + data = teal_data(MAE = miniACC), modules = example_module() ) diff --git a/vignettes/preprocessing-data.Rmd b/vignettes/preprocessing-data.Rmd index 3da46d6e21..38848a5ea5 100644 --- a/vignettes/preprocessing-data.Rmd +++ b/vignettes/preprocessing-data.Rmd @@ -35,7 +35,10 @@ new_iris <- transform(iris, id = seq_len(nrow(iris))) #