This repository has been archived by the owner on Aug 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[ios, macos] NSPredicate expression filters. #11587
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
3ecbc71
[ios, macos] Add NSAndPredicateType predicate expression filter.
fabian-guerra d6a8e13
[ios, macos] Add type to NSPredicate expressions.
fabian-guerra 038e5cb
[ios, macos] Add Expression filter support.
fabian-guerra 1ef2486
[ios, macos] Update NSPredicate expression based tests.
fabian-guerra 870e226
[ios, macos] Refactor ExpressionFilters.
fabian-guerra c7256af
[ios, macos] Add symmetric test to ExpressionFilters.
fabian-guerra 7bc47ae
[ios, macos] Update NSPredicate test to ExpressionFilters.
fabian-guerra bce8c17
[ios, macos] Re-introduce Filter tests.
fabian-guerra e0dde38
[ios, macos] Remove typed NSComparisonPredicate's comparable values.
fabian-guerra 027fd6f
[ios, macos] Update style layers predicate tests.
fabian-guerra e6f945f
[ios, macos] Remove unused predicate conversion code.
fabian-guerra d2ab1dd
[ios, macos] Update documentation exaple's test.
fabian-guerra a550621
[ios, macos] Update Predicate and Expressions guide..
fabian-guerra 40fda88
[ios, macos] Remove mgl_ prefix from variable expressions.
fabian-guerra 0dbfcd8
[ios, macos] Update predicates and expressions documentation.
fabian-guerra 59665b0
[ios, macos] Update changelogs.
fabian-guerra File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
223 changes: 2 additions & 221 deletions
223
platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,231 +1,12 @@ | ||
#import "NSComparisonPredicate+MGLAdditions.h" | ||
|
||
#import "MGLStyleValue_Private.h" | ||
|
||
#import "NSPredicate+MGLAdditions.h" | ||
#import "NSExpression+MGLPrivateAdditions.h" | ||
|
||
@implementation NSComparisonPredicate (MGLAdditions) | ||
|
||
- (mbgl::style::Filter)mgl_filter { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My mistake: we only need to keep |
||
NSExpression *leftExpression = self.leftExpression; | ||
NSExpression *rightExpression = self.rightExpression; | ||
NSExpressionType leftType = leftExpression.expressionType; | ||
NSExpressionType rightType = rightExpression.expressionType; | ||
BOOL isReversed = ((leftType == NSConstantValueExpressionType || leftType == NSAggregateExpressionType) | ||
&& rightType == NSKeyPathExpressionType); | ||
switch (self.predicateOperatorType) { | ||
case NSEqualToPredicateOperatorType: { | ||
mbgl::style::EqualsFilter eqFilter; | ||
eqFilter.key = self.mgl_keyPath.UTF8String; | ||
eqFilter.value = self.mgl_constantValue; | ||
|
||
// Convert $type == to TypeEqualsFilter. | ||
if (eqFilter.key == "$type") { | ||
mbgl::style::TypeEqualsFilter typeEqFilter; | ||
typeEqFilter.value = self.mgl_featureType; | ||
return typeEqFilter; | ||
} | ||
|
||
// Convert $id == to IdentifierEqualsFilter. | ||
if (eqFilter.key == "$id") { | ||
// Convert $id == nil to NotHasIdentifierFilter. | ||
if (eqFilter.value.is<mbgl::NullValue>()) { | ||
return mbgl::style::NotHasIdentifierFilter(); | ||
} | ||
|
||
mbgl::style::IdentifierEqualsFilter idEqFilter; | ||
idEqFilter.value = self.mgl_featureIdentifier; | ||
return idEqFilter; | ||
} | ||
|
||
// Convert == nil to NotHasFilter. | ||
if (eqFilter.value.is<mbgl::NullValue>()) { | ||
mbgl::style::NotHasFilter notHasFilter; | ||
notHasFilter.key = eqFilter.key; | ||
return notHasFilter; | ||
} | ||
|
||
return eqFilter; | ||
} | ||
case NSNotEqualToPredicateOperatorType: { | ||
mbgl::style::NotEqualsFilter neFilter; | ||
neFilter.key = self.mgl_keyPath.UTF8String; | ||
neFilter.value = self.mgl_constantValue; | ||
|
||
// Convert $type != to TypeNotEqualsFilter. | ||
if (neFilter.key == "$type") { | ||
mbgl::style::TypeNotEqualsFilter typeNeFilter; | ||
typeNeFilter.value = self.mgl_featureType; | ||
return typeNeFilter; | ||
} | ||
|
||
// Convert $id != to IdentifierNotEqualsFilter. | ||
if (neFilter.key == "$id") { | ||
// Convert $id != nil to HasIdentifierFilter. | ||
if (neFilter.value.is<mbgl::NullValue>()) { | ||
return mbgl::style::HasIdentifierFilter(); | ||
} | ||
|
||
mbgl::style::IdentifierNotEqualsFilter idNeFilter; | ||
idNeFilter.value = self.mgl_featureIdentifier; | ||
return idNeFilter; | ||
} | ||
|
||
// Convert != nil to HasFilter. | ||
if (neFilter.value.is<mbgl::NullValue>()) { | ||
mbgl::style::HasFilter hasFilter; | ||
hasFilter.key = neFilter.key; | ||
return hasFilter; | ||
} | ||
|
||
return neFilter; | ||
} | ||
case NSGreaterThanPredicateOperatorType: { | ||
if (isReversed) { | ||
mbgl::style::LessThanFilter ltFilter; | ||
ltFilter.key = self.mgl_keyPath.UTF8String; | ||
ltFilter.value = self.mgl_constantValue; | ||
return ltFilter; | ||
} else { | ||
mbgl::style::GreaterThanFilter gtFilter; | ||
gtFilter.key = self.mgl_keyPath.UTF8String; | ||
gtFilter.value = self.mgl_constantValue; | ||
return gtFilter; | ||
} | ||
} | ||
case NSGreaterThanOrEqualToPredicateOperatorType: { | ||
if (isReversed) { | ||
mbgl::style::LessThanEqualsFilter lteFilter; | ||
lteFilter.key = self.mgl_keyPath.UTF8String; | ||
lteFilter.value = self.mgl_constantValue; | ||
return lteFilter; | ||
} else { | ||
mbgl::style::GreaterThanEqualsFilter gteFilter; | ||
gteFilter.key = self.mgl_keyPath.UTF8String; | ||
gteFilter.value = self.mgl_constantValue; | ||
return gteFilter; | ||
} | ||
} | ||
case NSLessThanPredicateOperatorType: { | ||
if (isReversed) { | ||
mbgl::style::GreaterThanFilter gtFilter; | ||
gtFilter.key = self.mgl_keyPath.UTF8String; | ||
gtFilter.value = self.mgl_constantValue; | ||
return gtFilter; | ||
} else { | ||
mbgl::style::LessThanFilter ltFilter; | ||
ltFilter.key = self.mgl_keyPath.UTF8String; | ||
ltFilter.value = self.mgl_constantValue; | ||
return ltFilter; | ||
} | ||
} | ||
case NSLessThanOrEqualToPredicateOperatorType: { | ||
if (isReversed) { | ||
mbgl::style::GreaterThanEqualsFilter gteFilter; | ||
gteFilter.key = self.mgl_keyPath.UTF8String; | ||
gteFilter.value = self.mgl_constantValue; | ||
return gteFilter; | ||
} else { | ||
mbgl::style::LessThanEqualsFilter lteFilter; | ||
lteFilter.key = self.mgl_keyPath.UTF8String; | ||
lteFilter.value = self.mgl_constantValue; | ||
return lteFilter; | ||
} | ||
} | ||
case NSInPredicateOperatorType: { | ||
if (isReversed) { | ||
if (leftType == NSConstantValueExpressionType && [leftExpression.constantValue isKindOfClass:[NSString class]]) { | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"CONTAINS not supported for string comparison."]; | ||
} | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"Predicate cannot compare values IN attribute."]; | ||
} | ||
|
||
// Convert $type IN to TypeInFilter. | ||
if ([leftExpression.keyPath isEqualToString:@"$type"]) { | ||
mbgl::style::TypeInFilter typeInFilter; | ||
typeInFilter.values = rightExpression.mgl_aggregateFeatureType; | ||
return typeInFilter; | ||
} | ||
|
||
// Convert $id IN to IdentifierInFilter. | ||
if ([leftExpression.keyPath isEqualToString:@"$id"]) { | ||
mbgl::style::IdentifierInFilter idInFilter; | ||
idInFilter.values = rightExpression.mgl_aggregateFeatureIdentifier; | ||
return idInFilter; | ||
} | ||
|
||
mbgl::style::InFilter inFilter; | ||
inFilter.key = leftExpression.keyPath.UTF8String; | ||
inFilter.values = rightExpression.mgl_aggregateMBGLValue; | ||
return inFilter; | ||
} | ||
case NSContainsPredicateOperatorType: { | ||
if (!isReversed) { | ||
if (rightType == NSConstantValueExpressionType && [rightExpression.constantValue isKindOfClass:[NSString class]]) { | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"IN not supported for string comparison."]; | ||
} | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"Predicate cannot compare attribute CONTAINS values."]; | ||
} | ||
|
||
// Convert CONTAINS $type to TypeInFilter. | ||
if ([rightExpression.keyPath isEqualToString:@"$type"]) { | ||
mbgl::style::TypeInFilter typeInFilter; | ||
typeInFilter.values = leftExpression.mgl_aggregateFeatureType; | ||
return typeInFilter; | ||
} | ||
|
||
// Convert CONTAINS $id to IdentifierInFilter. | ||
if ([rightExpression.keyPath isEqualToString:@"$id"]) { | ||
mbgl::style::IdentifierInFilter idInFilter; | ||
idInFilter.values = leftExpression.mgl_aggregateFeatureIdentifier; | ||
return idInFilter; | ||
} | ||
|
||
mbgl::style::InFilter inFilter; | ||
inFilter.key = rightExpression.keyPath.UTF8String; | ||
inFilter.values = leftExpression.mgl_aggregateMBGLValue; | ||
return inFilter; | ||
} | ||
case NSBetweenPredicateOperatorType: { | ||
if (isReversed) { | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"Predicate cannot compare bounds BETWEEN attribute."]; | ||
} | ||
if (![rightExpression.constantValue isKindOfClass:[NSArray class]]) { | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"Right side of BETWEEN predicate must be an array."]; // not NSSet | ||
} | ||
auto values = rightExpression.mgl_aggregateMBGLValue; | ||
if (values.size() != 2) { | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"Right side of BETWEEN predicate must have two items."]; | ||
} | ||
mbgl::style::AllFilter allFilter; | ||
mbgl::style::GreaterThanEqualsFilter gteFilter; | ||
gteFilter.key = leftExpression.keyPath.UTF8String; | ||
gteFilter.value = values[0]; | ||
allFilter.filters.push_back(gteFilter); | ||
mbgl::style::LessThanEqualsFilter lteFilter; | ||
lteFilter.key = leftExpression.keyPath.UTF8String; | ||
lteFilter.value = values[1]; | ||
allFilter.filters.push_back(lteFilter); | ||
return allFilter; | ||
} | ||
case NSMatchesPredicateOperatorType: | ||
case NSLikePredicateOperatorType: | ||
case NSBeginsWithPredicateOperatorType: | ||
case NSEndsWithPredicateOperatorType: | ||
case NSCustomSelectorPredicateOperatorType: | ||
[NSException raise:NSInvalidArgumentException | ||
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType]; | ||
} | ||
|
||
return {}; | ||
} | ||
|
||
- (NSString *)mgl_keyPath { | ||
NSExpression *leftExpression = self.leftExpression; | ||
NSExpression *rightExpression = self.rightExpression; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This illustrates the fact that many existing uses of predicates in v3.x will need to be modified slightly when migrating to v4.0.0. On balance, I think this is necessary until mapbox/mapbox-gl-js#6459, but it does mean we’ll need to be clear about this requirement in the documentation, particularly the function-to-expression migration guide and the “Predicates and Expressions” guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, the iOS and macOS changelogs should have a blurb noting that: