diff --git a/R/query.R b/R/query.R index 89923818..83efa874 100644 --- a/R/query.R +++ b/R/query.R @@ -3,7 +3,7 @@ ##' ##' @title Construct outpack query ##' -##' @param expr The query expression +##' @param expr The query expression. A `NULL` expression matches everything. ##' ##' @param name Optionally, the name of the packet to scope the query on. This ##' will be intersected with `scope` arg and is a shorthand way of running @@ -48,6 +48,9 @@ outpack_query <- function(expr, name = NULL, scope = NULL, subquery = NULL) { as_outpack_query <- function(expr, ...) { + if (missing(expr)) { + expr <- NULL + } if (inherits(expr, "outpack_query")) { if (...length() > 0) { stop("If 'expr' is an 'outpack_query', no additional arguments allowed") @@ -71,7 +74,7 @@ query_parse <- function(expr, context, subquery_env) { } expr <- expr[[1L]] } - } else if (!is.language(expr)) { + } else if (!(is.null(expr) || is.language(expr))) { stop("Invalid input for query") } @@ -107,6 +110,7 @@ query_component <- function(type, expr, context, args, ...) { query_parse_expr <- function(expr, context, subquery_env) { type <- query_parse_check_call(expr, context) fn <- switch(type, + empty = query_parse_empty, test = query_parse_test, group = query_parse_group, latest = query_parse_latest, @@ -119,6 +123,11 @@ query_parse_expr <- function(expr, context, subquery_env) { } +query_parse_empty <- function(expr, context, subquery_env) { + query_component("empty", expr, context, list()) +} + + query_parse_test <- function(expr, context, subquery_env) { args <- lapply(expr[-1], query_parse_value, context) name <- deparse(expr[[1]]) @@ -301,6 +310,10 @@ query_eval_error <- function(msg, expr, context) { query_parse_check_call <- function(expr, context) { + if (is.null(expr)) { + return("empty") + } + if (!is.call(expr)) { query_parse_error(sprintf( "Invalid query '%s'; expected some sort of expression", diff --git a/R/query_search.R b/R/query_search.R index 2ba7dd20..91f1c040 100644 --- a/R/query_search.R +++ b/R/query_search.R @@ -129,6 +129,7 @@ query_eval <- function(query, index, parameters, subquery) { switch(query$type, literal = query$value, lookup = query_eval_lookup(query, index, parameters), + empty = query_eval_empty(query, index, parameters, subquery), group = query_eval_group(query, index, parameters, subquery), test = query_eval_test(query, index, parameters, subquery), latest = query_eval_latest(query, index, parameters, subquery), @@ -205,6 +206,11 @@ query_eval_lookup <- function(query, index, parameters) { } +query_eval_empty <- function(query, index, parameters, subquery) { + index$index$id +} + + query_eval_group <- function(query, index, parameters, subquery) { args <- lapply(query$args, query_eval, index, parameters, subquery) switch(query$name, diff --git a/man/outpack_query.Rd b/man/outpack_query.Rd index d73f0816..6185846f 100644 --- a/man/outpack_query.Rd +++ b/man/outpack_query.Rd @@ -7,7 +7,7 @@ outpack_query(expr, name = NULL, scope = NULL, subquery = NULL) } \arguments{ -\item{expr}{The query expression} +\item{expr}{The query expression. A \code{NULL} expression matches everything.} \item{name}{Optionally, the name of the packet to scope the query on. This will be intersected with \code{scope} arg and is a shorthand way of running diff --git a/tests/testthat/test-query-search.R b/tests/testthat/test-query-search.R index de225e47..bec18ee3 100644 --- a/tests/testthat/test-query-search.R +++ b/tests/testthat/test-query-search.R @@ -844,3 +844,16 @@ test_that("allow search before query", { ids) expect_setequal(names(root$a$index()$metadata), ids) }) + + + +test_that("empty search returns full set", { + root <- create_temporary_root(use_file_store = TRUE) + ids <- list(a = vcapply(1:3, function(i) create_random_packet(root, "a")), + b = vcapply(1:3, function(i) create_random_packet(root, "b"))) + + expect_equal(outpack_search(root = root), + c(ids$a, ids$b)) + expect_equal(outpack_search(name = "a", root = root), + c(ids$a)) +}) diff --git a/tests/testthat/test-query.R b/tests/testthat/test-query.R index 6d0e539f..c55afe8e 100644 --- a/tests/testthat/test-query.R +++ b/tests/testthat/test-query.R @@ -12,8 +12,23 @@ test_that("Parse basic query", { }) +test_that("empty query is possible", { + expect_equal( + query_parse(NULL, NULL, new.env(parent = emptyenv())), + query_component("empty", expr = NULL, context = NULL, args = list())) + expect_equal( + outpack_query(NULL), + structure( + list(value = query_parse(NULL, NULL, new.env(parent = emptyenv())), + subquery = list(), + info = list(single = FALSE, + parameters = character())), + class = "outpack_query")) +}) + + test_that("Prevent unparseable queries", { - expect_error(query_parse(NULL, NULL, emptyenv()), + expect_error(query_parse(1, NULL, emptyenv()), "Invalid input for query") expect_error(query_parse("latest(); latest()", NULL, emptyenv()), "Expected a single expression")