diff --git a/Parse/Internal/Query/PFQueryConstants.h b/Parse/Internal/Query/PFQueryConstants.h index d86c189fb..b311073df 100644 --- a/Parse/Internal/Query/PFQueryConstants.h +++ b/Parse/Internal/Query/PFQueryConstants.h @@ -21,6 +21,7 @@ extern NSString *const PFQueryKeyNotContainedIn; extern NSString *const PFQueryKeyContainsAll; extern NSString *const PFQueryKeyNearSphere; extern NSString *const PFQueryKeyWithin; +extern NSString *const PFQueryKeyGeoWithin; extern NSString *const PFQueryKeyRegex; extern NSString *const PFQueryKeyExists; extern NSString *const PFQueryKeyInQuery; @@ -35,6 +36,7 @@ extern NSString *const PFQueryKeyObject; extern NSString *const PFQueryOptionKeyMaxDistance; extern NSString *const PFQueryOptionKeyBox; +extern NSString *const PFQueryOptionKeyPolygon; extern NSString *const PFQueryOptionKeyRegexOptions; NS_ASSUME_NONNULL_END diff --git a/Parse/Internal/Query/PFQueryConstants.m b/Parse/Internal/Query/PFQueryConstants.m index 8a9d98be7..b84beb009 100644 --- a/Parse/Internal/Query/PFQueryConstants.m +++ b/Parse/Internal/Query/PFQueryConstants.m @@ -19,6 +19,7 @@ NSString *const PFQueryKeyContainsAll = @"$all"; NSString *const PFQueryKeyNearSphere = @"$nearSphere"; NSString *const PFQueryKeyWithin = @"$within"; +NSString *const PFQueryKeyGeoWithin = @"$geoWithin"; NSString *const PFQueryKeyRegex = @"$regex"; NSString *const PFQueryKeyExists = @"$exists"; NSString *const PFQueryKeyInQuery = @"$inQuery"; @@ -33,4 +34,5 @@ NSString *const PFQueryOptionKeyMaxDistance = @"$maxDistance"; NSString *const PFQueryOptionKeyBox = @"$box"; +NSString *const PFQueryOptionKeyPolygon = @"$polygon"; NSString *const PFQueryOptionKeyRegexOptions = @"$options"; diff --git a/Parse/PFQuery.h b/Parse/PFQuery.h index d28137c40..6f86cd1c1 100644 --- a/Parse/PFQuery.h +++ b/Parse/PFQuery.h @@ -308,6 +308,21 @@ typedef void (^PFQueryArrayResultBlock)(NSArray *_Nullable obje */ - (instancetype)whereKey:(NSString *)key withinGeoBoxFromSouthwest:(PFGeoPoint *)southwest toNortheast:(PFGeoPoint *)northeast; +/** + * Add a constraint to the query that requires a particular key's + * coordinates be contained within and on the bounds of a given polygon + * Supports closed and open (last point is connected to first) paths. + * (Requires parse-server@2.5.0) + * + * Polygon must have at least 3 points + * + * @param key The key to be constrained. + * @param points The polygon points as an Array of `PFGeoPoint`'s. + * + * @return The same instance of `PFQuery` as the receiver. This allows method chaining. + */ +- (instancetype)whereKey:(NSString *)key withinPolygon:(NSArray *)points; + ///-------------------------------------- #pragma mark - Adding String Constraints ///-------------------------------------- diff --git a/Parse/PFQuery.m b/Parse/PFQuery.m index e346d6401..3a1faa9e9 100644 --- a/Parse/PFQuery.m +++ b/Parse/PFQuery.m @@ -301,6 +301,11 @@ - (instancetype)whereKey:(NSString *)key withinGeoBoxFromSouthwest:(PFGeoPoint * return [self whereKey:key condition:PFQueryKeyWithin object:dictionary]; } +- (instancetype)whereKey:(NSString *)key withinPolygon:(NSArray *)points { + NSDictionary *dictionary = @{ PFQueryOptionKeyPolygon : points }; + return [self whereKey:key condition:PFQueryKeyGeoWithin object:dictionary]; +} + - (instancetype)whereKey:(NSString *)key matchesRegex:(NSString *)regex { return [self whereKey:key condition:PFQueryKeyRegex object:regex]; } diff --git a/Tests/Unit/QueryUnitTests.m b/Tests/Unit/QueryUnitTests.m index 24d33b634..b366452c6 100644 --- a/Tests/Unit/QueryUnitTests.m +++ b/Tests/Unit/QueryUnitTests.m @@ -415,6 +415,16 @@ - (void)testWhereKeyWithinGeobox { XCTAssertEqualObjects(query.state.conditions, (@{ @"yolo" : @{@"$within" : @{@"$box" : @[ geoPoint1, geoPoint2 ]}} })); } +- (void)testWhereKeyWithinPolygon { + PFGeoPoint *geoPoint1 = [PFGeoPoint geoPointWithLatitude:10.0 longitude:20.0]; + PFGeoPoint *geoPoint2 = [PFGeoPoint geoPointWithLatitude:20.0 longitude:30.0]; + PFGeoPoint *geoPoint3 = [PFGeoPoint geoPointWithLatitude:30.0 longitude:40.0]; + + PFQuery *query = [PFQuery queryWithClassName:@"a"]; + [query whereKey:@"yolo" withinPolygon:@[geoPoint1, geoPoint2, geoPoint3]]; + XCTAssertEqualObjects(query.state.conditions, (@{ @"yolo" : @{@"$geoWithin" : @{@"$polygon" : @[ geoPoint1, geoPoint2, geoPoint3 ]}} })); +} + - (void)testWhereKeyMatchesRegex { PFQuery *query = [PFQuery queryWithClassName:@"a"]; [query whereKey:@"yolo" matchesRegex:@"yarr"];