From 0ec836f9ca71b27fa54a11ae9e07e60b8c5cc002 Mon Sep 17 00:00:00 2001 From: Michael Lehenbauer Date: Wed, 16 May 2018 17:05:33 -0700 Subject: b/79432277: Limit Queries to only a single array-contains clause. (#1286) --- Firestore/Example/Tests/Integration/API/FIRValidationTests.mm | 7 +++++++ Firestore/Source/API/FIRQuery+Internal.h | 4 ++++ Firestore/Source/API/FIRQuery.mm | 5 +++++ Firestore/Source/Core/FSTQuery.h | 3 +++ Firestore/Source/Core/FSTQuery.mm | 10 ++++++++++ 5 files changed, 29 insertions(+) diff --git a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm index 8af8d15..599f1b2 100644 --- a/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm +++ b/Firestore/Example/Tests/Integration/API/FIRValidationTests.mm @@ -557,6 +557,13 @@ @"array_contains different than orderBy works."); } +- (void)testQueryMustNotHaveMultipleArrayContainsFilters { + FIRCollectionReference *coll = [self.db collectionWithPath:@"collection"]; + FSTAssertThrows( + [[coll queryWhereField:@"foo" arrayContains:@1] queryWhereField:@"foo" arrayContains:@2], + @"Invalid Query. Queries only support a single arrayContains filter."); +} + #pragma mark - GeoPoint Validation - (void)testInvalidGeoPointParameters { diff --git a/Firestore/Source/API/FIRQuery+Internal.h b/Firestore/Source/API/FIRQuery+Internal.h index c4f9f23..e207837 100644 --- a/Firestore/Source/API/FIRQuery+Internal.h +++ b/Firestore/Source/API/FIRQuery+Internal.h @@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN * 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. * + * A query can have only one arrayContains filter. + * * @param field The name of the field containing an array to search * @param value The value that must be contained in the array * @@ -49,6 +51,8 @@ NS_ASSUME_NONNULL_BEGIN * 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. * + * A query can have only one arrayContains filter. + * * @param path The path of the field containing an array to search * @param value The value that must be contained in the array * diff --git a/Firestore/Source/API/FIRQuery.mm b/Firestore/Source/API/FIRQuery.mm index 596f6ac..ad4d2aa 100644 --- a/Firestore/Source/API/FIRQuery.mm +++ b/Firestore/Source/API/FIRQuery.mm @@ -527,6 +527,11 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions if (firstOrderByField) { [self validateOrderByField:*firstOrderByField matchesInequalityField:filter.field]; } + } else if (filter.filterOperator == FSTRelationFilterOperatorArrayContains) { + if ([self.query hasArrayContainsFilter]) { + FSTThrowInvalidUsage(@"InvalidQueryException", + @"Invalid Query. Queries only support a single arrayContains filter."); + } } } diff --git a/Firestore/Source/Core/FSTQuery.h b/Firestore/Source/Core/FSTQuery.h index 572fabb..e38d3dd 100644 --- a/Firestore/Source/Core/FSTQuery.h +++ b/Firestore/Source/Core/FSTQuery.h @@ -245,6 +245,9 @@ typedef NS_ENUM(NSInteger, FSTRelationFilterOperator) { */ - (const firebase::firestore::model::FieldPath *)inequalityFilterField; +/** Returns YES if the query has an arrayContains filter already. */ +- (BOOL)hasArrayContainsFilter; + /** Returns the first field in an order-by constraint, or nullptr if none. */ - (const firebase::firestore::model::FieldPath *)firstSortOrderField; diff --git a/Firestore/Source/Core/FSTQuery.mm b/Firestore/Source/Core/FSTQuery.mm index d3961e8..13ebadb 100644 --- a/Firestore/Source/Core/FSTQuery.mm +++ b/Firestore/Source/Core/FSTQuery.mm @@ -724,6 +724,16 @@ NSString *FSTStringFromQueryRelationOperator(FSTRelationFilterOperator filterOpe return nullptr; } +- (BOOL)hasArrayContainsFilter { + for (id filter in self.filters) { + if ([filter isKindOfClass:[FSTRelationFilter class]] && + ((FSTRelationFilter *)filter).filterOperator == FSTRelationFilterOperatorArrayContains) { + return YES; + } + } + return NO; +} + - (const FieldPath *)firstSortOrderField { if (self.explicitSortOrders.count > 0) { return &self.explicitSortOrders.firstObject.field; -- cgit v1.2.3