From 7b7d9543b22b14012e03d0b9c2547e2d1396ff41 Mon Sep 17 00:00:00 2001 From: Nick Vigilante Date: Tue, 6 May 2025 16:47:56 -0400 Subject: [PATCH] Add `tiledb_query_condition_negate` wrapper to R API --- DESCRIPTION | 2 +- NAMESPACE | 1 + NEWS.md | 4 ++++ R/QueryCondition.R | 34 ++++++++++++++++++++++----- R/RcppExports.R | 4 ++++ inst/tinytest/test_querycondition.R | 21 +++++++++++++++++ man/tiledb_query_condition_combine.Rd | 7 +++--- man/tiledb_query_condition_negate.Rd | 17 ++++++++++++++ src/RcppExports.cpp | 12 ++++++++++ src/libtiledb.cpp | 10 ++++++++ 10 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 man/tiledb_query_condition_negate.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 862723e00a..280c075413 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: tiledb Type: Package -Version: 0.31.1 +Version: 0.31.1.1 Title: Modern Database Engine for Complex Data Based on Multi-Dimensional Arrays Authors@R: c( person("TileDB, Inc.", role = c("aut", "cph")), diff --git a/NAMESPACE b/NAMESPACE index 29f1cb29ba..333d13c41d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -251,6 +251,7 @@ export(tiledb_query_condition) export(tiledb_query_condition_combine) export(tiledb_query_condition_create) export(tiledb_query_condition_init) +export(tiledb_query_condition_negate) export(tiledb_query_condition_set_use_enumeration) export(tiledb_query_create_buffer_ptr) export(tiledb_query_create_buffer_ptr_char) diff --git a/NEWS.md b/NEWS.md index 145e0a98c4..42ea45af6c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# tiledb 0.31.2 + +* Add `tiledb_query_condition_negate()` function to act as a `NOT` operator for query conditions [#819](https://github.com/TileDB-Inc/TileDB-R/pull/819) + # tiledb 0.31.1 * Allow `parse_query_condition()` to work on dimensions when an array is passed diff --git a/R/QueryCondition.R b/R/QueryCondition.R index 2f89d5e3fd..10b5fbc058 100644 --- a/R/QueryCondition.R +++ b/R/QueryCondition.R @@ -86,12 +86,11 @@ tiledb_query_condition_init <- function(attr, value, dtype, op, qc = tiledb_quer #' Combine two 'tiledb_query_condition' objects #' -#' Combines two query condition object using a relatiional operator. Support for operator -#' 'AND' is generally available, the 'OR' operator is available if TileDB 2.10 or newer is -#' used. +#' Combines two query condition objects using a relational operator. Support for operator +#' 'AND' is generally available. The 'OR' operator is available in TileDB 2.10 and later. #' @param lhs A 'tiledb_query_condition' object on the left-hand side of the relation #' @param rhs A 'tiledb_query_condition' object on the left-hand side of the relation -#' @param op A character value with then relation, this must be one of 'AND', 'OR' or 'NOT'. +#' @param op A character value with then relation, this must be one of 'AND' or 'OR'. #' @return The combined 'tiledb_query_condition' object #' @export tiledb_query_condition_combine <- function(lhs, rhs, op) { @@ -100,13 +99,29 @@ tiledb_query_condition_combine <- function(lhs, rhs, op) { "Argument 'rhs' must be a query condition object" = is(rhs, "tiledb_query_condition"), "Argument 'op' must be a character" = is.character(op) ) - op <- match.arg(op, c("AND", "OR", "NOT")) + op <- match.arg(op, c("AND", "OR")) qc <- tiledb_query_condition() qc@ptr <- libtiledb_query_condition_combine(lhs@ptr, rhs@ptr, op) qc@init <- TRUE invisible(qc) } +#' Negate a 'tiledb_query_condition' object +#' +#' Takes a query condition object and negates it, similar to the '!' operator. +#' @param qc A 'tiledb_query_condition' object to negate +#' @return The negated 'tiledb_query_condition' object +#' @export +tiledb_query_condition_negate <- function(qc) { + stopifnot( + "Argument 'qc' must be a query condition object" = is(qc, "tiledb_query_condition") + ) + res <- tiledb_query_condition() + res@ptr <- libtiledb_query_condition_negate(qc@ptr) + res@init <- TRUE + invisible(res) +} + #' Create a 'tiledb_query_condition' object from an expression #' #' The grammar for query conditions is at present constraint to eight operators (\code{">"}, @@ -150,7 +165,8 @@ parse_query_condition <- function(expr, ta = NULL, debug = FALSE, strict = TRUE, if (.hasArray && length(ta@sil) == 0) ta@sil <- .fill_schema_info_list(ta@uri) `%!in%` <- Negate(`%in%`) .isComparisonOperator <- function(x) tolower(as.character(x)) %in% c(">", ">=", "<", "<=", "==", "!=", "%in%", "%nin%") - .isBooleanOperator <- function(x) as.character(x) %in% c("&&", "||", "!", "&", "|") + .isBooleanOperator <- function(x) as.character(x) %in% c("&&", "||", "&", "|") + .isNegationOperator <- function(x) as.character(x) == "!" .isAscii <- function(x) grepl("^[[:alnum:]_]+$", x) .isInteger <- function(x) grepl("^[[:digit:]]+$", as.character(x)) .isDouble <- function(x) grepl("^[[:digit:]\\.]+$", as.character(x)) && length(grepRaw(".", as.character(x), fixed = TRUE, all = TRUE)) == 1 @@ -224,6 +240,12 @@ parse_query_condition <- function(expr, ta = NULL, debug = FALSE, strict = TRUE, .makeExpr(x[[3]]), .mapBoolToCharacter(as.character(x[1])) ) + } else if (.isNegationOperator(x[1])) { + if (debug) { + cat(" ![", as.character(x[2]), "]") + } + .makeExpr(x[[2]], debug = debug) + tiledb_query_condition_negate(.makeExpr(x[[2]])) } else if (.isInOperator(x[1])) { if (debug) { cat("in: [", as.character(x[2]), "]", diff --git a/R/RcppExports.R b/R/RcppExports.R index dc816c62a4..908e38c75c 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -825,6 +825,10 @@ libtiledb_query_condition_combine <- function(lhs, rhs, str) { .Call(`_tiledb_libtiledb_query_condition_combine`, lhs, rhs, str) } +libtiledb_query_condition_negate <- function(qc) { + .Call(`_tiledb_libtiledb_query_condition_negate`, qc) +} + libtiledb_query_condition_set_use_enumeration <- function(ctx, cond, use_enumeration) { invisible(.Call(`_tiledb_libtiledb_query_condition_set_use_enumeration`, ctx, cond, use_enumeration)) } diff --git a/inst/tinytest/test_querycondition.R b/inst/tinytest/test_querycondition.R index c1d2f38eb9..ad46546812 100644 --- a/inst/tinytest/test_querycondition.R +++ b/inst/tinytest/test_querycondition.R @@ -75,6 +75,27 @@ expect_equal(nrow(ndf), 18) tiledb_array_close(arr) rm(qry) +## check the negative of the previous condition +qry <- tiledb_query(arr, "READ") +rows <- integer(20) +cola <- integer(20) +colb <- numeric(20) +tiledb_query_set_buffer(qry, "__tiledb_rows", rows) +tiledb_query_set_buffer(qry, "a", cola) +tiledb_query_set_buffer(qry, "b", colb) +lhs <- tiledb_query_condition_init("a", 2L, "INT32", "NE") +rhs <- tiledb_query_condition_init("a", 12L, "INT32", "NE") +qc <- tiledb_query_condition_combine(lhs, rhs, "AND") +qc_inv <- tiledb_query_condition_negate(qc) +qry <- tiledb_query_set_condition(qry, qc_inv) +tiledb_query_submit(qry) +tiledb_query_finalize(qry) +n <- tiledb_query_result_buffer_elements(qry, "a") +ndf <- data.frame(rows=rows,a=cola,b=colb)[1:n,] +expect_equal(nrow(ndf), 2) +tiledb_array_close(arr) +rm(qry) + ## check a >=5 && b <= 115 qry <- tiledb_query(arr, "READ") rows <- integer(20) diff --git a/man/tiledb_query_condition_combine.Rd b/man/tiledb_query_condition_combine.Rd index d5321cad95..56006b713d 100644 --- a/man/tiledb_query_condition_combine.Rd +++ b/man/tiledb_query_condition_combine.Rd @@ -11,13 +11,12 @@ tiledb_query_condition_combine(lhs, rhs, op) \item{rhs}{A 'tiledb_query_condition' object on the left-hand side of the relation} -\item{op}{A character value with then relation, this must be one of 'AND', 'OR' or 'NOT'.} +\item{op}{A character value with then relation, this must be one of 'AND' or 'OR'.} } \value{ The combined 'tiledb_query_condition' object } \description{ -Combines two query condition object using a relatiional operator. Support for operator -'AND' is generally available, the 'OR' operator is available if TileDB 2.10 or newer is -used. +Combines two query condition objects using a relational operator. Support for operator +'AND' is generally available. The 'OR' operator is available in TileDB 2.10 and later. } diff --git a/man/tiledb_query_condition_negate.Rd b/man/tiledb_query_condition_negate.Rd new file mode 100644 index 0000000000..292a7d2110 --- /dev/null +++ b/man/tiledb_query_condition_negate.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/QueryCondition.R +\name{tiledb_query_condition_negate} +\alias{tiledb_query_condition_negate} +\title{Negate a 'tiledb_query_condition' object} +\usage{ +tiledb_query_condition_negate(qc) +} +\arguments{ +\item{qc}{A 'tiledb_query_condition' object to negate} +} +\value{ +The negated 'tiledb_query_condition' object +} +\description{ +Takes a query condition object and negates it, similar to the '!' operator. +} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 9a838b9d0c..121cab16c1 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -2457,6 +2457,17 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// libtiledb_query_condition_negate +XPtr libtiledb_query_condition_negate(XPtr qc); +RcppExport SEXP _tiledb_libtiledb_query_condition_negate(SEXP qcSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< XPtr >::type qc(qcSEXP); + rcpp_result_gen = Rcpp::wrap(libtiledb_query_condition_negate(qc)); + return rcpp_result_gen; +END_RCPP +} // libtiledb_query_condition_set_use_enumeration void libtiledb_query_condition_set_use_enumeration(XPtr ctx, XPtr cond, bool use_enumeration); RcppExport SEXP _tiledb_libtiledb_query_condition_set_use_enumeration(SEXP ctxSEXP, SEXP condSEXP, SEXP use_enumerationSEXP) { @@ -3957,6 +3968,7 @@ static const R_CallMethodDef CallEntries[] = { {"_tiledb_libtiledb_query_condition", (DL_FUNC) &_tiledb_libtiledb_query_condition, 1}, {"_tiledb_libtiledb_query_condition_init", (DL_FUNC) &_tiledb_libtiledb_query_condition_init, 5}, {"_tiledb_libtiledb_query_condition_combine", (DL_FUNC) &_tiledb_libtiledb_query_condition_combine, 3}, + {"_tiledb_libtiledb_query_condition_negate", (DL_FUNC) &_tiledb_libtiledb_query_condition_negate, 1}, {"_tiledb_libtiledb_query_condition_set_use_enumeration", (DL_FUNC) &_tiledb_libtiledb_query_condition_set_use_enumeration, 3}, {"_tiledb_libtiledb_query_condition_create", (DL_FUNC) &_tiledb_libtiledb_query_condition_create, 4}, {"_tiledb_libtiledb_zip_coords_numeric", (DL_FUNC) &_tiledb_libtiledb_zip_coords_numeric, 2}, diff --git a/src/libtiledb.cpp b/src/libtiledb.cpp index 88e5d91152..13fec2a755 100644 --- a/src/libtiledb.cpp +++ b/src/libtiledb.cpp @@ -4476,6 +4476,16 @@ libtiledb_query_condition_combine(XPtr lhs, return query_cond; } +// [[Rcpp::export]] +XPtr +libtiledb_query_condition_negate(XPtr qc) { + check_xptr_tag(qc); + tiledb::QueryCondition res = qc->negate(); + auto query_cond = + make_xptr(new tiledb::QueryCondition(res)); + return query_cond; +} + // [[Rcpp::export]] void libtiledb_query_condition_set_use_enumeration( XPtr ctx, XPtr cond,