Skip to content

Commit

Permalink
fix: App crash when using QueryConstraint (#193)
Browse files Browse the repository at this point in the history
* fix: App crash when using QueryConstraint

* Update ci.yml

* fix tests
  • Loading branch information
cbaker6 authored Feb 27, 2025
1 parent 54de43d commit 157401b
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 58 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
runs-on: macos-15
strategy:
matrix:
destination: ['platform=iOS\ Simulator,OS=18.2,name=iPhone\ 16\ Pro\ Max', 'platform\=tvOS\ Simulator,OS=18.2,name\=Apple\ TV', 'platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 10\ \(42mm\)', 'platform=macOS', 'platform=visionOS\ Simulator,OS=2.2,name=Apple\ Vision\ Pro']
destination: ['platform=iOS\ Simulator,OS=18.2,name=iPhone\ 16\ Pro\ Max', 'platform\=tvOS\ Simulator,OS=18.2,name\=Apple\ TV', 'platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 10\ \(46mm\)', 'platform=macOS', 'platform=visionOS\ Simulator,OS=2.2,name=Apple\ Vision\ Pro']
action: ['test', 'build']
exclude:
- destination: 'platform=iOS\ Simulator,OS=18.2,name=iPhone\ 16\ Pro\ Max'
Expand All @@ -33,7 +33,7 @@ jobs:
action: 'build'
- destination: 'platform=visionOS\ Simulator,OS=2.2,name=Apple\ Vision\ Pro'
action: 'test'
- destination: 'platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 10\ \(42mm\)'
- destination: 'platform=watchOS\ Simulator,name=Apple\ Watch\ Series\ 10\ \(46mm\)'
action: 'test'
steps:
- uses: actions/checkout@v4
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.11.4...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.11.5...main), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/main/documentation/parseswift)
* _Contributing to this repo? Add info about your change here to be included in the next release_

### 5.11.5
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.11.4...5.11.5), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.11.5/documentation/parseswift)

__Fixes__
* Fix app crash when using QueryConstraint == ([#193](https://github.com/netreconlab/Parse-Swift/pull/193)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.11.4
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.11.3...5.11.4), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.11.4/documentation/parseswift)

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 = "5.11.3"
static let version = "5.11.5"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down
8 changes: 6 additions & 2 deletions Sources/ParseSwift/Types/ParseConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,12 @@ public struct ParseConfiguration {
/// - warning: This is experimental.
public internal(set) var isUsingTransactions = false

/// Use the **$eq** query constraint when querying.
/// - warning: This is known not to work for LiveQuery on Parse Servers <= 5.0.0.
/// ParseSwift uses the **$eq** query constraint by default when querying.
/// - warning: This method uses `$eq` and can
/// be combined with all other `QueryConstaint`'s. It has the limitation of
/// not to working for LiveQuery on Parse Servers `< 6.3.0`. If you are using
/// an older Parse Server, you should use `equalToNoComparator()`
@available(*, deprecated, message: "Changing has no effect. This will be remove in ParseSwift 6.0.0")
public internal(set) var isUsingEqualQueryConstraint = false

/// Use **POST** instead of **GET** when making query calls.
Expand Down
105 changes: 67 additions & 38 deletions Sources/ParseSwift/Types/QueryConstraint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ public func <= <T>(key: String, value: T) -> QueryConstraint where T: Codable {
- parameter value: The value to compare.
- returns: The same instance of `QueryConstraint` as the receiver.
- warning: See `equalTo` for more information.
Behavior changes based on `ParseSwift.configuration.isUsingEqualQueryConstraint`
where isUsingEqualQueryConstraint == true is known not to work for LiveQuery on
Parse Servers <= 5.0.0.
This method uses `$eq` and can
be combined with all other `QueryConstaint`'s. It has the limitation of
not to working for LiveQuery on Parse Servers `< 6.3.0`. If you are using
an older Parse Server, you should use `equalToNoComparator()`
instead.
*/
public func == <T>(key: String, value: T) -> QueryConstraint where T: Codable {
equalTo(key: key, value: value)
Expand All @@ -145,23 +147,33 @@ public func == <T>(key: String, value: T) -> QueryConstraint where T: Codable {
Add a constraint that requires that a key is equal to a value.
- parameter key: The key that the value is stored in.
- parameter value: The value to compare.
- parameter usingEqComparator: Set to **true** to use **$eq** comparater,
allowing for multiple `QueryConstraint`'s to be used on a single **key**.
Setting to *false* may override any `QueryConstraint`'s on the same **key**.
Defaults to `ParseSwift.configuration.isUsingEqualQueryConstraint`.
- returns: The same instance of `QueryConstraint` as the receiver.
- warning: `usingEqComparator == true` is known not to work for LiveQueries
on Parse Servers <= 5.0.0.
*/
public func equalTo <T>(key: String,
value: T,
// swiftlint:disable:next line_length
usingEqComparator: Bool = configuration.isUsingEqualQueryConstraint) -> QueryConstraint where T: Codable {
if !usingEqComparator {
return QueryConstraint(key: key, value: value)
} else {
return QueryConstraint(key: key, value: value, comparator: .equalTo)
}
- warning: This method uses `$eq` and can
be combined with all other `QueryConstaint`'s. It has the limitation of
not to working for LiveQuery on Parse Servers `< 6.3.0`. If you are using
an older Parse Server, you should use `equalToNoComparator()`
instead.
*/
public func equalTo<T>(
key: String,
value: T
) -> QueryConstraint where T: Codable {
QueryConstraint(key: key, value: value, comparator: .equalTo)
}

/**
Add a constraint that requires that a key is equal to a value.
- parameter key: The key that the value is stored in.
- parameter value: The value to compare.
- returns: The same instance of `QueryConstraint` as the receiver.
- warning: This `QueryConstaint` has the limitation of being able to be combined
with other `QueryConstraint`'s. It does however work with all versions of LiveQuery.
*/
public func equalToNoComparator<T>(
key: String,
value: T
) -> QueryConstraint where T: Codable {
QueryConstraint(key: key, value: value)
}

/**
Expand All @@ -171,9 +183,11 @@ public func equalTo <T>(key: String,
- returns: The same instance of `QueryConstraint` as the receiver.
- throws: An error of type `ParseError`.
- warning: See `equalTo` for more information.
Behavior changes based on `ParseSwift.configuration.isUsingEqualQueryConstraint`
where isUsingEqualQueryConstraint == true is known not to work for LiveQuery on
Parse Servers <= 5.0.0.
This method uses `$eq` and can
be combined with all other `QueryConstaint`'s. It has the limitation of
not to working for LiveQuery on Parse Servers `< 6.3.0`. If you are using
an older Parse Server, you should use `equalToNoComparator()`
instead.
*/
public func == <T>(key: String, object: T) throws -> QueryConstraint where T: ParseObject {
try equalTo(key: key, object: object)
Expand All @@ -183,24 +197,39 @@ public func == <T>(key: String, object: T) throws -> QueryConstraint where T: Pa
Add a constraint that requires that a key is equal to a `ParseObject`.
- parameter key: The key that the value is stored in.
- parameter object: The `ParseObject` to compare.
- parameter usingEqComparator: Set to **true** to use **$eq** comparater,
allowing for multiple `QueryConstraint`'s to be used on a single **key**.
Setting to *false* may override any `QueryConstraint`'s on the same **key**.
Defaults to `ParseSwift.configuration.isUsingEqualQueryConstraint`.
- returns: The same instance of `QueryConstraint` as the receiver.
- throws: An error of type `ParseError`.
- warning: `usingEqComparator == true` is known not to work for LiveQueries
on Parse Servers <= 5.0.0.
*/
public func equalTo <T>(key: String,
object: T,
// swiftlint:disable:next line_length
usingEqComparator: Bool = configuration.isUsingEqualQueryConstraint) throws -> QueryConstraint where T: ParseObject {
if !usingEqComparator {
return try QueryConstraint(key: key, value: object.toPointer())
} else {
return try QueryConstraint(key: key, value: object.toPointer(), comparator: .equalTo)
}
- warning: This method uses `$eq` and can
be combined with all other `QueryConstaint`'s. It has the limitation of
not to working for LiveQuery on Parse Servers `< 6.3.0`. If you are using
an older Parse Server, you should use `equalToNoComparator()`
instead.
*/
public func equalTo<T>(
key: String,
object: T
) throws -> QueryConstraint where T: ParseObject {
try QueryConstraint(
key: key,
value: object.toPointer(),
comparator: .equalTo
)
}

/**
Add a constraint that requires that a key is equal to a `ParseObject`.
- parameter key: The key that the value is stored in.
- parameter object: The `ParseObject` to compare.
- returns: The same instance of `QueryConstraint` as the receiver.
- throws: An error of type `ParseError`.
- warning: This `QueryConstaint` has the limitation of being able to be combined
with other `QueryConstraint`'s. It does however work with all versions of LiveQuery.
*/
public func equalToNoComparator<T>(
key: String,
object: T
) throws -> QueryConstraint where T: ParseObject {
try QueryConstraint(key: key, value: object.toPointer())
}

/**
Expand Down
14 changes: 12 additions & 2 deletions Tests/ParseSwiftTests/APICommandTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,12 @@ class APICommandTests: XCTestCase {
}

func testQueryWhereEncoding() async throws {
let query = Level.query("name" == "test@parse.com")
let query = Level.query(
equalToNoComparator(
key: "name",
value: "test@parse.com"
)
)
let parameters = try query.getQueryParameters()

let queryCommand = API.NonParseBodyCommand<Query<Level>, Level?>(
Expand All @@ -432,7 +437,12 @@ class APICommandTests: XCTestCase {
}

func testQueryWhereEncodingPlus() async throws {
let query = Level.query("name" == "test+1@parse.com")
let query = Level.query(
equalToNoComparator(
key: "name",
value: "test+1@parse.com"
)
)
let parameters = try query.getQueryParameters()

let queryCommand = API.NonParseBodyCommand<Query<Level>, Level?>(
Expand Down
41 changes: 29 additions & 12 deletions Tests/ParseSwiftTests/ParseQueryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1210,11 +1210,16 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

func testWhereKeyEqualTo() {
func testWhereKeyEqualToNoComparator() {
let expected: [String: String] = [
"yolo": "yarr"
]
let query = GameScore.query("yolo" == "yarr")
let query = GameScore.query(
equalToNoComparator(
key: "yolo",
value: "yarr"
)
)
let queryWhere = query.`where`

do {
Expand All @@ -1234,8 +1239,13 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertThrowsError(try GameScore.query("yolo" == compareObject))
}

func testWhereKeyEqualToBool() throws {
let query = GameScore.query("isCounts" == true)
func testWhereKeyEqualToBoolNoComparator() throws {
let query = GameScore.query(
equalToNoComparator(
key: "isCounts",
value: true
)
)
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"isCounts\":true}}"
XCTAssertEqual(query.debugDescription, expected)
XCTAssertEqual(query.description, expected)
Expand All @@ -1245,7 +1255,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
}

func testWhereKeyEqualToBoolEQ() throws {
let query = GameScore.query(equalTo(key: "isCounts", value: true, usingEqComparator: true))
let query = GameScore.query("isCounts" == true)
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"isCounts\":{\"$eq\":true}}}"
XCTAssertEqual(query.debugDescription, expected)
XCTAssertEqual(query.description, expected)
Expand All @@ -1254,10 +1264,15 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertEqual(query, decoded)
}

func testWhereKeyEqualToParseObject() throws {
func testWhereKeyEqualToParseObjectNoComparator() throws {
var compareObject = GameScore(points: 11)
compareObject.objectId = "hello"
let query = try GameScore.query("yolo" == compareObject)
let query = try GameScore.query(
equalToNoComparator(
key: "yolo",
object: compareObject
)
)
// swiftlint:disable:next line_length
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}"
XCTAssertEqual(query.debugDescription, expected)
Expand All @@ -1269,7 +1284,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
func testWhereKeyEqualToParseObjectEQ() throws {
var compareObject = GameScore(points: 11)
compareObject.objectId = "hello"
let query = try GameScore.query(equalTo(key: "yolo", object: compareObject, usingEqComparator: true))
let query = try GameScore.query("yolo" == compareObject)
// swiftlint:disable:next line_length
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"$eq\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}}"
XCTAssertEqual(query.debugDescription, expected)
Expand All @@ -1281,10 +1296,12 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
func testWhereKeyEqualToParseObjectDuplicateConstraint() throws {
var compareObject = GameScore(points: 11)
compareObject.objectId = "hello"
let query = try GameScore.query("yolo" == compareObject,
"yolo" == compareObject)
let query = try GameScore.query(
"yolo" == compareObject,
"yolo" == compareObject
)
// swiftlint:disable:next line_length
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}"
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"$eq\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}}"
XCTAssertEqual(query.debugDescription, expected)
let encoded = try ParseCoding.jsonEncoder().encode(query)
let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)
Expand All @@ -1297,7 +1314,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length
let pointer = try compareObject.toPointer()
let query = GameScore.query("yolo" == pointer)
// swiftlint:disable:next line_length
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}"
let expected = "{\"_method\":\"GET\",\"limit\":100,\"skip\":0,\"where\":{\"yolo\":{\"$eq\":{\"__type\":\"Pointer\",\"className\":\"GameScore\",\"objectId\":\"hello\"}}}}"
XCTAssertEqual(query.debugDescription, expected)
let encoded = try ParseCoding.jsonEncoder().encode(query)
let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)
Expand Down

0 comments on commit 157401b

Please sign in to comment.