Skip to content

Commit 631d4c8

Browse files
authored
Implement TargetIndexMatcher (#9490)
* Temp checkin * Tests half way * Implement TargetIndexMatcher * Feedback
1 parent 40c8bef commit 631d4c8

File tree

6 files changed

+812
-0
lines changed

6 files changed

+812
-0
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
146C140B254F3837A4DD7AE8 /* bits_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB380D01201BC69F00D97691 /* bits_test.cc */; };
120120
152543FD706D5E8851C8DA92 /* precondition_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5520A36E1F00BCEB75 /* precondition_test.cc */; };
121121
153F3E4E9E3A0174E29550B4 /* mutation.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE8220B89AAC00B5BCE7 /* mutation.pb.cc */; };
122+
15A5DEC8430E71D64424CBFD /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
122123
15A5F95DA733FD89A1E4147D /* limit_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 54DA129F1F315EE100DD57A1 /* limit_spec_test.json */; };
123124
15BF63DFF3A7E9A5376C4233 /* transform_operation_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 33607A3AE91548BD219EC9C6 /* transform_operation_test.cc */; };
124125
15F54E9538839D56A40C5565 /* watch_change_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2D7472BC70C024D736FF74D9 /* watch_change_test.cc */; };
@@ -184,6 +185,7 @@
184185
22A00AC39CAB3426A943E037 /* query.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 544129D621C2DDC800EFB9CC /* query.pb.cc */; };
185186
23C04A637090E438461E4E70 /* latlng.pb.cc in Sources */ = {isa = PBXBuildFile; fileRef = 618BBE9220B89AAC00B5BCE7 /* latlng.pb.cc */; };
186187
23EFC681986488B033C2B318 /* leveldb_opener_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 75860CD13AF47EB1EA39EC2F /* leveldb_opener_test.cc */; };
188+
2428E92E063EBAEA44BA5913 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
187189
248DE4F56DD938F4DBCCF39B /* bundle_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6ECAF7DE28A19C69DF386D88 /* bundle_reader_test.cc */; };
188190
24CB39421C63CD87242B31DF /* bundle_reader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6ECAF7DE28A19C69DF386D88 /* bundle_reader_test.cc */; };
189191
254CD651CB621D471BC5AC12 /* target_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B5C37696557C81A6C2B7271A /* target_cache_test.cc */; };
@@ -767,6 +769,7 @@
767769
84285C3F63D916A4786724A8 /* field_index_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = BF76A8DA34B5B67B4DD74666 /* field_index_test.cc */; };
768770
843EE932AA9A8F43721F189E /* leveldb_local_store_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5FF903AEFA7A3284660FA4C5 /* leveldb_local_store_test.cc */; };
769771
8460C97C9209D7DAF07090BD /* FIRFieldsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06A202154D500B64F25 /* FIRFieldsTests.mm */; };
772+
84E75527F3739131C09BEAA5 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
770773
851346D66DEC223E839E3AA9 /* memory_mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 74FBEFA4FE4B12C435011763 /* memory_mutation_queue_test.cc */; };
771774
856A1EAAD674ADBDAAEDAC37 /* bundle_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4F5B96F3ABCD2CA901DB1CD4 /* bundle_builder.cc */; };
772775
85B8918FC8C5DC62482E39C3 /* resource_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2B02024FFD70028D6BE /* resource_path_test.cc */; };
@@ -961,6 +964,7 @@
961964
B235E260EA0DCB7BAC04F69B /* field_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2AD2023DDB20028D6BE /* field_path_test.cc */; };
962965
B28ACC69EB1F232AE612E77B /* async_testing.cc in Sources */ = {isa = PBXBuildFile; fileRef = 872C92ABD71B12784A1C5520 /* async_testing.cc */; };
963966
B371628DA91E80B64AE53085 /* FIRFieldPathTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E04C202154AA00B64F25 /* FIRFieldPathTests.mm */; };
967+
B384E0F90D4CCC15C88CAF30 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
964968
B3A309CCF5D75A555C7196E1 /* path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 403DBF6EFB541DFD01582AA3 /* path_test.cc */; };
965969
B3B8608727430210C4405AC0 /* FSTMemorySpecTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02F20213FFC00B64F25 /* FSTMemorySpecTests.mm */; };
966970
B3C87C635527A2E57944B789 /* ordered_code_benchmark.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0473AFFF5567E667A125347B /* ordered_code_benchmark.cc */; };
@@ -1069,6 +1073,7 @@
10691073
C7F174164D7C55E35A526009 /* resource_path_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B686F2B02024FFD70028D6BE /* resource_path_test.cc */; };
10701074
C7F3C6F569BBA904477F011C /* memory_target_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2286F308EFB0534B1BDE05B9 /* memory_target_cache_test.cc */; };
10711075
C80B10E79CDD7EF7843C321E /* objc_type_traits_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A0CF41BA5AED6049B0BEB2C /* objc_type_traits_apple_test.mm */; };
1076+
C8722550B56CEB96F84DCE94 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
10721077
C8A573895D819A92BF16B5E5 /* mutation_queue_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3068AA9DFBBA86C1FE2A946E /* mutation_queue_test.cc */; };
10731078
C8BC50508337800E8B098F57 /* bundle_loader_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = A853C81A6A5A51C9D0389EDA /* bundle_loader_test.cc */; };
10741079
C8C4CB7B6E23FC340BEC6D7F /* load_bundle_task_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8F1A7B4158D9DD76EE4836BF /* load_bundle_task_test.cc */; };
@@ -1247,6 +1252,7 @@
12471252
F10A3E4E164A5458DFF7EDE6 /* leveldb_remote_document_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 0840319686A223CC4AD3FAB1 /* leveldb_remote_document_cache_test.cc */; };
12481253
F19B749671F2552E964422F7 /* FIRListenerRegistrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E06B202154D500B64F25 /* FIRListenerRegistrationTests.mm */; };
12491254
F272A8C41D2353700A11D1FB /* field_mask_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA5320A36E1F00BCEB75 /* field_mask_test.cc */; };
1255+
F27347560A963E8162C56FF3 /* target_index_matcher_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */; };
12501256
F2AB7EACA1B9B1A7046D3995 /* FSTSyncEngineTestDriver.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02E20213FFC00B64F25 /* FSTSyncEngineTestDriver.mm */; };
12511257
F3261CBFC169DB375A0D9492 /* FSTMockDatastore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5492E02D20213FFC00B64F25 /* FSTMockDatastore.mm */; };
12521258
F3DEF2DB11FADAABDAA4C8BB /* bundle_builder.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4F5B96F3ABCD2CA901DB1CD4 /* bundle_builder.cc */; };
@@ -1561,6 +1567,7 @@
15611567
61F72C5520BC48FD001A68CB /* serializer_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serializer_test.cc; sourceTree = "<group>"; };
15621568
620C1427763BA5D3CCFB5A1F /* BridgingHeader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = "<group>"; };
15631569
62E103B28B48A81D682A0DE9 /* Pods_Firestore_Example_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_Example_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1570+
63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; path = target_index_matcher_test.cc; sourceTree = "<group>"; };
15641571
64AA92CFA356A2360F3C5646 /* filesystem_testing.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = filesystem_testing.h; sourceTree = "<group>"; };
15651572
69E6C311558EC77729A16CF1 /* Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS/Pods-Firestore_Example_iOS-Firestore_SwiftTests_iOS.debug.xcconfig"; sourceTree = "<group>"; };
15661573
6AE927CDFC7A72BF825BE4CB /* Pods-Firestore_Tests_tvOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Tests_tvOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Tests_tvOS/Pods-Firestore_Tests_tvOS.release.xcconfig"; sourceTree = "<group>"; };
@@ -2432,6 +2439,7 @@
24322439
549CCA5520A36E1F00BCEB75 /* precondition_test.cc */,
24332440
B686F2B02024FFD70028D6BE /* resource_path_test.cc */,
24342441
ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */,
2442+
63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */,
24352443
33607A3AE91548BD219EC9C6 /* transform_operation_test.cc */,
24362444
40F9D09063A07F710811A84F /* value_util_test.cc */,
24372445
);
@@ -3659,6 +3667,7 @@
36593667
4A3FF3B16A39A5DC6B7EBA51 /* target.pb.cc in Sources */,
36603668
6D7F70938662E8CA334F11C2 /* target_cache_test.cc in Sources */,
36613669
E764F0F389E7119220EB212C /* target_id_generator_test.cc in Sources */,
3670+
B384E0F90D4CCC15C88CAF30 /* target_index_matcher_test.cc in Sources */,
36623671
88929ED628DA8DD9592974ED /* task_test.cc in Sources */,
36633672
32A95242C56A1A230231DB6A /* testutil.cc in Sources */,
36643673
5497CB78229DECDE000FB92F /* time_testing.cc in Sources */,
@@ -3856,6 +3865,7 @@
38563865
81B23D2D4E061074958AF12F /* target.pb.cc in Sources */,
38573866
6AED40FF444F0ACFE3AE96E3 /* target_cache_test.cc in Sources */,
38583867
DA4303684707606318E1914D /* target_id_generator_test.cc in Sources */,
3868+
2428E92E063EBAEA44BA5913 /* target_index_matcher_test.cc in Sources */,
38593869
67CF9FAA890307780731E1DA /* task_test.cc in Sources */,
38603870
8388418F43042605FB9BFB92 /* testutil.cc in Sources */,
38613871
5497CB79229DECDE000FB92F /* time_testing.cc in Sources */,
@@ -4067,6 +4077,7 @@
40674077
EC3331B17394886A3715CFD8 /* target.pb.cc in Sources */,
40684078
7DB0915EF7C22C700A423F7C /* target_cache_test.cc in Sources */,
40694079
71E2B154C4FB63F7B7CC4B50 /* target_id_generator_test.cc in Sources */,
4080+
C8722550B56CEB96F84DCE94 /* target_index_matcher_test.cc in Sources */,
40704081
76A5447D76F060E996555109 /* task_test.cc in Sources */,
40714082
409C0F2BFC2E1BECFFAC4D32 /* testutil.cc in Sources */,
40724083
6300709ECDE8E0B5A8645F8D /* time_testing.cc in Sources */,
@@ -4278,6 +4289,7 @@
42784289
B3E6F4CDB1663407F0980C7A /* target.pb.cc in Sources */,
42794290
66CA091F8B610E0FB0A3F8A4 /* target_cache_test.cc in Sources */,
42804291
A05BC6BDA2ABE405009211A9 /* target_id_generator_test.cc in Sources */,
4292+
15A5DEC8430E71D64424CBFD /* target_index_matcher_test.cc in Sources */,
42814293
93C8F772F4DC5A985FA3D815 /* task_test.cc in Sources */,
42824294
A17DBC8F24127DA8A381F865 /* testutil.cc in Sources */,
42834295
A25FF76DEF542E01A2DF3B0E /* time_testing.cc in Sources */,
@@ -4485,6 +4497,7 @@
44854497
618BBEA620B89AAC00B5BCE7 /* target.pb.cc in Sources */,
44864498
254CD651CB621D471BC5AC12 /* target_cache_test.cc in Sources */,
44874499
AB380CFB2019388600D97691 /* target_id_generator_test.cc in Sources */,
4500+
F27347560A963E8162C56FF3 /* target_index_matcher_test.cc in Sources */,
44884501
662793139A36E5CFC935B949 /* task_test.cc in Sources */,
44894502
54A0352A20A3B3BD003E0143 /* testutil.cc in Sources */,
44904503
5497CB77229DECDE000FB92F /* time_testing.cc in Sources */,
@@ -4715,6 +4728,7 @@
47154728
6FAC16B7FBD3B40D11A6A816 /* target.pb.cc in Sources */,
47164729
FA90FA91F7381E5C678EFA30 /* target_cache_test.cc in Sources */,
47174730
306E762DC6B829CED4FD995D /* target_id_generator_test.cc in Sources */,
4731+
84E75527F3739131C09BEAA5 /* target_index_matcher_test.cc in Sources */,
47184732
C57B15CADD8C3E806B154C19 /* task_test.cc in Sources */,
47194733
CA989C0E6020C372A62B7062 /* testutil.cc in Sources */,
47204734
2D220B9ABFA36CD7AC43D0A7 /* time_testing.cc in Sources */,
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2022 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "Firestore/core/src/model/target_index_matcher.h"
18+
19+
#include "Firestore/core/src/util/hard_assert.h"
20+
21+
namespace firebase {
22+
namespace firestore {
23+
namespace model {
24+
25+
using core::FieldFilter;
26+
using core::Filter;
27+
using core::OrderBy;
28+
using core::Target;
29+
30+
TargetIndexMatcher::TargetIndexMatcher(const core::Target& target) {
31+
collection_id_ = target.collection_group() != nullptr
32+
? *target.collection_group()
33+
: target.path().last_segment();
34+
order_bys_ = target.order_bys();
35+
inequality_filter_ = absl::nullopt;
36+
37+
for (const Filter& filter : target.filters()) {
38+
FieldFilter field_filter(filter);
39+
if (field_filter.IsInequality()) {
40+
HARD_ASSERT(!inequality_filter_.has_value() ||
41+
inequality_filter_->field() == field_filter.field(),
42+
"Only a single inequality is supported");
43+
inequality_filter_ = field_filter;
44+
} else {
45+
equality_filters_.push_back(field_filter);
46+
}
47+
}
48+
}
49+
50+
bool TargetIndexMatcher::ServedByIndex(const model::FieldIndex& index) {
51+
HARD_ASSERT(index.collection_group() == collection_id_,
52+
"Collection IDs do not match");
53+
54+
// If there is an array element, find a matching filter.
55+
const auto& array_segment = index.GetArraySegment();
56+
if (array_segment.has_value() &&
57+
!HasMatchingEqualityFilter(array_segment.value())) {
58+
return false;
59+
}
60+
61+
std::vector<Segment> segments = index.GetDirectionalSegments();
62+
size_t segment_index = 0;
63+
// Process all equalities first. Equalities can appear out of order.
64+
for (; segment_index < segments.size(); ++segment_index) {
65+
// We attempt to greedily match all segments to equality filters. If a
66+
// filter matches an index segment, we can mark the segment as used. Since
67+
// it is not possible to use the same field path in both an equality and
68+
// inequality/oderBy clause, we do not have to consider the possibility that
69+
// a matching equality segment should instead be used to map to an
70+
// inequality filter or orderBy clause.
71+
if (!HasMatchingEqualityFilter(segments[segment_index])) {
72+
// If we cannot find a matching filter, we need to verify whether the
73+
// remaining segments map to the target's inequality and its orderBy
74+
// clauses.
75+
break;
76+
}
77+
}
78+
79+
// If we already have processed all segments, all segments are used to serve
80+
// the equality filters and we do not need to map any segments to the target's
81+
// inequality and orderBy clauses.
82+
if (segment_index == segments.size()) {
83+
return true;
84+
}
85+
86+
// `order_bys_` has at least one element.
87+
auto order_by_iter = order_bys_.begin();
88+
89+
// If there is an inequality filter, the next segment must match both the
90+
// filter and the first OrderBy clause.
91+
if (inequality_filter_.has_value()) {
92+
if (!MatchesFilter(inequality_filter_, segments[segment_index]) ||
93+
!MatchesOrderBy(*order_by_iter, segments[segment_index])) {
94+
return false;
95+
}
96+
++order_by_iter;
97+
++segment_index;
98+
}
99+
100+
// All remaining segments need to represent the prefix of the target's
101+
// OrderBy.
102+
for (; segment_index < segments.size(); ++segment_index) {
103+
if (order_by_iter == order_bys_.end() ||
104+
!MatchesOrderBy(*order_by_iter, segments[segment_index])) {
105+
return false;
106+
}
107+
++order_by_iter;
108+
}
109+
110+
return true;
111+
}
112+
113+
bool TargetIndexMatcher::HasMatchingEqualityFilter(const Segment& segment) {
114+
for (const auto& filter : equality_filters_) {
115+
if (MatchesFilter(filter, segment)) {
116+
return true;
117+
}
118+
}
119+
return false;
120+
}
121+
122+
bool TargetIndexMatcher::MatchesFilter(
123+
const absl::optional<core::FieldFilter>& filter, const Segment& segment) {
124+
if (!filter.has_value()) {
125+
return false;
126+
}
127+
return MatchesFilter(filter.value(), segment);
128+
}
129+
130+
bool TargetIndexMatcher::MatchesFilter(const FieldFilter& filter,
131+
const Segment& segment) {
132+
if (filter.field() != segment.field_path()) {
133+
return false;
134+
}
135+
136+
bool is_array_op = filter.op() == FieldFilter::Operator::ArrayContains ||
137+
filter.op() == FieldFilter::Operator::ArrayContainsAny;
138+
return (segment.kind() == Segment::kContains) == is_array_op;
139+
}
140+
141+
bool TargetIndexMatcher::MatchesOrderBy(const OrderBy& order_by,
142+
const Segment& segment) {
143+
if (order_by.field() != segment.field_path()) {
144+
return false;
145+
}
146+
return (segment.kind() == Segment::kAscending &&
147+
order_by.direction() == core::Direction::Ascending) ||
148+
(segment.kind() == Segment::kDescending &&
149+
order_by.direction() == core::Direction::Descending);
150+
}
151+
152+
} // namespace model
153+
} // namespace firestore
154+
} // namespace firebase

0 commit comments

Comments
 (0)