Skip to content

Commit

Permalink
fix: polygon query not encoding properly (#381)
Browse files Browse the repository at this point in the history
* fix: polygon query not encoding properly

* fix tests

* swap longitude and latitude when encoding ParsePolygon

* Disable modified tests on linux
  • Loading branch information
cbaker6 authored Jul 13, 2022
1 parent 926fc05 commit 3b36877
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 74 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

### main

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

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

__Fixes__
- Encode withinPolygon Queryconstraint correctly ([#381](https://github.com/parse-community/Parse-Swift/pull/381)), thanks to [Corey Baker](https://github.com/cbaker6).
- 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).

### 4.7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,58 @@ query8.findAll { result in
}
}

do {
let points: [ParseGeoPoint] = [
try .init(latitude: 35.0, longitude: -28.0),
try .init(latitude: 45.0, longitude: -28.0),
try .init(latitude: 39.0, longitude: -35.0)
]
let query9 = GameScore.query(withinPolygon(key: "location", points: points))
query9.find { results in
switch results {
case .success(let scores):

scores.forEach { (score) in
print("""
Someone has a points value of \"\(String(describing: score.points))\"
with a geolocation \(String(describing: score.location)) within the
polygon using points: \(points)
""")
}
case .failure(let error):
assertionFailure("Error querying: \(error)")
}
}
} catch {
print("Could not create geopoints: \(error)")
}

do {
let points: [ParseGeoPoint] = [
try .init(latitude: 35.0, longitude: -28.0),
try .init(latitude: 45.0, longitude: -28.0),
try .init(latitude: 39.0, longitude: -35.0)
]
let polygon = try ParsePolygon(points)
let query10 = GameScore.query(withinPolygon(key: "location", polygon: polygon))
query10.find { results in
switch results {
case .success(let scores):
scores.forEach { (score) in
print("""
Someone has a points value of \"\(String(describing: score.points))\"
with a geolocation \(String(describing: score.location)) within the
polygon: \(polygon)
""")
}
case .failure(let error):
assertionFailure("Error querying: \(error)")
}
}
} catch {
print("Could not create geopoints: \(error)")
}

//: Hint of the previous query (asynchronous)
query2 = query2.hint("_id_")
query2.find { result in
Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/ParseConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

enum ParseConstants {
static let sdk = "swift"
static let version = "4.7.0"
static let version = "4.8.0"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down
6 changes: 3 additions & 3 deletions Sources/ParseSwift/Types/ParsePolygon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ extension ParsePolygon {
let points = try values.decode([[Double]].self, forKey: .coordinates)
try points.forEach {
if $0.count == 2 {
guard let latitude = $0.first,
let longitude = $0.last else {
guard let latitude = $0.last,
let longitude = $0.first else {
throw ParseError(code: .unknownError, message: "Could not decode ParsePolygon: \(points)")
}
decodedCoordinates.append(try ParseGeoPoint(latitude: latitude,
Expand All @@ -125,7 +125,7 @@ extension ParsePolygon {
try container.encode(__type, forKey: .__type)
var nestedUnkeyedContainer = container.nestedUnkeyedContainer(forKey: .coordinates)
try coordinates.forEach {
try nestedUnkeyedContainer.encode([$0.latitude, $0.longitude])
try nestedUnkeyedContainer.encode([$0.longitude, $0.latitude])
}
}
}
4 changes: 1 addition & 3 deletions Sources/ParseSwift/Types/QueryConstraint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,7 @@ public func withinGeoBox(key: String, fromSouthWest southwest: ParseGeoPoint,
- returns: The same instance of `QueryConstraint` as the receiver.
*/
public func withinPolygon(key: String, points: [ParseGeoPoint]) -> QueryConstraint {
let polygon = points.flatMap { [[$0.latitude, $0.longitude]]}
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: polygon]
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: points]
return .init(key: key, value: dictionary, comparator: .geoWithin)
}

Expand All @@ -604,7 +603,6 @@ public func withinPolygon(key: String, points: [ParseGeoPoint]) -> QueryConstrai
- returns: The same instance of `QueryConstraint` as the receiver.
*/
public func withinPolygon(key: String, polygon: ParsePolygon) -> QueryConstraint {
let polygon = polygon.coordinates.flatMap { [[$0.latitude, $0.longitude]]}
let dictionary = [QueryConstraint.Comparator.polygon.rawValue: polygon]
return .init(key: key, value: dictionary, comparator: .geoWithin)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/ParseSwiftTests/ParsePolygonTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,13 @@ class ParsePolygonTests: XCTestCase {

func testDebugString() throws {
let polygon = try ParsePolygon(points)
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[0,1],[1,1],[1,0],[0,0]]}"
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}"
XCTAssertEqual(polygon.debugDescription, expected)
}

func testDescription() throws {
let polygon = try ParsePolygon(points)
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[0,1],[1,1],[1,0],[0,0]]}"
let expected = "{\"__type\":\"Polygon\",\"coordinates\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}"
XCTAssertEqual(polygon.description, expected)
}
}
72 changes: 8 additions & 64 deletions Tests/ParseSwiftTests/ParseQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2924,89 +2924,33 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

#if !os(Linux) && !os(Android) && !os(Windows)
// swiftlint:disable:next function_body_length
func testWhereKeyWithinPolygonPoints() throws {
let expected: [String: AnyCodable] = [
"yolo": ["$geoWithin": ["$polygon": [
[10.1, 20.1],
[20.1, 30.1],
[30.1, 40.1]]
]
]
]
// swiftlint:disable:next line_length
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}]}}}"
let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)
let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)
let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)
let polygon = [geoPoint1, geoPoint2, geoPoint3]
let constraint = withinPolygon(key: "yolo", points: polygon)
let query = GameScore.query(constraint)
let queryWhere = query.`where`

do {
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
XCTAssertEqual(expected.keys, decodedDictionary.keys)

guard let expectedValues = expected.values.first?.value as? [String: [String: [[Double]]]],
let expectedBox = expectedValues["$geoWithin"]?["$polygon"] else {
XCTFail("Should have casted")
return
}

guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [[Double]]]],
let decodedBox = decodedValues["$geoWithin"]?["$polygon"] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(expectedBox, decodedBox)

} catch {
XCTFail(error.localizedDescription)
return
}
XCTAssertEqual(query.where.description, expected)
}

// swiftlint:disable:next function_body_length
func testWhereKeyWithinPolygon() throws {
let expected: [String: AnyCodable] = [
"yolo": ["$geoWithin": ["$polygon": [
[10.1, 20.1],
[20.1, 30.1],
[30.1, 40.1]]
]
]
]
// swiftlint:disable:next line_length
let expected = "{\"yolo\":{\"$geoWithin\":{\"$polygon\":{\"__type\":\"Polygon\",\"coordinates\":[[20.100000000000001,10.1],[30.100000000000001,20.100000000000001],[40.100000000000001,30.100000000000001]]}}}}"
let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)
let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)
let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)
let polygon = try ParsePolygon(geoPoint1, geoPoint2, geoPoint3)
let constraint = withinPolygon(key: "yolo", polygon: polygon)
let query = GameScore.query(constraint)
let queryWhere = query.`where`

do {
let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)
let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)
XCTAssertEqual(expected.keys, decodedDictionary.keys)

guard let expectedValues = expected.values.first?.value as? [String: [String: [[Double]]]],
let expectedBox = expectedValues["$geoWithin"]?["$polygon"] else {
XCTFail("Should have casted")
return
}

guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [[Double]]]],
let decodedBox = decodedValues["$geoWithin"]?["$polygon"] else {
XCTFail("Should have casted")
return
}
XCTAssertEqual(expectedBox, decodedBox)

} catch {
XCTFail(error.localizedDescription)
return
}
XCTAssertEqual(query.where.description, expected)
}
#endif

func testWhereKeyPolygonContains() throws {
let expected: [String: AnyCodable] = [
Expand Down

0 comments on commit 3b36877

Please sign in to comment.