diff options
Diffstat (limited to 'Firestore/Source')
-rw-r--r-- | Firestore/Source/API/FIRQuery+Internal.h | 2 | ||||
-rw-r--r-- | Firestore/Source/API/FIRQuery.m | 92 | ||||
-rw-r--r-- | Firestore/Source/Public/FIRQuery.h | 13 |
3 files changed, 107 insertions, 0 deletions
diff --git a/Firestore/Source/API/FIRQuery+Internal.h b/Firestore/Source/API/FIRQuery+Internal.h index 3c2b2a7..b443c2f 100644 --- a/Firestore/Source/API/FIRQuery+Internal.h +++ b/Firestore/Source/API/FIRQuery+Internal.h @@ -23,6 +23,8 @@ 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; +- (FIRQuery *)queryFilteredUsingComparisonPredicate:(NSPredicate *)predicate; +- (FIRQuery *)queryFilteredUsingCompoundPredicate:(NSPredicate *)predicate; @property(nonatomic, strong, readonly) FSTQuery *query; @end diff --git a/Firestore/Source/API/FIRQuery.m b/Firestore/Source/API/FIRQuery.m index 12e79c5..9ab854a 100644 --- a/Firestore/Source/API/FIRQuery.m +++ b/Firestore/Source/API/FIRQuery.m @@ -256,6 +256,98 @@ addSnapshotListenerInternalWithOptions:(FSTListenOptions *)internalOptions value:value]; } +- (FIRQuery *)queryFilteredUsingComparisonPredicate:(NSPredicate *)predicate { + NSComparisonPredicate *comparison = (NSComparisonPredicate *)predicate; + if (comparison.comparisonPredicateModifier != NSDirectPredicateModifier) { + FSTThrowInvalidArgument(@"Invalid query. Predicate cannot have an " + "aggregate modifier."); + } + NSString *path; + id value = nil; + if ([comparison.leftExpression expressionType] == NSKeyPathExpressionType && + [comparison.rightExpression expressionType] == NSConstantValueExpressionType) { + path = comparison.leftExpression.keyPath; + value = comparison.rightExpression.constantValue; + switch (comparison.predicateOperatorType) { + case NSEqualToPredicateOperatorType: + return [self queryWhereField:path isEqualTo:value]; + case NSLessThanPredicateOperatorType: + return [self queryWhereField:path isLessThan:value]; + case NSLessThanOrEqualToPredicateOperatorType: + return [self queryWhereField:path isLessThanOrEqualTo:value]; + case NSGreaterThanPredicateOperatorType: + return [self queryWhereField:path isGreaterThan:value]; + case NSGreaterThanOrEqualToPredicateOperatorType: + return [self queryWhereField:path isGreaterThanOrEqualTo:value]; + default: + ; // Fallback below to throw assertion. + } + } else if ([comparison.leftExpression expressionType] == NSConstantValueExpressionType && + [comparison.rightExpression expressionType] == NSKeyPathExpressionType) { + path = comparison.rightExpression.keyPath; + value = comparison.leftExpression.constantValue; + switch (comparison.predicateOperatorType) { + case NSEqualToPredicateOperatorType: + return [self queryWhereField:path isEqualTo:value]; + case NSLessThanPredicateOperatorType: + return [self queryWhereField:path isGreaterThan:value]; + case NSLessThanOrEqualToPredicateOperatorType: + return [self queryWhereField:path isGreaterThanOrEqualTo:value]; + case NSGreaterThanPredicateOperatorType: + return [self queryWhereField:path isLessThan:value]; + case NSGreaterThanOrEqualToPredicateOperatorType: + return [self queryWhereField:path isLessThanOrEqualTo:value]; + default: + ; // Fallback below to throw assertion. + } + } else { + FSTThrowInvalidArgument(@"Invalid query. Predicate comparisons must " + "include a key path and a constant."); + } + // Fallback cases of unsupported comparison operator. + switch (comparison.predicateOperatorType) { + case NSCustomSelectorPredicateOperatorType: + FSTThrowInvalidArgument(@"Invalid query. Custom predicate filters are " + "not supported."); + break; + default: + FSTThrowInvalidArgument(@"Invalid query. Operator type %lu is not supported.", + (unsigned long)comparison.predicateOperatorType); + } +} + +- (FIRQuery *)queryFilteredUsingCompoundPredicate:(NSPredicate *)predicate { + NSCompoundPredicate *compound = (NSCompoundPredicate *)predicate; + if (compound.compoundPredicateType != NSAndPredicateType || + compound.subpredicates.count == 0) { + FSTThrowInvalidArgument(@"Invalid query. Only compound queries using AND " + "are supported."); + } + FIRQuery *query = self; + for (NSPredicate *pred in compound.subpredicates) { + query = [query queryFilteredUsingPredicate:pred]; + } + return query; +} + +- (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate { + if ([predicate isKindOfClass:[NSComparisonPredicate class]]) { + return [self queryFilteredUsingComparisonPredicate:predicate]; + } else if ([predicate isKindOfClass:[NSCompoundPredicate class]]) { + return [self queryFilteredUsingCompoundPredicate:predicate]; + } else if ([predicate isKindOfClass: + [[NSPredicate predicateWithBlock: + ^BOOL(id obj, NSDictionary *bindings) { return true; }] class]]) { + FSTThrowInvalidArgument(@"Invalid query. Block-based predicates are not " + "supported. Please use predicateWithFormat to " + "create predicates instead."); + } else { + FSTThrowInvalidArgument(@"Invalid query. Expect comparison or compound of " + "comparison predicate. Please use " + "predicateWithFormat to create predicates."); + } +} + - (FIRQuery *)queryOrderedByField:(NSString *)field { return [self queryOrderedByFieldPath:[FIRFieldPath pathWithDotSeparatedString:field] descending:NO]; diff --git a/Firestore/Source/Public/FIRQuery.h b/Firestore/Source/Public/FIRQuery.h index 0f3aeed..ff15ac6 100644 --- a/Firestore/Source/Public/FIRQuery.h +++ b/Firestore/Source/Public/FIRQuery.h @@ -256,6 +256,19 @@ NS_SWIFT_NAME(Query) isGreaterThanOrEqualTo:(id)value NS_SWIFT_NAME(whereField(_:isGreaterThanOrEqualTo:)); // clang-format on +/** + * Creates and returns a new `FIRQuery` with the additional filter that documents must + * satisfy the specified predicate. + * + * @param predicate The predicate the document must satisfy. Can be either comparison + * or compound of comparison. In particular, block-based predicate is not supported. + * + * @return The created `FIRQuery`. + */ +// clang-format off +- (FIRQuery *)queryFilteredUsingPredicate:(NSPredicate *)predicate NS_SWIFT_NAME(filter(using:)); +// clang-format on + #pragma mark - Sorting Data /** * Creates and returns a new `FIRQuery` that's additionally sorted by the specified field. |