diff options
Diffstat (limited to 'icing/query')
-rw-r--r-- | icing/query/advanced_query_parser/parser.cc | 24 | ||||
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor.cc | 43 | ||||
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor.h | 14 | ||||
-rw-r--r-- | icing/query/advanced_query_parser/query-visitor_test.cc | 1017 | ||||
-rw-r--r-- | icing/query/query-features.h | 6 | ||||
-rw-r--r-- | icing/query/query-processor.cc | 11 | ||||
-rw-r--r-- | icing/query/query-processor_test.cc | 145 |
7 files changed, 843 insertions, 417 deletions
diff --git a/icing/query/advanced_query_parser/parser.cc b/icing/query/advanced_query_parser/parser.cc index fd74561..82576a1 100644 --- a/icing/query/advanced_query_parser/parser.cc +++ b/icing/query/advanced_query_parser/parser.cc @@ -116,7 +116,7 @@ Parser::ConsumeMember() { // Member could be either `TEXT (DOT TEXT)* (DOT function)?` or `TEXT STAR` // at this point. So check for 'STAR' to differentiate the two cases. if (Match(Lexer::TokenType::STAR)) { - Consume(Lexer::TokenType::STAR); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::STAR)); std::string_view raw_text = text_node->raw_value(); std::string text = std::move(*text_node).value(); text_node = std::make_unique<TextNode>(std::move(text), raw_text, @@ -125,7 +125,7 @@ Parser::ConsumeMember() { } else { children.push_back(std::move(text_node)); while (Match(Lexer::TokenType::DOT)) { - Consume(Lexer::TokenType::DOT); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::DOT)); if (MatchFunction()) { ICING_ASSIGN_OR_RETURN(std::unique_ptr<FunctionNode> function_node, ConsumeFunction()); @@ -201,7 +201,7 @@ Parser::ConsumeArgs() { ICING_ASSIGN_OR_RETURN(std::unique_ptr<Node> arg, ConsumeExpression()); args.push_back(std::move(arg)); while (Match(Lexer::TokenType::COMMA)) { - Consume(Lexer::TokenType::COMMA); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::COMMA)); ICING_ASSIGN_OR_RETURN(arg, ConsumeExpression()); args.push_back(std::move(arg)); } @@ -223,7 +223,7 @@ Parser::ConsumeRestriction() { bool has_minus = Match(Lexer::TokenType::MINUS); if (has_minus) { - Consume(Lexer::TokenType::MINUS); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::MINUS)); } std::unique_ptr<Node> arg; @@ -276,10 +276,10 @@ libtextclassifier3::StatusOr<std::unique_ptr<Node>> Parser::ConsumeTerm() { operator_text = "MINUS"; } else { if (Match(Lexer::TokenType::NOT)) { - Consume(Lexer::TokenType::NOT); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::NOT)); operator_text = "NOT"; } else { - Consume(Lexer::TokenType::MINUS); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::MINUS)); operator_text = "MINUS"; } } @@ -296,7 +296,7 @@ libtextclassifier3::StatusOr<std::unique_ptr<Node>> Parser::ConsumeFactor() { terms.push_back(std::move(term)); while (Match(Lexer::TokenType::OR)) { - Consume(Lexer::TokenType::OR); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::OR)); ICING_ASSIGN_OR_RETURN(term, ConsumeTerm()); terms.push_back(std::move(term)); } @@ -330,7 +330,7 @@ Parser::ConsumeQueryExpression() { sequences.push_back(std::move(sequence)); while (Match(Lexer::TokenType::AND)) { - Consume(Lexer::TokenType::AND); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::AND)); ICING_ASSIGN_OR_RETURN(sequence, ConsumeSequence()); sequences.push_back(std::move(sequence)); } @@ -348,7 +348,7 @@ libtextclassifier3::StatusOr<std::unique_ptr<Node>> Parser::ConsumeMultExpr() { while (Match(Lexer::TokenType::TIMES) || Match(Lexer::TokenType::DIV)) { while (Match(Lexer::TokenType::TIMES)) { - Consume(Lexer::TokenType::TIMES); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::TIMES)); ICING_ASSIGN_OR_RETURN(node, ConsumeTerm()); stack.push_back(std::move(node)); } @@ -357,7 +357,7 @@ libtextclassifier3::StatusOr<std::unique_ptr<Node>> Parser::ConsumeMultExpr() { stack.push_back(std::move(node)); while (Match(Lexer::TokenType::DIV)) { - Consume(Lexer::TokenType::DIV); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::DIV)); ICING_ASSIGN_OR_RETURN(node, ConsumeTerm()); stack.push_back(std::move(node)); } @@ -380,7 +380,7 @@ Parser::ConsumeScoringExpression() { while (Match(Lexer::TokenType::PLUS) || Match(Lexer::TokenType::MINUS)) { while (Match(Lexer::TokenType::PLUS)) { - Consume(Lexer::TokenType::PLUS); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::PLUS)); ICING_ASSIGN_OR_RETURN(node, ConsumeMultExpr()); stack.push_back(std::move(node)); } @@ -389,7 +389,7 @@ Parser::ConsumeScoringExpression() { stack.push_back(std::move(node)); while (Match(Lexer::TokenType::MINUS)) { - Consume(Lexer::TokenType::MINUS); + ICING_RETURN_IF_ERROR(Consume(Lexer::TokenType::MINUS)); ICING_ASSIGN_OR_RETURN(node, ConsumeMultExpr()); stack.push_back(std::move(node)); } diff --git a/icing/query/advanced_query_parser/query-visitor.cc b/icing/query/advanced_query_parser/query-visitor.cc index d75a550..31da959 100644 --- a/icing/query/advanced_query_parser/query-visitor.cc +++ b/icing/query/advanced_query_parser/query-visitor.cc @@ -33,9 +33,11 @@ #include "icing/index/iterator/doc-hit-info-iterator-none.h" #include "icing/index/iterator/doc-hit-info-iterator-not.h" #include "icing/index/iterator/doc-hit-info-iterator-or.h" +#include "icing/index/iterator/doc-hit-info-iterator-property-in-document.h" #include "icing/index/iterator/doc-hit-info-iterator-property-in-schema.h" #include "icing/index/iterator/doc-hit-info-iterator-section-restrict.h" #include "icing/index/iterator/doc-hit-info-iterator.h" +#include "icing/index/property-existence-indexing-handler.h" #include "icing/query/advanced_query_parser/lexer.h" #include "icing/query/advanced_query_parser/param.h" #include "icing/query/advanced_query_parser/parser.h" @@ -222,13 +224,23 @@ void QueryVisitor::RegisterFunctions() { 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::kString)}, std::move(property_defined)) .ValueOrDie(); registered_functions_.insert( {property_defined_function.name(), std::move(property_defined_function)}); + + // DocHitInfoIterator hasProperty(std::string); + auto has_property = [this](std::vector<PendingValue>&& args) { + return this->HasPropertyFunction(std::move(args)); + }; + Function has_property_function = + Function::Create(DataType::kDocumentIterator, "hasProperty", + {Param(DataType::kString)}, std::move(has_property)) + .ValueOrDie(); + registered_functions_.insert( + {has_property_function.name(), std::move(has_property_function)}); } libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction( @@ -279,7 +291,7 @@ libtextclassifier3::StatusOr<PendingValue> QueryVisitor::SearchFunction( // Update members based on results of processing the query. if (args.size() == 2 && pending_property_restricts_.has_active_property_restricts()) { - iterator = std::make_unique<DocHitInfoIteratorSectionRestrict>( + iterator = DocHitInfoIteratorSectionRestrict::ApplyRestrictions( std::move(iterator), &document_store_, &schema_store_, pending_property_restricts_.active_property_restricts(), current_time_ms_); @@ -322,6 +334,31 @@ QueryVisitor::PropertyDefinedFunction(std::vector<PendingValue>&& args) { return PendingValue(std::move(property_in_schema_iterator)); } +libtextclassifier3::StatusOr<PendingValue> QueryVisitor::HasPropertyFunction( + std::vector<PendingValue>&& args) { + // The first arg is guaranteed to be a STRING at this point. It should be safe + // to call ValueOrDie. + const std::string& property_path = args.at(0).string_val().ValueOrDie()->term; + + // Perform an exact search for the property existence metadata token. + ICING_ASSIGN_OR_RETURN( + std::unique_ptr<DocHitInfoIterator> meta_hit_iterator, + index_.GetIterator( + absl_ports::StrCat(kPropertyExistenceTokenPrefix, property_path), + /*term_start_index=*/0, + /*unnormalized_term_length=*/0, kSectionIdMaskAll, + TermMatchType::EXACT_ONLY, + /*need_hit_term_frequency=*/false)); + + std::unique_ptr<DocHitInfoIterator> property_in_document_iterator = + std::make_unique<DocHitInfoIteratorPropertyInDocument>( + std::move(meta_hit_iterator)); + + features_.insert(kHasPropertyFunctionFeature); + + return PendingValue(std::move(property_in_document_iterator)); +} + libtextclassifier3::StatusOr<int64_t> QueryVisitor::PopPendingIntValue() { if (pending_values_.empty()) { return absl_ports::InvalidArgumentError("Unable to retrieve int value."); @@ -647,7 +684,7 @@ libtextclassifier3::Status QueryVisitor::ProcessHasOperator( std::set<std::string> property_restricts = {std::move(text_value.term)}; pending_values_.push( - PendingValue(std::make_unique<DocHitInfoIteratorSectionRestrict>( + PendingValue(DocHitInfoIteratorSectionRestrict::ApplyRestrictions( std::move(delegate), &document_store_, &schema_store_, std::move(property_restricts), current_time_ms_))); return libtextclassifier3::Status::OK; diff --git a/icing/query/advanced_query_parser/query-visitor.h b/icing/query/advanced_query_parser/query-visitor.h index 38864f8..d090b3c 100644 --- a/icing/query/advanced_query_parser/query-visitor.h +++ b/icing/query/advanced_query_parser/query-visitor.h @@ -247,13 +247,23 @@ class QueryVisitor : public AbstractSyntaxTreeVisitor { libtextclassifier3::StatusOr<PendingValue> SearchFunction( std::vector<PendingValue>&& args); - // Implementation of the propertyDefined(member) custom function. + // Implementation of the propertyDefined(property_path) custom function. // Returns: - // - a Pending Value holding a DocHitIterator to be implemented. + // - a Pending Value holding a DocHitIterator that returns hits for all + // documents whose schema types have defined the property specified by + // property_path. // - any errors returned by Lexer::ExtractTokens libtextclassifier3::StatusOr<PendingValue> PropertyDefinedFunction( std::vector<PendingValue>&& args); + // Implementation of the hasProperty(property_path) custom function. + // Returns: + // - a Pending Value holding a DocHitIterator that returns hits for all + // documents that have the property specified by property_path. + // - any errors returned by Lexer::ExtractTokens + libtextclassifier3::StatusOr<PendingValue> HasPropertyFunction( + 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 59e924d..9455baa 100644 --- a/icing/query/advanced_query_parser/query-visitor_test.cc +++ b/icing/query/advanced_query_parser/query-visitor_test.cc @@ -17,17 +17,28 @@ #include <cstdint> #include <limits> #include <memory> +#include <string> #include <string_view> +#include <unordered_map> +#include <utility> +#include <vector> #include "icing/text_classifier/lib3/utils/base/status.h" +#include "icing/text_classifier/lib3/utils/base/statusor.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "icing/absl_ports/str_cat.h" #include "icing/document-builder.h" +#include "icing/file/filesystem.h" +#include "icing/file/portable-file-backed-proto-log.h" +#include "icing/index/hit/hit.h" #include "icing/index/index.h" +#include "icing/index/iterator/doc-hit-info-iterator-filter.h" #include "icing/index/iterator/doc-hit-info-iterator-test-util.h" #include "icing/index/iterator/doc-hit-info-iterator.h" #include "icing/index/numeric/dummy-numeric-index.h" #include "icing/index/numeric/numeric-index.h" +#include "icing/index/property-existence-indexing-handler.h" #include "icing/jni/jni-cache.h" #include "icing/legacy/index/icing-filesystem.h" #include "icing/portable/platform.h" @@ -35,7 +46,13 @@ #include "icing/query/advanced_query_parser/lexer.h" #include "icing/query/advanced_query_parser/parser.h" #include "icing/query/query-features.h" +#include "icing/query/query-results.h" #include "icing/schema-builder.h" +#include "icing/schema/schema-store.h" +#include "icing/schema/section.h" +#include "icing/store/document-id.h" +#include "icing/store/document-store.h" +#include "icing/store/namespace-id.h" #include "icing/testing/common-matchers.h" #include "icing/testing/icu-data-file-helper.h" #include "icing/testing/jni-test-helpers.h" @@ -47,6 +64,8 @@ #include "icing/tokenization/tokenizer.h" #include "icing/transform/normalizer-factory.h" #include "icing/transform/normalizer.h" +#include "icing/util/clock.h" +#include "icing/util/status-macros.h" #include "unicode/uloc.h" namespace icing { @@ -218,16 +237,16 @@ TEST_P(QueryVisitorTest, SimpleLessThan) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price < 2"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -261,16 +280,16 @@ TEST_P(QueryVisitorTest, SimpleLessThanEq) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price <= 1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -304,16 +323,16 @@ TEST_P(QueryVisitorTest, SimpleEqual) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price == 2"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -347,16 +366,16 @@ TEST_P(QueryVisitorTest, SimpleGreaterThanEq) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price >= 1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -390,16 +409,16 @@ TEST_P(QueryVisitorTest, SimpleGreaterThan) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price > 1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -434,16 +453,16 @@ TEST_P(QueryVisitorTest, IntMinLessThanEqual) { int64_t int_min = std::numeric_limits<int64_t>::min(); std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(int_min); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_min)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(std::numeric_limits<int64_t>::max()); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(std::numeric_limits<int64_t>::max())); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(int_min + 1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_min + 1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price <= " + std::to_string(int_min)); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -478,16 +497,16 @@ TEST_P(QueryVisitorTest, IntMaxGreaterThanEqual) { int64_t int_max = std::numeric_limits<int64_t>::max(); std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(std::numeric_limits<int64_t>::min()); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(std::numeric_limits<int64_t>::min())); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(int_max); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_max)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(int_max - 1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_max - 1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price >= " + std::to_string(int_max)); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -521,18 +540,18 @@ TEST_P(QueryVisitorTest, NestedPropertyLessThan) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("subscription.price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("subscription.price < 2"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -594,18 +613,18 @@ TEST_P(QueryVisitorTest, LessThanTooManyOperandsInvalid) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("subscription.price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); // Create an invalid AST for the query '3 < subscription.price 25' where '<' // has three operands @@ -669,18 +688,18 @@ TEST_P(QueryVisitorTest, LessThanNonExistentPropertyNotFound) { // respectively. std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("subscription.price", kDocumentId0, kSectionId0); - editor->BufferKey(0); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(0)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId1, kSectionId1); - editor->BufferKey(1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("subscription.price", kDocumentId2, kSectionId2); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("time < 25"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -722,16 +741,16 @@ TEST_P(QueryVisitorTest, IntMinLessThanInvalid) { int64_t int_min = std::numeric_limits<int64_t>::min(); std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(int_min); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_min)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(std::numeric_limits<int64_t>::max()); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(std::numeric_limits<int64_t>::max())); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(int_min + 1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_min + 1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price <" + std::to_string(int_min)); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -752,16 +771,16 @@ TEST_P(QueryVisitorTest, IntMaxGreaterThanInvalid) { int64_t int_max = std::numeric_limits<int64_t>::max(); std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(std::numeric_limits<int64_t>::min()); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(std::numeric_limits<int64_t>::min())); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId1); - editor->BufferKey(int_max); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_max)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId2); - editor->BufferKey(int_max - 1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(int_max - 1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); std::string query = CreateQuery("price >" + std::to_string(int_max)); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -807,34 +826,34 @@ TEST_P(QueryVisitorTest, NumericComparatorDoesntAffectLaterTerms) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); std::unique_ptr<NumericIndex<int64_t>::Editor> editor = numeric_index_->Edit("price", kDocumentId0, kSectionId0); - editor->BufferKey(-2); - editor->BufferKey(-1); - editor->BufferKey(1); - editor->BufferKey(2); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(-2)); + ICING_ASSERT_OK(editor->BufferKey(-1)); + ICING_ASSERT_OK(editor->BufferKey(1)); + ICING_ASSERT_OK(editor->BufferKey(2)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); Index::Editor term_editor = index_->Edit( kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - term_editor.BufferTerm("-2"); - term_editor.BufferTerm("-1"); - term_editor.BufferTerm("1"); - term_editor.BufferTerm("2"); - term_editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(term_editor.BufferTerm("-2")); + ICING_ASSERT_OK(term_editor.BufferTerm("-1")); + ICING_ASSERT_OK(term_editor.BufferTerm("1")); + ICING_ASSERT_OK(term_editor.BufferTerm("2")); + ICING_ASSERT_OK(term_editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = numeric_index_->Edit("price", kDocumentId1, kSectionId0); - editor->BufferKey(-1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(-1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = numeric_index_->Edit("price", kDocumentId2, kSectionId0); - editor->BufferKey(-1); - std::move(*editor).IndexAllBufferedKeys(); + ICING_ASSERT_OK(editor->BufferKey(-1)); + ICING_ASSERT_OK(std::move(*editor).IndexAllBufferedKeys()); term_editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - term_editor.BufferTerm("2"); - term_editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(term_editor.BufferTerm("2")); + ICING_ASSERT_OK(term_editor.IndexAllBufferedTerms()); // Translating MINUS chars that are interpreted as NOTs, this query would be // `price == -1 AND NOT 2` @@ -872,18 +891,18 @@ TEST_P(QueryVisitorTest, SingleTermTermFrequencyEnabled) { // "bar" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -924,18 +943,18 @@ TEST_P(QueryVisitorTest, SingleTermTermFrequencyDisabled) { // "bar" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -975,18 +994,18 @@ TEST_P(QueryVisitorTest, SingleTermPrefix) { // "bar" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // An EXACT query for 'fo' won't match anything. std::string query = CreateQuery("fo"); @@ -1071,21 +1090,21 @@ TEST_P(QueryVisitorTest, SegmentationWithPrefix) { // ["foo", "ba"] and ["bar", "fo"] respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("ba"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("ba")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("ba"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("ba")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.BufferTerm("fo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm("fo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // An EXACT query for `ba?fo` will be lexed into a single TEXT token. // The visitor will tokenize it into `ba` and `fo` (`?` is dropped because it @@ -1138,18 +1157,18 @@ TEST_P(QueryVisitorTest, SingleVerbatimTerm) { // "foo:bar(baz)" and "bar:baz(foo)" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo:bar(baz)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo:bar(baz)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo:bar(baz)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo:bar(baz)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar:baz(foo)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar:baz(foo)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("\"foo:bar(baz)\""); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1184,18 +1203,18 @@ TEST_P(QueryVisitorTest, SingleVerbatimTermPrefix) { // "foo:bar(abc)" and "bar:baz(foo)" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo:bar(baz)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo:bar(baz)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo:bar(abc)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo:bar(abc)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar:baz(foo)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar:baz(foo)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Query for `"foo:bar("*`. This should match docs 0 and 1. std::string query = CreateQuery("\"foo:bar(\"*"); @@ -1236,18 +1255,18 @@ TEST_P(QueryVisitorTest, VerbatimTermEscapingQuote) { // "foobar\" and "foobar"" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobary)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobary)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar\)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar")"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar")")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // From the comment above, verbatim_term = `foobar"` and verbatim_query = // `foobar\"` @@ -1288,19 +1307,19 @@ TEST_P(QueryVisitorTest, VerbatimTermEscapingEscape) { // "foobar\" and "foobar"" respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobary)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobary)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // From the comment above, verbatim_term = `foobar\`. - editor.BufferTerm(R"(foobar\)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar")"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar")")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Issue a query for the verbatim token `foobar\`. std::string query = CreateQuery(R"(("foobar\\"))"); @@ -1343,18 +1362,18 @@ TEST_P(QueryVisitorTest, VerbatimTermEscapingNonSpecialChar) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // From the comment above, verbatim_term = `foobary`. - editor.BufferTerm(R"(foobary)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobary)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar\)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar\y)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\y)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Issue a query for the verbatim token `foobary`. std::string query = CreateQuery(R"(("foobar\y"))"); @@ -1424,19 +1443,19 @@ TEST_P(QueryVisitorTest, VerbatimTermNewLine) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // From the comment above, verbatim_term = `foobar` + '\n'. - editor.BufferTerm("foobar\n"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foobar\n")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foobar\)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // verbatim_term = `foobar\n`. This is distinct from the term added above. - editor.BufferTerm(R"(foobar\n)"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foobar\n)")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Issue a query for the verbatim token `foobar` + '\n'. std::string query = CreateQuery("\"foobar\n\""); @@ -1498,20 +1517,20 @@ TEST_P(QueryVisitorTest, VerbatimTermEscapingComplex) { // `foo\\\"bar\\nbaz\"` and `foo\\"bar\\nbaz"` respectively. Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); - editor.BufferTerm(R"(foo\"bar\nbaz")"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foo\"bar\nbaz")")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // Add the verbatim_term from doc 0 but with all of the escapes left in - editor.BufferTerm(R"(foo\\\"bar\\nbaz\")"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foo\\\"bar\\nbaz\")")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_EXACT, /*namespace_id=*/0); // Add the verbatim_term from doc 0 but with the escapes for '\' chars left in - editor.BufferTerm(R"(foo\\"bar\\nbaz")"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm(R"(foo\\"bar\\nbaz")")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Issue a query for the verbatim token `foo\"bar\nbaz"`. std::string query = CreateQuery(R"(("foo\\\"bar\\nbaz\""))"); @@ -1556,22 +1575,22 @@ TEST_P(QueryVisitorTest, SingleMinusTerm) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("-foo"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1610,22 +1629,22 @@ TEST_P(QueryVisitorTest, SingleNotTerm) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("NOT foo"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1660,26 +1679,26 @@ TEST_P(QueryVisitorTest, NestedNotTerms) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Double negative could be rewritten as `(foo AND NOT bar) baz` std::string query = CreateQuery("NOT (-foo OR bar) baz"); @@ -1718,26 +1737,26 @@ TEST_P(QueryVisitorTest, DeeplyNestedNotTerms) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Simplifying: // NOT (-(NOT (foo -bar) baz) -bat) NOT bass @@ -1776,19 +1795,19 @@ TEST_P(QueryVisitorTest, DeeplyNestedNotTerms) { TEST_P(QueryVisitorTest, ImplicitAndTerms) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo bar"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1819,19 +1838,19 @@ TEST_P(QueryVisitorTest, ImplicitAndTerms) { TEST_P(QueryVisitorTest, ExplicitAndTerms) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo AND bar"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1862,19 +1881,19 @@ TEST_P(QueryVisitorTest, ExplicitAndTerms) { TEST_P(QueryVisitorTest, OrTerms) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("fo"); - editor.BufferTerm("ba"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("fo")); + ICING_ASSERT_OK(editor.BufferTerm("ba")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo OR bar"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -1905,20 +1924,20 @@ TEST_P(QueryVisitorTest, OrTerms) { TEST_P(QueryVisitorTest, AndOrTermPrecedence) { Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Should be interpreted like `foo (bar OR baz)` std::string query = CreateQuery("foo bar OR baz"); @@ -2012,24 +2031,24 @@ TEST_P(QueryVisitorTest, AndOrNotPrecedence) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("baz"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("baz")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Should be interpreted like `foo ((NOT bar) OR baz)` std::string query = CreateQuery("foo NOT bar OR baz"); @@ -2100,22 +2119,22 @@ TEST_P(QueryVisitorTest, PropertyFilter) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo", /*property_restrict=*/"prop1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2176,22 +2195,22 @@ TEST_F(QueryVisitorTest, MultiPropertyFilter) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop3_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = R"(search("foo", createList("prop1", "prop2")))"; ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2275,22 +2294,22 @@ TEST_P(QueryVisitorTest, PropertyFilterNonNormalized) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo", /*property_restrict=*/"PROP1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2345,22 +2364,22 @@ TEST_P(QueryVisitorTest, PropertyFilterWithGrouping) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("(foo OR bar)", /*property_restrict=*/"prop1"); @@ -2413,22 +2432,22 @@ TEST_P(QueryVisitorTest, ValidNestedPropertyFilter) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("(prop1:foo)", /*property_restrict=*/"prop1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2500,22 +2519,22 @@ TEST_P(QueryVisitorTest, InvalidNestedPropertyFilter) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("(prop2:foo)", /*property_restrict=*/"prop1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2583,22 +2602,22 @@ TEST_P(QueryVisitorTest, NotWithPropertyFilter) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Resulting queries: // - kPlain: `-prop1:(foo OR bar)` @@ -2667,30 +2686,43 @@ TEST_P(QueryVisitorTest, PropertyFilterWithNot) { SectionId prop1_section_id = 0; SectionId prop2_section_id = 1; + // Create documents as follows: + // Doc0: + // prop1: "bar" + // prop2: "" + // Doc1: + // prop1: "foo" + // prop2: "" + // Doc2: + // prop1: "" + // prop2: "foo" ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Resulting queries: // - kPlain: `prop1:(-foo OR bar)` // - kSearch: `search("-foo OR bar", createList("prop1"))` + // + // The query is equivalent to `-prop1:foo OR prop1:bar`, thus doc0 and doc2 + // will be matched. std::string query = CreateQuery("(-foo OR bar)", /*property_restrict=*/"prop1"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -2712,11 +2744,14 @@ TEST_P(QueryVisitorTest, PropertyFilterWithNot) { EXPECT_THAT(ExtractKeys(query_results.query_term_iterators), UnorderedElementsAre("bar")); EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), - ElementsAre(kDocumentId0)); + ElementsAre(kDocumentId2, kDocumentId0)); // Resulting queries: - // - kPlain: `prop1:(foo OR bar)` - // - kSearch: `search("foo OR bar", createList("prop1"))` + // - kPlain: `prop1:(-foo OR bar)` + // - kSearch: `search("-foo OR bar", createList("prop1"))` + // + // The query is equivalent to `-prop1:foo OR prop1:bar`, thus doc0 and doc2 + // will be matched. query = CreateQuery("(NOT foo OR bar)", /*property_restrict=*/"prop1"); ICING_ASSERT_OK_AND_ASSIGN(root_node, ParseQueryHelper(query)); QueryVisitor query_visitor_two( @@ -2735,7 +2770,7 @@ TEST_P(QueryVisitorTest, PropertyFilterWithNot) { EXPECT_THAT(ExtractKeys(query_results.query_term_iterators), UnorderedElementsAre("bar")); EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), - ElementsAre(kDocumentId0)); + ElementsAre(kDocumentId2, kDocumentId0)); } TEST_P(QueryVisitorTest, SegmentationTest) { @@ -2756,7 +2791,7 @@ TEST_P(QueryVisitorTest, SegmentationTest) { .Build(), /*ignore_errors_and_delete_documents=*/false, /*allow_circular_schema_definitions=*/false)); - + // Section ids are assigned alphabetically. SectionId prop1_section_id = 0; SectionId prop2_section_id = 1; @@ -2768,36 +2803,36 @@ TEST_P(QueryVisitorTest, SegmentationTest) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("上班"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("上班")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(kDocumentId0, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); if (IsCfStringTokenization()) { - editor.BufferTerm("每"); - editor.BufferTerm("天"); + ICING_ASSERT_OK(editor.BufferTerm("每")); + ICING_ASSERT_OK(editor.BufferTerm("天")); } else { - editor.BufferTerm("每天"); + ICING_ASSERT_OK(editor.BufferTerm("每天")); } - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("上班"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("上班")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop2_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); if (IsCfStringTokenization()) { - editor.BufferTerm("每"); - editor.BufferTerm("天"); + ICING_ASSERT_OK(editor.BufferTerm("每")); + ICING_ASSERT_OK(editor.BufferTerm("天")); } else { - editor.BufferTerm("每天"); + ICING_ASSERT_OK(editor.BufferTerm("每天")); } - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, ParseQueryHelper(query)); @@ -2862,55 +2897,55 @@ TEST_P(QueryVisitorTest, PropertyRestrictsPopCorrectly) { ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid0, document_store_->Put(doc)); Index::Editor editor = index_->Edit(docid0, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 1: Contains 'val0', 'val1', 'val2' in 'prop1'. Should match. doc = DocumentBuilder(doc).SetUri("uri1").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid1, document_store_->Put(doc)); editor = index_->Edit(docid1, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 2: Contains 'val0', 'val1', 'val2' in 'prop2'. Shouldn't match. doc = DocumentBuilder(doc).SetUri("uri2").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid2, document_store_->Put(doc)); editor = index_->Edit(docid2, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 3: Contains 'val0' in 'prop0', 'val1' in 'prop1' etc. Should match. doc = DocumentBuilder(doc).SetUri("uri3").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid3, document_store_->Put(doc)); editor = index_->Edit(docid3, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid3, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val1"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid3, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 4: Contains 'val1' in 'prop0', 'val2' in 'prop1', 'val0' in 'prop2'. // Shouldn't match. doc = DocumentBuilder(doc).SetUri("uri4").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid4, document_store_->Put(doc)); editor = index_->Edit(docid4, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val1"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid4, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid4, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Now issue a query with 'val1' restricted to 'prop1'. This should match only // docs 1 and 3. @@ -2977,55 +3012,55 @@ TEST_P(QueryVisitorTest, UnsatisfiablePropertyRestrictsPopCorrectly) { ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid0, document_store_->Put(doc)); Index::Editor editor = index_->Edit(docid0, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 1: Contains 'val0', 'val1', 'val2' in 'prop1'. Shouldn't match. doc = DocumentBuilder(doc).SetUri("uri1").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid1, document_store_->Put(doc)); editor = index_->Edit(docid1, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 2: Contains 'val0', 'val1', 'val2' in 'prop2'. Should match. doc = DocumentBuilder(doc).SetUri("uri2").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid2, document_store_->Put(doc)); editor = index_->Edit(docid2, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.BufferTerm("val1"); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 3: Contains 'val0' in 'prop0', 'val1' in 'prop1' etc. Should match. doc = DocumentBuilder(doc).SetUri("uri3").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid3, document_store_->Put(doc)); editor = index_->Edit(docid3, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid3, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val1"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid3, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // - Doc 4: Contains 'val1' in 'prop0', 'val2' in 'prop1', 'val0' in 'prop2'. // Shouldn't match. doc = DocumentBuilder(doc).SetUri("uri4").Build(); ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid4, document_store_->Put(doc)); editor = index_->Edit(docid4, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val1"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val1")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid4, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val2"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val2")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); editor = index_->Edit(docid4, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("val0"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("val0")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Now issue a query with 'val1' restricted to 'prop1'. This should match only // docs 1 and 3. @@ -3197,23 +3232,23 @@ TEST_F(QueryVisitorTest, SearchFunctionNestedFunctionCalls) { DocumentBuilder().SetKey("ns", "uri0").SetSchema("type").Build())); Index::Editor editor = index_->Edit(kDocumentId0, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri1").SetSchema("type").Build())); editor = index_->Edit(kDocumentId1, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK(document_store_->Put( DocumentBuilder().SetKey("ns", "uri2").SetSchema("type").Build())); editor = index_->Edit(kDocumentId2, prop1_section_id, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.BufferTerm("bar"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // *If* nested function calls were allowed, then this would simplify as: // `search("search(\"foo\") bar")` -> `search("foo bar")` -> `foo bar` @@ -3335,57 +3370,57 @@ TEST_F(QueryVisitorTest, SearchFunctionNestedPropertyRestrictsNarrowing) { ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid0, document_store_->Put(doc)); Index::Editor editor = index_->Edit(kDocumentId0, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid1, document_store_->Put(DocumentBuilder(doc).SetUri("uri1").Build())); editor = index_->Edit(docid1, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid2, document_store_->Put(DocumentBuilder(doc).SetUri("uri2").Build())); editor = index_->Edit(docid2, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid3, document_store_->Put(DocumentBuilder(doc).SetUri("uri3").Build())); editor = index_->Edit(docid3, prop3_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid4, document_store_->Put(DocumentBuilder(doc).SetUri("uri4").Build())); editor = index_->Edit(docid4, prop4_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid5, document_store_->Put(DocumentBuilder(doc).SetUri("uri5").Build())); editor = index_->Edit(docid5, prop5_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid6, document_store_->Put(DocumentBuilder(doc).SetUri("uri6").Build())); editor = index_->Edit(docid6, prop6_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid7, document_store_->Put(DocumentBuilder(doc).SetUri("uri7").Build())); editor = index_->Edit(docid7, prop7_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // *If* nested function calls were allowed, then this would simplify as: // `search("search(\"foo\") bar")` -> `search("foo bar")` -> `foo bar` @@ -3515,57 +3550,57 @@ TEST_F(QueryVisitorTest, SearchFunctionNestedPropertyRestrictsExpanding) { ICING_ASSERT_OK_AND_ASSIGN(DocumentId docid0, document_store_->Put(doc)); Index::Editor editor = index_->Edit(kDocumentId0, prop0_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid1, document_store_->Put(DocumentBuilder(doc).SetUri("uri1").Build())); editor = index_->Edit(docid1, prop1_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid2, document_store_->Put(DocumentBuilder(doc).SetUri("uri2").Build())); editor = index_->Edit(docid2, prop2_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid3, document_store_->Put(DocumentBuilder(doc).SetUri("uri3").Build())); editor = index_->Edit(docid3, prop3_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid4, document_store_->Put(DocumentBuilder(doc).SetUri("uri4").Build())); editor = index_->Edit(docid4, prop4_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid5, document_store_->Put(DocumentBuilder(doc).SetUri("uri5").Build())); editor = index_->Edit(docid5, prop5_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid6, document_store_->Put(DocumentBuilder(doc).SetUri("uri6").Build())); editor = index_->Edit(docid6, prop6_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); ICING_ASSERT_OK_AND_ASSIGN( DocumentId docid7, document_store_->Put(DocumentBuilder(doc).SetUri("uri7").Build())); editor = index_->Edit(docid7, prop7_id, TERM_MATCH_PREFIX, ns_id); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // *If* nested function calls were allowed, then this would simplify as: // `search("search(\"foo\") bar")` -> `search("foo bar")` -> `foo bar` @@ -3726,8 +3761,8 @@ TEST_P(QueryVisitorTest, PropertyDefinedFunctionReturnsMatchingDocuments) { 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(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Document 1 has the term "foo" and its schema DOESN'T have the url property. ICING_ASSERT_OK(document_store_->Put(DocumentBuilder() @@ -3736,16 +3771,16 @@ TEST_P(QueryVisitorTest, PropertyDefinedFunctionReturnsMatchingDocuments) { .Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Document 2 has the term "bar" and its schema has the url property. 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(); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo propertyDefined(\"url\")"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -3786,8 +3821,8 @@ TEST_P(QueryVisitorTest, 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(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Document 1 has the term "foo" and its schema DOESN'T have the url property. ICING_ASSERT_OK(document_store_->Put(DocumentBuilder() @@ -3796,8 +3831,8 @@ TEST_P(QueryVisitorTest, .Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Attempt to query a non-existent property. std::string query = CreateQuery("propertyDefined(\"nonexistentproperty\")"); @@ -3838,8 +3873,8 @@ TEST_P(QueryVisitorTest, 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(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); // Document 1 has the term "foo" and its schema DOESN'T have the url property. ICING_ASSERT_OK(document_store_->Put(DocumentBuilder() @@ -3848,8 +3883,8 @@ TEST_P(QueryVisitorTest, .Build())); editor = index_->Edit(kDocumentId1, kSectionId1, TERM_MATCH_PREFIX, /*namespace_id=*/0); - editor.BufferTerm("foo"); - editor.IndexAllBufferedTerms(); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); std::string query = CreateQuery("foo AND NOT propertyDefined(\"url\")"); ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, @@ -3869,6 +3904,204 @@ TEST_P(QueryVisitorTest, UnorderedElementsAre(kDocumentId1)); } +TEST_F(QueryVisitorTest, + HasPropertyFunctionWithNoArgumentReturnsInvalidArgument) { + std::string query = "hasProperty()"; + 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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F(QueryVisitorTest, + HasPropertyFunctionWithMoreThanOneStringArgumentReturnsInvalidArgument) { + std::string query = "hasProperty(\"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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F(QueryVisitorTest, + HasPropertyFunctionWithTextArgumentReturnsInvalidArgument) { + // The argument type is TEXT, not STRING here. + std::string query = "hasProperty(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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_F(QueryVisitorTest, + HasPropertyFunctionWithNonStringArgumentReturnsInvalidArgument) { + std::string query = "hasProperty(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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor); + EXPECT_THAT(std::move(query_visitor).ConsumeResults(), + StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); +} + +TEST_P(QueryVisitorTest, HasPropertyFunctionReturnsMatchingDocuments) { + ICING_ASSERT_OK(schema_store_->SetSchema( + SchemaBuilder() + .AddType(SchemaTypeConfigBuilder() + .SetType("Simple") + .AddProperty(PropertyConfigBuilder() + .SetName("name") + .SetDataType(TYPE_STRING) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("price") + .SetDataType(TYPE_INT64) + .SetCardinality(CARDINALITY_OPTIONAL))) + .Build(), + /*ignore_errors_and_delete_documents=*/false, + /*allow_circular_schema_definitions=*/false)); + + // Document 0 has the term "foo" and has the "price" property. + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri0").SetSchema("Simple").Build())); + Index::Editor editor = index_->Edit(kDocumentId0, kSectionId0, + TERM_MATCH_PREFIX, /*namespace_id=*/0); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm( + absl_ports::StrCat(kPropertyExistenceTokenPrefix, "price").c_str())); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); + + // Document 1 has the term "foo" and doesn't have the "price" property. + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri1").SetSchema("Simple").Build())); + editor = index_->Edit(kDocumentId1, kSectionId0, TERM_MATCH_PREFIX, + /*namespace_id=*/0); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); + + // Document 2 has the term "bar" and has the "price" property. + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri2").SetSchema("Simple").Build())); + editor = index_->Edit(kDocumentId2, kSectionId0, TERM_MATCH_PREFIX, + /*namespace_id=*/0); + ICING_ASSERT_OK(editor.BufferTerm("bar")); + ICING_ASSERT_OK(editor.BufferTerm( + absl_ports::StrCat(kPropertyExistenceTokenPrefix, "price").c_str())); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); + + // Test that `foo hasProperty("price")` matches document 0 only. + std::string query = CreateQuery("foo hasProperty(\"price\")"); + ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<Node> root_node, + ParseQueryHelper(query)); + QueryVisitor query_visitor1( + 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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor1); + ICING_ASSERT_OK_AND_ASSIGN(QueryResults query_results, + std::move(query_visitor1).ConsumeResults()); + EXPECT_THAT(query_results.features_in_use, + UnorderedElementsAre(kHasPropertyFunctionFeature, + kListFilterQueryLanguageFeature)); + EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), + UnorderedElementsAre(kDocumentId0)); + + // Test that `bar OR NOT hasProperty("price")` matches document 1 and + // document 2. + query = CreateQuery("bar OR NOT hasProperty(\"price\")"); + ICING_ASSERT_OK_AND_ASSIGN(root_node, ParseQueryHelper(query)); + QueryVisitor query_visitor2( + 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, clock_.GetSystemTimeMilliseconds()); + root_node->Accept(&query_visitor2); + ICING_ASSERT_OK_AND_ASSIGN(query_results, + std::move(query_visitor2).ConsumeResults()); + EXPECT_THAT(query_results.features_in_use, + UnorderedElementsAre(kHasPropertyFunctionFeature, + kListFilterQueryLanguageFeature)); + EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), + UnorderedElementsAre(kDocumentId1, kDocumentId2)); +} + +TEST_P(QueryVisitorTest, + HasPropertyFunctionReturnsNothingIfNoMatchingProperties) { + ICING_ASSERT_OK(schema_store_->SetSchema( + SchemaBuilder() + .AddType(SchemaTypeConfigBuilder() + .SetType("Simple") + .AddProperty(PropertyConfigBuilder() + .SetName("name") + .SetDataType(TYPE_STRING) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("price") + .SetDataType(TYPE_INT64) + .SetCardinality(CARDINALITY_OPTIONAL))) + .Build(), + /*ignore_errors_and_delete_documents=*/false, + /*allow_circular_schema_definitions=*/false)); + + // Document 0 has the term "foo" and has the "price" property. + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri0").SetSchema("Simple").Build())); + Index::Editor editor = index_->Edit(kDocumentId0, kSectionId0, + TERM_MATCH_PREFIX, /*namespace_id=*/0); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.BufferTerm( + absl_ports::StrCat(kPropertyExistenceTokenPrefix, "price").c_str())); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); + + // Document 1 has the term "foo" and doesn't have the "price" property. + ICING_ASSERT_OK(document_store_->Put( + DocumentBuilder().SetKey("ns", "uri1").SetSchema("Simple").Build())); + editor = index_->Edit(kDocumentId1, kSectionId0, TERM_MATCH_PREFIX, + /*namespace_id=*/0); + ICING_ASSERT_OK(editor.BufferTerm("foo")); + ICING_ASSERT_OK(editor.IndexAllBufferedTerms()); + + // Attempt to query a non-existent property. + std::string query = CreateQuery("hasProperty(\"nonexistentproperty\")"); + 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, clock_.GetSystemTimeMilliseconds()); + 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(kHasPropertyFunctionFeature, + kListFilterQueryLanguageFeature)); + + EXPECT_THAT(GetDocumentIds(query_results.root_iterator.get()), IsEmpty()); +} + INSTANTIATE_TEST_SUITE_P(QueryVisitorTest, QueryVisitorTest, testing::Values(QueryType::kPlain, QueryType::kSearch)); diff --git a/icing/query/query-features.h b/icing/query/query-features.h index 158e13e..d829cd7 100644 --- a/icing/query/query-features.h +++ b/icing/query/query-features.h @@ -48,9 +48,13 @@ constexpr Feature kVerbatimSearchFeature = constexpr Feature kListFilterQueryLanguageFeature = "LIST_FILTER_QUERY_LANGUAGE"; // Features#LIST_FILTER_QUERY_LANGUAGE +// This feature relates to the use of the "hasProperty(property_path)" function. +constexpr Feature kHasPropertyFunctionFeature = + "HAS_PROPERTY_FUNCTION"; // Features#HAS_PROPERTY_FUNCTION + inline std::unordered_set<Feature> GetQueryFeaturesSet() { return {kNumericSearchFeature, kVerbatimSearchFeature, - kListFilterQueryLanguageFeature}; + kListFilterQueryLanguageFeature, kHasPropertyFunctionFeature}; } } // namespace lib diff --git a/icing/query/query-processor.cc b/icing/query/query-processor.cc index 3e43ad9..bbfbf3c 100644 --- a/icing/query/query-processor.cc +++ b/icing/query/query-processor.cc @@ -176,12 +176,11 @@ libtextclassifier3::StatusOr<QueryResults> QueryProcessor::ParseSearch( results.root_iterator = std::make_unique<DocHitInfoIteratorFilter>( std::move(results.root_iterator), &document_store_, &schema_store_, options, current_time_ms); - // TODO(b/294114230): Move this SectionRestrict filter from root level to - // lower levels if that would improve performance. if (!search_spec.type_property_filters().empty()) { - results.root_iterator = std::make_unique<DocHitInfoIteratorSectionRestrict>( - std::move(results.root_iterator), &document_store_, &schema_store_, - search_spec, current_time_ms); + results.root_iterator = + DocHitInfoIteratorSectionRestrict::ApplyRestrictions( + std::move(results.root_iterator), &document_store_, &schema_store_, + search_spec, current_time_ms); } return results; } @@ -406,7 +405,7 @@ libtextclassifier3::StatusOr<QueryResults> QueryProcessor::ParseRawQuery( // the section restrict std::set<std::string> section_restricts; section_restricts.insert(std::move(frames.top().section_restrict)); - result_iterator = std::make_unique<DocHitInfoIteratorSectionRestrict>( + result_iterator = DocHitInfoIteratorSectionRestrict::ApplyRestrictions( std::move(result_iterator), &document_store_, &schema_store_, std::move(section_restricts), current_time_ms); diff --git a/icing/query/query-processor_test.cc b/icing/query/query-processor_test.cc index e64de32..53e3035 100644 --- a/icing/query/query-processor_test.cc +++ b/icing/query/query-processor_test.cc @@ -17,6 +17,7 @@ #include <cstdint> #include <memory> #include <string> +#include <vector> #include "icing/text_classifier/lib3/utils/base/status.h" #include "gmock/gmock.h" @@ -36,6 +37,7 @@ #include "icing/proto/search.pb.h" #include "icing/proto/term.pb.h" #include "icing/query/query-features.h" +#include "icing/query/query-results.h" #include "icing/schema-builder.h" #include "icing/schema/schema-store.h" #include "icing/schema/section.h" @@ -1099,7 +1101,7 @@ TEST_P(QueryProcessorTest, CombinedAndOrTerms) { IsOk()); EXPECT_THAT(AddTokenToIndex(document_id1, section_id, term_match_type, "dog"), IsOk()); - index_->Merge(); + ICING_ASSERT_OK(index_->Merge()); // Document 2 has content "animal kitten cat" EXPECT_THAT( @@ -3177,6 +3179,147 @@ TEST_P(QueryProcessorTest, NumericFilterWithoutEnablingFeatureFails) { StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT)); } +TEST_P(QueryProcessorTest, GroupingInSectionRestriction) { + if (GetParam() != + SearchSpecProto::SearchType::EXPERIMENTAL_ICING_ADVANCED_QUERY) { + GTEST_SKIP() << "Grouping in section restriction is only supported in " + "advanced query."; + } + + // Create the schema and document store + SchemaProto schema = + SchemaBuilder() + .AddType(SchemaTypeConfigBuilder() + .SetType("email") + .AddProperty(PropertyConfigBuilder() + .SetName("prop1") + .SetDataTypeString(TERM_MATCH_EXACT, + TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL)) + .AddProperty(PropertyConfigBuilder() + .SetName("prop2") + .SetDataTypeString(TERM_MATCH_EXACT, + TOKENIZER_PLAIN) + .SetCardinality(CARDINALITY_OPTIONAL))) + .Build(); + ASSERT_THAT(schema_store_->SetSchema( + schema, /*ignore_errors_and_delete_documents=*/false, + /*allow_circular_schema_definitions=*/false), + IsOk()); + + SectionId prop1_section_id = 0; + SectionId prop2_section_id = 1; + TermMatchType::Code term_match_type = TermMatchType::EXACT_ONLY; + + // Create documents as follows: + // Doc0: + // prop1: "foo" + // prop2: "bar" + // Doc1: + // prop1: "bar" + // prop2: "foo" + // Doc2: + // prop1: "foo bar" + // prop2: "" + ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id0, + document_store_->Put(DocumentBuilder() + .SetKey("namespace", "0") + .SetSchema("email") + .Build())); + EXPECT_THAT( + AddTokenToIndex(document_id0, prop1_section_id, term_match_type, "foo"), + IsOk()); + EXPECT_THAT( + AddTokenToIndex(document_id0, prop2_section_id, term_match_type, "bar"), + IsOk()); + + ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id1, + document_store_->Put(DocumentBuilder() + .SetKey("namespace", "1") + .SetSchema("email") + .Build())); + EXPECT_THAT( + AddTokenToIndex(document_id1, prop1_section_id, term_match_type, "bar"), + IsOk()); + EXPECT_THAT( + AddTokenToIndex(document_id1, prop2_section_id, term_match_type, "foo"), + IsOk()); + + ICING_ASSERT_OK_AND_ASSIGN(DocumentId document_id2, + document_store_->Put(DocumentBuilder() + .SetKey("namespace", "2") + .SetSchema("email") + .Build())); + EXPECT_THAT( + AddTokenToIndex(document_id2, prop1_section_id, term_match_type, "foo"), + IsOk()); + EXPECT_THAT( + AddTokenToIndex(document_id2, prop1_section_id, term_match_type, "bar"), + IsOk()); + + // prop1:(foo bar) <=> prop1:foo AND prop1:bar, which matches doc2. + SearchSpecProto search_spec; + search_spec.set_query("prop1:(foo bar)"); + search_spec.set_term_match_type(term_match_type); + search_spec.set_search_type(GetParam()); + search_spec.add_enabled_features( + std::string(kListFilterQueryLanguageFeature)); + ICING_ASSERT_OK_AND_ASSIGN( + QueryResults results, + query_processor_->ParseSearch(search_spec, + ScoringSpecProto::RankingStrategy::NONE, + fake_clock_.GetSystemTimeMilliseconds())); + EXPECT_THAT(GetDocHitInfos(results.root_iterator.get()), + ElementsAre(EqualsDocHitInfo( + document_id2, std::vector<SectionId>{prop1_section_id}))); + + // prop2:(foo bar) <=> prop2:foo AND prop2:bar, which matches nothing. + search_spec.set_query("prop2:(foo bar)"); + ICING_ASSERT_OK_AND_ASSIGN( + results, query_processor_->ParseSearch( + search_spec, ScoringSpecProto::RankingStrategy::NONE, + fake_clock_.GetSystemTimeMilliseconds())); + EXPECT_THAT(GetDocHitInfos(results.root_iterator.get()), IsEmpty()); + + // prop1:(foo -bar) <=> prop1:foo AND -prop1:bar, which matches doc0. + search_spec.set_query("prop1:(foo -bar)"); + ICING_ASSERT_OK_AND_ASSIGN( + results, query_processor_->ParseSearch( + search_spec, ScoringSpecProto::RankingStrategy::NONE, + fake_clock_.GetSystemTimeMilliseconds())); + EXPECT_THAT(GetDocHitInfos(results.root_iterator.get()), + ElementsAre(EqualsDocHitInfo( + document_id0, std::vector<SectionId>{prop1_section_id}))); + + // prop2:(-foo OR bar) <=> -prop2:foo OR prop2:bar, which matches doc0 and + // doc2. + search_spec.set_query("prop2:(-foo OR bar)"); + ICING_ASSERT_OK_AND_ASSIGN( + results, query_processor_->ParseSearch( + search_spec, ScoringSpecProto::RankingStrategy::NONE, + fake_clock_.GetSystemTimeMilliseconds())); + EXPECT_THAT( + GetDocHitInfos(results.root_iterator.get()), + ElementsAre(EqualsDocHitInfo(document_id2, std::vector<SectionId>{}), + EqualsDocHitInfo(document_id0, + std::vector<SectionId>{prop2_section_id}))); + + // prop1:((foo AND bar) OR (foo AND -baz)) + // <=> ((prop1:foo AND prop1:bar) OR (prop1:foo AND -prop1:baz)), which + // matches doc0 and doc2. + search_spec.set_query("prop1:((foo AND bar) OR (foo AND -baz))"); + ICING_ASSERT_OK_AND_ASSIGN( + results, query_processor_->ParseSearch( + search_spec, ScoringSpecProto::RankingStrategy::NONE, + fake_clock_.GetSystemTimeMilliseconds())); + EXPECT_THAT( + GetDocHitInfos(results.root_iterator.get()), + ElementsAre(EqualsDocHitInfo(document_id2, + std::vector<SectionId>{prop1_section_id}), + EqualsDocHitInfo(document_id0, + std::vector<SectionId>{prop1_section_id}))); +} + INSTANTIATE_TEST_SUITE_P( QueryProcessorTest, QueryProcessorTest, testing::Values( |