Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, macos] Add predicate like expressions to NSExpression (#11632)
Browse files Browse the repository at this point in the history
* [ios, macos] Add NSPredicate between function.

* [ios, macos] Add NSPredicate 'IN' expression filter support .

* [ios, macos] Add NSPredicate 'CONTAINS' expression filter support.

* [ios, macos] Refactor NSPredicate operators.

* [ios, macos] Simplify NSPredicate's expression conversion code.

* [ios, macos] Make 'match' the default predicate conversion option.
  • Loading branch information
fabian-guerra committed Apr 12, 2018
1 parent be3fc44 commit 23f0222
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 7 deletions.
37 changes: 34 additions & 3 deletions platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,45 @@ - (id)mgl_jsonExpressionObject {
case NSNotEqualToPredicateOperatorType:
op = @"!=";
break;
case NSBetweenPredicateOperatorType: {
op = @"all";
NSArray *limits = self.rightExpression.constantValue;
NSPredicate *leftHandPredicate = [NSComparisonPredicate predicateWithLeftExpression:limits[0]
rightExpression:self.leftExpression
modifier:NSDirectPredicateModifier
type:NSLessThanOrEqualToPredicateOperatorType
options:0];
NSPredicate *rightHandPredicate = [NSComparisonPredicate predicateWithLeftExpression:self.leftExpression
rightExpression:limits[1]
modifier:NSDirectPredicateModifier
type:NSLessThanOrEqualToPredicateOperatorType
options:0];
return @[op, leftHandPredicate.mgl_jsonExpressionObject, rightHandPredicate.mgl_jsonExpressionObject];
}
case NSInPredicateOperatorType: {
NSMutableArray *elements = [NSMutableArray arrayWithObjects:@"match", self.leftExpression.mgl_jsonExpressionObject, nil];
NSArray *optionsExpressions = self.rightExpression.constantValue;
for (id object in optionsExpressions) {
id option = ((NSExpression *)object).mgl_jsonExpressionObject;
[elements addObject:option];
[elements addObject:@YES];
}
[elements addObject:@NO];
return elements;
}
case NSContainsPredicateOperatorType: {
NSPredicate *inPredicate = [NSComparisonPredicate predicateWithLeftExpression:self.rightExpression
rightExpression:self.leftExpression
modifier:self.comparisonPredicateModifier
type:NSInPredicateOperatorType
options:self.options];
return inPredicate.mgl_jsonExpressionObject;
}
case NSMatchesPredicateOperatorType:
case NSLikePredicateOperatorType:
case NSBeginsWithPredicateOperatorType:
case NSEndsWithPredicateOperatorType:
case NSInPredicateOperatorType:
case NSCustomSelectorPredicateOperatorType:
case NSContainsPredicateOperatorType:
case NSBetweenPredicateOperatorType:
[NSException raise:NSInvalidArgumentException
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
}
Expand Down
49 changes: 45 additions & 4 deletions platform/darwin/src/NSPredicate+MGLAdditions.mm
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ + (instancetype)mgl_predicateWithJSONObject:(id)object {
}
if ([op isEqualToString:@">="]) {
NSArray *subexpressions = MGLSubexpressionsWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
return [NSPredicate predicateWithFormat:@"%K >= %@" argumentArray:subexpressions];
return [NSPredicate predicateWithFormat:@"%@ >= %@" argumentArray:subexpressions];
}
if ([op isEqualToString:@"!"]) {
NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
Expand All @@ -294,16 +294,57 @@ + (instancetype)mgl_predicateWithJSONObject:(id)object {
return [NSPredicate predicateWithValue:YES];
}
if ([op isEqualToString:@"all"]) {
NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
NSArray<NSPredicate *> *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
if (subpredicates.count == 2) {
// Determine if the expression is of BETWEEN type
if ([subpredicates[0] isKindOfClass:[NSComparisonPredicate class]] &&
[subpredicates[1] isKindOfClass:[NSComparisonPredicate class]]) {
NSComparisonPredicate *leftCondition = (NSComparisonPredicate *)subpredicates[0];
NSComparisonPredicate *rightCondition = (NSComparisonPredicate *)subpredicates[1];

NSArray *limits;
NSExpression *leftConditionExpression;

if(leftCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType &&
rightCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType) {
limits = @[leftCondition.rightExpression, rightCondition.rightExpression];
leftConditionExpression = leftCondition.leftExpression;

} else if (leftCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType &&
rightCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType) {
limits = @[leftCondition.leftExpression, rightCondition.rightExpression];
leftConditionExpression = leftCondition.rightExpression;

} else if(leftCondition.predicateOperatorType == NSLessThanOrEqualToPredicateOperatorType &&
rightCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType) {
limits = @[leftCondition.leftExpression, rightCondition.leftExpression];
leftConditionExpression = leftCondition.rightExpression;

} else if(leftCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType &&
rightCondition.predicateOperatorType == NSGreaterThanOrEqualToPredicateOperatorType) {
limits = @[leftCondition.rightExpression, rightCondition.leftExpression];
leftConditionExpression = leftCondition.leftExpression;
}

if (limits && leftConditionExpression) {
return [NSPredicate predicateWithFormat:@"%@ BETWEEN %@", leftConditionExpression, [NSExpression expressionForAggregate:limits]];
}
}
}
return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}
if ([op isEqualToString:@"any"]) {
NSArray *subpredicates = MGLSubpredicatesWithJSONObjects([objects subarrayWithRange:NSMakeRange(1, objects.count - 1)]);
return [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];
}

NSAssert(NO, @"Unrecognized expression conditional operator %@.", op);
return nil;
NSExpression *expression = [NSExpression expressionWithMGLJSONObject:object];
return [NSComparisonPredicate predicateWithLeftExpression:expression
rightExpression:[NSExpression expressionForConstantValue:@YES]
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];

}

- (id)mgl_jsonExpressionObject {
Expand Down
65 changes: 65 additions & 0 deletions platform/darwin/test/MGLPredicateTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,71 @@ - (void)testComparisonExpressionArray {
NSArray *expected = @[@"==", @1, @2];
XCTAssertEqualObjects([NSPredicate predicateWithFormat:@"1 = 2"].mgl_jsonExpressionObject, expected);
}
{
NSArray *expected = @[@"all", @[@"<=", @10, @[@"get", @"x"]], @[@"<=", @[@"get", @"x"], @100]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x BETWEEN {10, 100}"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"all", @[@">=", @[@"get", @"x"], @10], @[@"<=", @[@"get", @"x"], @100]];
NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x BETWEEN %@", limits];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"all", @[@"<=", @10, @[@"get", @"x"]], @[@"<=", @[@"get", @"x"], @100]];
NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x BETWEEN %@", limits];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"all", @[@"<=", @10, @[@"get", @"x"]], @[@">=", @100, @[@"get", @"x"]]];
NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x BETWEEN %@", limits];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"all", @[@">=", @[@"get", @"x"], @10], @[@">=", @100, @[@"get", @"x"]]];
NSExpression *limits = [NSExpression expressionForAggregate:@[[NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"x BETWEEN %@", limits];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"all", @[@"==", @10, @[@"get", @"x"]], @[@"<=", @[@"get", @"x"], @100]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ == x && x <= %@", [NSExpression expressionForConstantValue:@10], [NSExpression expressionForConstantValue:@100]];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicate);
}
{
NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$mgl_featureIdentifier IN { 6, 5, 4, 3}"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($mgl_featureIdentifier, 6, YES, 5, YES, 4, YES, 3, YES, NO) == YES"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicateAfter);
}
{
NSArray *expected = @[@"!", @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT x IN { 6, 5, 4, 3}"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"NOT MGL_MATCH(x, 6, YES, 5, YES, 4, YES, 3, YES, NO) == YES"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicateAfter);
}
{
NSArray *expected = @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS x"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(x, 6, YES, 5, YES, 4, YES, 3, YES, NO) == YES"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicateAfter);
}
{
NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS $mgl_featureIdentifier"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($mgl_featureIdentifier, 6, YES, 5, YES, 4, YES, 3, YES, NO) == YES"];
XCTAssertEqualObjects([NSPredicate mgl_predicateWithJSONObject:expected], predicateAfter);
}
}

@end

0 comments on commit 23f0222

Please sign in to comment.