summaryrefslogtreecommitdiff
path: root/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-12-26 14:24:05 -0800
committerMinh Nguyễn <mxn@1ec5.org>2017-01-04 08:52:41 -0800
commite6132d248b54d202c3fa132b3084660a0bbe3c06 (patch)
treef6b98d23625169ded08d8f3b8965d3619f3fe2da /platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
parent83309fd369c9623a1e2638f98f75206609d44258 (diff)
downloadqtlocation-mapboxgl-e6132d248b54d202c3fa132b3084660a0bbe3c06.tar.gz
[ios, macos] Rewrote predicate/filter conversion
When converting predicates to filters, symmetric comparison predicates can now compare a value to a key in addition to the usual key-to-value order. Added error checking for unhandled combinations like key-to-key. Fixed a crash converting a CONTAINS predicate into a filter. Added support for constant value expressions inside aggregate expressions. Allow sets as aggregate expressions just like arrays, except in BETWEEN predicates where order matters. Flatten NOT predicates into more specialized filters. When converting filters to predicates, use constant value expressions inside aggregate expressions. Convert to a BETWEEN predicate when possible. Replaced predicate round-tripping integration tests with systematic unit tests for converting in either direction, plus unit tests for round-tripping and symmetry. Refined exception names and messages. Realphabetized files in groups.
Diffstat (limited to 'platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm')
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm212
1 files changed, 153 insertions, 59 deletions
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index 19c264aa40..58390b0b81 100644
--- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -7,95 +7,189 @@
- (mbgl::style::Filter)mgl_filter
{
+ 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: {
- if (self.rightExpression.constantValue)
- {
- auto filter = mbgl::style::EqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
- }
- else
- {
- auto filter = mbgl::style::NotHasFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- return filter;
+ mbgl::style::EqualsFilter eqFilter;
+ eqFilter.key = self.mgl_keyPath.UTF8String;
+ eqFilter.value = self.mgl_constantValue;
+
+ // Convert == nil to NotHasFilter.
+ if (eqFilter.value.is<mbgl::NullValue>()) {
+ mbgl::style::NotHasFilter notHasFilter;
+ notHasFilter.key = eqFilter.key;
+ return notHasFilter;
}
+
+ return eqFilter;
}
case NSNotEqualToPredicateOperatorType: {
- if (self.rightExpression.constantValue)
- {
- auto filter = mbgl::style::NotEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
- }
- else
- {
- auto filter = mbgl::style::HasFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- return filter;
+ mbgl::style::NotEqualsFilter neFilter;
+ neFilter.key = self.mgl_keyPath.UTF8String;
+ neFilter.value = self.mgl_constantValue;
+
+ // Convert != nil to HasFilter.
+ if (neFilter.value.is<mbgl::NullValue>()) {
+ mbgl::style::HasFilter hasFilter;
+ hasFilter.key = neFilter.key;
+ return hasFilter;
}
+
+ return neFilter;
}
case NSGreaterThanPredicateOperatorType: {
- auto filter = mbgl::style::GreaterThanFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ 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: {
- auto filter = mbgl::style::GreaterThanEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ 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: {
- auto filter = mbgl::style::LessThanFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ 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: {
- auto filter = mbgl::style::LessThanEqualsFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.value = self.rightExpression.mgl_filterValue;
- return filter;
+ 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: {
- auto filter = mbgl::style::InFilter();
- filter.key = self.leftExpression.keyPath.UTF8String;
- filter.values = self.rightExpression.mgl_filterValues;
- return filter;
+ 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."];
+ }
+ mbgl::style::InFilter inFilter;
+ inFilter.key = leftExpression.keyPath.UTF8String;
+ inFilter.values = rightExpression.mgl_filterValues;
+ return inFilter;
}
case NSContainsPredicateOperatorType: {
- auto filter = mbgl::style::InFilter();
- filter.key = [self.rightExpression.constantValue UTF8String];
- filter.values = self.leftExpression.mgl_filterValues;
- return filter;
+ 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."];
+ }
+ mbgl::style::InFilter inFilter;
+ inFilter.key = rightExpression.keyPath.UTF8String;
+ inFilter.values = leftExpression.mgl_filterValues;
+ return inFilter;
}
case NSBetweenPredicateOperatorType: {
- auto filter = mbgl::style::AllFilter();
- auto gteFilter = mbgl::style::GreaterThanEqualsFilter();
- gteFilter.key = self.leftExpression.keyPath.UTF8String;
- gteFilter.value = self.rightExpression.mgl_filterValues[0];
- filter.filters.push_back(gteFilter);
- auto lteFilter = mbgl::style::LessThanEqualsFilter();
- lteFilter.key = self.leftExpression.keyPath.UTF8String;
- lteFilter.value = self.rightExpression.mgl_filterValues[1];
- filter.filters.push_back(lteFilter);
- return filter;
+ 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_filterValues;
+ 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:@"Unsupported operator type"
+ [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;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ return leftExpression.keyPath;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ return rightExpression.keyPath;
+ }
+
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ return nil;
+}
+
+- (mbgl::Value)mgl_constantValue {
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ mbgl::Value value;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ value = rightExpression.mgl_filterValue;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ value = leftExpression.mgl_filterValue;
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ }
+ return value;
+}
+
@end