From a1a639120d7662cb68f0ba5770e4f42cc9415069 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 9 Feb 2017 16:18:57 -0600 Subject: [core] Introduce dedicated filter types for $type and $id special cases (#7971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [core] Introduce dedicated filter types for $type and $id special cases * [ios, macos] Special-case $id, $type in predicates Also support $id ≟ nil. --- .../src/NSComparisonPredicate+MGLAdditions.mm | 105 +++++++++++++- platform/darwin/src/NSExpression+MGLAdditions.h | 3 + platform/darwin/src/NSExpression+MGLAdditions.mm | 61 ++++++++ platform/darwin/src/NSPredicate+MGLAdditions.mm | 72 +++++++++- platform/darwin/test/MGLExpressionTests.mm | 19 +++ platform/darwin/test/MGLPredicateTests.mm | 155 +++++++++++++++++++++ 6 files changed, 410 insertions(+), 5 deletions(-) (limited to 'platform/darwin') diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm index 295b3b21f8..ac2d598d05 100644 --- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm +++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm @@ -5,8 +5,7 @@ @implementation NSComparisonPredicate (MGLAdditions) -- (mbgl::style::Filter)mgl_filter -{ +- (mbgl::style::Filter)mgl_filter { NSExpression *leftExpression = self.leftExpression; NSExpression *rightExpression = self.rightExpression; NSExpressionType leftType = leftExpression.expressionType; @@ -18,6 +17,25 @@ 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()) { + return mbgl::style::NotHasIdentifierFilter(); + } + + mbgl::style::IdentifierEqualsFilter idEqFilter; + idEqFilter.value = self.mgl_featureIdentifier; + return idEqFilter; + } // Convert == nil to NotHasFilter. if (eqFilter.value.is()) { @@ -32,6 +50,25 @@ 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()) { + return mbgl::style::HasIdentifierFilter(); + } + + mbgl::style::IdentifierNotEqualsFilter idNeFilter; + idNeFilter.value = self.mgl_featureIdentifier; + return idNeFilter; + } // Convert != nil to HasFilter. if (neFilter.value.is()) { @@ -103,6 +140,21 @@ [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; @@ -117,6 +169,21 @@ [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; @@ -192,4 +259,38 @@ return value; } +- (mbgl::FeatureType)mgl_featureType { + NSExpression *leftExpression = self.leftExpression; + NSExpression *rightExpression = self.rightExpression; + NSExpressionType leftType = leftExpression.expressionType; + NSExpressionType rightType = rightExpression.expressionType; + mbgl::FeatureType type; + if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) { + type = rightExpression.mgl_featureType; + } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) { + type = leftExpression.mgl_featureType; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."]; + } + return type; +} + +- (mbgl::FeatureIdentifier)mgl_featureIdentifier { + NSExpression *leftExpression = self.leftExpression; + NSExpression *rightExpression = self.rightExpression; + NSExpressionType leftType = leftExpression.expressionType; + NSExpressionType rightType = rightExpression.expressionType; + mbgl::FeatureIdentifier identifier; + if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) { + identifier = rightExpression.mgl_featureIdentifier; + } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) { + identifier = leftExpression.mgl_featureIdentifier; + } else { + [NSException raise:NSInvalidArgumentException + format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."]; + } + return identifier; +} + @end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h index c60d6d78ba..491ed5a536 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.h +++ b/platform/darwin/src/NSExpression+MGLAdditions.h @@ -8,7 +8,10 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue; @property (nonatomic, readonly) std::vector mgl_aggregateMBGLValue; +@property (nonatomic, readonly) mbgl::FeatureType mgl_featureType; +@property (nonatomic, readonly) std::vector mgl_aggregateFeatureType; @property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier; +@property (nonatomic, readonly) std::vector mgl_aggregateFeatureIdentifier; @end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index f19a41327a..c54102b8c9 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -63,6 +63,67 @@ return {}; } +- (std::vector)mgl_aggregateFeatureType { + if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) { + std::vector convertedValues; + for (id value in self.constantValue) { + NSExpression *expression = value; + if (![expression isKindOfClass:[NSExpression class]]) { + expression = [NSExpression expressionForConstantValue:expression]; + } + convertedValues.push_back(expression.mgl_featureType); + } + return convertedValues; + } + [NSException raise:NSInvalidArgumentException + format:@"Constant value expression must contain an array or set."]; + return {}; +} + +- (mbgl::FeatureType)mgl_featureType { + id value = self.constantValue; + if ([value isKindOfClass:NSString.class]) { + if ([value isEqualToString:@"Point"]) { + return mbgl::FeatureType::Point; + } + if ([value isEqualToString:@"LineString"]) { + return mbgl::FeatureType::LineString; + } + if ([value isEqualToString:@"Polygon"]) { + return mbgl::FeatureType::Polygon; + } + } else if ([value isKindOfClass:NSNumber.class]) { + switch ([value integerValue]) { + case 1: + return mbgl::FeatureType::Point; + case 2: + return mbgl::FeatureType::LineString; + case 3: + return mbgl::FeatureType::Polygon; + default: + break; + } + } + return mbgl::FeatureType::Unknown; +} + +- (std::vector)mgl_aggregateFeatureIdentifier { + if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) { + std::vector convertedValues; + for (id value in self.constantValue) { + NSExpression *expression = value; + if (![expression isKindOfClass:[NSExpression class]]) { + expression = [NSExpression expressionForConstantValue:expression]; + } + convertedValues.push_back(expression.mgl_featureIdentifier); + } + return convertedValues; + } + [NSException raise:NSInvalidArgumentException + format:@"Constant value expression must contain an array or set."]; + return {}; +} + - (mbgl::FeatureIdentifier)mgl_featureIdentifier { mbgl::Value mbglValue = self.mgl_constantMBGLValue; diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm index 9fd6639b0a..e0511d8740 100644 --- a/platform/darwin/src/NSPredicate+MGLAdditions.mm +++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm @@ -13,14 +13,41 @@ public: return predicates; } - NSExpression *getValues(std::vector values) { + template + NSExpression *getValues(std::vector values) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()]; for (auto value : values) { - id constantValue = mbgl::Value::visit(value, ValueEvaluator()); + id constantValue = MBGLType::visit(value, ValueEvaluator()); [array addObject:[NSExpression expressionForConstantValue:constantValue]]; } return [NSExpression expressionForAggregate:array]; } + + NSString *getFeatureTypeString(mbgl::FeatureType type) { + switch (type) { + case mbgl::FeatureType::Point: + return @"Point"; + + case mbgl::FeatureType::LineString: + return @"LineString"; + + case mbgl::FeatureType::Polygon: + return @"Polygon"; + + default: + NSCAssert(NO, @"Unrecognized feature type %hhu", type); + return nil; + } + } + + NSExpression *getFeatureTypeStrings(std::vector values) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()]; + for (auto value : values) { + id typeString = getFeatureTypeString(value); + [array addObject:[NSExpression expressionForConstantValue:typeString]]; + } + return [NSExpression expressionForAggregate:array]; + } NSPredicate *operator()(mbgl::style::NullFilter filter) { return nil; @@ -57,6 +84,38 @@ public: NSPredicate *operator()(mbgl::style::NotInFilter filter) { return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @(filter.key.c_str()), getValues(filter.values)]; } + + NSPredicate *operator()(mbgl::style::TypeEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K == %@", @"$type", getFeatureTypeString(filter.value)]; + } + + NSPredicate *operator()(mbgl::style::TypeNotEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K != %@", @"$type", getFeatureTypeString(filter.value)]; + } + + NSPredicate *operator()(mbgl::style::TypeInFilter filter) { + return [NSPredicate predicateWithFormat:@"%K IN %@", @"$type", getFeatureTypeStrings(filter.values)]; + } + + NSPredicate *operator()(mbgl::style::TypeNotInFilter filter) { + return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @"$type", getFeatureTypeStrings(filter.values)]; + } + + NSPredicate *operator()(mbgl::style::IdentifierEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K == %@", @"$id", mbgl::FeatureIdentifier::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate *operator()(mbgl::style::IdentifierNotEqualsFilter filter) { + return [NSPredicate predicateWithFormat:@"%K != %@", @"$id", mbgl::FeatureIdentifier::visit(filter.value, ValueEvaluator())]; + } + + NSPredicate *operator()(mbgl::style::IdentifierInFilter filter) { + return [NSPredicate predicateWithFormat:@"%K IN %@", @"$id", getValues(filter.values)]; + } + + NSPredicate *operator()(mbgl::style::IdentifierNotInFilter filter) { + return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @"$id", getValues(filter.values)]; + } NSPredicate *operator()(mbgl::style::AnyFilter filter) { NSArray *subpredicates = getPredicates(filter.filters); @@ -127,7 +186,14 @@ public: NSPredicate *operator()(mbgl::style::NotHasFilter filter) { return [NSPredicate predicateWithFormat:@"%K == nil", @(filter.key.c_str())]; } - + + NSPredicate *operator()(mbgl::style::HasIdentifierFilter filter) { + return [NSPredicate predicateWithFormat:@"%K != nil", @"$id"]; + } + + NSPredicate *operator()(mbgl::style::NotHasIdentifierFilter filter) { + return [NSPredicate predicateWithFormat:@"%K == nil", @"$id"]; + } }; @implementation NSPredicate (MGLAdditions) diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 00b57c15f0..47315b97d6 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -212,4 +212,23 @@ XCTAssertTrue(convertedValue.is()); } +#pragma mark - Feature type tests + +- (void)testFeatureType { + XCTAssertEqual([NSExpression expressionWithFormat:@"'Point'"].mgl_featureType, mbgl::FeatureType::Point); + XCTAssertEqual([NSExpression expressionWithFormat:@"'LineString'"].mgl_featureType, mbgl::FeatureType::LineString); + XCTAssertEqual([NSExpression expressionWithFormat:@"'Polygon'"].mgl_featureType, mbgl::FeatureType::Polygon); + XCTAssertEqual([NSExpression expressionWithFormat:@"'Unknown'"].mgl_featureType, mbgl::FeatureType::Unknown); + XCTAssertEqual([NSExpression expressionWithFormat:@"''"].mgl_featureType, mbgl::FeatureType::Unknown); + + XCTAssertEqual([NSExpression expressionWithFormat:@"1"].mgl_featureType, mbgl::FeatureType::Point); + XCTAssertEqual([NSExpression expressionWithFormat:@"2"].mgl_featureType, mbgl::FeatureType::LineString); + XCTAssertEqual([NSExpression expressionWithFormat:@"3"].mgl_featureType, mbgl::FeatureType::Polygon); + XCTAssertEqual([NSExpression expressionWithFormat:@"0"].mgl_featureType, mbgl::FeatureType::Unknown); + XCTAssertEqual([NSExpression expressionWithFormat:@"-1"].mgl_featureType, mbgl::FeatureType::Unknown); + XCTAssertEqual([NSExpression expressionWithFormat:@"4"].mgl_featureType, mbgl::FeatureType::Unknown); + + XCTAssertEqual([NSExpression expressionWithFormat:@"nil"].mgl_featureType, mbgl::FeatureType::Unknown); +} + @end diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm index f34b480a25..6e6951dcdd 100644 --- a/platform/darwin/test/MGLPredicateTests.mm +++ b/platform/darwin/test/MGLPredicateTests.mm @@ -41,12 +41,48 @@ namespace mbgl { mbgl::style::EqualsFilter expected = { .key = "a", .value = std::string("b") }; MGLAssertEqualFilters(actual, expected); } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K = 'Point'", @"$type"].mgl_filter; + mbgl::style::TypeEqualsFilter expected = { .value = mbgl::FeatureType::Point }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K = 67086180", @"$id"].mgl_filter; + mbgl::style::IdentifierEqualsFilter expected = { .value = UINT64_C(67086180) }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K = nil", @"$id"].mgl_filter; + mbgl::style::NotHasIdentifierFilter expected; + MGLAssertEqualFilters(actual, expected); + } { auto actual = [NSPredicate predicateWithFormat:@"a = nil"].mgl_filter; mbgl::style::NotHasFilter expected = { .key = "a" }; MGLAssertEqualFilters(actual, expected); } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K != 'Point'", @"$type"].mgl_filter; + mbgl::style::TypeNotEqualsFilter expected = { .value = mbgl::FeatureType::Point }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K != 67086180", @"$id"].mgl_filter; + mbgl::style::IdentifierNotEqualsFilter expected = { .value = UINT64_C(67086180) }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"].mgl_filter; + mbgl::style::HasIdentifierFilter expected; + MGLAssertEqualFilters(actual, expected); + } { auto actual = [NSPredicate predicateWithFormat:@"a != 'b'"].mgl_filter; @@ -117,6 +153,30 @@ namespace mbgl { mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; MGLAssertEqualFilters(actual, expected); } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K IN {'LineString', 'Polygon'}", @"$type"].mgl_filter; + mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$type", @[@"LineString", @"Polygon"]].mgl_filter; + mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"].mgl_filter; + mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$id", @[@67086180, @3709678893, @3352016856, @4189833989]].mgl_filter; + mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + MGLAssertEqualFilters(actual, expected); + } XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException); @@ -131,6 +191,24 @@ namespace mbgl { mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } }; MGLAssertEqualFilters(actual, expected); } + + { + auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@"LineString", @"Polygon"], @"$type"].mgl_filter; + mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"{67086180, 3709678893, 3352016856, 4189833989} CONTAINS %K", @"$id"].mgl_filter; + mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + MGLAssertEqualFilters(actual, expected); + } + + { + auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@67086180, @3709678893, @3352016856, @4189833989], @"$id"].mgl_filter; + mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + MGLAssertEqualFilters(actual, expected); + } XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException); @@ -238,6 +316,41 @@ namespace mbgl { mbgl::style::EqualsFilter filter = { .key = "a", .value = std::string("b") }; XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = 'b'"]); } + + { + mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Point }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'Point'", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::LineString }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'LineString'", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Polygon }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'Polygon'", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::IdentifierEqualsFilter filter = { .value = UINT64_C(67086180) }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 67086180", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::NotHasIdentifierFilter filter; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = nil", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Unknown }; + XCTAssertThrowsSpecificNamed([NSPredicate mgl_predicateWithFilter:filter], NSException, NSInternalInconsistencyException); + } { mbgl::style::NotHasFilter filter = { .key = "a" }; @@ -248,6 +361,24 @@ namespace mbgl { mbgl::style::NotEqualsFilter filter = { .key = "a", .value = std::string("b") }; XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != 'b'"]); } + + { + mbgl::style::TypeNotEqualsFilter filter = { .value = mbgl::FeatureType::Point }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != 'Point'", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::IdentifierNotEqualsFilter filter = { .value = UINT64_C(67086180) }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != 67086180", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } + + { + mbgl::style::HasIdentifierFilter filter; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } { mbgl::style::HasFilter filter = { .key = "a" }; @@ -298,11 +429,35 @@ namespace mbgl { mbgl::style::InFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } }; XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].predicateFormat); } + + { + mbgl::style::TypeInFilter filter = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K IN {'LineString', 'Polygon'}", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, expected.predicateFormat); + } + + { + mbgl::style::IdentifierInFilter filter = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } { mbgl::style::NotInFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } }; XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].predicateFormat); } + + { + mbgl::style::TypeNotInFilter filter = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"NOT %K IN {'LineString', 'Polygon'}", @"$type"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, expected.predicateFormat); + } + + { + mbgl::style::IdentifierNotInFilter filter = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } }; + NSPredicate *expected = [NSPredicate predicateWithFormat:@"NOT %K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"]; + XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected); + } { mbgl::style::AllFilter filter; -- cgit v1.2.1