Skip to content

Commit 3b36877

Browse files
authored
fix: polygon query not encoding properly (#381)
* fix: polygon query not encoding properly * fix tests * swap longitude and latitude when encoding ParsePolygon * Disable modified tests on linux
1 parent 926fc05 commit 3b36877

File tree

7 files changed

+69
-74
lines changed

7 files changed

+69
-74
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
### main
44

5-
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.7.0...main)
5+
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.8.0...main)
66
* _Contributing to this repo? Add info about your change here to be included in the next release_
77

88
__New features__
99
- Add ParseSpotify authentication ([#375](https://github.com/parse-community/Parse-Swift/pull/375)), thanks to [Ulaş Sancak](https://github.com/rocxteady).
1010

1111
__Fixes__
12+
- Encode withinPolygon Queryconstraint correctly ([#381](https://github.com/parse-community/Parse-Swift/pull/381)), thanks to [Corey Baker](https://github.com/cbaker6).
1213
- Use select for ParseLiveQuery when fields are not present ([#376](https://github.com/parse-community/Parse-Swift/pull/376)), thanks to [Corey Baker](https://github.com/cbaker6).
1314

1415
### 4.7.0

ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift

+52
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,58 @@ query8.findAll { result in
251251
}
252252
}
253253

254+
do {
255+
let points: [ParseGeoPoint] = [
256+
try .init(latitude: 35.0, longitude: -28.0),
257+
try .init(latitude: 45.0, longitude: -28.0),
258+
try .init(latitude: 39.0, longitude: -35.0)
259+
]
260+
let query9 = GameScore.query(withinPolygon(key: "location", points: points))
261+
query9.find { results in
262+
switch results {
263+
case .success(let scores):
264+
265+
scores.forEach { (score) in
266+
print("""
267+
Someone has a points value of \"\(String(describing: score.points))\"
268+
with a geolocation \(String(describing: score.location)) within the
269+
polygon using points: \(points)
270+
""")
271+
}
272+
case .failure(let error):
273+
assertionFailure("Error querying: \(error)")
274+
}
275+
}
276+
} catch {
277+
print("Could not create geopoints: \(error)")
278+
}
279+
280+
do {
281+
let points: [ParseGeoPoint] = [
282+
try .init(latitude: 35.0, longitude: -28.0),
283+
try .init(latitude: 45.0, longitude: -28.0),
284+
try .init(latitude: 39.0, longitude: -35.0)
285+
]
286+
let polygon = try ParsePolygon(points)
287+
let query10 = GameScore.query(withinPolygon(key: "location", polygon: polygon))
288+
query10.find { results in
289+
switch results {
290+
case .success(let scores):
291+
scores.forEach { (score) in
292+
print("""
293+
Someone has a points value of \"\(String(describing: score.points))\"
294+
with a geolocation \(String(describing: score.location)) within the
295+
polygon: \(polygon)
296+
""")
297+
}
298+
case .failure(let error):
299+
assertionFailure("Error querying: \(error)")
300+
}
301+
}
302+
} catch {
303+
print("Could not create geopoints: \(error)")
304+
}
305+
254306
//: Hint of the previous query (asynchronous)
255307
query2 = query2.hint("_id_")
256308
query2.find { result in

Sources/ParseSwift/ParseConstants.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010

1111
enum ParseConstants {
1212
static let sdk = "swift"
13-
static let version = "4.7.0"
13+
static let version = "4.8.0"
1414
static let fileManagementDirectory = "parse/"
1515
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
1616
static let fileManagementLibraryDirectory = "Library/"

Sources/ParseSwift/Types/ParsePolygon.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ extension ParsePolygon {
105105
let points = try values.decode([[Double]].self, forKey: .coordinates)
106106
try points.forEach {
107107
if $0.count == 2 {
108-
guard let latitude = $0.first,
109-
let longitude = $0.last else {
108+
guard let latitude = $0.last,
109+
let longitude = $0.first else {
110110
throw ParseError(code: .unknownError, message: "Could not decode ParsePolygon: \(points)")
111111
}
112112
decodedCoordinates.append(try ParseGeoPoint(latitude: latitude,
@@ -125,7 +125,7 @@ extension ParsePolygon {
125125
try container.encode(__type, forKey: .__type)
126126
var nestedUnkeyedContainer = container.nestedUnkeyedContainer(forKey: .coordinates)
127127
try coordinates.forEach {
128-
try nestedUnkeyedContainer.encode([$0.latitude, $0.longitude])
128+
try nestedUnkeyedContainer.encode([$0.longitude, $0.latitude])
129129
}
130130
}
131131
}

Sources/ParseSwift/Types/QueryConstraint.swift

+1-3
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,7 @@ public func withinGeoBox(key: String, fromSouthWest southwest: ParseGeoPoint,
588588
- returns: The same instance of `QueryConstraint` as the receiver.
589589
*/
590590
public func withinPolygon(key: String, points: [ParseGeoPoint]) -> QueryConstraint {
591-
let polygon = points.flatMap { [[$0.latitude, $0.longitude]]}
592-
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: polygon]
591+
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: points]
593592
return .init(key: key, value: dictionary, comparator: .geoWithin)
594593
}
595594

@@ -604,7 +603,6 @@ public func withinPolygon(key: String, points: [ParseGeoPoint]) -> QueryConstrai
604603
- returns: The same instance of `QueryConstraint` as the receiver.
605604
*/
606605
public func withinPolygon(key: String, polygon: ParsePolygon) -> QueryConstraint {
607-
let polygon = polygon.coordinates.flatMap { [[$0.latitude, $0.longitude]]}
608606
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: polygon]
609607
return .init(key: key, value: dictionary, comparator: .geoWithin)
610608
}

Tests/ParseSwiftTests/ParsePolygonTests.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,13 @@ class ParsePolygonTests: XCTestCase {
117117

118118
func testDebugString() throws {
119119
let polygon = try ParsePolygon(points)
120-
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[0,1],[1,1],[1,0],[0,0]]}"
120+
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}"
121121
XCTAssertEqual(polygon.debugDescription, expected)
122122
}
123123

124124
func testDescription() throws {
125125
let polygon = try ParsePolygon(points)
126-
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[0,1],[1,1],[1,0],[0,0]]}"
126+
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}"
127127
XCTAssertEqual(polygon.description, expected)
128128
}
129129
}

Tests/ParseSwiftTests/ParseQueryTests.swift

+8-64
Original file line numberDiff line numberDiff line change
@@ -2924,89 +2924,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
29242924
}
29252925
}
29262926

2927+
#if !os(Linux) && !os(Android) && !os(Windows)
29272928
// swiftlint:disable:next function_body_length
29282929
func testWhereKeyWithinPolygonPoints() throws {
2929-
let expected: [String: AnyCodable] = [
2930-
"yolo": ["$geoWithin": ["$polygon": [
2931-
[10.1, 20.1],
2932-
[20.1, 30.1],
2933-
[30.1, 40.1]]
2934-
]
2935-
]
2936-
]
2930+
// swiftlint:disable:next line_length
2931+
let expected = "{\"yolo\":{\"$geoWithin\":{\"$polygon\":[{\"__type\":\"GeoPoint\",\"latitude\":10.1,\"longitude\":20.100000000000001},{\"__type\":\"GeoPoint\",\"latitude\":20.100000000000001,\"longitude\":30.100000000000001},{\"__type\":\"GeoPoint\",\"latitude\":30.100000000000001,\"longitude\":40.100000000000001}]}}}"
29372932
let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)
29382933
let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)
29392934
let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)
29402935
let polygon = [geoPoint1, geoPoint2, geoPoint3]
29412936
let constraint = withinPolygon(key: "yolo", points: polygon)
29422937
let query = GameScore.query(constraint)
2943-
let queryWhere = query.`where`
2944-
2945-
do {
2946-
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
2947-
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
2948-
XCTAssertEqual(expected.keys, decodedDictionary.keys)
2949-
2950-
guard let expectedValues = expected.values.first?.value as? [String: [String: [[Double]]]],
2951-
let expectedBox = expectedValues["$geoWithin"]?["$polygon"] else {
2952-
XCTFail("Should have casted")
2953-
return
2954-
}
2955-
2956-
guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [[Double]]]],
2957-
let decodedBox = decodedValues["$geoWithin"]?["$polygon"] else {
2958-
XCTFail("Should have casted")
2959-
return
2960-
}
2961-
XCTAssertEqual(expectedBox, decodedBox)
2962-
2963-
} catch {
2964-
XCTFail(error.localizedDescription)
2965-
return
2966-
}
2938+
XCTAssertEqual(query.where.description, expected)
29672939
}
29682940

29692941
// swiftlint:disable:next function_body_length
29702942
func testWhereKeyWithinPolygon() throws {
2971-
let expected: [String: AnyCodable] = [
2972-
"yolo": ["$geoWithin": ["$polygon": [
2973-
[10.1, 20.1],
2974-
[20.1, 30.1],
2975-
[30.1, 40.1]]
2976-
]
2977-
]
2978-
]
2943+
// swiftlint:disable:next line_length
2944+
let expected = "{\"yolo\":{\"$geoWithin\":{\"$polygon\":{\"__type\":\"Polygon\",\"coordinates\":[[20.100000000000001,10.1],[30.100000000000001,20.100000000000001],[40.100000000000001,30.100000000000001]]}}}}"
29792945
let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)
29802946
let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)
29812947
let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)
29822948
let polygon = try ParsePolygon(geoPoint1, geoPoint2, geoPoint3)
29832949
let constraint = withinPolygon(key: "yolo", polygon: polygon)
29842950
let query = GameScore.query(constraint)
2985-
let queryWhere = query.`where`
2986-
2987-
do {
2988-
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
2989-
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
2990-
XCTAssertEqual(expected.keys, decodedDictionary.keys)
2991-
2992-
guard let expectedValues = expected.values.first?.value as? [String: [String: [[Double]]]],
2993-
let expectedBox = expectedValues["$geoWithin"]?["$polygon"] else {
2994-
XCTFail("Should have casted")
2995-
return
2996-
}
2997-
2998-
guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [[Double]]]],
2999-
let decodedBox = decodedValues["$geoWithin"]?["$polygon"] else {
3000-
XCTFail("Should have casted")
3001-
return
3002-
}
3003-
XCTAssertEqual(expectedBox, decodedBox)
3004-
3005-
} catch {
3006-
XCTFail(error.localizedDescription)
3007-
return
3008-
}
2951+
XCTAssertEqual(query.where.description, expected)
30092952
}
2953+
#endif
30102954

30112955
func testWhereKeyPolygonContains() throws {
30122956
let expected: [String: AnyCodable] = [

0 commit comments

Comments
 (0)