Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export("cell_val_num<-")
export("datetimes_as_int64<-")
export("extended<-")
export("filter_list<-")
export("query_condition<-")
export("query_layout<-")
export("return.data.frame<-")
export("return.matrix<-")
Expand Down Expand Up @@ -47,6 +48,7 @@ export(limitTileDBCores)
export(max_chunk_size)
export(name)
export(nfilters)
export(query_condition)
export(query_layout)
export(r_to_tiledb_type)
export(return.data.frame)
Expand Down Expand Up @@ -127,6 +129,9 @@ export(tiledb_query_add_range_with_type)
export(tiledb_query_alloc_buffer_ptr_char)
export(tiledb_query_alloc_buffer_ptr_char_subarray)
export(tiledb_query_buffer_alloc_ptr)
export(tiledb_query_condition)
export(tiledb_query_condition_combine)
export(tiledb_query_condition_init)
export(tiledb_query_create_buffer_ptr)
export(tiledb_query_create_buffer_ptr_char)
export(tiledb_query_export_buffer)
Expand All @@ -146,6 +151,7 @@ export(tiledb_query_result_buffer_elements)
export(tiledb_query_set_buffer)
export(tiledb_query_set_buffer_ptr)
export(tiledb_query_set_buffer_ptr_char)
export(tiledb_query_set_condition)
export(tiledb_query_set_layout)
export(tiledb_query_set_subarray)
export(tiledb_query_status)
Expand Down Expand Up @@ -199,6 +205,7 @@ exportClasses(tiledb_domain)
exportClasses(tiledb_filter)
exportClasses(tiledb_filter_list)
exportClasses(tiledb_query)
exportClasses(tiledb_query_condition)
exportClasses(tiledb_sparse)
exportClasses(tiledb_vfs)
exportMethods("[")
Expand All @@ -209,6 +216,7 @@ exportMethods("cell_val_num<-")
exportMethods("datetimes_as_int64<-")
exportMethods("extended<-")
exportMethods("filter_list<-")
exportMethods("query_condition<-")
exportMethods("query_layout<-")
exportMethods("return.data.frame<-")
exportMethods("return.matrix<-")
Expand All @@ -231,6 +239,7 @@ exportMethods(is.sparse)
exportMethods(max_chunk_size)
exportMethods(name)
exportMethods(nfilters)
exportMethods(query_condition)
exportMethods(query_layout)
exportMethods(return.data.frame)
exportMethods(return.matrix)
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

* The builds now uses TileDB Embedded 2.3.0 (unless another version is found during build) (#258)

* Dense arrays with more than two dimensions can now be written (#260)

* Query condition support is available for TileDB 2.3.0 or later, allowing (possibly multiple) numerical constraints on attributes (#261)


# tiledb 0.9.3

Expand Down
15 changes: 14 additions & 1 deletion R/Query.R
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ tiledb_query_add_range <- function(query, schema, attr, lowval, highval, stride=
invisible(query)
}

#' Set a range for a given query
#' Set a range for a given query, also supplying type
#'
#' @param query A TileDB Query object
#' @param idx An integer index, zero based, of the dimensions
Expand Down Expand Up @@ -465,3 +465,16 @@ tiledb_query_get_range <- function(query, dimidx, rngidx) {
rngidx_argument=is.numeric(rngidx))
libtiledb_query_get_range_var(query@ptr, dimidx-1, rngidx-1)
}

#' Set a query combination object for a query
#'
#' @param query A TileDB Query object
#' @param qc A TileDB Query Combination object
#' @return The modified query object, invisibly
#' @export
tiledb_query_set_condition <- function(query, qc) {
stopifnot(`needs query object`=is(query, "tiledb_query"),
`needs query condition object`=is(qc, "tiledb_query_condition"))
query@ptr <- libtiledb_query_set_condition(query@ptr, qc@ptr)
invisible(query)
}
94 changes: 94 additions & 0 deletions R/QueryCondition.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# MIT License
#
# Copyright (c) 2021 TileDB Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

#' An S4 class for a TileDB QueryCondition object
#'
#' @slot ptr An external pointer to the underlying implementation
#' @slot init A logical variable tracking if the query condition object has been
#' initialized
#' @exportClass tiledb_query_condition
setClass("tiledb_query_condition",
slots = list(ptr = "externalptr",
init = "logical"))

#' Creates a 'tiledb_query_condition' object
#'
#' @param ctx (optional) A TileDB Ctx object; if not supplied the default
#' context object is retrieved
#' @return A 'tiledb_query_condition' object
#' @export
tiledb_query_condition <- function(ctx = tiledb_get_context()) {
stopifnot(`needs ctx object` = is(ctx, "tiledb_ctx"),
`needs TileDB 2.3.0 or newer` = tiledb_version(TRUE) >= "2.3.0")
ptr <- libtiledb_query_condition(ctx@ptr)
query_condition <- new("tiledb_query_condition", ptr = ptr, init = FALSE)
invisible(query_condition)
}

#' Initialize a 'tiledb_query_condition' object
#'
#' Initializes (and possibly allocates) a query condition object using a triplet of
#' attribute name, comparison value, and operator. Six types of conditions are supported,
#' they all take a single scalar comparison argument and attribute to compare against.
#' At present only integer or numeric attribute comparisons are implemented.
#' @param attr A character value with the scheme attribute name
#' @param value A scalar value that the attribute is compared against
#' @param dtype A character value with the TileDB data type of the attribute column, for
#' example 'FLOAT64' or 'INT32'
#' @param op A character value with then comparison operation, this must be one of
#' 'LT', 'LE', 'GT', 'GE', 'EQ', 'NE'.
#' @param qc (optional) A 'tiledb_query_condition' object to be initialized by this call,
#' if none is given a new one is allocated.
#' @return The initialized 'tiledb_query_condition' object
#' @export
tiledb_query_condition_init <- function(attr, value, dtype, op, qc = tiledb_query_condition()) {
stopifnot(`needs query condition object`=is(qc, "tiledb_query_condition"),
`attr must be character`=is.character(attr),
`value must be of length one`=is.vector(value) && all.equal(length(value),1),
`dtype must be character`=is.character(dtype),
`op must be character`=is.character(op))
op <- match.arg(op, c("LT", "LE", "GT", "GE", "EQ", "NE"))
## maybe check dtype too
libtiledb_query_condition_init(qc@ptr, attr, value, dtype, op)
qc@init <- TRUE
invisible(qc)
}

#' Combine two 'tiledb_query_condition' objects
#'
#' Combines two query condition object using a relatiional operator. Note that at present
#' only 'AND' is supported.
#' @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'.
#' @return The combined 'tiledb_query_condition' object
#' @export
tiledb_query_condition_combine <- function(lhs, rhs, op) {
stopifnot(`needs query condition object on lhs`=is(lhs, "tiledb_query_condition"),
`needs query condition object on rhs`=is(rhs, "tiledb_query_condition"),
`op must be character`=is.character(op))
op <- match.arg(op, c("AND", "OR", "NOT"))
qc <- tiledb_query_condition()
qc@ptr <- libtiledb_query_condition_combine(lhs@ptr, rhs@ptr, op)
qc@init <- TRUE
invisible(qc)
}
16 changes: 16 additions & 0 deletions R/RcppExports.R
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,22 @@ libtiledb_query_get_range_var <- function(query, dim_idx, rng_idx) {
.Call(`_tiledb_libtiledb_query_get_range_var`, query, dim_idx, rng_idx)
}

libtiledb_query_set_condition <- function(query, query_cond) {
.Call(`_tiledb_libtiledb_query_set_condition`, query, query_cond)
}

libtiledb_query_condition <- function(ctx) {
.Call(`_tiledb_libtiledb_query_condition`, ctx)
}

libtiledb_query_condition_init <- function(query_cond, attr_name, condition_value, cond_val_type, cond_op_string) {
invisible(.Call(`_tiledb_libtiledb_query_condition_init`, query_cond, attr_name, condition_value, cond_val_type, cond_op_string))
}

libtiledb_query_condition_combine <- function(lhs, rhs, str) {
.Call(`_tiledb_libtiledb_query_condition_combine`, lhs, rhs, str)
}

libtiledb_zip_coords_numeric <- function(coords, coord_length) {
.Call(`_tiledb_libtiledb_zip_coords_numeric`, coords, coord_length)
}
Expand Down
55 changes: 54 additions & 1 deletion R/TileDBArray.R
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#' @slot encryption_key A character value
#' @slot timestamp A POSIXct datetime variable
#' @slot as.matrix A logical value
#' @slot query_condition A Query Condition object
#' @slot ptr External pointer to the underlying implementation
#' @exportClass tiledb_array
setClass("tiledb_array",
Expand All @@ -55,6 +56,7 @@ setClass("tiledb_array",
encryption_key = "character",
timestamp = "POSIXct",
as.matrix = "logical",
query_condition = "tiledb_query_condition",
ptr = "externalptr"))

#' Constructs a tiledb_array object backed by a persisted tiledb array uri
Expand Down Expand Up @@ -82,6 +84,8 @@ setClass("tiledb_array",
#' to be openened.
#' @param as.matrix optional logical switch, defaults to "FALSE"; currently limited to dense
#' matrices; in the case of multiple attributes in query lists of matrices are returned
#' @param query_condition optional \code{tiledb_query_condition} object, by default uninitialized
#' without a condition; this functionality requires TileDB 2.3.0 or later
#' @param ctx tiledb_ctx (optional)
#' @return tiledb_array object
#' @export
Expand All @@ -97,6 +101,7 @@ tiledb_array <- function(uri,
encryption_key = character(),
timestamp = as.POSIXct(double(), origin="1970-01-01"),
as.matrix = FALSE,
query_condition = new("tiledb_query_condition"),
ctx = tiledb_get_context()) {
query_type = match.arg(query_type)
if (!is(ctx, "tiledb_ctx"))
Expand Down Expand Up @@ -149,6 +154,7 @@ tiledb_array <- function(uri,
encryption_key = encryption_key,
timestamp = timestamp,
as.matrix = as.matrix,
query_condition = query_condition,
ptr = array_xptr)
}

Expand Down Expand Up @@ -210,6 +216,7 @@ setMethod("show", signature = "tiledb_array",
," encryption_key = ", if (length(object@encryption_key) == 0) "(none)" else "(set)", "\n"
," timestamp = ", if (length(object@timestamp) == 0) "(none)" else format(object@timestamp), "\n"
," as.matrix = ", if (object@as.matrix) "TRUE" else "FALSE", "\n"
," query_condition = ", if (isTRUE(object@query_condition@init)) "(set)" else "(none)", "\n"
,sep="")
})

Expand Down Expand Up @@ -295,6 +302,11 @@ setValidity("tiledb_array", function(object) {
msg <- c(msg, "The 'as.data.frame' and 'as.matrix' slots cannot be both set to 'TRUE'.")
}

if (!is(object@query_condition, "tiledb_query_condition")) {
valid <- FALSE
msg <- c(msg, "The 'query_condition' slot does not contain a query condition object.")
}

if (!is(object@ptr, "externalptr")) {
valid <- FALSE
msg <- c(msg, "The 'ptr' slot does not contain an external pointer.")
Expand All @@ -311,7 +323,7 @@ setValidity("tiledb_array", function(object) {
## which, being an R date, has an internal representation of _days_ since the epoch, i.e.
## as.numeric(as.Date("2021-01-01")) yields 18628.
##
## We also convert to integer64 because that is
## We also convert the value to integer64 because that is the internal storage format
.mapDatetime2integer64 <- function(val, dtype) {
## in case it is not a datetime type, or already an int64, return unchanged
if (!grepl("^DATETIME_", dtype) || inherits(val, "integer64"))
Expand Down Expand Up @@ -581,6 +593,11 @@ setMethod("[", "tiledb_array",
MoreArgs=list(resrv=resrv, qryptr=qryptr, arrptr=arrptr),
SIMPLIFY=FALSE)

## if we have a query condition, apply it
if (isTRUE(x@query_condition@init)) {
qryptr <- libtiledb_query_set_condition(qryptr, x@query_condition@ptr)
}

## fire off query and close array
qryptr <- libtiledb_query_submit(qryptr)
libtiledb_array_close(arrptr)
Expand Down Expand Up @@ -1257,3 +1274,39 @@ setReplaceMethod("return.matrix",
validObject(x)
x
})


## -- query_condition accessors

#' @rdname query_condition-tiledb_array-method
#' @export
setGeneric("query_condition", function(object) standardGeneric("query_condition"))

#' @rdname query_condition-set-tiledb_array-method
#' @export
setGeneric("query_condition<-", function(x, value) standardGeneric("query_condition<-"))

#' Retrieve query_condition value for the array
#'
#' A \code{tiledb_array} object can have a corresponding query condition object.
#' This methods returns it.
#' @param object A \code{tiledb_array} object
#' @return A \code{tiledb_query_condition} object
#' @export
setMethod("query_condition", signature = "tiledb_array", function(object) object@query_condition)

#' Set query_condition object for the array
#'
#' A \code{tiledb_array} object can have an associated query condition object to set
#' conditions on the read queries. This methods sets the \sQuote{query_condition} object.
#' @param x A \code{tiledb_array} object
#'
#' @param value A \code{tiledb_query_conditon_object}
#' @return The modified \code{tiledb_array} array object
#' @export
setReplaceMethod("query_condition", signature = "tiledb_array", function(x, value) {
stopifnot(`need query_condition object` = is(value, "tiledb_query_condition"))
x@query_condition <- value
validObject(x)
x
})
8 changes: 8 additions & 0 deletions inst/include/tiledb.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,12 @@ struct vfs_fh {
typedef struct vfs_fh vfs_fh_t;


#if TILEDB_VERSION_MAJOR == 2 && TILEDB_VERSION_MINOR < 3
// we need a placeholder as tiledb::QueryCondition is in at least one function signature
namespace tiledb {
class QueryCondition {
};
}
#endif

#endif // __tiledb_h__
Loading