aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrace Zhao <gracezrx@google.com>2023-06-28 15:35:44 -0700
committerGrace Zhao <gracezrx@google.com>2023-06-28 22:39:16 +0000
commitb8e8a914804b5ef6ee8ca77a9ca7b9797fe55e94 (patch)
treefa0309938bf2b0d5155b94cb2516cb3142536556
parent3a5d5836780120152cfade6a77ba233efbac5070 (diff)
parentf1f564329ad560f580c03f9e928057ad4e4fadc9 (diff)
downloadicing-b8e8a914804b5ef6ee8ca77a9ca7b9797fe55e94.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into androidx-main
* aosp/upstream-master: Update Icing from upstream. Descriptions: ======================================================================== [Join][cleanup][ez] Rename QualifiedIdTypeJoinableIndex as QualifiedIdJoinIndex ======================================================================== Better evaluation for persistent hash map size in join index ======================================================================== Add num_to_score into ResultSpecProto ======================================================================== [Indexable_nested_properties_list 1/5] Add indexable_nested_properties to DocumentIndexingConfig and check it during schema validation. ======================================================================== [Indexable_nested_properties_list 2/5] Add check for indexable_neseted_properties when computing SchemaDelta ======================================================================== [Indexable_nested_properties_list 3/5] Add indexable_nested_properties to schema-property-iterator ======================================================================== [Indexable_nested_properties_list 4/5] Integrate circular schema definitions with schema-property-iterator ======================================================================== Bug: 272145329 Bug: 284232550 Bug: 285636503 Bug: 265304217 Bug: 289150947 Change-Id: Icfcd4901015b75f4af2d231f8a8613c6e33034a0
-rw-r--r--icing/icing-search-engine.cc34
-rw-r--r--icing/icing-search-engine.h4
-rw-r--r--icing/icing-search-engine_initialization_test.cc51
-rw-r--r--icing/icing-search-engine_schema_test.cc8
-rw-r--r--icing/icing-search-engine_search_test.cc121
-rw-r--r--icing/index/index-processor_test.cc27
-rw-r--r--icing/join/join-children-fetcher.h2
-rw-r--r--icing/join/join-processor.h15
-rw-r--r--icing/join/join-processor_test.cc10
-rw-r--r--icing/join/qualified-id-join-index.cc (renamed from icing/join/qualified-id-type-joinable-index.cc)98
-rw-r--r--icing/join/qualified-id-join-index.h (renamed from icing/join/qualified-id-type-joinable-index.h)65
-rw-r--r--icing/join/qualified-id-join-index_test.cc (renamed from icing/join/qualified-id-type-joinable-index_test.cc)421
-rw-r--r--icing/join/qualified-id-join-indexing-handler.cc4
-rw-r--r--icing/join/qualified-id-join-indexing-handler.h13
-rw-r--r--icing/join/qualified-id-join-indexing-handler_test.cc10
-rw-r--r--icing/performance-configuration.cc12
-rw-r--r--icing/performance-configuration.h7
-rw-r--r--icing/schema-builder.h16
-rw-r--r--icing/schema/property-util.cc19
-rw-r--r--icing/schema/property-util.h20
-rw-r--r--icing/schema/property-util_test.cc17
-rw-r--r--icing/schema/schema-property-iterator.cc114
-rw-r--r--icing/schema/schema-property-iterator.h69
-rw-r--r--icing/schema/schema-property-iterator_test.cc2518
-rw-r--r--icing/schema/schema-type-manager.cc2
-rw-r--r--icing/schema/schema-util.cc52
-rw-r--r--icing/schema/schema-util.h14
-rw-r--r--icing/schema/schema-util_test.cc366
-rw-r--r--proto/icing/proto/schema.proto11
-rw-r--r--proto/icing/proto/search.proto14
-rw-r--r--synced_AOSP_CL_number.txt2
31 files changed, 3649 insertions, 487 deletions
diff --git a/icing/icing-search-engine.cc b/icing/icing-search-engine.cc
index 2cdf930..3ffb297 100644
--- a/icing/icing-search-engine.cc
+++ b/icing/icing-search-engine.cc
@@ -42,8 +42,8 @@
#include "icing/index/numeric/integer-index.h"
#include "icing/index/string-section-indexing-handler.h"
#include "icing/join/join-processor.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id-join-indexing-handler.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
#include "icing/legacy/index/icing-filesystem.h"
#include "icing/portable/endian.h"
#include "icing/proto/debug.pb.h"
@@ -141,6 +141,15 @@ libtextclassifier3::Status ValidateResultSpec(
"ResultSpecProto.num_total_bytes_per_page_threshold cannot be "
"non-positive.");
}
+ if (result_spec.max_joined_children_per_parent_to_return() < 0) {
+ return absl_ports::InvalidArgumentError(
+ "ResultSpecProto.max_joined_children_per_parent_to_return cannot be "
+ "negative.");
+ }
+ if (result_spec.num_to_score() <= 0) {
+ return absl_ports::InvalidArgumentError(
+ "ResultSpecProto.num_to_score cannot be non-positive.");
+ }
// Validate ResultGroupings.
std::unordered_set<int32_t> unique_entry_ids;
ResultSpecProto::ResultGroupingType result_grouping_type =
@@ -621,8 +630,8 @@ libtextclassifier3::Status IcingSearchEngine::InitializeMembers(
if (!filesystem_->DeleteDirectoryRecursively(doc_store_dir.c_str()) ||
!filesystem_->DeleteDirectoryRecursively(index_dir.c_str()) ||
!IntegerIndex::Discard(*filesystem_, integer_index_dir).ok() ||
- !QualifiedIdTypeJoinableIndex::Discard(*filesystem_,
- qualified_id_join_index_dir)
+ !QualifiedIdJoinIndex::Discard(*filesystem_,
+ qualified_id_join_index_dir)
.ok()) {
return absl_ports::InternalError(absl_ports::StrCat(
"Could not delete directories: ", index_dir, ", ", integer_index_dir,
@@ -666,11 +675,11 @@ libtextclassifier3::Status IcingSearchEngine::InitializeMembers(
// Discard qualified id join index directory and instantiate a new one.
std::string qualified_id_join_index_dir =
MakeQualifiedIdJoinIndexWorkingPath(options_.base_dir());
- ICING_RETURN_IF_ERROR(QualifiedIdTypeJoinableIndex::Discard(
+ ICING_RETURN_IF_ERROR(QualifiedIdJoinIndex::Discard(
*filesystem_, qualified_id_join_index_dir));
ICING_ASSIGN_OR_RETURN(
qualified_id_join_index_,
- QualifiedIdTypeJoinableIndex::Create(
+ QualifiedIdJoinIndex::Create(
*filesystem_, std::move(qualified_id_join_index_dir),
options_.pre_mapping_fbv(), options_.use_persistent_hash_map()));
@@ -842,11 +851,11 @@ libtextclassifier3::Status IcingSearchEngine::InitializeIndex(
std::string qualified_id_join_index_dir =
MakeQualifiedIdJoinIndexWorkingPath(options_.base_dir());
InitializeStatsProto::RecoveryCause qualified_id_join_index_recovery_cause;
- auto qualified_id_join_index_or = QualifiedIdTypeJoinableIndex::Create(
+ auto qualified_id_join_index_or = QualifiedIdJoinIndex::Create(
*filesystem_, qualified_id_join_index_dir, options_.pre_mapping_fbv(),
options_.use_persistent_hash_map());
if (!qualified_id_join_index_or.ok()) {
- ICING_RETURN_IF_ERROR(QualifiedIdTypeJoinableIndex::Discard(
+ ICING_RETURN_IF_ERROR(QualifiedIdJoinIndex::Discard(
*filesystem_, qualified_id_join_index_dir));
qualified_id_join_index_recovery_cause = InitializeStatsProto::IO_ERROR;
@@ -854,7 +863,7 @@ libtextclassifier3::Status IcingSearchEngine::InitializeIndex(
// Try recreating it from scratch and rebuild everything.
ICING_ASSIGN_OR_RETURN(
qualified_id_join_index_,
- QualifiedIdTypeJoinableIndex::Create(
+ QualifiedIdJoinIndex::Create(
*filesystem_, std::move(qualified_id_join_index_dir),
options_.pre_mapping_fbv(), options_.use_persistent_hash_map()));
} else {
@@ -2124,7 +2133,7 @@ IcingSearchEngine::QueryScoringResults IcingSearchEngine::ProcessQueryAndScore(
std::move(scoring_processor_or).ValueOrDie();
std::vector<ScoredDocumentHit> scored_document_hits =
scoring_processor->Score(std::move(query_results.root_iterator),
- performance_configuration_.num_to_score,
+ result_spec.num_to_score(),
&query_results.query_term_iterators);
int64_t scoring_latency_ms = component_timer->GetElapsedMilliseconds();
@@ -2471,13 +2480,12 @@ IcingSearchEngine::CreateDataIndexingHandlers() {
clock_.get(), integer_index_.get()));
handlers.push_back(std::move(integer_section_indexing_handler));
- // Qualified id joinable property index handler
+ // Qualified id join index handler
ICING_ASSIGN_OR_RETURN(std::unique_ptr<QualifiedIdJoinIndexingHandler>
- qualified_id_joinable_property_indexing_handler,
+ qualified_id_join_indexing_handler,
QualifiedIdJoinIndexingHandler::Create(
clock_.get(), qualified_id_join_index_.get()));
- handlers.push_back(
- std::move(qualified_id_joinable_property_indexing_handler));
+ handlers.push_back(std::move(qualified_id_join_indexing_handler));
return handlers;
}
diff --git a/icing/icing-search-engine.h b/icing/icing-search-engine.h
index 15da142..d9d5ff6 100644
--- a/icing/icing-search-engine.h
+++ b/icing/icing-search-engine.h
@@ -31,7 +31,7 @@
#include "icing/index/numeric/numeric-index.h"
#include "icing/jni/jni-cache.h"
#include "icing/join/join-children-fetcher.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/legacy/index/icing-filesystem.h"
#include "icing/performance-configuration.h"
#include "icing/proto/debug.pb.h"
@@ -479,7 +479,7 @@ class IcingSearchEngine {
ICING_GUARDED_BY(mutex_);
// Storage for all join qualified ids from the document store.
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index_
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index_
ICING_GUARDED_BY(mutex_);
// Pointer to JNI class references
diff --git a/icing/icing-search-engine_initialization_test.cc b/icing/icing-search-engine_initialization_test.cc
index 74cc78f..64bcc98 100644
--- a/icing/icing-search-engine_initialization_test.cc
+++ b/icing/icing-search-engine_initialization_test.cc
@@ -34,8 +34,8 @@
#include "icing/jni/jni-cache.h"
#include "icing/join/doc-join-info.h"
#include "icing/join/join-processor.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id-join-indexing-handler.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
#include "icing/legacy/index/icing-filesystem.h"
#include "icing/legacy/index/icing-mock-filesystem.h"
#include "icing/portable/endian.h"
@@ -3571,10 +3571,10 @@ TEST_F(IcingSearchEngineInitializationTest,
{
Filesystem filesystem;
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem, GetQualifiedIdJoinIndexDir(), /*pre_mapping_fbv=*/false,
- /*use_persistent_hash_map=*/false));
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index,
+ QualifiedIdJoinIndex::Create(filesystem, GetQualifiedIdJoinIndexDir(),
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
// Add data for document 0.
ASSERT_THAT(qualified_id_join_index->last_added_document_id(),
kInvalidDocumentId);
@@ -3641,10 +3641,10 @@ TEST_F(IcingSearchEngineInitializationTest,
{
Filesystem filesystem;
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem, GetQualifiedIdJoinIndexDir(), /*pre_mapping_fbv=*/false,
- /*use_persistent_hash_map=*/false));
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index,
+ QualifiedIdJoinIndex::Create(filesystem, GetQualifiedIdJoinIndexDir(),
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
EXPECT_THAT(qualified_id_join_index->Get(
DocJoinInfo(/*document_id=*/0, /*joinable_property_id=*/0)),
StatusIs(libtextclassifier3::StatusCode::NOT_FOUND));
@@ -3742,10 +3742,10 @@ TEST_F(IcingSearchEngineInitializationTest,
{
Filesystem filesystem;
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem, GetQualifiedIdJoinIndexDir(), /*pre_mapping_fbv=*/false,
- /*use_persistent_hash_map=*/false));
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index,
+ QualifiedIdJoinIndex::Create(filesystem, GetQualifiedIdJoinIndexDir(),
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
// Add data for document 4.
DocumentId original_last_added_doc_id =
qualified_id_join_index->last_added_document_id();
@@ -3839,10 +3839,9 @@ TEST_F(IcingSearchEngineInitializationTest,
// `name:person` with a child query for `body:consectetur` based on the
// child's `senderQualifiedId` field.
- // Add document 4 without "senderQualifiedId". If joinable index is not
- // rebuilt correctly, then it will still have the previously added
- // senderQualifiedId for document 4 and include document 4 incorrectly in
- // the right side.
+ // Add document 4 without "senderQualifiedId". If join index is not rebuilt
+ // correctly, then it will still have the previously added senderQualifiedId
+ // for document 4 and include document 4 incorrectly in the right side.
DocumentProto another_message =
DocumentBuilder()
.SetKey("namespace", "message/4")
@@ -4829,7 +4828,7 @@ TEST_F(IcingSearchEngineInitializationTest,
auto mock_filesystem = std::make_unique<MockFilesystem>();
EXPECT_CALL(*mock_filesystem, PRead(A<const char*>(), _, _, _))
.WillRepeatedly(DoDefault());
- // This fails QualifiedIdTypeJoinableIndex::Create() once.
+ // This fails QualifiedIdJoinIndex::Create() once.
EXPECT_CALL(
*mock_filesystem,
PRead(Matcher<const char*>(Eq(qualified_id_join_index_metadata_file)), _,
@@ -5146,8 +5145,8 @@ TEST_P(IcingSearchEngineInitializationVersionChangeTest,
/*pre_mapping_fbv=*/false));
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index,
- QualifiedIdTypeJoinableIndex::Create(
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index,
+ QualifiedIdJoinIndex::Create(
*filesystem(), GetQualifiedIdJoinIndexDir(),
/*pre_mapping_fbv=*/false, /*use_persistent_hash_map=*/false));
@@ -5160,16 +5159,14 @@ TEST_P(IcingSearchEngineInitializationVersionChangeTest,
integer_section_indexing_handler,
IntegerSectionIndexingHandler::Create(
&fake_clock, integer_index.get()));
- ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdJoinIndexingHandler>
- qualified_id_joinable_property_indexing_handler,
- QualifiedIdJoinIndexingHandler::Create(&fake_clock,
- qualified_id_join_index.get()));
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<QualifiedIdJoinIndexingHandler>
+ qualified_id_join_indexing_handler,
+ QualifiedIdJoinIndexingHandler::Create(
+ &fake_clock, qualified_id_join_index.get()));
std::vector<std::unique_ptr<DataIndexingHandler>> handlers;
handlers.push_back(std::move(string_section_indexing_handler));
handlers.push_back(std::move(integer_section_indexing_handler));
- handlers.push_back(
- std::move(qualified_id_joinable_property_indexing_handler));
+ handlers.push_back(std::move(qualified_id_join_indexing_handler));
IndexProcessor index_processor(std::move(handlers), &fake_clock);
DocumentProto incorrect_message =
diff --git a/icing/icing-search-engine_schema_test.cc b/icing/icing-search-engine_schema_test.cc
index 2609cce..1987afe 100644
--- a/icing/icing-search-engine_schema_test.cc
+++ b/icing/icing-search-engine_schema_test.cc
@@ -1614,8 +1614,8 @@ TEST_F(IcingSearchEngineSchemaTest,
// - "senderQualifiedId": qualified id joinable. Joinable property id = 0.
//
// If the index is not correctly rebuilt, then the joinable data of
- // "senderQualifiedId" in the joinable index will still have old joinable
- // property id of 1 and therefore won't take effect for join search query.
+ // "senderQualifiedId" in the join index will still have old joinable property
+ // id of 1 and therefore won't take effect for join search query.
SchemaProto email_without_receiver_schema =
SchemaBuilder()
.AddType(SchemaTypeConfigBuilder().SetType("Person").AddProperty(
@@ -1917,8 +1917,8 @@ TEST_F(
// - "zQualifiedId": qualified id joinable. Joinable property id = 1.
//
// If the index is not correctly rebuilt, then the joinable data of
- // "senderQualifiedId" in the joinable index will still have old joinable
- // property id of 1 and therefore won't take effect for join search query.
+ // "senderQualifiedId" in the join index will still have old joinable property
+ // id of 1 and therefore won't take effect for join search query.
SchemaProto email_no_body_schema =
SchemaBuilder()
.AddType(SchemaTypeConfigBuilder().SetType("Person").AddProperty(
diff --git a/icing/icing-search-engine_search_test.cc b/icing/icing-search-engine_search_test.cc
index f1b49fb..fd2c939 100644
--- a/icing/icing-search-engine_search_test.cc
+++ b/icing/icing-search-engine_search_test.cc
@@ -502,6 +502,71 @@ TEST_P(IcingSearchEngineSearchTest,
expected_search_result_proto));
}
+TEST_P(IcingSearchEngineSearchTest, SearchWithNumToScore) {
+ auto fake_clock = std::make_unique<FakeClock>();
+ fake_clock->SetTimerElapsedMilliseconds(1000);
+ TestIcingSearchEngine icing(GetDefaultIcingOptions(),
+ std::make_unique<Filesystem>(),
+ std::make_unique<IcingFilesystem>(),
+ std::move(fake_clock), GetTestJniCache());
+ ASSERT_THAT(icing.Initialize().status(), ProtoIsOk());
+ ASSERT_THAT(icing.SetSchema(CreateMessageSchema()).status(), ProtoIsOk());
+
+ DocumentProto document_one = CreateMessageDocument("namespace", "uri1");
+ document_one.set_score(10);
+ ASSERT_THAT(icing.Put(document_one).status(), ProtoIsOk());
+
+ DocumentProto document_two = CreateMessageDocument("namespace", "uri2");
+ document_two.set_score(5);
+ ASSERT_THAT(icing.Put(document_two).status(), ProtoIsOk());
+
+ SearchSpecProto search_spec;
+ search_spec.set_term_match_type(TermMatchType::PREFIX);
+ search_spec.set_query("message");
+ search_spec.set_search_type(GetParam());
+
+ ResultSpecProto result_spec;
+ result_spec.set_num_per_page(10);
+ result_spec.set_num_to_score(10);
+
+ ScoringSpecProto scoring_spec = GetDefaultScoringSpec();
+
+ SearchResultProto expected_search_result_proto1;
+ expected_search_result_proto1.mutable_status()->set_code(StatusProto::OK);
+ *expected_search_result_proto1.mutable_results()->Add()->mutable_document() =
+ document_one;
+ *expected_search_result_proto1.mutable_results()->Add()->mutable_document() =
+ document_two;
+
+ SearchResultProto search_result_proto =
+ icing.Search(search_spec, GetDefaultScoringSpec(), result_spec);
+ EXPECT_THAT(search_result_proto.status(), ProtoIsOk());
+ EXPECT_THAT(search_result_proto, EqualsSearchResultIgnoreStatsAndScores(
+ expected_search_result_proto1));
+
+ result_spec.set_num_to_score(1);
+ // By setting num_to_score = 1, only document_two will be scored, ranked, and
+ // returned.
+ // - num_to_score cutoff is only affected by the reading order from posting
+ // list. IOW, since we read posting lists in doc id descending order,
+ // ScoringProcessor scores documents with higher doc ids first and cuts off
+ // if exceeding num_to_score.
+ // - Therefore, even though document_one has higher score, ScoringProcessor
+ // still skips document_one, because posting list reads document_two first
+ // and ScoringProcessor stops after document_two given that total # of
+ // scored document has already reached num_to_score.
+ SearchResultProto expected_search_result_google::protobuf;
+ expected_search_result_google::protobuf.mutable_status()->set_code(StatusProto::OK);
+ *expected_search_result_google::protobuf.mutable_results()->Add()->mutable_document() =
+ document_two;
+
+ search_result_proto =
+ icing.Search(search_spec, GetDefaultScoringSpec(), result_spec);
+ EXPECT_THAT(search_result_proto.status(), ProtoIsOk());
+ EXPECT_THAT(search_result_proto, EqualsSearchResultIgnoreStatsAndScores(
+ expected_search_result_google::protobuf));
+}
+
TEST_P(IcingSearchEngineSearchTest,
SearchNegativeResultLimitReturnsInvalidArgument) {
IcingSearchEngine icing(GetDefaultIcingOptions(), GetTestJniCache());
@@ -577,6 +642,62 @@ TEST_P(IcingSearchEngineSearchTest,
ProtoStatusIs(StatusProto::INVALID_ARGUMENT));
}
+TEST_P(IcingSearchEngineSearchTest,
+ SearchNegativeMaxJoinedChildrenPerParentReturnsInvalidArgument) {
+ IcingSearchEngine icing(GetDefaultIcingOptions(), GetTestJniCache());
+ ASSERT_THAT(icing.Initialize().status(), ProtoIsOk());
+
+ SearchSpecProto search_spec;
+ search_spec.set_term_match_type(TermMatchType::PREFIX);
+ search_spec.set_query("");
+ search_spec.set_search_type(GetParam());
+
+ ResultSpecProto result_spec;
+ result_spec.set_max_joined_children_per_parent_to_return(-1);
+
+ SearchResultProto expected_search_result_proto;
+ expected_search_result_proto.mutable_status()->set_code(
+ StatusProto::INVALID_ARGUMENT);
+ expected_search_result_proto.mutable_status()->set_message(
+ "ResultSpecProto.max_joined_children_per_parent_to_return cannot be "
+ "negative.");
+ SearchResultProto actual_results =
+ icing.Search(search_spec, GetDefaultScoringSpec(), result_spec);
+ EXPECT_THAT(actual_results, EqualsSearchResultIgnoreStatsAndScores(
+ expected_search_result_proto));
+}
+
+TEST_P(IcingSearchEngineSearchTest,
+ SearchNonPositiveNumToScoreReturnsInvalidArgument) {
+ IcingSearchEngine icing(GetDefaultIcingOptions(), GetTestJniCache());
+ ASSERT_THAT(icing.Initialize().status(), ProtoIsOk());
+
+ SearchSpecProto search_spec;
+ search_spec.set_term_match_type(TermMatchType::PREFIX);
+ search_spec.set_query("");
+ search_spec.set_search_type(GetParam());
+
+ ResultSpecProto result_spec;
+ result_spec.set_num_to_score(-1);
+
+ SearchResultProto expected_search_result_proto;
+ expected_search_result_proto.mutable_status()->set_code(
+ StatusProto::INVALID_ARGUMENT);
+ expected_search_result_proto.mutable_status()->set_message(
+ "ResultSpecProto.num_to_score cannot be non-positive.");
+
+ SearchResultProto actual_results1 =
+ icing.Search(search_spec, GetDefaultScoringSpec(), result_spec);
+ EXPECT_THAT(actual_results1, EqualsSearchResultIgnoreStatsAndScores(
+ expected_search_result_proto));
+
+ result_spec.set_num_to_score(0);
+ SearchResultProto actual_results2 =
+ icing.Search(search_spec, GetDefaultScoringSpec(), result_spec);
+ EXPECT_THAT(actual_results2, EqualsSearchResultIgnoreStatsAndScores(
+ expected_search_result_proto));
+}
+
TEST_P(IcingSearchEngineSearchTest, SearchWithPersistenceReturnsValidResults) {
IcingSearchEngineOptions icing_options = GetDefaultIcingOptions();
diff --git a/icing/index/index-processor_test.cc b/icing/index/index-processor_test.cc
index 0a0108d..9505dbd 100644
--- a/icing/index/index-processor_test.cc
+++ b/icing/index/index-processor_test.cc
@@ -40,8 +40,8 @@
#include "icing/index/numeric/numeric-index.h"
#include "icing/index/string-section-indexing-handler.h"
#include "icing/index/term-property-id.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id-join-indexing-handler.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
#include "icing/legacy/index/icing-filesystem.h"
#include "icing/legacy/index/icing-mock-filesystem.h"
#include "icing/portable/platform.h"
@@ -177,9 +177,9 @@ class IndexProcessorTest : public Test {
ICING_ASSERT_OK_AND_ASSIGN(
qualified_id_join_index_,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem_, qualified_id_join_index_dir_,
- /*pre_mapping_fbv=*/false, /*use_persistent_hash_map=*/false));
+ QualifiedIdJoinIndex::Create(filesystem_, qualified_id_join_index_dir_,
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
language_segmenter_factory::SegmenterOptions segmenter_options(ULOC_US);
ICING_ASSERT_OK_AND_ASSIGN(
@@ -297,14 +297,13 @@ class IndexProcessorTest : public Test {
&fake_clock_, integer_index_.get()));
ICING_ASSERT_OK_AND_ASSIGN(
std::unique_ptr<QualifiedIdJoinIndexingHandler>
- qualified_id_joinable_property_indexing_handler,
+ qualified_id_join_indexing_handler,
QualifiedIdJoinIndexingHandler::Create(&fake_clock_,
qualified_id_join_index_.get()));
std::vector<std::unique_ptr<DataIndexingHandler>> handlers;
handlers.push_back(std::move(string_section_indexing_handler));
handlers.push_back(std::move(integer_section_indexing_handler));
- handlers.push_back(
- std::move(qualified_id_joinable_property_indexing_handler));
+ handlers.push_back(std::move(qualified_id_join_indexing_handler));
index_processor_ =
std::make_unique<IndexProcessor>(std::move(handlers), &fake_clock_);
@@ -339,7 +338,7 @@ class IndexProcessorTest : public Test {
std::unique_ptr<Index> index_;
std::unique_ptr<NumericIndex<int64_t>> integer_index_;
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index_;
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index_;
std::unique_ptr<LanguageSegmenter> lang_segmenter_;
std::unique_ptr<Normalizer> normalizer_;
std::unique_ptr<SchemaStore> schema_store_;
@@ -827,16 +826,14 @@ TEST_F(IndexProcessorTest, OutOfOrderDocumentIdsInRecoveryMode) {
integer_section_indexing_handler,
IntegerSectionIndexingHandler::Create(
&fake_clock_, integer_index_.get()));
- ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdJoinIndexingHandler>
- qualified_id_joinable_property_indexing_handler,
- QualifiedIdJoinIndexingHandler::Create(&fake_clock_,
- qualified_id_join_index_.get()));
+ ICING_ASSERT_OK_AND_ASSIGN(std::unique_ptr<QualifiedIdJoinIndexingHandler>
+ qualified_id_join_indexing_handler,
+ QualifiedIdJoinIndexingHandler::Create(
+ &fake_clock_, qualified_id_join_index_.get()));
std::vector<std::unique_ptr<DataIndexingHandler>> handlers;
handlers.push_back(std::move(string_section_indexing_handler));
handlers.push_back(std::move(integer_section_indexing_handler));
- handlers.push_back(
- std::move(qualified_id_joinable_property_indexing_handler));
+ handlers.push_back(std::move(qualified_id_join_indexing_handler));
IndexProcessor index_processor(std::move(handlers), &fake_clock_,
/*recovery_mode=*/true);
diff --git a/icing/join/join-children-fetcher.h b/icing/join/join-children-fetcher.h
index 5f799b8..1b875bc 100644
--- a/icing/join/join-children-fetcher.h
+++ b/icing/join/join-children-fetcher.h
@@ -44,7 +44,7 @@ class JoinChildrenFetcher {
// Get a vector of children ScoredDocumentHit by parent document id.
//
// TODO(b/256022027): Implement property value joins with types of string and
- // int. In these cases, GetChildren should look up joinable cache to fetch
+ // int. In these cases, GetChildren should look up join index to fetch
// joinable property value of the given parent_doc_id according to
// join_spec_.parent_property_expression, and then fetch children by the
// corresponding map in this class using the joinable property value.
diff --git a/icing/join/join-processor.h b/icing/join/join-processor.h
index 347ce85..517e9db 100644
--- a/icing/join/join-processor.h
+++ b/icing/join/join-processor.h
@@ -22,7 +22,7 @@
#include "icing/text_classifier/lib3/utils/base/statusor.h"
#include "icing/join/join-children-fetcher.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/proto/search.pb.h"
#include "icing/schema/schema-store.h"
#include "icing/scoring/scored-document-hit.h"
@@ -35,10 +35,10 @@ class JoinProcessor {
public:
static constexpr std::string_view kQualifiedIdExpr = "this.qualifiedId()";
- explicit JoinProcessor(
- const DocumentStore* doc_store, const SchemaStore* schema_store,
- const QualifiedIdTypeJoinableIndex* qualified_id_join_index,
- int64_t current_time_ms)
+ explicit JoinProcessor(const DocumentStore* doc_store,
+ const SchemaStore* schema_store,
+ const QualifiedIdJoinIndex* qualified_id_join_index,
+ int64_t current_time_ms)
: doc_store_(doc_store),
schema_store_(schema_store),
qualified_id_join_index_(qualified_id_join_index),
@@ -72,14 +72,13 @@ class JoinProcessor {
// - kInvalidDocumentId if the given document is not found, doesn't have
// qualified id joinable type for the given property_path, or doesn't have
// joinable value (an optional property)
- // - Any other QualifiedIdTypeJoinableIndex errors
+ // - Any other QualifiedIdJoinIndex errors
libtextclassifier3::StatusOr<DocumentId> FetchReferencedQualifiedId(
const DocumentId& document_id, const std::string& property_path) const;
const DocumentStore* doc_store_; // Does not own.
const SchemaStore* schema_store_; // Does not own.
- const QualifiedIdTypeJoinableIndex*
- qualified_id_join_index_; // Does not own.
+ const QualifiedIdJoinIndex* qualified_id_join_index_; // Does not own.
int64_t current_time_ms_;
};
diff --git a/icing/join/join-processor_test.cc b/icing/join/join-processor_test.cc
index 95d1392..3dd7c87 100644
--- a/icing/join/join-processor_test.cc
+++ b/icing/join/join-processor_test.cc
@@ -25,8 +25,8 @@
#include "icing/document-builder.h"
#include "icing/file/filesystem.h"
#include "icing/file/portable-file-backed-proto-log.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id-join-indexing-handler.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
#include "icing/portable/platform.h"
#include "icing/proto/document.pb.h"
#include "icing/proto/document_wrapper.pb.h"
@@ -129,9 +129,9 @@ class JoinProcessorTest : public ::testing::Test {
ICING_ASSERT_OK_AND_ASSIGN(
qualified_id_join_index_,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem_, qualified_id_join_index_dir_,
- /*pre_mapping_fbv=*/false, /*use_persistent_hash_map=*/false));
+ QualifiedIdJoinIndex::Create(filesystem_, qualified_id_join_index_dir_,
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
}
void TearDown() override {
@@ -185,7 +185,7 @@ class JoinProcessorTest : public ::testing::Test {
std::unique_ptr<LanguageSegmenter> lang_segmenter_;
std::unique_ptr<SchemaStore> schema_store_;
std::unique_ptr<DocumentStore> doc_store_;
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index_;
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index_;
FakeClock fake_clock_;
};
diff --git a/icing/join/qualified-id-type-joinable-index.cc b/icing/join/qualified-id-join-index.cc
index a1df3d0..86f1921 100644
--- a/icing/join/qualified-id-type-joinable-index.cc
+++ b/icing/join/qualified-id-join-index.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include <cstring>
#include <memory>
@@ -43,6 +43,11 @@ namespace lib {
namespace {
+// Set 1M for max # of qualified id entries and 10 bytes for key-value bytes.
+// This will take at most 23 MiB disk space and mmap for persistent hash map.
+static constexpr int32_t kDocJoinInfoMapperMaxNumEntries = 1 << 20;
+static constexpr int32_t kDocJoinInfoMapperAverageKVByteSize = 10;
+
static constexpr int32_t kDocJoinInfoMapperDynamicTrieMaxSize =
128 * 1024 * 1024; // 128 MiB
@@ -69,12 +74,10 @@ std::string GetQualifiedIdStoragePath(std::string_view working_path) {
} // namespace
-/* static */ libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
-QualifiedIdTypeJoinableIndex::Create(const Filesystem& filesystem,
- std::string working_path,
- bool pre_mapping_fbv,
- bool use_persistent_hash_map) {
+/* static */ libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
+QualifiedIdJoinIndex::Create(const Filesystem& filesystem,
+ std::string working_path, bool pre_mapping_fbv,
+ bool use_persistent_hash_map) {
if (!filesystem.FileExists(GetMetadataFilePath(working_path).c_str()) ||
!filesystem.DirectoryExists(
GetDocJoinInfoMapperPath(working_path).c_str()) ||
@@ -90,7 +93,7 @@ QualifiedIdTypeJoinableIndex::Create(const Filesystem& filesystem,
pre_mapping_fbv, use_persistent_hash_map);
}
-QualifiedIdTypeJoinableIndex::~QualifiedIdTypeJoinableIndex() {
+QualifiedIdJoinIndex::~QualifiedIdJoinIndex() {
if (!PersistToDisk().ok()) {
ICING_LOG(WARNING) << "Failed to persist qualified id type joinable index "
"to disk while destructing "
@@ -98,7 +101,7 @@ QualifiedIdTypeJoinableIndex::~QualifiedIdTypeJoinableIndex() {
}
}
-libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Put(
+libtextclassifier3::Status QualifiedIdJoinIndex::Put(
const DocJoinInfo& doc_join_info, std::string_view ref_qualified_id_str) {
if (!doc_join_info.is_valid()) {
return absl_ports::InvalidArgumentError(
@@ -123,8 +126,8 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Put(
return libtextclassifier3::Status::OK;
}
-libtextclassifier3::StatusOr<std::string_view>
-QualifiedIdTypeJoinableIndex::Get(const DocJoinInfo& doc_join_info) const {
+libtextclassifier3::StatusOr<std::string_view> QualifiedIdJoinIndex::Get(
+ const DocJoinInfo& doc_join_info) const {
if (!doc_join_info.is_valid()) {
return absl_ports::InvalidArgumentError(
"Cannot get data for an invalid DocJoinInfo");
@@ -139,7 +142,7 @@ QualifiedIdTypeJoinableIndex::Get(const DocJoinInfo& doc_join_info) const {
return std::string_view(data, strlen(data));
}
-libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Optimize(
+libtextclassifier3::Status QualifiedIdJoinIndex::Optimize(
const std::vector<DocumentId>& document_id_old_to_new,
DocumentId new_last_added_document_id) {
std::string temp_working_path = working_path_ + "_temp";
@@ -157,10 +160,9 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Optimize(
// Transfer all data from the current to new qualified id type joinable
// index. Also PersistToDisk and destruct the instance after finishing, so
// we can safely swap directories later.
- ICING_ASSIGN_OR_RETURN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> new_index,
- Create(filesystem_, temp_working_path_ddir.dir(), pre_mapping_fbv_,
- use_persistent_hash_map_));
+ ICING_ASSIGN_OR_RETURN(std::unique_ptr<QualifiedIdJoinIndex> new_index,
+ Create(filesystem_, temp_working_path_ddir.dir(),
+ pre_mapping_fbv_, use_persistent_hash_map_));
ICING_RETURN_IF_ERROR(
TransferIndex(document_id_old_to_new, new_index.get()));
new_index->set_last_added_document_id(new_last_added_document_id);
@@ -190,7 +192,9 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Optimize(
doc_join_info_mapper_,
PersistentHashMapKeyMapper<int32_t>::Create(
filesystem_, GetDocJoinInfoMapperPath(working_path_),
- pre_mapping_fbv_));
+ pre_mapping_fbv_,
+ /*max_num_entries=*/kDocJoinInfoMapperMaxNumEntries,
+ /*average_kv_byte_size=*/kDocJoinInfoMapperAverageKVByteSize));
} else {
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper_,
@@ -210,7 +214,7 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Optimize(
return libtextclassifier3::Status::OK;
}
-libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Clear() {
+libtextclassifier3::Status QualifiedIdJoinIndex::Clear() {
doc_join_info_mapper_.reset();
// Discard and reinitialize doc join info mapper.
std::string doc_join_info_mapper_path =
@@ -221,8 +225,9 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Clear() {
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper_,
PersistentHashMapKeyMapper<int32_t>::Create(
- filesystem_, std::move(doc_join_info_mapper_path),
- pre_mapping_fbv_));
+ filesystem_, std::move(doc_join_info_mapper_path), pre_mapping_fbv_,
+ /*max_num_entries=*/kDocJoinInfoMapperMaxNumEntries,
+ /*average_kv_byte_size=*/kDocJoinInfoMapperAverageKVByteSize));
} else {
ICING_RETURN_IF_ERROR(DynamicTrieKeyMapper<int32_t>::Delete(
filesystem_, doc_join_info_mapper_path));
@@ -243,12 +248,11 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::Clear() {
return libtextclassifier3::Status::OK;
}
-/* static */ libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
-QualifiedIdTypeJoinableIndex::InitializeNewFiles(const Filesystem& filesystem,
- std::string&& working_path,
- bool pre_mapping_fbv,
- bool use_persistent_hash_map) {
+/* static */ libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
+QualifiedIdJoinIndex::InitializeNewFiles(const Filesystem& filesystem,
+ std::string&& working_path,
+ bool pre_mapping_fbv,
+ bool use_persistent_hash_map) {
// Create working directory.
if (!filesystem.CreateDirectoryRecursively(working_path.c_str())) {
return absl_ports::InternalError(
@@ -262,8 +266,9 @@ QualifiedIdTypeJoinableIndex::InitializeNewFiles(const Filesystem& filesystem,
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper,
PersistentHashMapKeyMapper<int32_t>::Create(
- filesystem, GetDocJoinInfoMapperPath(working_path),
- pre_mapping_fbv));
+ filesystem, GetDocJoinInfoMapperPath(working_path), pre_mapping_fbv,
+ /*max_num_entries=*/kDocJoinInfoMapperMaxNumEntries,
+ /*average_kv_byte_size=*/kDocJoinInfoMapperAverageKVByteSize));
} else {
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper,
@@ -282,8 +287,8 @@ QualifiedIdTypeJoinableIndex::InitializeNewFiles(const Filesystem& filesystem,
/*pre_mapping_mmap_size=*/pre_mapping_fbv ? 1024 * 1024 : 0));
// Create instance.
- auto new_index = std::unique_ptr<QualifiedIdTypeJoinableIndex>(
- new QualifiedIdTypeJoinableIndex(
+ auto new_index =
+ std::unique_ptr<QualifiedIdJoinIndex>(new QualifiedIdJoinIndex(
filesystem, std::move(working_path),
/*metadata_buffer=*/std::make_unique<uint8_t[]>(kMetadataFileSize),
std::move(doc_join_info_mapper), std::move(qualified_id_storage),
@@ -298,11 +303,11 @@ QualifiedIdTypeJoinableIndex::InitializeNewFiles(const Filesystem& filesystem,
return new_index;
}
-/* static */ libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
-QualifiedIdTypeJoinableIndex::InitializeExistingFiles(
- const Filesystem& filesystem, std::string&& working_path,
- bool pre_mapping_fbv, bool use_persistent_hash_map) {
+/* static */ libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
+QualifiedIdJoinIndex::InitializeExistingFiles(const Filesystem& filesystem,
+ std::string&& working_path,
+ bool pre_mapping_fbv,
+ bool use_persistent_hash_map) {
// PRead metadata file.
auto metadata_buffer = std::make_unique<uint8_t[]>(kMetadataFileSize);
if (!filesystem.PRead(GetMetadataFilePath(working_path).c_str(),
@@ -328,8 +333,9 @@ QualifiedIdTypeJoinableIndex::InitializeExistingFiles(
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper,
PersistentHashMapKeyMapper<int32_t>::Create(
- filesystem, GetDocJoinInfoMapperPath(working_path),
- pre_mapping_fbv));
+ filesystem, GetDocJoinInfoMapperPath(working_path), pre_mapping_fbv,
+ /*max_num_entries=*/kDocJoinInfoMapperMaxNumEntries,
+ /*average_kv_byte_size=*/kDocJoinInfoMapperAverageKVByteSize));
} else {
ICING_ASSIGN_OR_RETURN(
doc_join_info_mapper,
@@ -348,8 +354,8 @@ QualifiedIdTypeJoinableIndex::InitializeExistingFiles(
/*pre_mapping_mmap_size=*/pre_mapping_fbv ? 1024 * 1024 : 0));
// Create instance.
- auto type_joinable_index = std::unique_ptr<QualifiedIdTypeJoinableIndex>(
- new QualifiedIdTypeJoinableIndex(
+ auto type_joinable_index =
+ std::unique_ptr<QualifiedIdJoinIndex>(new QualifiedIdJoinIndex(
filesystem, std::move(working_path), std::move(metadata_buffer),
std::move(doc_join_info_mapper), std::move(qualified_id_storage),
pre_mapping_fbv, use_persistent_hash_map));
@@ -364,9 +370,9 @@ QualifiedIdTypeJoinableIndex::InitializeExistingFiles(
return type_joinable_index;
}
-libtextclassifier3::Status QualifiedIdTypeJoinableIndex::TransferIndex(
+libtextclassifier3::Status QualifiedIdJoinIndex::TransferIndex(
const std::vector<DocumentId>& document_id_old_to_new,
- QualifiedIdTypeJoinableIndex* new_index) const {
+ QualifiedIdJoinIndex* new_index) const {
std::unique_ptr<KeyMapper<int32_t>::Iterator> iter =
doc_join_info_mapper_->GetIterator();
while (iter->Advance()) {
@@ -394,8 +400,7 @@ libtextclassifier3::Status QualifiedIdTypeJoinableIndex::TransferIndex(
return libtextclassifier3::Status::OK;
}
-libtextclassifier3::Status
-QualifiedIdTypeJoinableIndex::PersistMetadataToDisk() {
+libtextclassifier3::Status QualifiedIdJoinIndex::PersistMetadataToDisk() {
std::string metadata_file_path = GetMetadataFilePath(working_path_);
ScopedFd sfd(filesystem_.OpenForWrite(metadata_file_path.c_str()));
@@ -415,20 +420,19 @@ QualifiedIdTypeJoinableIndex::PersistMetadataToDisk() {
return libtextclassifier3::Status::OK;
}
-libtextclassifier3::Status
-QualifiedIdTypeJoinableIndex::PersistStoragesToDisk() {
+libtextclassifier3::Status QualifiedIdJoinIndex::PersistStoragesToDisk() {
ICING_RETURN_IF_ERROR(doc_join_info_mapper_->PersistToDisk());
ICING_RETURN_IF_ERROR(qualified_id_storage_->PersistToDisk());
return libtextclassifier3::Status::OK;
}
libtextclassifier3::StatusOr<Crc32>
-QualifiedIdTypeJoinableIndex::ComputeInfoChecksum() {
+QualifiedIdJoinIndex::ComputeInfoChecksum() {
return info().ComputeChecksum();
}
libtextclassifier3::StatusOr<Crc32>
-QualifiedIdTypeJoinableIndex::ComputeStoragesChecksum() {
+QualifiedIdJoinIndex::ComputeStoragesChecksum() {
ICING_ASSIGN_OR_RETURN(Crc32 doc_join_info_mapper_crc,
doc_join_info_mapper_->ComputeChecksum());
ICING_ASSIGN_OR_RETURN(Crc32 qualified_id_storage_crc,
diff --git a/icing/join/qualified-id-type-joinable-index.h b/icing/join/qualified-id-join-index.h
index 4844433..6accfaf 100644
--- a/icing/join/qualified-id-type-joinable-index.h
+++ b/icing/join/qualified-id-join-index.h
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#ifndef ICING_JOIN_QUALIFIED_ID_TYPE_JOINABLE_INDEX_H_
-#define ICING_JOIN_QUALIFIED_ID_TYPE_JOINABLE_INDEX_H_
+#ifndef ICING_JOIN_QUALIFIED_ID_JOIN_INDEX_H_
+#define ICING_JOIN_QUALIFIED_ID_JOIN_INDEX_H_
#include <cstdint>
#include <memory>
@@ -34,9 +34,9 @@
namespace icing {
namespace lib {
-// QualifiedIdTypeJoinableIndex: a class to maintain data mapping DocJoinInfo to
+// QualifiedIdJoinIndex: a class to maintain data mapping DocJoinInfo to
// joinable qualified ids and delete propagation info.
-class QualifiedIdTypeJoinableIndex : public PersistentStorage {
+class QualifiedIdJoinIndex : public PersistentStorage {
public:
struct Info {
static constexpr int32_t kMagic = 0x48cabdc6;
@@ -61,23 +61,23 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
static constexpr WorkingPathType kWorkingPathType =
WorkingPathType::kDirectory;
- // Creates a QualifiedIdTypeJoinableIndex instance to store qualified ids for
- // future joining search. If any of the underlying file is missing, then
- // delete the whole working_path and (re)initialize with new ones. Otherwise
- // initialize and create the instance by existing files.
+ // Creates a QualifiedIdJoinIndex instance to store qualified ids for future
+ // joining search. If any of the underlying file is missing, then delete the
+ // whole working_path and (re)initialize with new ones. Otherwise initialize
+ // and create the instance by existing files.
//
// filesystem: Object to make system level calls
// working_path: Specifies the working path for PersistentStorage.
- // QualifiedIdTypeJoinableIndex uses working path as working
- // directory and all related files will be stored under this
- // directory. It takes full ownership and of working_path_,
- // including creation/deletion. It is the caller's
- // responsibility to specify correct working path and avoid
- // mixing different persistent storages together under the same
- // path. Also the caller has the ownership for the parent
- // directory of working_path_, and it is responsible for parent
- // directory creation/deletion. See PersistentStorage for more
- // details about the concept of working_path.
+ // QualifiedIdJoinIndex uses working path as working directory
+ // and all related files will be stored under this directory. It
+ // takes full ownership and of working_path_, including
+ // creation/deletion. It is the caller's responsibility to
+ // specify correct working path and avoid mixing different
+ // persistent storages together under the same path. Also the
+ // caller has the ownership for the parent directory of
+ // working_path_, and it is responsible for parent directory
+ // creation/deletion. See PersistentStorage for more details
+ // about the concept of working_path.
// pre_mapping_fbv: flag indicating whether memory map max possible file size
// for underlying FileBackedVector before growing the actual
// file size.
@@ -90,12 +90,11 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
// checksum
// - INTERNAL_ERROR on I/O errors
// - Any KeyMapper errors
- static libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
+ static libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
Create(const Filesystem& filesystem, std::string working_path,
bool pre_mapping_fbv, bool use_persistent_hash_map);
- // Deletes QualifiedIdTypeJoinableIndex under working_path.
+ // Deletes QualifiedIdJoinIndex under working_path.
//
// Returns:
// - OK on success
@@ -107,15 +106,13 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
}
// Delete copy and move constructor/assignment operator.
- QualifiedIdTypeJoinableIndex(const QualifiedIdTypeJoinableIndex&) = delete;
- QualifiedIdTypeJoinableIndex& operator=(const QualifiedIdTypeJoinableIndex&) =
- delete;
+ QualifiedIdJoinIndex(const QualifiedIdJoinIndex&) = delete;
+ QualifiedIdJoinIndex& operator=(const QualifiedIdJoinIndex&) = delete;
- QualifiedIdTypeJoinableIndex(QualifiedIdTypeJoinableIndex&&) = delete;
- QualifiedIdTypeJoinableIndex& operator=(QualifiedIdTypeJoinableIndex&&) =
- delete;
+ QualifiedIdJoinIndex(QualifiedIdJoinIndex&&) = delete;
+ QualifiedIdJoinIndex& operator=(QualifiedIdJoinIndex&&) = delete;
- ~QualifiedIdTypeJoinableIndex() override;
+ ~QualifiedIdJoinIndex() override;
// Puts a new data into index: DocJoinInfo (DocumentId, JoinablePropertyId)
// references to ref_qualified_id_str (the identifier of another document).
@@ -183,7 +180,7 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
}
private:
- explicit QualifiedIdTypeJoinableIndex(
+ explicit QualifiedIdJoinIndex(
const Filesystem& filesystem, std::string&& working_path,
std::unique_ptr<uint8_t[]> metadata_buffer,
std::unique_ptr<KeyMapper<int32_t>> doc_join_info_mapper,
@@ -197,13 +194,11 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
pre_mapping_fbv_(pre_mapping_fbv),
use_persistent_hash_map_(use_persistent_hash_map) {}
- static libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
+ static libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
InitializeNewFiles(const Filesystem& filesystem, std::string&& working_path,
bool pre_mapping_fbv, bool use_persistent_hash_map);
- static libtextclassifier3::StatusOr<
- std::unique_ptr<QualifiedIdTypeJoinableIndex>>
+ static libtextclassifier3::StatusOr<std::unique_ptr<QualifiedIdJoinIndex>>
InitializeExistingFiles(const Filesystem& filesystem,
std::string&& working_path, bool pre_mapping_fbv,
bool use_persistent_hash_map);
@@ -217,7 +212,7 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
// - INTERNAL_ERROR on I/O error
libtextclassifier3::Status TransferIndex(
const std::vector<DocumentId>& document_id_old_to_new,
- QualifiedIdTypeJoinableIndex* new_index) const;
+ QualifiedIdJoinIndex* new_index) const;
// Flushes contents of metadata file.
//
@@ -291,4 +286,4 @@ class QualifiedIdTypeJoinableIndex : public PersistentStorage {
} // namespace lib
} // namespace icing
-#endif // ICING_JOIN_QUALIFIED_ID_TYPE_JOINABLE_INDEX_H_
+#endif // ICING_JOIN_QUALIFIED_ID_JOIN_INDEX_H_
diff --git a/icing/join/qualified-id-type-joinable-index_test.cc b/icing/join/qualified-id-join-index_test.cc
index 8ef9167..3d59f4b 100644
--- a/icing/join/qualified-id-type-joinable-index_test.cc
+++ b/icing/join/qualified-id-join-index_test.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include <memory>
#include <string>
@@ -49,7 +49,7 @@ using ::testing::Pointee;
using ::testing::SizeIs;
using Crcs = PersistentStorage::Crcs;
-using Info = QualifiedIdTypeJoinableIndex::Info;
+using Info = QualifiedIdJoinIndex::Info;
static constexpr int32_t kCorruptedValueOffset = 3;
@@ -63,7 +63,7 @@ struct QualifiedIdJoinIndexTestParam {
use_persistent_hash_map(use_persistent_hash_map_in) {}
};
-class QualifiedIdTypeJoinableIndexTest
+class QualifiedIdJoinIndexTest
: public ::testing::TestWithParam<QualifiedIdJoinIndexTestParam> {
protected:
void SetUp() override {
@@ -71,7 +71,7 @@ class QualifiedIdTypeJoinableIndexTest
ASSERT_THAT(filesystem_.CreateDirectoryRecursively(base_dir_.c_str()),
IsTrue());
- working_path_ = base_dir_ + "/qualified_id_type_joinable_index_test";
+ working_path_ = base_dir_ + "/qualified_id_join_index_test";
}
void TearDown() override {
@@ -83,27 +83,26 @@ class QualifiedIdTypeJoinableIndexTest
std::string working_path_;
};
-TEST_P(QualifiedIdTypeJoinableIndexTest, InvalidWorkingPath) {
+TEST_P(QualifiedIdJoinIndexTest, InvalidWorkingPath) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
- EXPECT_THAT(
- QualifiedIdTypeJoinableIndex::Create(
- filesystem_, "/dev/null/qualified_id_type_joinable_index_test",
- param.pre_mapping_fbv, param.use_persistent_hash_map),
- StatusIs(libtextclassifier3::StatusCode::INTERNAL));
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(
+ filesystem_, "/dev/null/qualified_id_join_index_test",
+ param.pre_mapping_fbv, param.use_persistent_hash_map),
+ StatusIs(libtextclassifier3::StatusCode::INTERNAL));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, InitializeNewFiles) {
+TEST_P(QualifiedIdJoinIndexTest, InitializeNewFiles) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ASSERT_FALSE(filesystem_.DirectoryExists(working_path_.c_str()));
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index, Pointee(IsEmpty()));
ICING_ASSERT_OK(index->PersistToDisk());
@@ -113,25 +112,23 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, InitializeNewFiles) {
// sections.
const std::string metadata_file_path =
absl_ports::StrCat(working_path_, "/metadata");
- auto metadata_buffer = std::make_unique<uint8_t[]>(
- QualifiedIdTypeJoinableIndex::kMetadataFileSize);
+ auto metadata_buffer =
+ std::make_unique<uint8_t[]>(QualifiedIdJoinIndex::kMetadataFileSize);
ASSERT_THAT(
filesystem_.PRead(metadata_file_path.c_str(), metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize,
+ QualifiedIdJoinIndex::kMetadataFileSize,
/*offset=*/0),
IsTrue());
// Check info section
const Info* info = reinterpret_cast<const Info*>(
- metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kInfoMetadataBufferOffset);
+ metadata_buffer.get() + QualifiedIdJoinIndex::kInfoMetadataBufferOffset);
EXPECT_THAT(info->magic, Eq(Info::kMagic));
EXPECT_THAT(info->last_added_document_id, Eq(kInvalidDocumentId));
// Check crcs section
const Crcs* crcs = reinterpret_cast<const Crcs*>(
- metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kCrcsMetadataBufferOffset);
+ metadata_buffer.get() + QualifiedIdJoinIndex::kCrcsMetadataBufferOffset);
// There are some initial info in KeyMapper, so storages_crc should be
// non-zero.
EXPECT_THAT(crcs->component_crcs.storages_crc, Ne(0));
@@ -146,16 +143,16 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, InitializeNewFiles) {
.Get()));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializationShouldFailWithoutPersistToDiskOrDestruction) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
// Insert some data.
ICING_ASSERT_OK(
@@ -171,24 +168,23 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
// Without calling PersistToDisk, checksums will not be recomputed or synced
// to disk, so initializing another instance on the same files should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(param.use_persistent_hash_map
? libtextclassifier3::StatusCode::FAILED_PRECONDITION
: libtextclassifier3::StatusCode::INTERNAL));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
- InitializationShouldSucceedWithPersistToDisk) {
+TEST_P(QualifiedIdJoinIndexTest, InitializationShouldSucceedWithPersistToDisk) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index1,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index1,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
// Insert some data.
ICING_ASSERT_OK(
@@ -208,10 +204,10 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ICING_EXPECT_OK(index1->PersistToDisk());
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index2,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index2,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index2, Pointee(SizeIs(3)));
EXPECT_THAT(
index2->Get(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20)),
@@ -224,17 +220,16 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
IsOkAndHolds(/*ref_qualified_id_str=*/"namespace#uriC"));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
- InitializationShouldSucceedAfterDestruction) {
+TEST_P(QualifiedIdJoinIndexTest, InitializationShouldSucceedAfterDestruction) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
// Insert some data.
ICING_ASSERT_OK(
@@ -255,10 +250,10 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
// thus initializing another instance on the same files should succeed, and
// we should be able to get the same contents.
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index, Pointee(SizeIs(3)));
EXPECT_THAT(index->Get(DocJoinInfo(/*document_id=*/1,
/*joinable_property_id=*/20)),
@@ -272,17 +267,17 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
}
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializeExistingFilesWithDifferentMagicShouldFail) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -297,50 +292,49 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ScopedFd metadata_sfd(filesystem_.OpenForWrite(metadata_file_path.c_str()));
ASSERT_THAT(metadata_sfd.is_valid(), IsTrue());
- auto metadata_buffer = std::make_unique<uint8_t[]>(
- QualifiedIdTypeJoinableIndex::kMetadataFileSize);
- ASSERT_THAT(
- filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize,
- /*offset=*/0),
- IsTrue());
+ auto metadata_buffer =
+ std::make_unique<uint8_t[]>(QualifiedIdJoinIndex::kMetadataFileSize);
+ ASSERT_THAT(filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize,
+ /*offset=*/0),
+ IsTrue());
// Manually change magic and update checksums.
Crcs* crcs = reinterpret_cast<Crcs*>(
metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kCrcsMetadataBufferOffset);
+ QualifiedIdJoinIndex::kCrcsMetadataBufferOffset);
Info* info = reinterpret_cast<Info*>(
metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kInfoMetadataBufferOffset);
+ QualifiedIdJoinIndex::kInfoMetadataBufferOffset);
info->magic += kCorruptedValueOffset;
crcs->component_crcs.info_crc = info->ComputeChecksum().Get();
crcs->all_crc = crcs->component_crcs.ComputeChecksum().Get();
- ASSERT_THAT(filesystem_.PWrite(
- metadata_sfd.get(), /*offset=*/0, metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize),
+ ASSERT_THAT(filesystem_.PWrite(metadata_sfd.get(), /*offset=*/0,
+ metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize),
IsTrue());
}
- // Attempt to create the qualified id type joinable index with different
- // magic. This should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ // Attempt to create the qualified id join index with different magic. This
+ // should fail.
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION,
HasSubstr("Incorrect magic value")));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializeExistingFilesWithWrongAllCrcShouldFail) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -354,46 +348,45 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ScopedFd metadata_sfd(filesystem_.OpenForWrite(metadata_file_path.c_str()));
ASSERT_THAT(metadata_sfd.is_valid(), IsTrue());
- auto metadata_buffer = std::make_unique<uint8_t[]>(
- QualifiedIdTypeJoinableIndex::kMetadataFileSize);
- ASSERT_THAT(
- filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize,
- /*offset=*/0),
- IsTrue());
+ auto metadata_buffer =
+ std::make_unique<uint8_t[]>(QualifiedIdJoinIndex::kMetadataFileSize);
+ ASSERT_THAT(filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize,
+ /*offset=*/0),
+ IsTrue());
// Manually corrupt all_crc
Crcs* crcs = reinterpret_cast<Crcs*>(
metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kCrcsMetadataBufferOffset);
+ QualifiedIdJoinIndex::kCrcsMetadataBufferOffset);
crcs->all_crc += kCorruptedValueOffset;
- ASSERT_THAT(filesystem_.PWrite(
- metadata_sfd.get(), /*offset=*/0, metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize),
+ ASSERT_THAT(filesystem_.PWrite(metadata_sfd.get(), /*offset=*/0,
+ metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize),
IsTrue());
}
- // Attempt to create the qualified id type joinable index with metadata
- // containing corrupted all_crc. This should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ // Attempt to create the qualified id join index with metadata containing
+ // corrupted all_crc. This should fail.
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION,
HasSubstr("Invalid all crc")));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializeExistingFilesWithCorruptedInfoShouldFail) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -407,47 +400,46 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ScopedFd metadata_sfd(filesystem_.OpenForWrite(metadata_file_path.c_str()));
ASSERT_THAT(metadata_sfd.is_valid(), IsTrue());
- auto metadata_buffer = std::make_unique<uint8_t[]>(
- QualifiedIdTypeJoinableIndex::kMetadataFileSize);
- ASSERT_THAT(
- filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize,
- /*offset=*/0),
- IsTrue());
+ auto metadata_buffer =
+ std::make_unique<uint8_t[]>(QualifiedIdJoinIndex::kMetadataFileSize);
+ ASSERT_THAT(filesystem_.PRead(metadata_sfd.get(), metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize,
+ /*offset=*/0),
+ IsTrue());
// Modify info, but don't update the checksum. This would be similar to
// corruption of info.
Info* info = reinterpret_cast<Info*>(
metadata_buffer.get() +
- QualifiedIdTypeJoinableIndex::kInfoMetadataBufferOffset);
+ QualifiedIdJoinIndex::kInfoMetadataBufferOffset);
info->last_added_document_id += kCorruptedValueOffset;
- ASSERT_THAT(filesystem_.PWrite(
- metadata_sfd.get(), /*offset=*/0, metadata_buffer.get(),
- QualifiedIdTypeJoinableIndex::kMetadataFileSize),
+ ASSERT_THAT(filesystem_.PWrite(metadata_sfd.get(), /*offset=*/0,
+ metadata_buffer.get(),
+ QualifiedIdJoinIndex::kMetadataFileSize),
IsTrue());
}
- // Attempt to create the qualified id type joinable index with info that
- // doesn't match its checksum. This should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ // Attempt to create the qualified id join index with info that doesn't match
+ // its checksum. This should fail.
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION,
HasSubstr("Invalid info crc")));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializeExistingFilesWithCorruptedDocJoinInfoMapperShouldFail) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -478,26 +470,26 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ASSERT_THAT(old_crc, Not(Eq(new_crc)));
}
- // Attempt to create the qualified id type joinable index with corrupted
+ // Attempt to create the qualified id join index with corrupted
// doc_join_info_mapper. This should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION,
HasSubstr("Invalid storages crc")));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
+TEST_P(QualifiedIdJoinIndexTest,
InitializeExistingFilesWithCorruptedQualifiedIdStorageShouldFail) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -524,24 +516,24 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
ASSERT_THAT(old_crc, Not(Eq(new_crc)));
}
- // Attempt to create the qualified id type joinable index with corrupted
+ // Attempt to create the qualified id join index with corrupted
// qualified_id_storage. This should fail.
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map),
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION,
HasSubstr("Invalid storages crc")));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, InvalidPut) {
+TEST_P(QualifiedIdJoinIndexTest, InvalidPut) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
DocJoinInfo default_invalid;
EXPECT_THAT(
@@ -549,22 +541,22 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, InvalidPut) {
StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, InvalidGet) {
+TEST_P(QualifiedIdJoinIndexTest, InvalidGet) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
DocJoinInfo default_invalid;
EXPECT_THAT(index->Get(default_invalid),
StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, PutAndGet) {
+TEST_P(QualifiedIdJoinIndexTest, PutAndGet) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
DocJoinInfo target_info1(/*document_id=*/1, /*joinable_property_id=*/20);
@@ -577,12 +569,12 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, PutAndGet) {
std::string_view ref_qualified_id_str_c = "namespace#uriC";
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index->Put(target_info1, ref_qualified_id_str_a), IsOk());
EXPECT_THAT(index->Put(target_info2, ref_qualified_id_str_b), IsOk());
@@ -598,29 +590,28 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, PutAndGet) {
// Verify we can get all of them after destructing and re-initializing.
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index, Pointee(SizeIs(3)));
EXPECT_THAT(index->Get(target_info1), IsOkAndHolds(ref_qualified_id_str_a));
EXPECT_THAT(index->Get(target_info2), IsOkAndHolds(ref_qualified_id_str_b));
EXPECT_THAT(index->Get(target_info3), IsOkAndHolds(ref_qualified_id_str_c));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest,
- GetShouldReturnNotFoundErrorIfNotExist) {
+TEST_P(QualifiedIdJoinIndexTest, GetShouldReturnNotFoundErrorIfNotExist) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
DocJoinInfo target_info(/*document_id=*/1, /*joinable_property_id=*/20);
std::string_view ref_qualified_id_str = "namespace#uriA";
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
// Verify entry is not found in the beginning.
EXPECT_THAT(index->Get(target_info),
@@ -636,14 +627,14 @@ TEST_P(QualifiedIdTypeJoinableIndexTest,
StatusIs(libtextclassifier3::StatusCode::NOT_FOUND));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, SetLastAddedDocumentId) {
+TEST_P(QualifiedIdJoinIndexTest, SetLastAddedDocumentId) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index->last_added_document_id(), Eq(kInvalidDocumentId));
@@ -657,15 +648,15 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, SetLastAddedDocumentId) {
}
TEST_P(
- QualifiedIdTypeJoinableIndexTest,
+ QualifiedIdJoinIndexTest,
SetLastAddedDocumentIdShouldIgnoreNewDocumentIdNotGreaterThanTheCurrent) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
constexpr DocumentId kDocumentId = 123;
index->set_last_added_document_id(kDocumentId);
@@ -678,14 +669,14 @@ TEST_P(
EXPECT_THAT(index->last_added_document_id(), Eq(kDocumentId));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, Optimize) {
+TEST_P(QualifiedIdJoinIndexTest, Optimize) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/3, /*joinable_property_id=*/10),
@@ -759,14 +750,14 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, Optimize) {
IsOkAndHolds("namespace#uriD"));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, OptimizeOutOfRangeDocumentId) {
+TEST_P(QualifiedIdJoinIndexTest, OptimizeOutOfRangeDocumentId) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/99, /*joinable_property_id=*/10),
@@ -788,14 +779,14 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, OptimizeOutOfRangeDocumentId) {
EXPECT_THAT(index, Pointee(IsEmpty()));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, OptimizeDeleteAll) {
+TEST_P(QualifiedIdJoinIndexTest, OptimizeDeleteAll) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/3, /*joinable_property_id=*/10),
@@ -827,19 +818,19 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, OptimizeDeleteAll) {
EXPECT_THAT(index, Pointee(IsEmpty()));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, Clear) {
+TEST_P(QualifiedIdJoinIndexTest, Clear) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
DocJoinInfo target_info1(/*document_id=*/1, /*joinable_property_id=*/20);
DocJoinInfo target_info2(/*document_id=*/3, /*joinable_property_id=*/5);
DocJoinInfo target_info3(/*document_id=*/6, /*joinable_property_id=*/13);
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(target_info1, /*ref_qualified_id_str=*/"namespace#uriA"));
ICING_ASSERT_OK(
@@ -862,7 +853,7 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, Clear) {
EXPECT_THAT(index->Get(target_info3),
StatusIs(libtextclassifier3::StatusCode::NOT_FOUND));
- // Joinable index should be able to work normally after Clear().
+ // Join index should be able to work normally after Clear().
DocJoinInfo target_info4(/*document_id=*/2, /*joinable_property_id=*/19);
ICING_ASSERT_OK(
index->Put(target_info4, /*ref_qualified_id_str=*/"namespace#uriD"));
@@ -876,9 +867,9 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, Clear) {
// Verify index after reconstructing.
ICING_ASSERT_OK_AND_ASSIGN(
- index, QualifiedIdTypeJoinableIndex::Create(
- filesystem_, working_path_, param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ index, QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
EXPECT_THAT(index->last_added_document_id(), Eq(2));
EXPECT_THAT(index->Get(target_info1),
StatusIs(libtextclassifier3::StatusCode::NOT_FOUND));
@@ -889,16 +880,16 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, Clear) {
EXPECT_THAT(index->Get(target_info4), IsOkAndHolds("namespace#uriD"));
}
-TEST_P(QualifiedIdTypeJoinableIndexTest, SwitchKeyMapperTypeShouldReturnError) {
+TEST_P(QualifiedIdJoinIndexTest, SwitchKeyMapperTypeShouldReturnError) {
const QualifiedIdJoinIndexTestParam& param = GetParam();
{
- // Create new qualified id type joinable index
+ // Create new qualified id join index
ICING_ASSERT_OK_AND_ASSIGN(
- std::unique_ptr<QualifiedIdTypeJoinableIndex> index,
- QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- param.use_persistent_hash_map));
+ std::unique_ptr<QualifiedIdJoinIndex> index,
+ QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ param.use_persistent_hash_map));
ICING_ASSERT_OK(
index->Put(DocJoinInfo(/*document_id=*/1, /*joinable_property_id=*/20),
/*ref_qualified_id_str=*/"namespace#uriA"));
@@ -907,14 +898,14 @@ TEST_P(QualifiedIdTypeJoinableIndexTest, SwitchKeyMapperTypeShouldReturnError) {
}
bool switch_key_mapper_flag = !param.use_persistent_hash_map;
- EXPECT_THAT(QualifiedIdTypeJoinableIndex::Create(filesystem_, working_path_,
- param.pre_mapping_fbv,
- switch_key_mapper_flag),
+ EXPECT_THAT(QualifiedIdJoinIndex::Create(filesystem_, working_path_,
+ param.pre_mapping_fbv,
+ switch_key_mapper_flag),
StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION));
}
INSTANTIATE_TEST_SUITE_P(
- QualifiedIdTypeJoinableIndexTest, QualifiedIdTypeJoinableIndexTest,
+ QualifiedIdJoinIndexTest, QualifiedIdJoinIndexTest,
testing::Values(
QualifiedIdJoinIndexTestParam(/*pre_mapping_fbv_in=*/true,
/*use_persistent_hash_map_in=*/true),
diff --git a/icing/join/qualified-id-join-indexing-handler.cc b/icing/join/qualified-id-join-indexing-handler.cc
index 86af043..344cf41 100644
--- a/icing/join/qualified-id-join-indexing-handler.cc
+++ b/icing/join/qualified-id-join-indexing-handler.cc
@@ -21,7 +21,7 @@
#include "icing/text_classifier/lib3/utils/base/statusor.h"
#include "icing/absl_ports/canonical_errors.h"
#include "icing/join/doc-join-info.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id.h"
#include "icing/legacy/core/icing-string-util.h"
#include "icing/proto/logging.pb.h"
@@ -38,7 +38,7 @@ namespace lib {
/* static */ libtextclassifier3::StatusOr<
std::unique_ptr<QualifiedIdJoinIndexingHandler>>
QualifiedIdJoinIndexingHandler::Create(
- const Clock* clock, QualifiedIdTypeJoinableIndex* qualified_id_join_index) {
+ const Clock* clock, QualifiedIdJoinIndex* qualified_id_join_index) {
ICING_RETURN_ERROR_IF_NULL(clock);
ICING_RETURN_ERROR_IF_NULL(qualified_id_join_index);
diff --git a/icing/join/qualified-id-join-indexing-handler.h b/icing/join/qualified-id-join-indexing-handler.h
index 434403e..f44e45d 100644
--- a/icing/join/qualified-id-join-indexing-handler.h
+++ b/icing/join/qualified-id-join-indexing-handler.h
@@ -17,7 +17,7 @@
#include "icing/text_classifier/lib3/utils/base/status.h"
#include "icing/index/data-indexing-handler.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/proto/logging.pb.h"
#include "icing/store/document-id.h"
#include "icing/util/clock.h"
@@ -37,13 +37,12 @@ class QualifiedIdJoinIndexingHandler : public DataIndexingHandler {
// - FAILED_PRECONDITION_ERROR if any of the input pointer is null
static libtextclassifier3::StatusOr<
std::unique_ptr<QualifiedIdJoinIndexingHandler>>
- Create(const Clock* clock,
- QualifiedIdTypeJoinableIndex* qualified_id_join_index);
+ Create(const Clock* clock, QualifiedIdJoinIndex* qualified_id_join_index);
~QualifiedIdJoinIndexingHandler() override = default;
// Handles the joinable qualified id data indexing process: add data into the
- // qualified id type joinable cache.
+ // qualified id join index.
//
/// Returns:
// - OK on success.
@@ -51,18 +50,18 @@ class QualifiedIdJoinIndexingHandler : public DataIndexingHandler {
// than or equal to the document_id of a previously indexed document in
// non recovery mode.
// - INTERNAL_ERROR if any other errors occur.
- // - Any QualifiedIdTypeJoinableIndex errors.
+ // - Any QualifiedIdJoinIndex errors.
libtextclassifier3::Status Handle(
const TokenizedDocument& tokenized_document, DocumentId document_id,
bool recovery_mode, PutDocumentStatsProto* put_document_stats) override;
private:
explicit QualifiedIdJoinIndexingHandler(
- const Clock* clock, QualifiedIdTypeJoinableIndex* qualified_id_join_index)
+ const Clock* clock, QualifiedIdJoinIndex* qualified_id_join_index)
: DataIndexingHandler(clock),
qualified_id_join_index_(*qualified_id_join_index) {}
- QualifiedIdTypeJoinableIndex& qualified_id_join_index_; // Does not own.
+ QualifiedIdJoinIndex& qualified_id_join_index_; // Does not own.
};
} // namespace lib
diff --git a/icing/join/qualified-id-join-indexing-handler_test.cc b/icing/join/qualified-id-join-indexing-handler_test.cc
index e48dc33..7e89dfa 100644
--- a/icing/join/qualified-id-join-indexing-handler_test.cc
+++ b/icing/join/qualified-id-join-indexing-handler_test.cc
@@ -23,7 +23,7 @@
#include "gtest/gtest.h"
#include "icing/document-builder.h"
#include "icing/file/filesystem.h"
-#include "icing/join/qualified-id-type-joinable-index.h"
+#include "icing/join/qualified-id-join-index.h"
#include "icing/join/qualified-id.h"
#include "icing/portable/platform.h"
#include "icing/proto/document.pb.h"
@@ -92,9 +92,9 @@ class QualifiedIdJoinIndexingHandlerTest : public ::testing::Test {
ICING_ASSERT_OK_AND_ASSIGN(
qualified_id_join_index_,
- QualifiedIdTypeJoinableIndex::Create(
- filesystem_, qualified_id_join_index_dir_,
- /*pre_mapping_fbv=*/false, /*use_persistent_hash_map=*/false));
+ QualifiedIdJoinIndex::Create(filesystem_, qualified_id_join_index_dir_,
+ /*pre_mapping_fbv=*/false,
+ /*use_persistent_hash_map=*/false));
language_segmenter_factory::SegmenterOptions segmenter_options(ULOC_US);
ICING_ASSERT_OK_AND_ASSIGN(
@@ -156,7 +156,7 @@ class QualifiedIdJoinIndexingHandlerTest : public ::testing::Test {
std::string qualified_id_join_index_dir_;
std::string schema_store_dir_;
- std::unique_ptr<QualifiedIdTypeJoinableIndex> qualified_id_join_index_;
+ std::unique_ptr<QualifiedIdJoinIndex> qualified_id_join_index_;
std::unique_ptr<LanguageSegmenter> lang_segmenter_;
std::unique_ptr<SchemaStore> schema_store_;
};
diff --git a/icing/performance-configuration.cc b/icing/performance-configuration.cc
index 07ff9bc..1518381 100644
--- a/icing/performance-configuration.cc
+++ b/icing/performance-configuration.cc
@@ -38,20 +38,17 @@ namespace {
// rendering 2 frames.
//
// With the information above, we then try to choose default values for
-// query_length and num_to_score so that the overall time can comfortably fit
-// in with our goal.
+// query_length so that the overall time can comfortably fit in with our goal
+// (note that num_to_score will be decided by the client, which is specified in
+// ResultSpecProto).
// 1. Set query_length to 23000 so that any query can be executed by
// QueryProcessor within 15 ms on a Pixel 3 XL according to results of
// //icing/query:query-processor_benchmark.
-// 2. Set num_to_score to 30000 so that results can be scored and ranked within
-// 3 ms on a Pixel 3 XL according to results of
-// //icing/scoring:score-and-rank_benchmark.
//
// In the worse-case scenario, we still have [33 ms - 15 ms - 3 ms] = 15 ms left
// for all the other things like proto parsing, document fetching, and even
// Android Binder calls if Icing search engine runs in a separate process.
constexpr int kMaxQueryLength = 23000;
-constexpr int kDefaultNumToScore = 30000;
// New Android devices nowadays all allow more than 16 MB memory per app. Using
// that as a guideline and being more conservative, we set 4 MB as the safe
@@ -67,8 +64,7 @@ constexpr int kMaxNumTotalHits = kSafeMemoryUsage / sizeof(ScoredDocumentHit);
} // namespace
PerformanceConfiguration::PerformanceConfiguration()
- : PerformanceConfiguration(kMaxQueryLength, kDefaultNumToScore,
- kMaxNumTotalHits) {}
+ : PerformanceConfiguration(kMaxQueryLength, kMaxNumTotalHits) {}
} // namespace lib
} // namespace icing
diff --git a/icing/performance-configuration.h b/icing/performance-configuration.h
index b9282ca..3ec67f3 100644
--- a/icing/performance-configuration.h
+++ b/icing/performance-configuration.h
@@ -23,10 +23,8 @@ struct PerformanceConfiguration {
// Loads default configuration.
PerformanceConfiguration();
- PerformanceConfiguration(int max_query_length_in, int num_to_score_in,
- int max_num_total_hits)
+ PerformanceConfiguration(int max_query_length_in, int max_num_total_hits)
: max_query_length(max_query_length_in),
- num_to_score(num_to_score_in),
max_num_total_hits(max_num_total_hits) {}
// Search performance
@@ -34,9 +32,6 @@ struct PerformanceConfiguration {
// Maximum length of query to execute in IndexProcessor.
int max_query_length;
- // Number of results to score in ScoringProcessor for every query.
- int num_to_score;
-
// Memory
// Maximum number of ScoredDocumentHits to cache in the ResultStateManager at
diff --git a/icing/schema-builder.h b/icing/schema-builder.h
index e8be483..c74505e 100644
--- a/icing/schema-builder.h
+++ b/icing/schema-builder.h
@@ -127,6 +127,22 @@ class PropertyConfigBuilder {
property_.set_schema_type(std::string(schema_type));
property_.mutable_document_indexing_config()->set_index_nested_properties(
index_nested_properties);
+ property_.mutable_document_indexing_config()
+ ->clear_indexable_nested_properties_list();
+ return *this;
+ }
+
+ PropertyConfigBuilder& SetDataTypeDocument(
+ std::string_view schema_type,
+ std::initializer_list<std::string> indexable_nested_properties_list) {
+ property_.set_data_type(PropertyConfigProto::DataType::DOCUMENT);
+ property_.set_schema_type(std::string(schema_type));
+ property_.mutable_document_indexing_config()->set_index_nested_properties(
+ false);
+ for (const std::string& property : indexable_nested_properties_list) {
+ property_.mutable_document_indexing_config()
+ ->add_indexable_nested_properties_list(property);
+ }
return *this;
}
diff --git a/icing/schema/property-util.cc b/icing/schema/property-util.cc
index 7370328..67ff748 100644
--- a/icing/schema/property-util.cc
+++ b/icing/schema/property-util.cc
@@ -16,11 +16,9 @@
#include <string>
#include <string_view>
-#include <utility>
#include <vector>
#include "icing/text_classifier/lib3/utils/base/statusor.h"
-#include "icing/absl_ports/canonical_errors.h"
#include "icing/absl_ports/str_cat.h"
#include "icing/absl_ports/str_join.h"
#include "icing/proto/document.pb.h"
@@ -85,6 +83,23 @@ std::vector<PropertyInfo> ParsePropertyPathExpr(
return property_infos;
}
+bool IsParentPropertyPath(std::string_view property_path_expr1,
+ std::string_view property_path_expr2) {
+ if (property_path_expr2.length() < property_path_expr1.length()) {
+ return false;
+ }
+ if (property_path_expr1 !=
+ property_path_expr2.substr(0, property_path_expr1.length())) {
+ return false;
+ }
+ if (property_path_expr2.length() > property_path_expr1.length() &&
+ property_path_expr2[property_path_expr1.length()] !=
+ kPropertyPathSeparator[0]) {
+ return false;
+ }
+ return true;
+}
+
const PropertyProto* GetPropertyProto(const DocumentProto& document,
std::string_view property_name) {
for (const PropertyProto& property : document.properties()) {
diff --git a/icing/schema/property-util.h b/icing/schema/property-util.h
index efa599c..7557879 100644
--- a/icing/schema/property-util.h
+++ b/icing/schema/property-util.h
@@ -113,6 +113,26 @@ PropertyInfo ParsePropertyNameExpr(std::string_view property_name_expr);
std::vector<PropertyInfo> ParsePropertyPathExpr(
std::string_view property_path_expr);
+// A property path property_path_expr1 is considered a parent of another
+// property path property_path_expr2 if:
+// 1. property_path_expr2 == property_path_expr1, OR
+// 2. property_path_expr2 consists of the entire path of property_path_expr1
+// + "." + [some other property path].
+//
+// Note that this can only be used for property name strings that do not
+// contain the property index.
+//
+// Examples:
+// - IsParentPropertyPath("foo", "foo") will return true.
+// - IsParentPropertyPath("foo", "foo.bar") will return true.
+// - IsParentPropertyPath("foo", "bar.foo") will return false.
+// - IsParentPropertyPath("foo.bar", "foo.foo.bar") will return false.
+//
+// Returns: true if property_path_expr1 is a parent property path of
+// property_path_expr2.
+bool IsParentPropertyPath(std::string_view property_path_expr1,
+ std::string_view property_path_expr2);
+
// Gets the desired PropertyProto from the document by given property name.
// Since the input parameter is property name, this function only deals with
// the first level of properties in the document and cannot deal with nested
diff --git a/icing/schema/property-util_test.cc b/icing/schema/property-util_test.cc
index 1fabb32..eddcc84 100644
--- a/icing/schema/property-util_test.cc
+++ b/icing/schema/property-util_test.cc
@@ -43,6 +43,23 @@ static constexpr std::string_view kTypeNestedTest = "NestedTest";
static constexpr std::string_view kPropertyStr = "str";
static constexpr std::string_view kPropertyNestedDocument = "nestedDocument";
+TEST(PropertyUtilTest, IsParentPropertyPath) {
+ EXPECT_TRUE(property_util::IsParentPropertyPath("foo", "foo"));
+ EXPECT_TRUE(property_util::IsParentPropertyPath("foo", "foo.bar"));
+ EXPECT_TRUE(property_util::IsParentPropertyPath("foo", "foo.bar.foo"));
+ EXPECT_TRUE(property_util::IsParentPropertyPath("foo", "foo.foo.bar"));
+ EXPECT_TRUE(property_util::IsParentPropertyPath("foo.bar", "foo.bar.foo"));
+
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo", "foofoo.bar"));
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo.bar", "foo.foo.bar"));
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo.bar", "foofoo.bar"));
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo.bar.foo", "foo"));
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo.bar.foo", "foo.bar"));
+ EXPECT_FALSE(
+ property_util::IsParentPropertyPath("foo.foo.bar", "foo.bar.foo"));
+ EXPECT_FALSE(property_util::IsParentPropertyPath("foo", "foo#bar.foo"));
+}
+
TEST(PropertyUtilTest, ExtractPropertyValuesTypeString) {
PropertyProto property;
property.mutable_string_values()->Add("Hello, world");
diff --git a/icing/schema/schema-property-iterator.cc b/icing/schema/schema-property-iterator.cc
index e1078c2..2d1ca7e 100644
--- a/icing/schema/schema-property-iterator.cc
+++ b/icing/schema/schema-property-iterator.cc
@@ -14,9 +14,17 @@
#include "icing/schema/schema-property-iterator.h"
+#include <algorithm>
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
#include "icing/text_classifier/lib3/utils/base/status.h"
#include "icing/absl_ports/canonical_errors.h"
#include "icing/absl_ports/str_cat.h"
+#include "icing/proto/schema.pb.h"
+#include "icing/schema/property-util.h"
namespace icing {
namespace lib {
@@ -27,16 +35,56 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() {
// When finishing iterating all properties of the current level, pop it
// from the stack (levels_), return to the previous level and resume the
// iteration.
- parent_type_config_names_.erase(levels_.back().GetSchemaTypeName());
+ parent_type_config_names_.erase(
+ parent_type_config_names_.find(levels_.back().GetSchemaTypeName()));
levels_.pop_back();
continue;
}
const PropertyConfigProto& curr_property_config =
levels_.back().GetCurrentPropertyConfig();
+ std::string curr_property_path = levels_.back().GetCurrentPropertyPath();
+
+ // Iterate through the sorted_top_level_indexable_nested_properties_ in
+ // order until we find the first element that is >= curr_property_path.
+ while (current_top_level_indexable_nested_properties_idx_ <
+ sorted_top_level_indexable_nested_properties_.size() &&
+ sorted_top_level_indexable_nested_properties_.at(
+ current_top_level_indexable_nested_properties_idx_) <
+ curr_property_path) {
+ // If an element in sorted_top_level_indexable_nested_properties_ < the
+ // current property path, it means that we've already iterated past the
+ // possible position for it without seeing it.
+ // It's not a valid property path in our schema definition. Ignore it and
+ // advance current_top_level_indexable_nested_properties_idx_.
+ ++current_top_level_indexable_nested_properties_idx_;
+ }
+
if (curr_property_config.data_type() !=
PropertyConfigProto::DataType::DOCUMENT) {
// We've advanced to a leaf property.
+ // Set whether this property is indexable according to its level's
+ // indexable config. If this property is declared in
+ // indexable_nested_properties_list of the top-level schema, it is also
+ // nested indexable.
+ std::string* current_indexable_nested_prop =
+ current_top_level_indexable_nested_properties_idx_ <
+ sorted_top_level_indexable_nested_properties_.size()
+ ? &sorted_top_level_indexable_nested_properties_.at(
+ current_top_level_indexable_nested_properties_idx_)
+ : nullptr;
+ if (current_indexable_nested_prop == nullptr ||
+ *current_indexable_nested_prop > curr_property_path) {
+ // Current property is not in the indexable list. Set its indexable
+ // config according to the current level's indexable config.
+ levels_.back().SetCurrentPropertyIndexable(
+ levels_.back().GetLevelNestedIndexable());
+ } else if (*current_indexable_nested_prop == curr_property_path) {
+ // Current property is in the indexable list. Set its indexable config
+ // to true.
+ levels_.back().SetCurrentPropertyIndexable(true);
+ ++current_top_level_indexable_nested_properties_idx_;
+ }
return libtextclassifier3::Status::OK;
}
@@ -55,27 +103,71 @@ libtextclassifier3::Status SchemaPropertyIterator::Advance() {
return absl_ports::NotFoundError(absl_ports::StrCat(
"Type config not found: ", curr_property_config.schema_type()));
}
+ const SchemaTypeConfigProto& nested_type_config =
+ nested_type_config_iter->second;
+
+ if (levels_.back().GetLevelNestedIndexable()) {
+ // We should set sorted_top_level_indexable_nested_properties_ to the list
+ // defined by the current level.
+ // GetLevelNestedIndexable() is true either because:
+ // 1. We're looking at a document property of the top-level schema --
+ // The first LevelInfo for the iterator is initialized with
+ // all_nested_properties_indexable_ = true.
+ // 2. All previous levels set index_nested_properties = true:
+ // This indicates that upper-level schema types want to follow nested
+ // properties definition of its document subtypes. If this is the first
+ // subtype level that defines a list, we should set it as
+ // top_level_indexable_nested_properties_ for the current top-level
+ // schema.
+ sorted_top_level_indexable_nested_properties_.clear();
+ sorted_top_level_indexable_nested_properties_.reserve(
+ curr_property_config.document_indexing_config()
+ .indexable_nested_properties_list()
+ .size());
+ for (const std::string& property :
+ curr_property_config.document_indexing_config()
+ .indexable_nested_properties_list()) {
+ // Concat the current property name to each property to get the full
+ // property path expression for each indexable nested property.
+ sorted_top_level_indexable_nested_properties_.push_back(
+ property_util::ConcatenatePropertyPathExpr(curr_property_path,
+ property));
+ }
+ current_top_level_indexable_nested_properties_idx_ = 0;
+ std::sort(sorted_top_level_indexable_nested_properties_.begin(),
+ sorted_top_level_indexable_nested_properties_.end());
+ }
- if (parent_type_config_names_.count(
- nested_type_config_iter->second.schema_type()) > 0) {
+ bool is_cycle =
+ parent_type_config_names_.find(nested_type_config.schema_type()) !=
+ parent_type_config_names_.end();
+ bool is_parent_property_path =
+ current_top_level_indexable_nested_properties_idx_ <
+ sorted_top_level_indexable_nested_properties_.size() &&
+ property_util::IsParentPropertyPath(
+ curr_property_path,
+ sorted_top_level_indexable_nested_properties_.at(
+ current_top_level_indexable_nested_properties_idx_));
+ if (is_cycle && !is_parent_property_path) {
// Cycle detected. The schema definition is guaranteed to be valid here
// since it must have already been validated during SchemaUtil::Validate,
// which would have rejected any schema with bad cycles.
//
+ // There are no properties in the indexable_nested_properties_list that
+ // are a part of this circular reference.
// We do not need to iterate this type further so we simply move on to
// other properties in the parent type.
continue;
}
- std::string curr_property_path = levels_.back().GetCurrentPropertyPath();
- bool is_nested_indexable = levels_.back().GetCurrentNestedIndexable() &&
- curr_property_config.document_indexing_config()
- .index_nested_properties();
- levels_.push_back(LevelInfo(nested_type_config_iter->second,
+ bool all_nested_properties_indexable =
+ levels_.back().GetLevelNestedIndexable() &&
+ curr_property_config.document_indexing_config()
+ .index_nested_properties();
+ levels_.push_back(LevelInfo(nested_type_config,
std::move(curr_property_path),
- is_nested_indexable));
- parent_type_config_names_.insert(
- nested_type_config_iter->second.schema_type());
+ all_nested_properties_indexable));
+ parent_type_config_names_.insert(nested_type_config.schema_type());
}
return absl_ports::OutOfRangeError("End of iterator");
}
diff --git a/icing/schema/schema-property-iterator.h b/icing/schema/schema-property-iterator.h
index f60a56e..3babf9e 100644
--- a/icing/schema/schema-property-iterator.h
+++ b/icing/schema/schema-property-iterator.h
@@ -18,6 +18,9 @@
#include <algorithm>
#include <numeric>
#include <string>
+#include <string_view>
+#include <unordered_set>
+#include <utility>
#include <vector>
#include "icing/text_classifier/lib3/utils/base/status.h"
@@ -44,7 +47,7 @@ class SchemaPropertyIterator {
: type_config_map_(type_config_map) {
levels_.push_back(LevelInfo(base_schema_type_config,
/*base_property_path=*/"",
- /*is_nested_indexable=*/true));
+ /*all_nested_properties_indexable=*/true));
parent_type_config_names_.insert(base_schema_type_config.schema_type());
}
@@ -62,11 +65,22 @@ class SchemaPropertyIterator {
return levels_.back().GetCurrentPropertyPath();
}
- // Gets if the current property is nested indexable.
+ // Returns whether the current property is indexable. This would be true if
+ // either the current level is nested indexable, or if the current property is
+ // declared indexable in the indexable_nested_properties_list of the top-level
+ // schema type.
//
// REQUIRES: The preceding call for Advance() is OK.
- bool GetCurrentNestedIndexable() const {
- return levels_.back().GetCurrentNestedIndexable();
+ bool GetCurrentPropertyIndexable() const {
+ return levels_.back().GetCurrentPropertyIndexable();
+ }
+
+ // Returns whether the current schema level is nested indexable. If this is
+ // true, all properties in the level are indexed.
+ //
+ // REQUIRES: The preceding call for Advance() is OK.
+ bool GetLevelNestedIndexable() const {
+ return levels_.back().GetLevelNestedIndexable();
}
// Advances to the next leaf property.
@@ -87,12 +101,14 @@ class SchemaPropertyIterator {
class LevelInfo {
public:
explicit LevelInfo(const SchemaTypeConfigProto& schema_type_config,
- std::string base_property_path, bool is_nested_indexable)
+ std::string base_property_path,
+ bool all_nested_properties_indexable)
: schema_type_config_(schema_type_config),
base_property_path_(std::move(base_property_path)),
sorted_property_indices_(schema_type_config.properties_size()),
current_vec_idx_(-1),
- is_nested_indexable_(is_nested_indexable) {
+ sorted_property_indexable_(schema_type_config.properties_size()),
+ all_nested_properties_indexable_(all_nested_properties_indexable) {
// Index sort property by lexicographical order.
std::iota(sorted_property_indices_.begin(),
sorted_property_indices_.end(),
@@ -119,7 +135,17 @@ class SchemaPropertyIterator {
base_property_path_, GetCurrentPropertyConfig().property_name());
}
- bool GetCurrentNestedIndexable() const { return is_nested_indexable_; }
+ bool GetLevelNestedIndexable() const {
+ return all_nested_properties_indexable_;
+ }
+
+ bool GetCurrentPropertyIndexable() const {
+ return sorted_property_indexable_[current_vec_idx_];
+ }
+
+ void SetCurrentPropertyIndexable(bool indexable) {
+ sorted_property_indexable_[current_vec_idx_] = indexable;
+ }
std::string_view GetSchemaTypeName() const {
return schema_type_config_.schema_type();
@@ -137,12 +163,20 @@ class SchemaPropertyIterator {
std::vector<int> sorted_property_indices_;
int current_vec_idx_;
- // Indicates if the current level is nested indexable. Document type
- // property has index_nested_properties flag indicating whether properties
- // under this level should be indexed or not. If any of parent document type
- // property sets its flag false, then all child level properties should not
- // be indexed.
- bool is_nested_indexable_;
+ // Vector indicating whether each property in the current level is
+ // indexable. We can declare different indexable settings for properties in
+ // the same level using indexable_nested_properties_list.
+ //
+ // Element indices in this vector correspond to property indices in the
+ // sorted order.
+ std::vector<bool> sorted_property_indexable_;
+
+ // Indicates if all properties in the current level is nested indexable.
+ // This would be true for a level if the document declares
+ // index_nested_properties=true. If any of parent document type
+ // property sets its flag false, then this would be false for all its child
+ // properties.
+ bool all_nested_properties_indexable_;
};
const SchemaUtil::TypeConfigMap& type_config_map_; // Does not own
@@ -154,7 +188,14 @@ class SchemaPropertyIterator {
// Maintaining all traversed parent schema type config names of the current
// stack (levels_). It is used to detect nested schema cycle dependency.
- std::unordered_set<std::string_view> parent_type_config_names_;
+ std::unordered_multiset<std::string_view> parent_type_config_names_;
+
+ // Sorted list of indexable nested properties for the top-level schema.
+ std::vector<std::string> sorted_top_level_indexable_nested_properties_;
+
+ // Current iteration index in the sorted_top_level_indexable_nested_properties
+ // list.
+ int current_top_level_indexable_nested_properties_idx_ = 0;
};
} // namespace lib
diff --git a/icing/schema/schema-property-iterator_test.cc b/icing/schema/schema-property-iterator_test.cc
index 080d574..ed71134 100644
--- a/icing/schema/schema-property-iterator_test.cc
+++ b/icing/schema/schema-property-iterator_test.cc
@@ -14,6 +14,7 @@
#include "icing/schema/schema-property-iterator.h"
+#include <initializer_list>
#include <string>
#include "icing/text_classifier/lib3/utils/base/status.h"
@@ -57,19 +58,19 @@ TEST(SchemaPropertyIteratorTest,
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Alphabet"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config.properties(2)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Youtube"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -139,49 +140,49 @@ TEST(SchemaPropertyIteratorTest,
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Hello"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config3.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Bar.Alphabet"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(2)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Bar.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Bar.Youtube"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Icing.Foo"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config2.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World.Alphabet"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(2)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World.Youtube"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -338,13 +339,13 @@ TEST(SchemaPropertyIteratorTest, NestedIndexable) {
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz1.Bar.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz1.Foo"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config2.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
// For Baz2, the parent level sets index_nested_properties = false, so all
// leaf properties in child levels should be nested unindexable even if
@@ -353,13 +354,13 @@ TEST(SchemaPropertyIteratorTest, NestedIndexable) {
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz2.Bar.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz2.Foo"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config2.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
// For Baz3, the parent level sets index_nested_properties = true, but the
// child level sets index_nested_properties = false.
@@ -369,13 +370,13 @@ TEST(SchemaPropertyIteratorTest, NestedIndexable) {
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz3.Bar.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz3.Foo"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config2.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
// For Baz4, all levels set index_nested_properties = false, so all leaf
// properties should be nested unindexable.
@@ -383,37 +384,954 @@ TEST(SchemaPropertyIteratorTest, NestedIndexable) {
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz4.Bar.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Baz4.Foo"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config2.properties(1)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
// Verify 1 and 0 level of nested document type properties.
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Hello1.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("Hello2.Google"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config1.properties(0)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(iterator.Advance(), IsOk());
EXPECT_THAT(iterator.GetCurrentPropertyPath(), Eq("World"));
EXPECT_THAT(iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config4.properties(6)));
- EXPECT_THAT(iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
}
+TEST(SchemaPropertyIteratorTest,
+ IndexableNestedPropertiesList_singleNestedLevel) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop2")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop3")
+ .SetDataTypeString(TERM_MATCH_UNKNOWN, TOKENIZER_NONE))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop1")
+ .SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/{"schema1prop2",
+ "schema1prop3"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2}};
+
+ // Order of iteration for Schema2:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2",
+ // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"}
+ //
+ // Indexable properties:
+ // {"schema2prop1.schema1prop2", "schema2prop1.schema1prop3", "schema2prop2",
+ // "schema2prop3"}
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest,
+ IndexableNestedPropertiesList_indexBooleanTrueDoesNotAffectOtherLevels) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+ std::string schema_type_name3 = "SchemaThree";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop2")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop3")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop1")
+ .SetDataTypeDocument(schema_type_name1,
+ /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config3 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name3)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop3")
+ .SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/{"schema1prop1",
+ "schema1prop3"}))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schema3prop1")
+ .SetDataTypeDocument(
+ schema_type_name2,
+ /*indexable_nested_properties_list=*/
+ {"schema2prop2", "schema2prop1.schema1prop1",
+ "schema2prop1.schema1prop3"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2},
+ {schema_type_name3, schema_type_config3}};
+
+ // Order of iteration for Schema3:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop2",
+ // "schema3prop1.schema2prop1.schema1prop3",
+ // "schema3prop1.schema2prop2", "schema3prop1.schema2prop3", "schema3prop2",
+ // "schema3prop3.schema1prop1", "schema3prop3.schema1prop2",
+ // "schema3prop3.schema1prop3"}.
+ //
+ // Indexable properties:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop3",
+ // "schema3prop1.schema2prop2", "schema3prop2", "schema3prop3.schema1prop1",
+ // "schema3prop3.schema1prop3"}
+ //
+ // Schema2 setting index_nested_properties=true does not affect nested
+ // properties indexing for Schema3.
+ SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map);
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("schema3prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config3.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema2:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2",
+ // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"}
+ //
+ // Indexable properties:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2",
+ // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"}
+ //
+ // All properties are indexed because index_nested_properties=true for
+ // Schema2.schema2prop1. Schema3's indexable_nested_properties setting does
+ // not affect this.
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest,
+ IndexableNestedPropertiesList_indexBooleanFalseDoesNotAffectOtherLevels) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+ std::string schema_type_name3 = "SchemaThree";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop2")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop1")
+ .SetDataTypeDocument(schema_type_name1,
+ /*index_nested_properties=*/false))
+ .Build();
+ SchemaTypeConfigProto schema_type_config3 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name3)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop1")
+ .SetDataTypeDocument(schema_type_name2,
+ /*indexable_nested_properties_list=*/
+ std::initializer_list<std::string>{
+ "schema2prop1.schema1prop2"}))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2},
+ {schema_type_name3, schema_type_config3}};
+
+ // Order of iteration for Schema3:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop2"}.
+ //
+ // Indexable properties: {"schema3prop1.schema2prop1.schema1prop2"}
+ //
+ // Schema2 setting index_nested_properties=false, does not affect Schema3's
+ // indexable list.
+ SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map);
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema2:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2"}
+ //
+ // Indexable properties: None
+ //
+ // The indexable list for Schema3 does not propagate to Schema2.
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest,
+ IndexableNestedPropertiesList_indexableSetDoesNotAffectOtherLevels) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+ std::string schema_type_name3 = "SchemaThree";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop2")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop3")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop1")
+ .SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/
+ std::initializer_list<std::string>{"schema1prop2"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config3 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name3)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop3")
+ .SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/{"schema1prop1",
+ "schema1prop3"}))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schema3prop1")
+ .SetDataTypeDocument(
+ schema_type_name2,
+ /*indexable_nested_properties_list=*/
+ {"schema2prop2", "schema2prop1.schema1prop1",
+ "schema2prop1.schema1prop3"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2},
+ {schema_type_name3, schema_type_config3}};
+
+ // Order of iteration for Schema3:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop2",
+ // "schema3prop1.schema2prop1.schema1prop3",
+ // "schema3prop1.schema2prop2", "schema3prop1.schema2prop3", "schema3prop2",
+ // "schema3prop3.schema1prop1", "schema3prop3.schema1prop2",
+ // "schema3prop3.schema1prop3"}.
+ //
+ // Indexable properties:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop3",
+ // "schema3prop1.schema2prop2", "schema3prop2", "schema3prop3.schema1prop1",
+ // "schema3prop3.schema1prop3"}
+ //
+ // Schema2 setting indexable_nested_properties_list={schema1prop2} does not
+ // affect nested properties indexing for Schema3.
+ SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map);
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("schema3prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config3.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop3.schema1prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema2:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2",
+ // "schema2prop1.schema1prop3", "schema2prop2", "schema2prop3"}
+ //
+ // Indexable properties:
+ // {"schema2prop1.schema1prop2", "schema2prop2", "schema2prop3"}
+ //
+ // Indexable_nested_properties set for Schema3.schema3prop1 does not propagate
+ // to Schema2.
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("schema2prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(
+ SchemaPropertyIteratorTest,
+ IndexableNestedPropertiesList_upperLevelIndexTrueIndexesListOfNestedLevel) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+ std::string schema_type_name3 = "SchemaThree";
+ std::string schema_type_name4 = "SchemaFour";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema1prop2")
+ .SetDataTypeString(TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema2prop1")
+ .SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/
+ std::initializer_list<std::string>{"schema1prop2"}))
+ .Build();
+ SchemaTypeConfigProto schema_type_config3 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name3)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema3prop1")
+ .SetDataTypeDocument(schema_type_name2,
+ /*index_nested_properties=*/true))
+ .Build();
+ SchemaTypeConfigProto schema_type_config4 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name4)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schema4prop1")
+ .SetDataTypeDocument(schema_type_name3,
+ /*index_nested_properties=*/true))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2},
+ {schema_type_name3, schema_type_config3},
+ {schema_type_name4, schema_type_config4}};
+
+ // Order of iteration for Schema4:
+ // {"schema4prop1.schema3prop1.schema2prop1.schema1prop1",
+ // "schema4prop1.schema3prop1.schema2prop1.schema1prop2"}.
+ //
+ // Indexable properties: {schema4prop1.schema3prop1.schema2prop1.schema1prop2}
+ //
+ // Both Schema4 and Schema3 sets index_nested_properties=true, so they both
+ // want to follow the indexing behavior of its subtype.
+ // Schema2 is the first subtype to define an indexing config, so we index its
+ // list for both Schema3 and Schema4 even though it sets
+ // index_nested_properties=false.
+ SchemaPropertyIterator schema4_iterator(schema_type_config4, type_config_map);
+
+ EXPECT_THAT(schema4_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(),
+ Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema4_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyPath(),
+ Eq("schema4prop1.schema3prop1.schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema4_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema4_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema3:
+ // {"schema3prop1.schema2prop1.schema1prop1",
+ // "schema3prop1.schema2prop1.schema1prop2"}.
+ //
+ // Indexable properties: {schema3prop1.schema2prop1.schema1prop2}
+ SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map);
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("schema3prop1.schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema2:
+ // {"schema2prop1.schema1prop1", "schema2prop1.schema1prop2"}
+ //
+ // Indexable properties:
+ // {"schema2prop1.schema1prop2"}
+ //
+ // Schema3 setting index_nested_properties=true does not propagate to Schema2.
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(),
+ Eq("schema2prop1.schema1prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest,
+ IndexableNestedProperties_duplicatePropertyNamesInDifferentProperties) {
+ std::string schema_type_name1 = "SchemaOne";
+ std::string schema_type_name2 = "SchemaTwo";
+ std::string schema_type_name3 = "SchemaThree";
+
+ SchemaTypeConfigProto schema_type_config1 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name1)
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop1").SetDataTypeString(
+ TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop2").SetDataTypeString(
+ TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop3").SetDataTypeString(
+ TERM_MATCH_PREFIX, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config2 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name2)
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop1").SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/
+ std::initializer_list<std::string>{"prop2"}))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop2").SetDataTypeString(
+ TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop3").SetDataTypeString(
+ TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config3 =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_type_name3)
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop3").SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/
+ {"prop1", "prop3"}))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop1").SetDataTypeDocument(
+ schema_type_name2,
+ /*indexable_nested_properties_list=*/
+ {"prop2", "prop1.prop1", "prop1.prop3"}))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop2").SetDataTypeString(
+ TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder().SetName("prop4").SetDataTypeDocument(
+ schema_type_name1,
+ /*indexable_nested_properties_list=*/
+ {"prop2", "prop3"}))
+ .Build();
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_type_name1, schema_type_config1},
+ {schema_type_name2, schema_type_config2},
+ {schema_type_name3, schema_type_config3}};
+
+ // Order of iteration for Schema3:
+ // {"prop1.prop1.prop1", "prop1.prop1.prop2", "prop1.prop1.prop3",
+ // "prop1.prop2", "prop1.prop3", "prop2",
+ // "prop3.prop1", "prop3.prop2", "prop3.prop3",
+ // "prop4.prop1", "prop4.prop2", "prop4.prop3"}.
+ //
+ // Indexable properties:
+ // {"prop1.prop1.prop1", "prop1.prop1.prop3", "prop1.prop2", "prop2",
+ // "prop3.prop1", "prop3.prop3", "prop4.prop2", "prop4.prop3"}
+ //
+ // Properties do not affect other properties with the same name from different
+ // properties.
+ SchemaPropertyIterator schema3_iterator(schema_type_config3, type_config_map);
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("prop1.prop1.prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("prop1.prop1.prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(),
+ Eq("prop1.prop1.prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop1.prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop1.prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config3.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop3.prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop3.prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop3.prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop4.prop1"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop4.prop2"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyPath(), Eq("prop4.prop3"));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema3_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema3_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for Schema2:
+ // {"prop1.prop1", "prop1.prop2",
+ // "prop1.prop3", "prop2", "prop3"}
+ //
+ // Indexable properties:
+ // {"prop1.prop2", "prop1.prop3", "prop2", "prop3"}
+ //
+ // Indexable_nested_properties set for Schema3.prop1 does not propagate
+ // to Schema2.
+ SchemaPropertyIterator schema2_iterator(schema_type_config2, type_config_map);
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("prop1.prop1"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(0)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("prop1.prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("prop1.prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config1.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("prop2"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(1)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyPath(), Eq("prop3"));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config2.properties(2)));
+ EXPECT_THAT(schema2_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema2_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
TEST(SchemaPropertyIteratorTest, SingleLevelCycle) {
std::string schema_a = "A";
std::string schema_b = "B";
@@ -457,13 +1375,13 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycle) {
Eq("schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -477,7 +1395,7 @@ TEST(SchemaPropertyIteratorTest, SingleLevelCycle) {
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_b_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -542,20 +1460,20 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) {
Eq("schemaAprop1.schemaBprop1.schemaCprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
Eq("schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -573,20 +1491,20 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) {
Eq("schemaBprop1.schemaCprop1.schemaAprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
Eq("schemaBprop1.schemaCprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_b_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -604,32 +1522,226 @@ TEST(SchemaPropertyIteratorTest, MultipleLevelCycle) {
Eq("schemaCprop1.schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
Eq("schemaCprop1.schemaAprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(), Eq("schemaCprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_c_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
}
+TEST(SchemaPropertyIteratorTest, SingleLevelCycleWithIndexableList) {
+ std::string schema_a = "A";
+ std::string schema_b = "B";
+
+ // Create schema with A -> B -> B -> B...
+ SchemaTypeConfigProto schema_type_config_a =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_a)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaAprop1")
+ .SetDataTypeDocument(
+ schema_b, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_b =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_b)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaBprop2")
+ .SetDataTypeDocument(
+ schema_b, /*indexable_nested_properties_list=*/
+ {"schemaBprop1", "schemaBprop2.schemaBprop1",
+ "schemaBprop2.schemaBprop3",
+ "schemaBprop2.schemaBprop2.schemaBprop3"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_a, schema_type_config_a}, {schema_b, schema_type_config_b}};
+
+ // Order of iteration and whether each property is indexable for schema A:
+ // {"schemaAprop1.schemaBprop1" (true),
+ // "schemaAprop1.schemaBprop2.schemaBprop1" (true),
+ // "schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop1" (true),
+ // "schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop1" (false),
+ // "schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop3" (true),
+ // "schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop3" (true),
+ // "schemaAprop1.schemaBprop2.schemaBprop3" (false),
+ // "schemaAprop1.schemaBprop3" (true),
+ // "schemaAprop2" (true)}
+ SchemaPropertyIterator schema_a_iterator(schema_type_config_a,
+ type_config_map);
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for schema B:
+ // {"schemaBprop1" (true),
+ // "schemaBprop2.schemaBprop1" (true),
+ // "schemaBprop2.schemaBprop2.schemaBprop1" (true),
+ // "schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop1" (false),
+ // "schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop3" (true),
+ // "schemaBprop2.schemaBprop2.schemaBprop3" (true),
+ // "schemaBprop2.schemaBprop3" (false),
+ // "schemaBprop3" (true)}
+ SchemaPropertyIterator schema_b_iterator(schema_type_config_b,
+ type_config_map);
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop1"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop1"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop2.schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop2.schemaBprop3"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop3"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
TEST(SchemaPropertyIteratorTest, MultipleCycles) {
std::string schema_a = "A";
std::string schema_b = "B";
std::string schema_c = "C";
std::string schema_d = "D";
- // Create schema with D <-> A -> B -> C -> A -> B -> C -> A...
+ // Create the following schema:
+ // D <--> A <--- C
+ // \ ^
+ // v /
+ // B
// Schema type A has two cycles: A-B-C-A and A-D-A
SchemaTypeConfigProto schema_type_config_a =
SchemaTypeConfigBuilder()
@@ -701,27 +1813,27 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) {
Eq("schemaAprop1.schemaBprop1.schemaCprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
Eq("schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
Eq("schemaAprop3.schemaDprop2"));
EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_d.properties(1)));
- EXPECT_THAT(schema_a_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_a_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -740,27 +1852,27 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) {
Eq("schemaBprop1.schemaCprop1.schemaAprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_d.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
Eq("schemaBprop1.schemaCprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_b_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_b_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -778,27 +1890,27 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) {
Eq("schemaCprop1.schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
Eq("schemaCprop1.schemaAprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
Eq("schemaCprop1.schemaAprop3.schemaDprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_d.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(), Eq("schemaCprop2"));
EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_c_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_c_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
@@ -817,32 +1929,1336 @@ TEST(SchemaPropertyIteratorTest, MultipleCycles) {
Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_c.properties(1)));
- EXPECT_THAT(schema_d_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(), Eq("schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList) {
+ std::string schema_a = "A";
+ std::string schema_b = "B";
+ std::string schema_c = "C";
+ std::string schema_d = "D";
+
+ // Create the following schema:
+ // D <--> A <--- C
+ // \ ^
+ // v /
+ // B
+ // Schema type A has two cycles: A-B-C-A and A-D-A
+ SchemaTypeConfigProto schema_type_config_a =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_a)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop1")
+ .SetDataTypeDocument(
+ schema_b, /*indexable_nested_properties_list=*/
+ {"schemaBprop2", "schemaBprop1.schemaCprop1.schemaAprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop2"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop3")
+ .SetDataTypeDocument(
+ schema_d, /*indexable_nested_properties_list=*/
+ {"schemaDprop2", "schemaDprop1.schemaAprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2",
+ "schemaDprop1.schemaAprop3.schemaDprop2"}))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_b =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_b)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaBprop1")
+ .SetDataTypeDocument(
+ schema_c, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_c =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_c)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaCprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/false))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaCprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_d =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_d)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaDprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/false))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaDprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_a, schema_type_config_a},
+ {schema_b, schema_type_config_b},
+ {schema_c, schema_type_config_c},
+ {schema_d, schema_type_config_d}};
+
+ // Order of iteration and whether each property is indexable for schema A:
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaAprop3.schemaDprop2" (true)
+ SchemaPropertyIterator schema_a_iterator(schema_type_config_a,
+ type_config_map);
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3."
+ "schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration and whether each property is indexable for schema B:
+ // "schemaBprop1.schemaCprop1.schemaAprop2" (false),
+ // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" (false),
+ // "schemaBprop1.schemaCprop2" (true),
+ // "schemaBprop2" (true)
+ SchemaPropertyIterator schema_b_iterator(schema_type_config_b,
+ type_config_map);
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for schema C:
+ // "schemaCprop1.schemaAprop1.schemaBprop2" (false),
+ // "schemaCprop1.schemaAprop2" (false),
+ // "schemaCprop1.schemaAprop3.schemaDprop2" (false),
+ // "schemaCprop2" (true)
+ SchemaPropertyIterator schema_c_iterator(schema_type_config_c,
+ type_config_map);
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(), Eq("schemaCprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for schema D:
+ // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaDprop1.schemaAprop1.schemaBprop2" (false),
+ // "schemaDprop1.schemaAprop2" (false),
+ // "schemaDprop2" (true)
+ SchemaPropertyIterator schema_d_iterator(schema_type_config_d,
+ type_config_map);
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(), Eq("schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest, MultipleCyclesWithIndexableList_allIndexTrue) {
+ std::string schema_a = "A";
+ std::string schema_b = "B";
+ std::string schema_c = "C";
+ std::string schema_d = "D";
+
+ // Create the following schema:
+ // D <--> A <--- C
+ // \ ^
+ // v /
+ // B
+ // Schema type A has two cycles: A-B-C-A and A-D-A
+ SchemaTypeConfigProto schema_type_config_a =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_a)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop1")
+ .SetDataTypeDocument(
+ schema_b, /*indexable_nested_properties_list=*/
+ {"schemaBprop2", "schemaBprop1.schemaCprop1.schemaAprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop2"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop3")
+ .SetDataTypeDocument(
+ schema_d, /*indexable_nested_properties_list=*/
+ {"schemaDprop2", "schemaDprop1.schemaAprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2",
+ "schemaDprop1.schemaAprop3.schemaDprop2"}))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_b =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_b)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaBprop1")
+ .SetDataTypeDocument(
+ schema_c, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_c =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_c)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaCprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaCprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_d =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_d)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaDprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaDprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_a, schema_type_config_a},
+ {schema_b, schema_type_config_b},
+ {schema_c, schema_type_config_c},
+ {schema_d, schema_type_config_d}};
+
+ // Order of iteration and whether each property is indexable for schema A:
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaAprop3.schemaDprop2" (true)
+ SchemaPropertyIterator schema_a_iterator(schema_type_config_a,
+ type_config_map);
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3."
+ "schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration and whether each property is indexable for schema B:
+ // "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"
+ // (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"
+ // (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop2"
+ // (false), "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop2" (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"
+ // (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"
+ // (true), "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true),
+ // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" (true)
+ // "schemaBprop1.schemaCprop2" (true)
+ // "schemaBprop2" (true)
+
+ SchemaPropertyIterator schema_b_iterator(schema_type_config_b,
+ type_config_map);
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1."
+ "schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1."
+ "schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1."
+ "schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1."
+ "schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration and whether each property is indexable for schema C:
+ // "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"
+ // (true), "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"
+ // (true),
+ // "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true),
+ // "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true),
+ // "schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaCprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaCprop1.schemaAprop2" (true),
+ // "schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"
+ // (true),
+ // "schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2" (true),
+ // "schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaCprop1.schemaAprop3.schemaDprop2" (true)
+ // "schemaCprop2" (true)
+ SchemaPropertyIterator schema_c_iterator(schema_type_config_c,
+ type_config_map);
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1."
+ "schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(), Eq("schemaCprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration and whether each property is indexable for schema D:
+ // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"
+ // (true), "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"
+ // (true),
+ // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true),
+ // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaDprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaDprop1.schemaAprop2" (true),
+ // "schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"
+ // (true), "schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"
+ // (true), "schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop2" (true),
+ // "schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaDprop2" (true)
+ SchemaPropertyIterator schema_d_iterator(schema_type_config_d,
+ type_config_map);
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop1."
+ "schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop1."
+ "schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(), Eq("schemaDprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_d_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
+TEST(SchemaPropertyIteratorTest,
+ MultipleCyclesWithIndexableList_nonExistentPropPaths) {
+ std::string schema_a = "A";
+ std::string schema_b = "B";
+ std::string schema_c = "C";
+ std::string schema_d = "D";
+
+ // Create the following schema:
+ // D <--> A <--- C
+ // \ ^
+ // v /
+ // B
+ // Schema type A has two cycles: A-B-C-A and A-D-A
+ SchemaTypeConfigProto schema_type_config_a =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_a)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop1")
+ .SetDataTypeDocument(
+ schema_b, /*indexable_nested_properties_list=*/
+ {"schemaBprop2", "schemaBprop1.schemaCprop1.schemaAprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2",
+ "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1."
+ "schemaAprop2",
+ "schemaBprop1.schemaCprop1",
+ "schemaBprop1.schemaCprop1.schemaAprop3", "schemaAprop2",
+ "schemaBprop2.schemaCprop2", "schemaBprop1.foo.bar",
+ "foo", "foo", "bar"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop3")
+ .SetDataTypeDocument(
+ schema_d, /*indexable_nested_properties_list=*/
+ {"schemaDprop2", "schemaDprop1.schemaAprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop2",
+ "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2",
+ "schemaDprop1.schemaAprop3.schemaDprop2", "schemaBprop2",
+ "bar", "schemaDprop2.foo", "schemaDprop1",
+ "schemaAprop3.schemaDprop2"}))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_b =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_b)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaBprop1")
+ .SetDataTypeDocument(
+ schema_c, /*index_nested_properties=*/true))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_c =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_c)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaCprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/false))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaCprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_d =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_d)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaDprop1")
+ .SetDataTypeDocument(
+ schema_a, /*index_nested_properties=*/false))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaDprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_a, schema_type_config_a},
+ {schema_b, schema_type_config_b},
+ {schema_c, schema_type_config_c},
+ {schema_d, schema_type_config_d}};
+
+ // Order of iteration and whether each property is indexable for schema A:
+ // {"schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2" (true),
+ // "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop1.schemaAprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"
+ // (true), "schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop2" (true),
+ // "schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2" (true),
+ // "schemaAprop3.schemaDprop2" (true)
+ //
+ // The following properties listed in the indexable_list are not defined
+ // in the schema and should not be seen during iteration:
+ // - From schemaAprop1's list:
+ // "schemaBprop1.schemaCprop1", "schemaBprop1.schemaCprop1.schemaAprop3",
+ // "schemaAprop2", "schemaBprop2.schemaCprop2", "schemaBprop1.foo.bar",
+ // "foo", "bar"
+ // - From schemaAprop3's list:
+ // "schemaBprop2", "bar", "schemaDprop2.foo", "schemaDprop1",
+ // "schemaAprop3.schemaDprop2"
+ SchemaPropertyIterator schema_a_iterator(schema_type_config_a,
+ type_config_map);
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3."
+ "schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(
+ schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration and whether each property is indexable for schema B:
+ // "schemaBprop1.schemaCprop1.schemaAprop2" (false),
+ // "schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2" (false),
+ // "schemaBprop1.schemaCprop2" (true),
+ // "schemaBprop2" (true)
+ SchemaPropertyIterator schema_b_iterator(schema_type_config_b,
+ type_config_map);
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(),
+ Eq("schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyPath(), Eq("schemaBprop2"));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_b_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_b_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for schema C:
+ // "schemaCprop1.schemaAprop1.schemaBprop2" (false),
+ // "schemaCprop1.schemaAprop2" (false),
+ // "schemaCprop1.schemaAprop3.schemaDprop2" (false),
+ // "schemaCprop2" (true)
+ SchemaPropertyIterator schema_c_iterator(schema_type_config_c,
+ type_config_map);
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(),
+ Eq("schemaCprop1.schemaAprop3.schemaDprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_d.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_c_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyPath(), Eq("schemaCprop2"));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_c_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_c_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+
+ // Order of iteration for schema D:
+ // "schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2" (false),
+ // "schemaDprop1.schemaAprop1.schemaBprop2" (false),
+ // "schemaDprop1.schemaAprop2" (false),
+ // "schemaDprop2" (true)
+ SchemaPropertyIterator schema_d_iterator(schema_type_config_d,
+ type_config_map);
+
+ EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
+ Eq("schemaDprop1.schemaAprop1.schemaBprop1.schemaCprop2"));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_c.properties(1)));
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
Eq("schemaDprop1.schemaAprop1.schemaBprop2"));
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_b.properties(1)));
- EXPECT_THAT(schema_d_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(),
Eq("schemaDprop1.schemaAprop2"));
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_a.properties(1)));
- EXPECT_THAT(schema_d_iterator.GetCurrentNestedIndexable(), IsFalse());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsFalse());
EXPECT_THAT(schema_d_iterator.Advance(), IsOk());
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyPath(), Eq("schemaDprop2"));
EXPECT_THAT(schema_d_iterator.GetCurrentPropertyConfig(),
EqualsProto(schema_type_config_d.properties(1)));
- EXPECT_THAT(schema_d_iterator.GetCurrentNestedIndexable(), IsTrue());
+ EXPECT_THAT(schema_d_iterator.GetCurrentPropertyIndexable(), IsTrue());
EXPECT_THAT(schema_d_iterator.Advance(),
StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
}
+TEST(SchemaPropertyIteratorTest, TopLevelCycleWithMultipleIndexableLists) {
+ std::string schema_a = "A";
+ std::string schema_b = "B";
+ std::string schema_c = "C";
+ std::string schema_d = "D";
+
+ // Create the following schema:
+ // A <-> A -> B
+ // A has a top-level property that is a self-reference.
+ SchemaTypeConfigProto schema_type_config_a =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_a)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaAprop1")
+ .SetDataTypeDocument(
+ schema_b, /*indexable_nested_properties_list=*/
+ {"schemaBprop1", "schemaBprop2"}))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("schemaAprop2")
+ .SetDataTypeDocument(
+ schema_a, /*indexable_nested_properties_list=*/
+ {"schemaAprop1.schemaBprop2",
+ "schemaAprop1.schemaBprop3"}))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaAprop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+ SchemaTypeConfigProto schema_type_config_b =
+ SchemaTypeConfigBuilder()
+ .SetType(schema_b)
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop1")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop2")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("schemaBprop3")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN))
+ .Build();
+
+ SchemaUtil::TypeConfigMap type_config_map = {
+ {schema_a, schema_type_config_a}, {schema_b, schema_type_config_b}};
+
+ // Order of iteration for Schema A:
+ // "schemaAprop1.schemaBprop1" (true)
+ // "schemaAprop1.schemaBprop2" (true)
+ // "schemaAprop1.schemaBprop3" (false)
+ // "schemaAprop2.schemaAprop1.schemaBprop1" (false)
+ // "schemaAprop2.schemaAprop1.schemaBprop2" (true)
+ // "schemaAprop2.schemaAprop1.schemaBprop3" (true)
+ // "schemaAprop2.schemaAprop3" (false)
+ // "schemaAprop3" (true)
+ SchemaPropertyIterator schema_a_iterator(schema_type_config_a,
+ type_config_map);
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop1.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop2.schemaAprop1.schemaBprop1"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(0)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop2.schemaAprop1.schemaBprop2"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(1)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop2.schemaAprop1.schemaBprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_b.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(),
+ Eq("schemaAprop2.schemaAprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsFalse());
+
+ EXPECT_THAT(schema_a_iterator.Advance(), IsOk());
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyPath(), Eq("schemaAprop3"));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyConfig(),
+ EqualsProto(schema_type_config_a.properties(2)));
+ EXPECT_THAT(schema_a_iterator.GetCurrentPropertyIndexable(), IsTrue());
+
+ EXPECT_THAT(schema_a_iterator.Advance(),
+ StatusIs(libtextclassifier3::StatusCode::OUT_OF_RANGE));
+}
+
} // namespace
} // namespace lib
diff --git a/icing/schema/schema-type-manager.cc b/icing/schema/schema-type-manager.cc
index f3a86d4..ca2f45c 100644
--- a/icing/schema/schema-type-manager.cc
+++ b/icing/schema/schema-type-manager.cc
@@ -55,7 +55,7 @@ SchemaTypeManager::Create(const SchemaUtil::TypeConfigMap& type_config_map,
}
// Process section (indexable property)
- if (iterator.GetCurrentNestedIndexable()) {
+ if (iterator.GetCurrentPropertyIndexable()) {
ICING_RETURN_IF_ERROR(
section_manager_builder.ProcessSchemaTypePropertyConfig(
schema_type_id, iterator.GetCurrentPropertyConfig(),
diff --git a/icing/schema/schema-util.cc b/icing/schema/schema-util.cc
index 371ed00..6d63b10 100644
--- a/icing/schema/schema-util.cc
+++ b/icing/schema/schema-util.cc
@@ -115,6 +115,34 @@ bool IsIntegerNumericMatchTypeCompatible(
return old_indexed.numeric_match_type() == new_indexed.numeric_match_type();
}
+bool IsDocumentIndexingCompatible(const DocumentIndexingConfig& old_indexed,
+ const DocumentIndexingConfig& new_indexed) {
+ // TODO(b/265304217): This could mark the new schema as incompatible and
+ // generate some unnecessary index rebuilds if the two schemas have an
+ // equivalent set of indexed properties, but changed the way that it is
+ // declared.
+ if (old_indexed.index_nested_properties() !=
+ new_indexed.index_nested_properties()) {
+ return false;
+ }
+
+ if (old_indexed.indexable_nested_properties_list().size() !=
+ new_indexed.indexable_nested_properties_list().size()) {
+ return false;
+ }
+
+ std::unordered_set<std::string_view> old_indexable_nested_properies_set(
+ old_indexed.indexable_nested_properties_list().begin(),
+ old_indexed.indexable_nested_properties_list().end());
+ for (const auto& property : new_indexed.indexable_nested_properties_list()) {
+ if (old_indexable_nested_properies_set.find(property) ==
+ old_indexable_nested_properies_set.end()) {
+ return false;
+ }
+ }
+ return true;
+}
+
void AddIncompatibleChangeToDelta(
std::unordered_set<std::string>& incompatible_delta,
const SchemaTypeConfigProto& old_type_config,
@@ -571,6 +599,10 @@ libtextclassifier3::StatusOr<SchemaUtil::DependentMap> SchemaUtil::Validate(
"data_types in schema property '",
schema_type, ".", property_name, "'"));
}
+
+ ICING_RETURN_IF_ERROR(ValidateDocumentIndexingConfig(
+ property_config.document_indexing_config(), schema_type,
+ property_name));
}
ICING_RETURN_IF_ERROR(ValidateCardinality(property_config.cardinality(),
@@ -751,6 +783,19 @@ libtextclassifier3::Status SchemaUtil::ValidateJoinableConfig(
return libtextclassifier3::Status::OK;
}
+libtextclassifier3::Status SchemaUtil::ValidateDocumentIndexingConfig(
+ const DocumentIndexingConfig& config, std::string_view schema_type,
+ std::string_view property_name) {
+ if (!config.indexable_nested_properties_list().empty() &&
+ config.index_nested_properties()) {
+ return absl_ports::InvalidArgumentError(absl_ports::StrCat(
+ "DocumentIndexingConfig.index_nested_properties is required to be "
+ "false when providing a non-empty indexable_nested_properties_list "
+ "for property '", schema_type, ".", property_name, "'"));
+ }
+ return libtextclassifier3::Status::OK;
+}
+
/* static */ bool SchemaUtil::IsIndexedProperty(
const PropertyConfigProto& property_config) {
switch (property_config.data_type()) {
@@ -1005,10 +1050,9 @@ const SchemaUtil::SchemaDelta SchemaUtil::ComputeCompatibilityDelta(
!IsIntegerNumericMatchTypeCompatible(
old_property_config.integer_indexing_config(),
new_property_config->integer_indexing_config()) ||
- old_property_config.document_indexing_config()
- .index_nested_properties() !=
- new_property_config->document_indexing_config()
- .index_nested_properties()) {
+ !IsDocumentIndexingCompatible(
+ old_property_config.document_indexing_config(),
+ new_property_config->document_indexing_config())) {
is_index_incompatible = true;
}
diff --git a/icing/schema/schema-util.h b/icing/schema/schema-util.h
index e707758..0adc0ae 100644
--- a/icing/schema/schema-util.h
+++ b/icing/schema/schema-util.h
@@ -157,6 +157,9 @@ class SchemaUtil {
// (property whose joinable config is not NONE), OR
// ii. Any type node in the cycle has a nested-type (direct or
// indirect) with a joinable property.
+ // 15. For DOCUMENT data types, if
+ // DocumentIndexingConfig.indexable_nested_properties_list is non-empty,
+ // DocumentIndexingConfig.index_nested_properties must be false.
//
// Returns:
// On success, a dependent map from each types to their dependent types
@@ -315,6 +318,17 @@ class SchemaUtil {
PropertyConfigProto::Cardinality::Code cardinality,
std::string_view schema_type, std::string_view property_name);
+ // Checks that the 'document_indexing_config' satisfies the following rule:
+ // 1. If indexable_nested_properties is non-empty, index_nested_properties
+ // must be set to false.
+ //
+ // Returns:
+ // INVALID_ARGUMENT if any of the rules are not followed
+ // OK on success
+ static libtextclassifier3::Status ValidateDocumentIndexingConfig(
+ const DocumentIndexingConfig& config, std::string_view schema_type,
+ std::string_view property_name);
+
// Returns if 'parent_type' is a direct or indirect parent of 'child_type'.
static bool IsParent(const SchemaUtil::InheritanceMap& inheritance_map,
std::string_view parent_type,
diff --git a/icing/schema/schema-util_test.cc b/icing/schema/schema-util_test.cc
index 40e30b0..6f9e420 100644
--- a/icing/schema/schema-util_test.cc
+++ b/icing/schema/schema-util_test.cc
@@ -14,6 +14,8 @@
#include "icing/schema/schema-util.h"
+#include <initializer_list>
+#include <string>
#include <string_view>
#include <unordered_set>
@@ -3081,6 +3083,239 @@ TEST_P(SchemaUtilTest, IndexNestedDocumentsIndexIncompatible) {
EXPECT_THAT(actual, Eq(schema_delta));
}
+TEST_P(SchemaUtilTest, AddOrDropIndexableNestedProperties_IndexIncompatible) {
+ SchemaTypeConfigProto email_type_config =
+ SchemaTypeConfigBuilder()
+ .SetType(kEmailType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("recipient")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("subject")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("body")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .Build();
+ SchemaProto schema_1 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"recipient", "subject", "body"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaProto schema_2 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties=*/
+ {"recipient", "subject"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ // Dropping some indexable_nested_properties should make kPersonType
+ // index_incompatible. kEmailType should be unaffected.
+ SchemaUtil::SchemaDelta schema_delta;
+ schema_delta.schema_types_index_incompatible.emplace(kPersonType);
+ SchemaUtil::DependentMap dependents_map = {{kEmailType, {{kPersonType, {}}}}};
+ SchemaUtil::SchemaDelta actual =
+ SchemaUtil::ComputeCompatibilityDelta(schema_1, schema_2, dependents_map);
+ EXPECT_THAT(actual, Eq(schema_delta));
+
+ // Adding some indexable_nested_properties should also make kPersonType
+ // index_incompatible. kEmailType should be unaffected.
+ actual =
+ SchemaUtil::ComputeCompatibilityDelta(schema_2, schema_1, dependents_map);
+ EXPECT_THAT(actual, Eq(schema_delta));
+}
+
+TEST_P(SchemaUtilTest, ChangingIndexableNestedProperties_IndexIncompatible) {
+ SchemaTypeConfigProto email_type_config =
+ SchemaTypeConfigBuilder()
+ .SetType(kEmailType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("recipient")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("subject")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("body")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .Build();
+ SchemaProto schema_1 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"recipient", "subject"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaProto schema_2 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"recipient", "body"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ // Changing 'subject' to 'body' for indexable_nested_properties_list should
+ // make kPersonType index_incompatible. kEmailType should be unaffected.
+ SchemaUtil::SchemaDelta schema_delta;
+ schema_delta.schema_types_index_incompatible.emplace(kPersonType);
+ SchemaUtil::DependentMap dependents_map = {{kEmailType, {{kPersonType, {}}}}};
+ SchemaUtil::SchemaDelta actual =
+ SchemaUtil::ComputeCompatibilityDelta(schema_1, schema_2, dependents_map);
+ EXPECT_THAT(actual, Eq(schema_delta));
+}
+
+TEST_P(SchemaUtilTest, IndexableNestedPropertiesFullSet_IndexIncompatible) {
+ SchemaTypeConfigProto email_type_config =
+ SchemaTypeConfigBuilder()
+ .SetType(kEmailType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("recipient")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("subject")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("body")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .Build();
+ SchemaProto schema_1 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*index_nested_properties=*/true)
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaProto schema_2 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"recipient", "body", "subject"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ // This scenario also invalidates kPersonType and triggers an index rebuild at
+ // the moment, even though the set of indexable_nested_properties from
+ // schema_1 to schema_2 should be the same.
+ SchemaUtil::SchemaDelta schema_delta;
+ schema_delta.schema_types_index_incompatible.emplace(kPersonType);
+ SchemaUtil::DependentMap dependents_map = {{kEmailType, {{kPersonType, {}}}}};
+ SchemaUtil::SchemaDelta actual =
+ SchemaUtil::ComputeCompatibilityDelta(schema_1, schema_2, dependents_map);
+ EXPECT_THAT(actual, Eq(schema_delta));
+}
+
+TEST_P(SchemaUtilTest,
+ ChangingIndexableNestedPropertiesOrder_IndexIsCompatible) {
+ SchemaTypeConfigProto email_type_config =
+ SchemaTypeConfigBuilder()
+ .SetType(kEmailType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("recipient")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("subject")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("body")
+ .SetDataTypeString(TERM_MATCH_EXACT, TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .Build();
+ SchemaProto schema_1 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"recipient", "subject", "body"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaProto schema_2 =
+ SchemaBuilder()
+ .AddType(email_type_config)
+ .AddType(
+ SchemaTypeConfigBuilder()
+ .SetType(kPersonType)
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("emails")
+ .SetDataTypeDocument(
+ kEmailType,
+ /*indexable_nested_properties_list=*/
+ {"subject", "body", "recipient"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ // Changing order of elements in indexable_nested_properties_list should have
+ // no effect on schema compatibility.
+ SchemaUtil::SchemaDelta schema_delta;
+ SchemaUtil::DependentMap dependents_map = {{kEmailType, {{kPersonType, {}}}}};
+ SchemaUtil::SchemaDelta actual =
+ SchemaUtil::ComputeCompatibilityDelta(schema_1, schema_2, dependents_map);
+ EXPECT_THAT(actual, Eq(schema_delta));
+ EXPECT_THAT(actual.schema_types_index_incompatible, IsEmpty());
+}
+
TEST_P(SchemaUtilTest, ValidateStringIndexingConfigShouldHaveTermMatchType) {
SchemaProto schema =
SchemaBuilder()
@@ -3673,6 +3908,137 @@ TEST_P(SchemaUtilTest, ValidateNestedJoinablePropertyDiamondRelationship) {
StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
}
+TEST_P(SchemaUtilTest,
+ ValidDocumentIndexingConfigFields_emptyIndexableListBooleanTrue) {
+ SchemaProto schema =
+ SchemaBuilder()
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("InnerSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop1")
+ .SetDataTypeString(TERM_MATCH_PREFIX,
+ TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop2")
+ .SetDataTypeString(TERM_MATCH_UNKNOWN,
+ TOKENIZER_NONE)
+ .SetCardinality(CARDINALITY_OPTIONAL)))
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("OuterSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("InnerProperty")
+ .SetDataTypeDocument(
+ "InnerSchema",
+ /*index_nested_properties=*/true)
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaTypeConfigProto* outerSchemaType = schema.mutable_types(1);
+ outerSchemaType->mutable_properties(0)
+ ->mutable_document_indexing_config()
+ ->clear_indexable_nested_properties_list();
+
+ EXPECT_THAT(SchemaUtil::Validate(schema, GetParam()), IsOk());
+}
+
+TEST_P(SchemaUtilTest,
+ ValidDocumentIndexingConfigFields_emptyIndexableListBooleanFalse) {
+ SchemaProto schema =
+ SchemaBuilder()
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("InnerSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop1")
+ .SetDataTypeString(TERM_MATCH_PREFIX,
+ TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL))
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop2")
+ .SetDataTypeString(TERM_MATCH_UNKNOWN,
+ TOKENIZER_NONE)
+ .SetCardinality(CARDINALITY_OPTIONAL)))
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("OuterSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("InnerProperty")
+ .SetDataTypeDocument(
+ "InnerSchema",
+ /*index_nested_properties=*/false)
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaTypeConfigProto* outerSchemaType = schema.mutable_types(1);
+ outerSchemaType->mutable_properties(0)
+ ->mutable_document_indexing_config()
+ ->clear_indexable_nested_properties_list();
+
+ EXPECT_THAT(SchemaUtil::Validate(schema, GetParam()), IsOk());
+}
+
+TEST_P(SchemaUtilTest,
+ ValidDocumentIndexingConfigFields_nonEmptyIndexableList) {
+ SchemaProto schema =
+ SchemaBuilder()
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("InnerSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop1")
+ .SetDataTypeString(TERM_MATCH_PREFIX,
+ TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL)))
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("OuterSchema")
+ .AddProperty(
+ PropertyConfigBuilder()
+ .SetName("InnerProperty")
+ .SetDataTypeDocument(
+ "InnerSchema",
+ /*indexable_nested_properties_list=*/
+ std::initializer_list<std::string>{"prop1"})
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ SchemaTypeConfigProto* outerSchemaType = schema.mutable_types(1);
+ outerSchemaType->mutable_properties(0)
+ ->mutable_document_indexing_config()
+ ->set_index_nested_properties(false);
+ EXPECT_THAT(SchemaUtil::Validate(schema, GetParam()), IsOk());
+}
+
+TEST_P(SchemaUtilTest, InvalidDocumentIndexingConfigFields) {
+ // If indexable_nested_properties is non-empty, index_nested_properties is
+ // required to be false.
+ SchemaProto schema =
+ SchemaBuilder()
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("InnerSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("prop1")
+ .SetDataTypeString(TERM_MATCH_PREFIX,
+ TOKENIZER_PLAIN)
+ .SetCardinality(CARDINALITY_OPTIONAL)))
+ .AddType(SchemaTypeConfigBuilder()
+ .SetType("OuterSchema")
+ .AddProperty(PropertyConfigBuilder()
+ .SetName("InnerProperty")
+ .SetDataTypeDocument(
+ "InnerSchema",
+ /*index_nested_properties=*/true)
+ .SetCardinality(CARDINALITY_REPEATED)))
+ .Build();
+
+ // Setting a non-empty indexable_nested_properties_list while
+ // index_nested_properties=true is invalid.
+ SchemaTypeConfigProto* outerSchemaType = schema.mutable_types(1);
+ outerSchemaType->mutable_properties(0)
+ ->mutable_document_indexing_config()
+ ->add_indexable_nested_properties_list("prop");
+
+ EXPECT_THAT(SchemaUtil::Validate(schema, GetParam()),
+ StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
+}
+
TEST_P(SchemaUtilTest, MultipleReferencesToSameNestedSchemaOk) {
SchemaProto schema =
SchemaBuilder()
diff --git a/proto/icing/proto/schema.proto b/proto/icing/proto/schema.proto
index b972ece..c716dba 100644
--- a/proto/icing/proto/schema.proto
+++ b/proto/icing/proto/schema.proto
@@ -138,15 +138,22 @@ message StringIndexingConfig {
}
// Describes how a document property should be indexed.
-// Next tag: 2
+// Next tag: 3
message DocumentIndexingConfig {
// OPTIONAL: Whether nested properties within the document property should be
- // indexed. If true, then the nested properties will be indexed according to
+ // indexed. If true, then all nested properties will be indexed according to
// the property's own indexing configurations. If false, nested documents'
// properties will not be indexed even if they have an indexing configuration.
//
// The default value is false.
optional bool index_nested_properties = 1;
+
+ // List of nested properties within the document to index. Only the
+ // provided list of properties will be indexed according to the property's
+ // indexing configurations.
+ //
+ // index_nested_properties must be false in order to use this feature.
+ repeated string indexable_nested_properties_list = 2;
}
// Describes how a int64 property should be indexed.
diff --git a/proto/icing/proto/search.proto b/proto/icing/proto/search.proto
index fca669a..411ad3e 100644
--- a/proto/icing/proto/search.proto
+++ b/proto/icing/proto/search.proto
@@ -106,7 +106,7 @@ message SearchSpecProto {
// Client-supplied specifications on what to include/how to format the search
// results.
-// Next tag: 9
+// Next tag: 10
message ResultSpecProto {
// The results will be returned in pages, and num_per_page specifies the
// number of documents in one page.
@@ -211,6 +211,18 @@ message ResultSpecProto {
// The max # of child documents will be attached and returned in the result
// for each parent. It is only used for join API.
optional int32 max_joined_children_per_parent_to_return = 8;
+
+ // The max # of results being scored and ranked.
+ // Running time of ScoringProcessor and Ranker is O(num_to_score) according to
+ // results of //icing/scoring:score-and-rank_benchmark. Note that
+ // the process includes scoring, building a heap, and popping results from the
+ // heap.
+ //
+ // 30000 results can be scored and ranked within 3 ms on a Pixel 3 XL
+ // according to results of
+ // //icing/scoring:score-and-rank_benchmark, so set it as the
+ // default value.
+ optional int32 num_to_score = 9 [default = 30000];
}
// The representation of a single match within a DocumentProto property.
diff --git a/synced_AOSP_CL_number.txt b/synced_AOSP_CL_number.txt
index afb1234..20e7738 100644
--- a/synced_AOSP_CL_number.txt
+++ b/synced_AOSP_CL_number.txt
@@ -1 +1 @@
-set(synced_AOSP_CL_number=537223436)
+set(synced_AOSP_CL_number=544124118)