diff --git a/R/sxpdb.R b/R/sxpdb.R index 6dc86ad..b81fe78 100644 --- a/R/sxpdb.R +++ b/R/sxpdb.R @@ -539,6 +539,8 @@ query_from_value <- function(value) { #' * na: boolean #' * ndims: integer #' * attributes: boolean +#' * package: character vector of package names +#' * func: character vector of function names #' @returns query object #' @seealso [query_from_value()], [relax_query()], [close_query()], [view_db()], [map_db()] #' @export diff --git a/src/classnames.h b/src/classnames.h index c814a27..f76aea9 100644 --- a/src/classnames.h +++ b/src/classnames.h @@ -137,6 +137,10 @@ class ClassNames { class_names.load_all(); } + bool is_loaded() const { + return class_names.is_loaded(); + } + SEXP class_name_cache() const { return class_names.to_sexp();} std::optional get_class_id(const std::string& class_name) const { diff --git a/src/database.cpp b/src/database.cpp index 8600ae8..1b19449 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -513,8 +513,16 @@ const std::optional Database::sample_index() { void Database::update_query(Query& query) const { if(new_elements || !query.is_initialized()) { - // Make sure the reverse indexes are loaded. - const_cast(classes).load_all(); + // Make sure the reverse indexes are loaded if we need classes + if(query.class_names.size() > 0) { + const_cast(classes).load_all(); + } + // Make sure the origins are loaded + if(query.functions.size() > 0 || query.packages.size() > 0) + { + const_cast(origins).load_hashtables(); + } + query.update(*this); } } diff --git a/src/origins.h b/src/origins.h index db8673c..ed25856 100644 --- a/src/origins.h +++ b/src/origins.h @@ -194,11 +194,11 @@ class Origins { const std::string& function_name(uint32_t i) const { return function_names.read(i);} const std::string& param_name(uint32_t i) const { return param_names.read(i); } - const std::optional package_id(const std::string& package_name) { + const std::optional package_id(const std::string& package_name) const { return package_names.get_index(package_name); } - const std::optional function_id(const std::string& function_name) { + const std::optional function_id(const std::string& function_name) const { return function_names.get_index(function_name); } @@ -266,6 +266,10 @@ class Origins { // not for the parameters } + bool is_loaded() const { + return package_names.is_loaded() && function_names.is_loaded(); + } + uint64_t nb_values() const { if(write_mode) { return locations.size(); diff --git a/src/query.cpp b/src/query.cpp index 35caabc..f7654e9 100644 --- a/src/query.cpp +++ b/src/query.cpp @@ -107,6 +107,7 @@ void Query::update(const Database& db) { } } + assert(class_names.size() == 0 || db.classes.is_loaded()); for(const std::string& class_name : class_names) { std::optional class_id = db.classes.get_class_id(class_name); @@ -121,5 +122,40 @@ void Query::update(const Database& db) { } } } - //index_cache.runOptimize(); // Maybe not worth it... + + // refine with function and package name indexes + assert((packages.size() == 0 && functions.size() == 0) || db.origins.is_loaded()); + + + for(const std::string& package_name : packages) { + auto pkg_id = db.origins.package_id(package_name); + + if(pkg_id.has_value()) { + auto pkg_index = search_index.packages_index.at(pkg_id.value()); + index_cache &= pkg_index; + } + } + + for(const std::string& function_name : functions) { + auto fun_id = db.origins.function_id(function_name); + + if(fun_id.has_value()) { + int bin_index = -1; + for(int i = 0 ; i < search_index.function_index.size() ; i ++) { + if(search_index.function_index[i].first > fun_id.value()) { + bin_index = i; + break; + } + } + if(bin_index == -1) { + bin_index = search_index.function_index.size() - 1; + } + + if(bin_index >= 0) { // function index not empty + auto fun_index = search_index.search_function(db, search_index.function_index[bin_index].second, fun_id.value()); + index_cache &= fun_index; + } + } + } + } diff --git a/src/query.h b/src/query.h index b661db7..065dc49 100644 --- a/src/query.h +++ b/src/query.h @@ -58,6 +58,8 @@ class Query { std::optional length; std::optional ndims; // 2 = matrix, 0 = nothing, otherwise = array std::vector class_names; + std::vector packages; + std::vector functions; std::vector queries;// For union types, lists... public: Query(bool quiet_ = true) : quiet(quiet_), dist_cache(0, 0) {} @@ -191,6 +193,22 @@ class Query { else if (cur_name == "attributes") { d.has_attributes = Rf_asLogical(cur_sexp); } + else if (cur_name == "package") { + if(TYPEOF(cur_sexp) == STRSXP) { + d.packages = std::vector(Rf_xlength(cur_sexp)); + for(R_xlen_t j = 0; j < Rf_xlength(cur_sexp); j++) { + d.packages[j] = CHAR(STRING_ELT(cur_sexp, j)); + } + } + } + else if (cur_name == "func") { + if(TYPEOF(cur_sexp) == STRSXP) { + d.functions = std::vector(Rf_xlength(cur_sexp)); + for(R_xlen_t j = 0; j < Rf_xlength(cur_sexp); j++) { + d.functions[j] = CHAR(STRING_ELT(cur_sexp, j)); + } + } + } } return d; @@ -237,6 +255,8 @@ class Query { // Non quietness wins! d.quiet = d1.quiet || d2.quiet; + // TODO: implement other query parameters + return d; } diff --git a/src/table.h b/src/table.h index 01e76a4..d046715 100644 --- a/src/table.h +++ b/src/table.h @@ -655,6 +655,10 @@ class UniqTextTable : public Table { unique_loaded = true; } + bool is_loaded() const { + return unique_loaded; + } + uint64_t append_index(const std::string& value) { auto it = unique_lines.find(value); diff --git a/tests/testthat/test-query.R b/tests/testthat/test-query.R index 6180050..fdbdc9f 100644 --- a/tests/testthat/test-query.R +++ b/tests/testthat/test-query.R @@ -208,7 +208,7 @@ test_that("dimensions", { }) -test_that("origin queries", { +test_that("origin queries with values_from_origin", { l <- list(1L, "tu", 45.9, TRUE, c(2.1, 4)) origs <- rep.int(list(c("p", "fun", "param")), length(l)) @@ -249,3 +249,50 @@ test_that("origin queries", { close(db) }) + + +test_that("origin queries with query plan ", { + l <- list(1L, "tu", 45.9, TRUE, c(2.1, 4)) + origs <- rep.int(list(c("p", "fun", "param")), length(l)) + + # "tu" + origs[[2]][[1]] <- "package" + + # TRUE + origs[[4]][[2]] <- "g" + + # c(2.1, 4) + origs[[5]][[1]] <- "pack" + origs[[5]][[2]] <- "h" + + has_search_index(db) + + db <- db_from_values(l, origins = origs, with_search_index = TRUE) + + expect_equal(nb_values_db(db), length(l)) + + q <- query_from_plan(list(package = "p")) + vals <- view_db(db, q) + expect_equal(length(vals), length(l) - 2) + + q <- query_from_plan(list(package = "p", func = "fun")) + vals <- view_db(db, q) + expect_equal(length(vals), length(l) - 3) + + q <- query_from_plan(list(package = "package", func = "fun")) + vals <- view_db(db, q) + expect_equal(length(vals), 1) + expect_equal(vals[[1]], "tu") + + q <- query_from_plan(list(package = "p", func = "g")) + vals <- view_db(db, q) + expect_equal(length(vals), 1) + expect_equal(vals[[1]], TRUE) + + q <- query_from_plan(list(package = "pack", func = "h")) + vals <- view_db(db, q) + expect_equal(length(vals), 1) + expect_equal(vals[[1]], c(2.1, 4)) + + close(db) +})