aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Michael Lehenbauer <mikelehen@gmail.com>2018-04-23 10:03:55 -0700
committerGravatar GitHub <noreply@github.com>2018-04-23 10:03:55 -0700
commite4384c3e809556e75907df74cd116307f397472f (patch)
tree98841eba1d45eb94adcb798b6f792c16ba4b8d18
parent8e70791465f9b5e4bb75dfc18de4a4ed90961974 (diff)
Array Contains Queries (not added to public headers yet). (#1138)
-rw-r--r--Firestore/Example/SwiftBuildTest/main.swift3
-rw-r--r--Firestore/Example/Tests/Core/FSTQueryTests.mm49
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRQueryTests.mm45
-rw-r--r--Firestore/Example/Tests/Integration/API/FIRValidationTests.mm22
-rw-r--r--Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm24
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.h2
-rw-r--r--Firestore/Example/Tests/Util/FSTHelpers.mm2
-rw-r--r--Firestore/Source/API/FIRQuery+Internal.h35
-rw-r--r--Firestore/Source/API/FIRQuery.mm16
-rw-r--r--Firestore/Source/Core/FSTQuery.h1
-rw-r--r--Firestore/Source/Core/FSTQuery.mm25
-rw-r--r--Firestore/Source/Remote/FSTSerializerBeta.mm4
12 files changed, 217 insertions, 11 deletions
diff --git a/Firestore/Example/SwiftBuildTest/main.swift b/Firestore/Example/SwiftBuildTest/main.swift
index f04de5b..c5034da 100644
--- a/Firestore/Example/SwiftBuildTest/main.swift
+++ b/Firestore/Example/SwiftBuildTest/main.swift
@@ -83,6 +83,9 @@ func makeRefs(database db: Firestore) -> (CollectionReference, DocumentReference
func makeQuery(collection collectionRef: CollectionReference) -> Query {
let query = collectionRef.whereField(FieldPath(["name"]), isEqualTo: "Fred")
.whereField("age", isGreaterThanOrEqualTo: 24)
+ // TODO(array-features): Uncomment when API is publicly exposed.
+ // .whereField("tags", arrayContains:"active")
+ // .whereField(FieldPath(["tags"]), arrayContains:"active")
.whereField(FieldPath.documentID(), isEqualTo: "fred")
.order(by: FieldPath(["age"]))
.order(by: "name", descending: true)
diff --git a/Firestore/Example/Tests/Core/FSTQueryTests.mm b/Firestore/Example/Tests/Core/FSTQueryTests.mm
index 02310aa..6118d0f 100644
--- a/Firestore/Example/Tests/Core/FSTQueryTests.mm
+++ b/Firestore/Example/Tests/Core/FSTQueryTests.mm
@@ -151,6 +151,55 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertFalse([query2 matchesDocument:doc6]);
}
+- (void)testArrayContainsFilter {
+ FSTQuery *query = [FSTTestQuery("collection")
+ queryByAddingFilter:FSTTestFilter("array", @"array_contains", @42)];
+
+ // not an array.
+ FSTDocument *doc = FSTTestDoc("collection/1", 0, @{ @"array" : @1 }, NO);
+ XCTAssertFalse([query matchesDocument:doc]);
+
+ // empty array.
+ doc = FSTTestDoc("collection/1", 0, @{ @"array" : @[] }, NO);
+ XCTAssertFalse([query matchesDocument:doc]);
+
+ // array without element (and make sure it doesn't match in a nested field or a different field).
+ doc = FSTTestDoc(
+ "collection/1", 0,
+ @{ @"array" : @[ @41, @"42",
+ @{ @"a" : @42,
+ @"b" : @[ @42 ] } ],
+ @"different" : @[ @42 ] },
+ NO);
+ XCTAssertFalse([query matchesDocument:doc]);
+
+ // array with element.
+ doc = FSTTestDoc("collection/1", 0, @{ @"array" : @[ @1, @"2", @42, @{ @"a" : @1 } ] }, NO);
+ XCTAssertTrue([query matchesDocument:doc]);
+}
+
+- (void)testArrayContainsFilterWithObjectValue {
+ // Search for arrays containing the object { a: [42] }
+ FSTQuery *query =
+ [FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("array", @"array_contains",
+ @{ @"a" : @[ @42 ] })];
+
+ // array without element.
+ FSTDocument *doc = FSTTestDoc(
+ "collection/1", 0,
+ @{ @"array" : @[
+ @{ @"a" : @42 },
+ @{ @"a" : @[ @42, @43 ] },
+ @{ @"b" : @[ @42 ] }
+ ] },
+ NO);
+ XCTAssertFalse([query matchesDocument:doc]);
+
+ // array with element.
+ doc = FSTTestDoc("collection/1", 0, @{ @"array" : @[ @1, @"2", @42, @{ @"a" : @[ @42 ] } ] }, NO);
+ XCTAssertTrue([query matchesDocument:doc]);
+}
+
- (void)testNullFilter {
FSTQuery *query =
[FSTTestQuery("collection") queryByAddingFilter:FSTTestFilter("sort", @"==", [NSNull null])];
diff --git a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm
index d1c0d75..bdd3df1 100644
--- a/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm
+++ b/Firestore/Example/Tests/Integration/API/FIRQueryTests.mm
@@ -20,8 +20,7 @@
#import "Firestore/Example/Tests/Util/FSTEventAccumulator.h"
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
-#import "Firestore/Source/API/FIRFirestore+Internal.h"
-#import "Firestore/Source/Core/FSTFirestoreClient.h"
+#import "Firestore/Source/API/FIRQuery+Internal.h"
@interface FIRQueryTests : FSTIntegrationTestCase
@end
@@ -294,4 +293,46 @@
]));
}
+// TODO(array-features): Enable once backend support lands.
+- (void)xtestArrayContainsQueries {
+ NSDictionary *testDocs = @{
+ @"a" : @{@"array" : @[ @42 ]},
+ @"b" : @{@"array" : @[ @"a", @42, @"c" ]},
+ @"c" : @{@"array" : @[ @41.999, @"42",
+ @{ @"a" : @[ @42 ] } ]},
+ @"d" : @{@"array" : @[ @42 ], @"array2" : @[ @"bingo" ]}
+ };
+ FIRCollectionReference *collection = [self collectionRefWithDocuments:testDocs];
+
+ // Search for 42
+ FIRQuerySnapshot *snapshot =
+ [self readDocumentSetForRef:[collection queryWhereField:@"array" arrayContains:@42]];
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[
+ @{ @"array" : @[ @42 ] },
+ @{ @"array" : @[ @"a", @42, @"c" ] },
+ @{ @"array" : @[ @42 ],
+ @"array2" : @[ @"bingo" ] }
+ ]));
+
+ // Search for "array" to contain both @42 and "a".
+ snapshot = [self readDocumentSetForRef:[[collection queryWhereField:@"array" arrayContains:@42]
+ queryWhereField:@"array"
+ arrayContains:@"a"]];
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[
+ @{ @"array" : @[ @"a", @42, @"c" ] },
+ ]));
+
+ // Search two different array fields ("array" contains 42 and "array2" contains "bingo").
+ snapshot = [self readDocumentSetForRef:[[collection queryWhereField:@"array" arrayContains:@42]
+ queryWhereField:@"array2"
+ arrayContains:@"bingo"]];
+ XCTAssertEqualObjects(FIRQuerySnapshotGetData(snapshot), (@[
+ @{ @"array" : @[ @42 ],
+ @"array2" : @[ @"bingo" ] }
+ ]));
+
+ // NOTE: The backend doesn't currently support null, NaN, objects, or arrays, so there isn't much
+ // of anything else interesting to test.
+}
+
@end
diff --git a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
index ee0f386..6d10aba 100644
--- a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
+++ b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm
@@ -19,6 +19,7 @@
#import <XCTest/XCTest.h>
#import "Firestore/Source/API/FIRFieldValue+Internal.h"
+#import "Firestore/Source/API/FIRQuery+Internal.h"
#import "Firestore/Example/Tests/Util/FSTHelpers.h"
#import "Firestore/Example/Tests/Util/FSTIntegrationTestCase.h"
@@ -419,14 +420,20 @@
@"Invalid Query. Query limit (-1) is invalid. Limit must be positive.");
}
-- (void)testQueryInequalityOnNullOrNaNFails {
+- (void)testNonEqualityQueriesOnNullOrNaNFail {
FSTAssertThrows([[self collectionRef] queryWhereField:@"a" isGreaterThan:nil],
@"Invalid Query. You can only perform equality comparisons on nil / NSNull.");
FSTAssertThrows([[self collectionRef] queryWhereField:@"a" isGreaterThan:[NSNull null]],
@"Invalid Query. You can only perform equality comparisons on nil / NSNull.");
+ FSTAssertThrows([[self collectionRef] queryWhereField:@"a" arrayContains:nil],
+ @"Invalid Query. You can only perform equality comparisons on nil / NSNull.");
+ FSTAssertThrows([[self collectionRef] queryWhereField:@"a" arrayContains:[NSNull null]],
+ @"Invalid Query. You can only perform equality comparisons on nil / NSNull.");
FSTAssertThrows([[self collectionRef] queryWhereField:@"a" isGreaterThan:@(NAN)],
@"Invalid Query. You can only perform equality comparisons on NaN.");
+ FSTAssertThrows([[self collectionRef] queryWhereField:@"a" arrayContains:@(NAN)],
+ @"Invalid Query. You can only perform equality comparisons on NaN.");
}
- (void)testQueryCannotBeCreatedFromDocumentsMissingSortValues {
@@ -498,6 +505,12 @@
@"Invalid query. When querying by document ID you must provide a valid string or "
"DocumentReference, but it was of type: __NSCFNumber";
FSTAssertThrows([collection queryWhereFieldPath:[FIRFieldPath documentID] isEqualTo:@1], reason);
+
+ reason =
+ @"Invalid query. You can't do arrayContains queries on document ID since document IDs are "
+ @"not arrays.";
+ FSTAssertThrows([collection queryWhereFieldPath:[FIRFieldPath documentID] arrayContains:@1],
+ reason);
}
- (void)testQueryInequalityFieldMustMatchFirstOrderByField {
@@ -526,6 +539,8 @@
XCTAssertNoThrow([base queryWhereField:@"y" isEqualTo:@"cat"],
@"Inequality and equality on different fields works");
+ XCTAssertNoThrow([base queryWhereField:@"y" arrayContains:@"cat"],
+ @"Inequality and array_contains on different fields works");
XCTAssertNoThrow([base queryOrderedByField:@"x"], @"inequality same as order by works");
XCTAssertNoThrow([[coll queryOrderedByField:@"x"] queryWhereField:@"x" isGreaterThan:@32],
@@ -535,6 +550,11 @@
XCTAssertNoThrow([[[coll queryOrderedByField:@"x"] queryOrderedByField:@"y"] queryWhereField:@"x"
isGreaterThan:@32],
@"inequality same as first order by works.");
+
+ XCTAssertNoThrow([[coll queryOrderedByField:@"x"] queryWhereField:@"y" isEqualTo:@"cat"],
+ @"equality different than orderBy works.");
+ XCTAssertNoThrow([[coll queryOrderedByField:@"x"] queryWhereField:@"y" arrayContains:@"cat"],
+ @"array_contains different than orderBy works.");
}
#pragma mark - GeoPoint Validation
diff --git a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
index 8d62b4d..bbb3822 100644
--- a/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
+++ b/Firestore/Example/Tests/Remote/FSTSerializerBetaTests.mm
@@ -487,6 +487,18 @@ NS_ASSUME_NONNULL_BEGIN
XCTAssertEqualObjects(actual, expected);
}
+- (void)testEncodesArrayContainsFilter {
+ FSTRelationFilter *input = FSTTestFilter("item.tags", @"array_contains", @"food");
+ GCFSStructuredQuery_Filter *actual = [self.serializer encodedRelationFilter:input];
+
+ GCFSStructuredQuery_Filter *expected = [GCFSStructuredQuery_Filter message];
+ GCFSStructuredQuery_FieldFilter *prop = expected.fieldFilter;
+ prop.field.fieldPath = @"item.tags";
+ prop.op = GCFSStructuredQuery_FieldFilter_Operator_ArrayContains;
+ prop.value.stringValue = @"food";
+ XCTAssertEqualObjects(actual, expected);
+}
+
#pragma mark - encodedQuery
- (void)testEncodesFirstLevelKeyQueries {
@@ -556,9 +568,10 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)testEncodesMultipleFiltersOnDeeperCollections {
- FSTQuery *q = [[FSTTestQuery("rooms/1/messages/10/attachments")
+ FSTQuery *q = [[[FSTTestQuery("rooms/1/messages/10/attachments")
queryByAddingFilter:FSTTestFilter("prop", @">=", @(42))]
- queryByAddingFilter:FSTTestFilter("author", @"==", @"dimond")];
+ queryByAddingFilter:FSTTestFilter("author", @"==", @"dimond")]
+ queryByAddingFilter:FSTTestFilter("tags", @"array_contains", @"pending")];
FSTQueryData *model = [self queryDataForQuery:q];
GCFSTarget *expected = [GCFSTarget message];
@@ -579,11 +592,18 @@ NS_ASSUME_NONNULL_BEGIN
field2.op = GCFSStructuredQuery_FieldFilter_Operator_Equal;
field2.value.stringValue = @"dimond";
+ GCFSStructuredQuery_Filter *filter3 = [GCFSStructuredQuery_Filter message];
+ GCFSStructuredQuery_FieldFilter *field3 = filter3.fieldFilter;
+ field3.field.fieldPath = @"tags";
+ field3.op = GCFSStructuredQuery_FieldFilter_Operator_ArrayContains;
+ field3.value.stringValue = @"pending";
+
GCFSStructuredQuery_CompositeFilter *composite =
expected.query.structuredQuery.where.compositeFilter;
composite.op = GCFSStructuredQuery_CompositeFilter_Operator_And;
[composite.filtersArray addObject:filter1];
[composite.filtersArray addObject:filter2];
+ [composite.filtersArray addObject:filter3];
[expected.query.structuredQuery.orderByArray
addObject:[GCFSStructuredQuery_Order messageWithProperty:@"prop" ascending:YES]];
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.h b/Firestore/Example/Tests/Util/FSTHelpers.h
index 9b5f96a..131da2d 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.h
+++ b/Firestore/Example/Tests/Util/FSTHelpers.h
@@ -212,7 +212,7 @@ FSTQuery *FSTTestQuery(const absl::string_view path);
/**
* A convenience method to create a FSTFilter using a string representation for both field
- * and operator (<, <=, ==, >=, >).
+ * and operator (<, <=, ==, >=, >, array_contains).
*/
id<FSTFilter> FSTTestFilter(const absl::string_view field, NSString *op, id value);
diff --git a/Firestore/Example/Tests/Util/FSTHelpers.mm b/Firestore/Example/Tests/Util/FSTHelpers.mm
index e1ed18c..888a45f 100644
--- a/Firestore/Example/Tests/Util/FSTHelpers.mm
+++ b/Firestore/Example/Tests/Util/FSTHelpers.mm
@@ -210,6 +210,8 @@ id<FSTFilter> FSTTestFilter(const absl::string_view field, NSString *opString, i
op = FSTRelationFilterOperatorGreaterThanOrEqual;
} else if ([opString isEqualToString:@">"]) {
op = FSTRelationFilterOperatorGreaterThan;
+ } else if ([opString isEqualToString:@"array_contains"]) {
+ op = FSTRelationFilterOperatorArrayContains;
} else {
FSTCFail(@"Unsupported operator type: %@", opString);
}
diff --git a/Firestore/Source/API/FIRQuery+Internal.h b/Firestore/Source/API/FIRQuery+Internal.h
index 3c2b2a7..c4f9f23 100644
--- a/Firestore/Source/API/FIRQuery+Internal.h
+++ b/Firestore/Source/API/FIRQuery+Internal.h
@@ -23,7 +23,42 @@ NS_ASSUME_NONNULL_BEGIN
/** Internal FIRQuery API we don't want exposed in our public header files. */
@interface FIRQuery (Internal)
+ (FIRQuery *)referenceWithQuery:(FSTQuery *)query firestore:(FIRFirestore *)firestore;
+
@property(nonatomic, strong, readonly) FSTQuery *query;
+
+@end
+
+// TODO(array-features): Move to FIRQuery.h once backend support is available.
+@interface FIRQuery ()
+
+/**
+ * Creates and returns a new `FIRQuery` with the additional filter that documents must contain
+ * the specified field, it must be an array, and the array must contain the provided value.
+ *
+ * @param field The name of the field containing an array to search
+ * @param value The value that must be contained in the array
+ *
+ * @return The created `FIRQuery`.
+ */
+// clang-format off
+- (FIRQuery *)queryWhereField:(NSString *)field
+ arrayContains:(id)value NS_SWIFT_NAME(whereField(_:arrayContains:));
+// clang-format on
+
+/**
+ * Creates and returns a new `FIRQuery` with the additional filter that documents must contain
+ * the specified field, it must be an array, and the array must contain the provided value.
+ *
+ * @param path The path of the field containing an array to search
+ * @param value The value that must be contained in the array
+ *
+ * @return The created `FIRQuery`.
+ */
+// clang-format off
+- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path
+ arrayContains:(id)value NS_SWIFT_NAME(whereField(_:arrayContains:));
+// clang-format on
+
@end
NS_ASSUME_NONNULL_END
diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm
index 2d78ac0..32d8327 100644
--- a/Firestore/Source/API/FIRQuery.mm
+++ b/Firestore/Source/API/FIRQuery.mm
@@ -238,6 +238,17 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
value:value];
}
+- (FIRQuery *)queryWhereField:(NSString *)field arrayContains:(id)value {
+ return
+ [self queryWithFilterOperator:FSTRelationFilterOperatorArrayContains field:field value:value];
+}
+
+- (FIRQuery *)queryWhereFieldPath:(FIRFieldPath *)path arrayContains:(id)value {
+ return [self queryWithFilterOperator:FSTRelationFilterOperatorArrayContains
+ path:path.internalValue
+ value:value];
+}
+
- (FIRQuery *)queryWhereField:(NSString *)field isGreaterThanOrEqualTo:(id)value {
return [self queryWithFilterOperator:FSTRelationFilterOperatorGreaterThanOrEqual
field:field
@@ -443,6 +454,11 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions
value:(id)value {
FSTFieldValue *fieldValue;
if (fieldPath.IsKeyFieldPath()) {
+ if (filterOperator == FSTRelationFilterOperatorArrayContains) {
+ FSTThrowInvalidArgument(
+ @"Invalid query. You can't do arrayContains queries on document ID since document IDs "
+ @"are not arrays.");
+ }
if ([value isKindOfClass:[NSString class]]) {
NSString *documentKey = (NSString *)value;
if ([documentKey containsString:@"/"]) {
diff --git a/Firestore/Source/Core/FSTQuery.h b/Firestore/Source/Core/FSTQuery.h
index 3a67e7f..572fabb 100644
--- a/Firestore/Source/Core/FSTQuery.h
+++ b/Firestore/Source/Core/FSTQuery.h
@@ -34,6 +34,7 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) {
FSTRelationFilterOperatorEqual,
FSTRelationFilterOperatorGreaterThanOrEqual,
FSTRelationFilterOperatorGreaterThan,
+ FSTRelationFilterOperatorArrayContains,
};
/** Interface used for all query filters. */
diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm
index 8f49c26..0cd11e8 100644
--- a/Firestore/Source/Core/FSTQuery.mm
+++ b/Firestore/Source/Core/FSTQuery.mm
@@ -58,6 +58,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
return @">=";
case FSTRelationFilterOperatorGreaterThan:
return @">";
+ case FSTRelationFilterOperatorArrayContains:
+ return @"array_contains";
default:
FSTCFail(@"Unknown FSTRelationFilterOperator %lu", (unsigned long)filterOperator);
}
@@ -119,7 +121,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
#pragma mark - Public Methods
- (BOOL)isInequality {
- return self.filterOperator != FSTRelationFilterOperatorEqual;
+ return self.filterOperator != FSTRelationFilterOperatorEqual &&
+ self.filterOperator != FSTRelationFilterOperatorArrayContains;
}
- (const firebase::firestore::model::FieldPath &)field {
@@ -150,6 +153,8 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
if (_field.IsKeyFieldPath()) {
FSTAssert([self.value isKindOfClass:[FSTReferenceValue class]],
@"Comparing on key, but filter value not a FSTReferenceValue.");
+ FSTAssert(self.filterOperator != FSTRelationFilterOperatorArrayContains,
+ @"arrayContains queries don't make sense on document keys.");
FSTReferenceValue *refValue = (FSTReferenceValue *)self.value;
NSComparisonResult comparison = FSTDocumentKeyComparator(document.key, refValue.value);
return [self matchesComparison:comparison];
@@ -180,9 +185,19 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
/** Returns YES if receiver is true with the given value as its LHS. */
- (BOOL)matchesValue:(FSTFieldValue *)other {
- // Only compare types with matching backend order (such as double and int).
- return self.value.typeOrder == other.typeOrder &&
- [self matchesComparison:[other compare:self.value]];
+ if (self.filterOperator == FSTRelationFilterOperatorArrayContains) {
+ if ([other isMemberOfClass:[FSTArrayValue class]]) {
+ FSTArrayValue *arrayValue = (FSTArrayValue *)other;
+ return [arrayValue.internalValue containsObject:self.value];
+ } else {
+ return false;
+ }
+ } else {
+ // Only perform comparison queries on types with matching backend order (such as double and
+ // int).
+ return self.value.typeOrder == other.typeOrder &&
+ [self matchesComparison:[other compare:self.value]];
+ }
}
- (BOOL)matchesComparison:(NSComparisonResult)comparison {
@@ -701,7 +716,7 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe
- (const FieldPath *)inequalityFilterField {
for (id<FSTFilter> filter in self.filters) {
if ([filter isKindOfClass:[FSTRelationFilter class]] &&
- ((FSTRelationFilter *)filter).filterOperator != FSTRelationFilterOperatorEqual) {
+ ((FSTRelationFilter *)filter).isInequality) {
return &filter.field;
}
}
diff --git a/Firestore/Source/Remote/FSTSerializerBeta.mm b/Firestore/Source/Remote/FSTSerializerBeta.mm
index ebb49a7..5cbfecc 100644
--- a/Firestore/Source/Remote/FSTSerializerBeta.mm
+++ b/Firestore/Source/Remote/FSTSerializerBeta.mm
@@ -952,6 +952,8 @@ NS_ASSUME_NONNULL_BEGIN
return GCFSStructuredQuery_FieldFilter_Operator_GreaterThanOrEqual;
case FSTRelationFilterOperatorGreaterThan:
return GCFSStructuredQuery_FieldFilter_Operator_GreaterThan;
+ case FSTRelationFilterOperatorArrayContains:
+ return GCFSStructuredQuery_FieldFilter_Operator_ArrayContains;
default:
FSTFail(@"Unhandled FSTRelationFilterOperator: %ld", (long)filterOperator);
}
@@ -970,6 +972,8 @@ NS_ASSUME_NONNULL_BEGIN
return FSTRelationFilterOperatorGreaterThanOrEqual;
case GCFSStructuredQuery_FieldFilter_Operator_GreaterThan:
return FSTRelationFilterOperatorGreaterThan;
+ case GCFSStructuredQuery_FieldFilter_Operator_ArrayContains:
+ return FSTRelationFilterOperatorArrayContains;
default:
FSTFail(@"Unhandled FieldFilter.operator: %d", filterOperator);
}