Skip to content

Commit b673b2a

Browse files
authored
Reimplement FSTFilter classes in terms of C++ Filter classes (#3348)
* Reimplement FSTNullFilter with core::NullFilter * Reimplement FSTRelationFilter with model::RelationFilter * Implement Filter equality
1 parent 722b16d commit b673b2a

File tree

13 files changed

+100
-131
lines changed

13 files changed

+100
-131
lines changed

Firestore/Example/Tests/API/FIRQuerySnapshotTests.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#import "Firestore/Source/Model/FSTDocument.h"
3333

3434
#include "Firestore/core/src/firebase/firestore/core/view_snapshot.h"
35+
#include "Firestore/core/src/firebase/firestore/model/document.h"
3536
#include "Firestore/core/src/firebase/firestore/model/document_set.h"
3637
#include "Firestore/core/src/firebase/firestore/util/string_apple.h"
3738

Firestore/Example/Tests/Model/FSTDocumentSetTests.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#import "Firestore/Source/Model/FSTDocument.h"
2323

2424
// TODO(wilhuff) move to first include once this test filename matches
25+
#include "Firestore/core/src/firebase/firestore/model/document.h"
2526
#include "Firestore/core/src/firebase/firestore/model/document_set.h"
2627
#include "Firestore/core/src/firebase/firestore/util/delayed_constructor.h"
2728
#include "Firestore/core/test/firebase/firestore/testutil/xcgmock.h"

Firestore/Source/Core/FSTQuery.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ NS_ASSUME_NONNULL_BEGIN
8888
- (const model::FieldPath &)field;
8989

9090
/** The type of equality/inequality operator to use in the relation. */
91-
@property(nonatomic, assign, readonly) core::Filter::Operator filterOperator;
91+
- (core::Filter::Operator)filterOperator;
9292

9393
/** The right hand side of the relation. A constant value to compare to. */
94-
@property(nonatomic, assign, readonly) const model::FieldValue &value;
94+
- (const model::FieldValue &)value;
9595

9696
@end
9797

Firestore/Source/Core/FSTQuery.mm

Lines changed: 44 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828

2929
#include "Firestore/core/src/firebase/firestore/api/input_validation.h"
3030
#include "Firestore/core/src/firebase/firestore/core/filter.h"
31+
#include "Firestore/core/src/firebase/firestore/core/nan_filter.h"
32+
#include "Firestore/core/src/firebase/firestore/core/null_filter.h"
3133
#include "Firestore/core/src/firebase/firestore/core/query.h"
34+
#include "Firestore/core/src/firebase/firestore/core/relation_filter.h"
3235
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
3336
#include "Firestore/core/src/firebase/firestore/model/field_path.h"
3437
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
@@ -58,25 +61,6 @@
5861

5962
#pragma mark - Filter::Operator functions
6063

61-
NSString *FSTStringFromQueryRelationOperator(Filter::Operator filterOperator) {
62-
switch (filterOperator) {
63-
case Filter::Operator::LessThan:
64-
return @"<";
65-
case Filter::Operator::LessThanOrEqual:
66-
return @"<=";
67-
case Filter::Operator::Equal:
68-
return @"==";
69-
case Filter::Operator::GreaterThanOrEqual:
70-
return @">=";
71-
case Filter::Operator::GreaterThan:
72-
return @">";
73-
case Filter::Operator::ArrayContains:
74-
return @"array_contains";
75-
default:
76-
HARD_FAIL("Unknown Filter::Operator %s", filterOperator);
77-
}
78-
}
79-
8064
@implementation FSTFilter
8165

8266
+ (instancetype)filterWithField:(const FieldPath &)field
@@ -141,7 +125,7 @@ - (NSString *)canonicalID;
141125
@end
142126

143127
@implementation FSTRelationFilter {
144-
FieldValue _value;
128+
core::RelationFilter _filter;
145129
}
146130

147131
#pragma mark - Constructor methods
@@ -151,202 +135,137 @@ - (instancetype)initWithField:(FieldPath)field
151135
value:(FieldValue)value {
152136
self = [super init];
153137
if (self) {
154-
_field = std::move(field);
155-
_filterOperator = filterOperator;
156-
_value = value;
138+
_filter = core::RelationFilter(std::move(field), filterOperator, std::move(value));
157139
}
158140
return self;
159141
}
160142

161143
#pragma mark - Public Methods
162144

163145
- (BOOL)isInequality {
164-
return self.filterOperator != Filter::Operator::Equal &&
165-
self.filterOperator != Filter::Operator::ArrayContains;
146+
return _filter.IsInequality();
166147
}
167148

168-
- (const firebase::firestore::model::FieldPath &)field {
169-
return _field;
149+
- (const model::FieldPath &)field {
150+
return _filter.field();
151+
}
152+
153+
- (core::Filter::Operator)filterOperator {
154+
return _filter.op();
155+
}
156+
157+
- (const model::FieldValue &)value {
158+
return _filter.value();
170159
}
171160

172161
#pragma mark - NSObject methods
173162

174163
- (NSString *)description {
175-
return [NSString stringWithFormat:@"%s %@ %s", _field.CanonicalString().c_str(),
176-
FSTStringFromQueryRelationOperator(self.filterOperator),
177-
self.value.ToString().c_str()];
164+
return util::MakeNSString(_filter.ToString());
178165
}
179166

180167
- (BOOL)isEqual:(id)other {
181-
if (self == other) {
182-
return YES;
183-
}
184-
if (![other isKindOfClass:[FSTRelationFilter class]]) {
185-
return NO;
186-
}
187-
return [self isEqualToFilter:(FSTRelationFilter *)other];
168+
if (self == other) return YES;
169+
if (![other isKindOfClass:[FSTRelationFilter class]]) return NO;
170+
171+
return _filter == ((FSTRelationFilter *)other)->_filter;
188172
}
189173

190174
#pragma mark - Private methods
191175

192176
- (BOOL)matchesDocument:(FSTDocument *)document {
193-
if (_field.IsKeyFieldPath()) {
194-
HARD_ASSERT(self.value.type() == FieldValue::Type::Reference,
195-
"Comparing on key, but filter value not a Reference.");
196-
HARD_ASSERT(self.filterOperator != Filter::Operator::ArrayContains,
197-
"arrayContains queries don't make sense on document keys.");
198-
const auto &ref = self.value.reference_value();
199-
ComparisonResult comparison = document.key.CompareTo(ref.key());
200-
return [self matchesComparison:comparison];
201-
} else {
202-
auto value = [document fieldForPath:self.field];
203-
if (!value) return false;
204-
205-
return [self matchesValue:*value];
206-
}
177+
model::Document converted(document);
178+
return _filter.Matches(converted);
207179
}
208180

209181
- (NSString *)canonicalID {
210-
// TODO(b/37283291): This should be collision robust and avoid relying on |description| methods.
211-
return [NSString stringWithFormat:@"%s%@%s", _field.CanonicalString().c_str(),
212-
FSTStringFromQueryRelationOperator(self.filterOperator),
213-
self.value.ToString().c_str()];
214-
}
215-
216-
- (BOOL)isEqualToFilter:(FSTRelationFilter *)other {
217-
if (self.filterOperator != other.filterOperator) {
218-
return NO;
219-
}
220-
if (_field != other.field) {
221-
return NO;
222-
}
223-
return self.value == other.value;
224-
}
225-
226-
/** Returns YES if receiver is true with the given value as its LHS. */
227-
- (BOOL)matchesValue:(const FieldValue &)other {
228-
if (self.filterOperator == Filter::Operator::ArrayContains) {
229-
if (other.type() == FieldValue::Type::Array) {
230-
const auto &array = other.array_value();
231-
auto found = absl::c_find(array, self.value);
232-
return found != array.end();
233-
} else {
234-
return false;
235-
}
236-
} else {
237-
// Only perform comparison queries on types with matching backend order (such as double and
238-
// int).
239-
return FieldValue::Comparable(self.value.type(), other.type()) &&
240-
[self matchesComparison:other.CompareTo(self.value)];
241-
}
242-
}
243-
244-
- (BOOL)matchesComparison:(util::ComparisonResult)comparison {
245-
switch (self.filterOperator) {
246-
case Filter::Operator::LessThan:
247-
return comparison == ComparisonResult::Ascending;
248-
case Filter::Operator::LessThanOrEqual:
249-
return comparison == ComparisonResult::Ascending || comparison == ComparisonResult::Same;
250-
case Filter::Operator::Equal:
251-
return comparison == ComparisonResult::Same;
252-
case Filter::Operator::GreaterThanOrEqual:
253-
return comparison == ComparisonResult::Descending || comparison == ComparisonResult::Same;
254-
case Filter::Operator::GreaterThan:
255-
return comparison == ComparisonResult::Descending;
256-
default:
257-
HARD_FAIL("Unknown operator: %s", self.filterOperator);
258-
}
182+
return util::MakeNSString(_filter.CanonicalId());
259183
}
260184

261185
@end
262186

263187
#pragma mark - FSTNullFilter
264188

265-
@interface FSTNullFilter () {
266-
FieldPath _field;
189+
@implementation FSTNullFilter {
190+
core::NullFilter _filter;
267191
}
268-
@end
269192

270-
@implementation FSTNullFilter
271193
- (instancetype)initWithField:(FieldPath)field {
272194
if (self = [super init]) {
273-
_field = std::move(field);
195+
_filter = core::NullFilter(std::move(field));
274196
}
275197
return self;
276198
}
277199

278200
- (BOOL)matchesDocument:(FSTDocument *)document {
279-
absl::optional<FieldValue> fieldValue = [document fieldForPath:self.field];
280-
return fieldValue && fieldValue->type() == FieldValue::Type::Null;
201+
model::Document converted(document);
202+
return _filter.Matches(converted);
281203
}
282204

283205
- (NSString *)canonicalID {
284-
return [NSString stringWithFormat:@"%s IS NULL", _field.CanonicalString().c_str()];
206+
return util::MakeNSString(_filter.CanonicalId());
285207
}
286208

287209
- (const firebase::firestore::model::FieldPath &)field {
288-
return _field;
210+
return _filter.field();
289211
}
290212

291213
- (NSString *)description {
292-
return [self canonicalID];
214+
return util::MakeNSString(_filter.ToString());
293215
}
294216

295217
- (BOOL)isEqual:(id)other {
296218
if (other == self) return YES;
297219
if (![[other class] isEqual:[self class]]) return NO;
298220

299-
return _field == ((FSTNullFilter *)other)->_field;
221+
return _filter == ((FSTNullFilter *)other)->_filter;
300222
}
301223

302224
- (NSUInteger)hash {
303-
return util::Hash(_field);
225+
return _filter.Hash();
304226
}
305227

306228
@end
307229

308230
#pragma mark - FSTNanFilter
309231

310-
@interface FSTNanFilter () {
311-
FieldPath _field;
232+
@implementation FSTNanFilter {
233+
core::NanFilter _filter;
312234
}
313-
@end
314-
315-
@implementation FSTNanFilter
316235

317236
- (instancetype)initWithField:(FieldPath)field {
318237
if (self = [super init]) {
319-
_field = std::move(field);
238+
_filter = core::NanFilter(field);
320239
}
321240
return self;
322241
}
323242

324243
- (BOOL)matchesDocument:(FSTDocument *)document {
325-
absl::optional<FieldValue> fieldValue = [document fieldForPath:self.field];
326-
return fieldValue && fieldValue->is_nan();
244+
model::Document converted(document);
245+
return _filter.Matches(converted);
327246
}
328247

329248
- (NSString *)canonicalID {
330-
return [NSString stringWithFormat:@"%s IS NaN", _field.CanonicalString().c_str()];
249+
return util::MakeNSString(_filter.CanonicalId());
331250
}
332251

333252
- (const firebase::firestore::model::FieldPath &)field {
334-
return _field;
253+
return _filter.field();
335254
}
336255

337256
- (NSString *)description {
338-
return [self canonicalID];
257+
return util::MakeNSString(_filter.ToString());
339258
}
340259

341260
- (BOOL)isEqual:(id)other {
342261
if (other == self) return YES;
343262
if (![[other class] isEqual:[self class]]) return NO;
344263

345-
return _field == ((FSTNanFilter *)other)->_field;
264+
return _filter == ((FSTNanFilter *)other)->_filter;
346265
}
347266

348267
- (NSUInteger)hash {
349-
return util::Hash(_field);
268+
return _filter.Hash();
350269
}
351270
@end
352271

Firestore/Source/Model/FSTDocument.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#import <Foundation/Foundation.h>
1818

19-
#include "Firestore/core/src/firebase/firestore/model/document.h"
2019
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2120
#include "Firestore/core/src/firebase/firestore/model/field_path.h"
2221
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
@@ -26,6 +25,16 @@
2625
@class GCFSDocument;
2726
@class FSTObjectValue;
2827

28+
namespace firebase {
29+
namespace firestore {
30+
namespace model {
31+
32+
enum class DocumentState;
33+
34+
} // namespace model
35+
} // namespace firestore
36+
} // namespace firebase
37+
2938
namespace model = firebase::firestore::model;
3039

3140
NS_ASSUME_NONNULL_BEGIN
@@ -63,6 +72,7 @@ NS_ASSUME_NONNULL_BEGIN
6372
- (bool)hasCommittedMutations;
6473

6574
@property(nonatomic, assign, readonly) const model::ObjectValue &data;
75+
@property(nonatomic, assign, readonly) model::DocumentState documentState;
6676

6777
/**
6878
* Memoized serialized form of the document for optimization purposes (avoids repeated

Firestore/Source/Model/FSTDocument.mm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#import "Firestore/Source/Util/FSTClasses.h"
2222

23+
#include "Firestore/core/src/firebase/firestore/model/document.h"
2324
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
2425
#include "Firestore/core/src/firebase/firestore/model/field_path.h"
2526
#include "Firestore/core/src/firebase/firestore/model/field_value.h"
@@ -31,6 +32,7 @@
3132
#include "absl/types/optional.h"
3233

3334
namespace util = firebase::firestore::util;
35+
using firebase::firestore::model::Document;
3436
using firebase::firestore::model::DocumentKey;
3537
using firebase::firestore::model::DocumentState;
3638
using firebase::firestore::model::FieldPath;

Firestore/Source/Model/FSTMutation.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#import "Firestore/Source/Util/FSTClasses.h"
2929

3030
#include "Firestore/core/include/firebase/firestore/timestamp.h"
31+
#include "Firestore/core/src/firebase/firestore/model/document.h"
3132
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
3233
#include "Firestore/core/src/firebase/firestore/model/field_mask.h"
3334
#include "Firestore/core/src/firebase/firestore/model/field_path.h"

Firestore/core/src/firebase/firestore/core/nan_filter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace core {
2929
/** Filter that matches NaN (not-a-number) values. */
3030
class NanFilter : public Filter {
3131
public:
32+
NanFilter() = default;
33+
3234
explicit NanFilter(model::FieldPath field);
3335

3436
Type type() const override {

Firestore/core/src/firebase/firestore/core/null_filter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace core {
2929
/** Filter that matches NaN (not-a-number) values. */
3030
class NullFilter : public Filter {
3131
public:
32+
NullFilter() = default;
33+
3234
explicit NullFilter(model::FieldPath field);
3335

3436
Type type() const override {

0 commit comments

Comments
 (0)