diff options
Diffstat (limited to 'Firestore/Source')
-rw-r--r-- | Firestore/Source/API/FIRQuery+Internal.h | 35 | ||||
-rw-r--r-- | Firestore/Source/API/FIRQuery.mm | 16 | ||||
-rw-r--r-- | Firestore/Source/Core/FSTQuery.h | 1 | ||||
-rw-r--r-- | Firestore/Source/Core/FSTQuery.mm | 25 | ||||
-rw-r--r-- | Firestore/Source/Remote/FSTSerializerBeta.mm | 4 |
5 files changed, 76 insertions, 5 deletions
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); } |