aboutsummaryrefslogtreecommitdiff
path: root/icing/query/advanced_query_parser
diff options
context:
space:
mode:
authorTim Barron <tjbarron@google.com>2023-03-31 16:48:52 -0700
committerTim Barron <tjbarron@google.com>2023-03-31 16:48:52 -0700
commitb59049b030cc330b6c8ae1d03ea4c1a34235ac9b (patch)
tree09bb4692739de390a5ad70e5dc4f9acb7830fa3e /icing/query/advanced_query_parser
parentf3155ae11285c16d8d9de56b1ec1a1e0def2cf62 (diff)
downloadicing-b59049b030cc330b6c8ae1d03ea4c1a34235ac9b.tar.gz
Update Icing from upstream.
Descriptions: ======================================================================== Make int64_t the CreateUsageReport timestamp type ======================================================================== Create ResultAdjustmentInfo and refactor ResultStateV2 ======================================================================== Wrap parent/child adjustment info to std::unique_ptr ======================================================================== Apply join child snippet ======================================================================== Apply join child projection ======================================================================== Add IntegerSectionIndexingHandlerTest ======================================================================== Delete Result Retriever this class is dead code. ======================================================================== Introduce a placeholder for the custom function hasPropertyDefined(member) ======================================================================== Fix libtextclassifier3::StatusOr ======================================================================== Performance improvements to SnippetRetriever. ======================================================================== Bug: 193244409 Bug: 256022027 Bug: 259744228 Bug: 268680462 Bug: 270102295 Bug: 271015984 Bug: 274627497 Change-Id: I6bad316b28bb289fa8e3f5b0982d6aaa9e0d135f
Diffstat (limited to 'icing/query/advanced_query_parser')
-rw-r--r--icing/query/advanced_query_parser/query-visitor.cc36
-rw-r--r--icing/query/advanced_query_parser/query-visitor.h7
-rw-r--r--icing/query/advanced_query_parser/query-visitor_test.cc119
3 files changed, 160 insertions, 2 deletions
diff --git a/icing/query/advanced_query_parser/query-visitor.cc b/icing/query/advanced_query_parser/query-visitor.cc
index 31223a5..c2cee47 100644
--- a/icing/query/advanced_query_parser/query-visitor.cc
+++ b/icing/query/advanced_query_parser/query-visitor.cc
@@ -28,6 +28,7 @@
#include "icing/text_classifier/lib3/utils/base/statusor.h"
#include "icing/absl_ports/canonical_errors.h"
#include "icing/absl_ports/str_cat.h"
+#include "icing/index/iterator/doc-hit-info-iterator-all-document-id.h"
#include "icing/index/iterator/doc-hit-info-iterator-and.h"
#include "icing/index/iterator/doc-hit-info-iterator-none.h"
#include "icing/index/iterator/doc-hit-info-iterator-not.h"
@@ -204,8 +205,9 @@ void QueryVisitor::RegisterFunctions() {
// DocHitInfoIterator search(std::string);
// DocHitInfoIterator search(std::string, std::vector<std::string>);
- Function::EvalFunction search_eval =
- std::bind(&QueryVisitor::SearchFunction, this, std::placeholders::_1);
+ auto search_eval = [this](std::vector<PendingValue>&& args) {
+ return this->SearchFunction(std::move(args));
+ };
Function search_function =
Function::Create(DataType::kDocumentIterator, "search",
{Param(DataType::kString),
@@ -214,6 +216,18 @@ void QueryVisitor::RegisterFunctions() {
.ValueOrDie();
registered_functions_.insert(
{search_function.name(), std::move(search_function)});
+
+ // DocHitInfoIterator propertyDefined(std::string);
+ auto property_defined = [this](std::vector<PendingValue>&& args) {
+ return this->PropertyDefinedFunction(std::move(args));
+ };
+
+ Function property_defined_function =
+ Function::Create(DataType::kDocumentIterator, "propertyDefined",
+ {Param(DataType::kText)}, std::move(property_defined))
+ .ValueOrDie();
+ registered_functions_.insert(
+ {property_defined_function.name(), std::move(property_defined_function)});
}
libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction(
@@ -285,6 +299,24 @@ libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction(
return PendingValue(std::move(iterator));
}
+libtextclassifier3::StatusOr<PendingValue>
+QueryVisitor::PropertyDefinedFunction(std::vector<PendingValue>&& args) {
+ // The first arg is guaranteed to be a TEXT at this point. It should be safe
+ // to call ValueOrDie.
+
+ // TODO(b/268680462): Consume this and implement the actual iterator.
+ // const QueryTerm* member =
+ args.at(0).text_val().ValueOrDie();
+
+ std::unique_ptr<DocHitInfoIterator> iterator =
+ std::make_unique<DocHitInfoIteratorAllDocumentId>(
+ document_store_.last_added_document_id());
+
+ features_.insert(kPropertyDefinedInSchemaCustomFunctionFeature);
+
+ return PendingValue(std::move(iterator));
+}
+
libtextclassifier3::StatusOr<int64_t> QueryVisitor::PopPendingIntValue() {
if (pending_values_.empty()) {
return absl_ports::InvalidArgumentError("Unable to retrieve int value.");
diff --git a/icing/query/advanced_query_parser/query-visitor.h b/icing/query/advanced_query_parser/query-visitor.h
index 9fcaec0..c5598dd 100644
--- a/icing/query/advanced_query_parser/query-visitor.h
+++ b/icing/query/advanced_query_parser/query-visitor.h
@@ -242,6 +242,13 @@ class QueryVisitor : public AbstractSyntaxTreeVisitor {
libtextclassifier3::StatusOr<PendingValue> SearchFunction(
std::vector<PendingValue>&& args);
+ // Implementation of the propertyDefined(member) custom function.
+ // Returns:
+ // - a Pending Value holding a DocHitIterator to be implemented.
+ // - any errors returned by Lexer::ExtractTokens
+ libtextclassifier3::StatusOr<PendingValue> PropertyDefinedFunction(
+ std::vector<PendingValue>&& args);
+
// Handles a NaryOperatorNode where the operator is HAS (':') and pushes an
// iterator with the proper section filter applied. If the current property
// restriction represented by pending_property_restricts and the first child
diff --git a/icing/query/advanced_query_parser/query-visitor_test.cc b/icing/query/advanced_query_parser/query-visitor_test.cc
index b560d52..7aef40f 100644
--- a/icing/query/advanced_query_parser/query-visitor_test.cc
+++ b/icing/query/advanced_query_parser/query-visitor_test.cc
@@ -3583,6 +3583,125 @@ TEST_F(QueryVisitorTest, SearchFunctionNestedPropertyRestrictsExpanding) {
ElementsAre(docid6, docid0));
}
+TEST_F(QueryVisitorTest,
+ PropertyDefinedFunctionWithNoArgumentReturnsInvalidArgument) {
+ std::string query = "propertyDefined()";
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node,
+ ParseQueryHelper(query));
+ QueryVisitor query_visitor(
+ index_.get(), numeric_index_.get(), document_store_.get(),
+ schema_store_.get(), normalizer_.get(), tokenizer_.get(), query,
+ DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX,
+ /*needs_term_frequency_info_=*/true);
+ root_node->Accept(&query_visitor);
+ EXPECT_THAT(std::move(query_visitor).ConsumeResults(),
+ StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
+}
+
+TEST_F(
+ QueryVisitorTest,
+ PropertyDefinedFunctionWithMoreThanOneTextArgumentReturnsInvalidArgument) {
+ std::string query = "propertyDefined(foo, bar)";
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node,
+ ParseQueryHelper(query));
+ QueryVisitor query_visitor(
+ index_.get(), numeric_index_.get(), document_store_.get(),
+ schema_store_.get(), normalizer_.get(), tokenizer_.get(), query,
+ DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX,
+ /*needs_term_frequency_info_=*/true);
+ root_node->Accept(&query_visitor);
+ EXPECT_THAT(std::move(query_visitor).ConsumeResults(),
+ StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
+}
+
+TEST_F(QueryVisitorTest,
+ PropertyDefinedFunctionWithStringArgumentReturnsInvalidArgument) {
+ // The argument type is STRING, not TEXT here.
+ std::string query = "propertyDefined(\"foo\")";
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node,
+ ParseQueryHelper(query));
+ QueryVisitor query_visitor(
+ index_.get(), numeric_index_.get(), document_store_.get(),
+ schema_store_.get(), normalizer_.get(), tokenizer_.get(), query,
+ DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX,
+ /*needs_term_frequency_info_=*/true);
+ root_node->Accept(&query_visitor);
+ EXPECT_THAT(std::move(query_visitor).ConsumeResults(),
+ StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
+}
+
+TEST_F(QueryVisitorTest,
+ PropertyDefinedFunctionWithNonTextArgumentReturnsInvalidArgument) {
+ std::string query = "propertyDefined(1 < 2)";
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node,
+ ParseQueryHelper(query));
+ QueryVisitor query_visitor(
+ index_.get(), numeric_index_.get(), document_store_.get(),
+ schema_store_.get(), normalizer_.get(), tokenizer_.get(), query,
+ DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX,
+ /*needs_term_frequency_info_=*/true);
+ root_node->Accept(&query_visitor);
+ EXPECT_THAT(std::move(query_visitor).ConsumeResults(),
+ StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
+}
+
+TEST_P(QueryVisitorTest, PropertyDefinedFunctionCurrentlyReturnsEverything) {
+ // Set up two schemas, one with a "url" field and one without.
+ ICING_ASSERT_OK(schema_store_->SetSchema(
+ SchemaBuilder()
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("typeWithUrl")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("url")
+ .SetDataType(TYPE_STRING)
+ .SetCardinality(CARDINALITY_OPTIONAL)))
+ .AddType(SchemaTypeConfigBuilder().SetType("typeWithoutUrl"))
+ .Build()));
+
+ ICING_ASSERT_OK(document_store_->Put(
+ DocumentBuilder().SetKey("ns", "uri0").SetSchema("typeWithUrl").Build()));
+ Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1,
+ TERM_MATCH_PREFIX, /*namespace_id=*/0);
+ editor.BufferTerm("foo");
+ editor.IndexAllBufferedTerms();
+
+ ICING_ASSERT_OK(document_store_->Put(DocumentBuilder()
+ .SetKey("ns", "uri1")
+ .SetSchema("typeWithoutUrl")
+ .Build()));
+ editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX,
+ /*namespace_id=*/0);
+ editor.BufferTerm("foo");
+ editor.IndexAllBufferedTerms();
+
+ ICING_ASSERT_OK(document_store_->Put(
+ DocumentBuilder().SetKey("ns", "uri2").SetSchema("typeWithUrl").Build()));
+ editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX,
+ /*namespace_id=*/0);
+ editor.BufferTerm("bar");
+ editor.IndexAllBufferedTerms();
+
+ std::string query = CreateQuery("foo propertyDefined(url)");
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node,
+ ParseQueryHelper(query));
+ QueryVisitor query_visitor(
+ index_.get(), numeric_index_.get(), document_store_.get(),
+ schema_store_.get(), normalizer_.get(), tokenizer_.get(), query,
+ DocHitInfoIteratorFilter::Options(), TERM_MATCH_PREFIX,
+ /*needs_term_frequency_info_=*/true);
+ root_node->Accept(&query_visitor);
+ ICING_ASSERT_OK_AND_ASSIGN(QueryResults query_results,
+ std::move(query_visitor).ConsumeResults());
+ EXPECT_THAT(
+ query_results.features_in_use,
+ UnorderedElementsAre(kPropertyDefinedInSchemaCustomFunctionFeature,
+ kListFilterQueryLanguageFeature));
+
+ // TODO(b/268680462): Update once the feature is actually implemented.
+ EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()),
+ UnorderedElementsAre(kDocumentId0, kDocumentId1));
+}
+
INSTANTIATE_TEST_SUITE_P(QueryVisitorTest, QueryVisitorTest,
testing::Values(QueryType::kPlain,
QueryType::kSearch));