From c899b5f725b375e81be8966c3211819e75ffcb0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 9 Feb 2017 04:42:06 -0800 Subject: [PATCH] [ios, macos] Special-case $id, $type in predicates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also support $id ≟ nil. --- .../src/NSComparisonPredicate+MGLAdditions.mm | 105 +++++++++++- .../darwin/src/NSExpression+MGLAdditions.h | 3 + .../darwin/src/NSExpression+MGLAdditions.mm | 61 +++++++ .../darwin/src/NSPredicate+MGLAdditions.mm | 72 +++++++- platform/darwin/test/MGLExpressionTests.mm | 19 +++ platform/darwin/test/MGLPredicateTests.mm | 155 ++++++++++++++++++ platform/ios/CHANGELOG.md | 3 +- platform/macos/CHANGELOG.md | 3 +- 8 files changed, 414 insertions(+), 7 deletions(-) diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm index 295b3b21f85..ac2d598d053 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 @@ @implementation NSComparisonPredicate (MGLAdditions) 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 @@ @implementation NSComparisonPredicate (MGLAdditions) 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 @@ @implementation NSComparisonPredicate (MGLAdditions) [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 @@ @implementation NSComparisonPredicate (MGLAdditions) [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 @@ - (NSString *)mgl_keyPath { 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 c60d6d78ba0..491ed5a5367 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 f19a41327af..c54102b8c97 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -63,6 +63,67 @@ @implementation NSExpression (MGLAdditions) 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 9fd6639b0ab..e0511d87406 100644 --- a/platform/darwin/src/NSPredicate+MGLAdditions.mm +++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm @@ -13,14 +13,41 @@ 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 @@ 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 @@ 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 00b57c15f04..47315b97d6f 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -212,4 +212,23 @@ - (void)testExpressionConversionNull 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 f34b480a259..6e6951dcdd9 100644 --- a/platform/darwin/test/MGLPredicateTests.mm +++ b/platform/darwin/test/MGLPredicateTests.mm @@ -41,12 +41,48 @@ - (void)testFilterization { 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 @@ - (void)testFilterization { 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 @@ - (void)testFilterization { 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 @@ - (void)testPredication { 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 @@ - (void)testPredication { 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 @@ - (void)testPredication { 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; diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 53a0538506a..f366cef47a2 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -23,7 +23,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Removed support for the `ref` property in layers in style JSON files. ([#7586](https://github.com/mapbox/mapbox-gl-native/pull/7586)) * Fixed an issue that collapsed consecutive newlines within text labels. ([#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446)) * Fixed artifacts when drawing particularly acute line joins. ([#7786](https://github.com/mapbox/mapbox-gl-native/pull/7786)) -* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989)) +* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989), [#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971)) +* Fixed an issue causing vector style layer predicates to be evaluated as if each feature had a `$type` attribute of 1, 2, or 3. The `$type` key path can now be compared to `Point`, `LineString`, or `Polygon`, as described in the documentation. ([#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971)) ### Networking and offline maps diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index eb06c36e367..728f1798f32 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -21,7 +21,8 @@ * Removed support for the `ref` property in layers in style JSON files. ([#7586](https://github.com/mapbox/mapbox-gl-native/pull/7586)) * Fixed an issue that collapsed consecutive newlines within text labels. ([#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446)) * Fixed artifacts when drawing particularly acute line joins. ([#7786](https://github.com/mapbox/mapbox-gl-native/pull/7786)) -* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989)) +* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989), [#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971)) +* Fixed an issue causing vector style layer predicates to be evaluated as if each feature had a `$type` attribute of 1, 2, or 3. The `$type` key path can now be compared to `Point`, `LineString`, or `Polygon`, as described in the documentation. ([#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971)) ### Networking and offline maps