Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Improve Equatable and Hashable conformance #148

Merged
merged 5 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ __New features__
* Add fetchAll method to array of Parse Pointer Object's ([#141](https://github.com/netreconlab/Parse-Swift/pull/141)), thanks to [Corey Baker](https://github.com/cbaker6).

__Fixes__
* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).
* Improve mutiple types conformance to Equatable and Hashable ([#148](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).
* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/148)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.8.2
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.1...5.8.2), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.8.2/documentation/parseswift)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ score.save { result in
}

//: This will store the second batch score to be used later.
var score2ForFetchedLater: GameScore?
var scoreToFetchLater: GameScore?
var score2ToFetchLater: GameScore?

//: Saving multiple GameScores at once with batching.
[score, score2].saveAll { results in
Expand All @@ -179,8 +180,10 @@ var score2ForFetchedLater: GameScore?
Saved \"\(savedScore.className)\" with
points \(String(describing: savedScore.points)) successfully
""")
if index == 1 {
score2ForFetchedLater = savedScore
if index == 0 {
scoreToFetchLater = savedScore
} else if index == 1 {
score2ToFetchLater = savedScore
}
index += 1
case .failure(let error):
Expand All @@ -203,8 +206,10 @@ var score2ForFetchedLater: GameScore?
switch otherResult {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with points \(savedScore.points) successfully")
if index == 1 {
score2ForFetchedLater = savedScore
if index == 0 {
scoreToFetchLater = savedScore
} else if index == 1 {
score2ToFetchLater = savedScore
}
index += 1
case .failure(let error):
Expand Down Expand Up @@ -299,7 +304,7 @@ Task {
}

//: Now we will fetch a ParseObject that has already been saved based on its' objectId.
let scoreToFetch = GameScore(objectId: score2ForFetchedLater?.objectId)
let scoreToFetch = GameScore(objectId: scoreToFetchLater?.objectId)

//: Asynchronous completion block fetch this GameScore based on it is objectId alone.
scoreToFetch.fetch { result in
Expand All @@ -322,7 +327,7 @@ Task {
}

//: Now we will fetch `ParseObject`'s in batch that have already been saved based on its' objectId.
let score2ToFetch = GameScore(objectId: score2ForFetchedLater?.objectId)
let score2ToFetch = GameScore(objectId: score2ToFetchLater?.objectId)

//: Asynchronous completion block fetch GameScores based on it is objectId alone.
[scoreToFetch, score2ToFetch].fetchAll { result in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ import ParseSwift

PlaygroundPage.current.needsIndefiniteExecution = true

Task {
do {
try await initializeParse()
} catch {
assertionFailure("Error initializing Parse-Swift: \(error)")
}
}

struct User: ParseUser {
//: These are required by `ParseObject`.
var objectId: String?
Expand Down Expand Up @@ -52,6 +44,19 @@ struct User: ParseUser {
}
}

Task {
do {
try await initializeParse()
} catch {
assertionFailure("Error initializing Parse-Swift: \(error)")
}
do {
try await User.logout()
} catch let error {
print("Error logging out: \(error)")
}
}

/*:
Sign up user asynchronously - Performs work on background
queue and returns to specified callbackQueue.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ Task {
let currentUser = try? await User.current()
currentUser?.fetch(includeKeys: ["gameScore"]) { result in
switch result {
case .success:
print("Successfully fetched user with gameScore key: \(String(describing: User.current))")
case .success(let user):
print("Successfully fetched user with gameScore key: \(user)")
case .failure(let error):
print("Error fetching User: \(error)")
}
Expand All @@ -196,8 +196,8 @@ Task {
let currentUser = try? await User.current()
currentUser?.fetch(includeKeys: ["*"]) { result in
switch result {
case .success:
print("Successfully fetched user with all keys: \(String(describing: User.current))")
case .success(let user):
print("Successfully fetched user with all keys: \(user)")
case .failure(let error):
print("Error fetching User: \(error)")
}
Expand Down
16 changes: 11 additions & 5 deletions Sources/ParseSwift/API/API+Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ internal extension API {
uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,
stream: InputStream,
completion: @escaping (ParseError?) -> Void) {
guard method == .POST || method == .PUT || method == .PATCH else {
guard method == .POST ||
method == .PUT ||
method == .PATCH else {
callbackQueue.async {
completion(nil)
}
Expand Down Expand Up @@ -133,7 +135,9 @@ internal extension API {
}
} else {
// ParseFiles are handled with a dedicated URLSession
if method == .POST || method == .PUT || method == .PATCH {
if method == .POST ||
method == .PUT ||
method == .PATCH {
switch await self.prepareURLRequest(options: options,
batching: batching,
childObjects: childObjects,
Expand Down Expand Up @@ -258,7 +262,8 @@ internal extension API {
Task {
do {
var headers = try await API.getHeaders(options: options)
if method == .GET || method == .DELETE {
if method == .GET ||
method == .DELETE {
headers.removeValue(forKey: "X-Parse-Request-Id")
}
let url = parseURL == nil ?
Expand Down Expand Up @@ -405,8 +410,9 @@ internal extension API.Command {
original data: Data?,
ignoringCustomObjectIdConfig: Bool,
batching: Bool = false) async throws -> API.Command<V, V> where V: ParseObject {
if Parse.configuration.isRequiringCustomObjectIds
&& object.objectId == nil && !ignoringCustomObjectIdConfig {
if Parse.configuration.isRequiringCustomObjectIds &&
object.objectId == nil &&
!ignoringCustomObjectIdConfig {
throw ParseError(code: .missingObjectId, message: "objectId must not be nil")
}
if try await object.isSaved() {
Expand Down
3 changes: 2 additions & 1 deletion Sources/ParseSwift/API/API+NonParseBodyCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ internal extension API {
let params = self.params?.getURLQueryItems()
do {
var headers = try await API.getHeaders(options: options)
if method == .GET || method == .DELETE {
if method == .GET ||
method == .DELETE {
headers.removeValue(forKey: "X-Parse-Request-Id")
}
let url = API.serverURL(options: options).appendingPathComponent(path.urlComponent)
Expand Down
37 changes: 31 additions & 6 deletions Sources/ParseSwift/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,22 @@ public struct API {
}
}

// swiftlint:disable:next cyclomatic_complexity
public static func == (lhs: API.Option, rhs: API.Option) -> Bool {
lhs.hashValue == rhs.hashValue
switch (lhs, rhs) {
case (.usePrimaryKey, .usePrimaryKey): return true
case (.removeMimeType, .removeMimeType): return true
case (.sessionToken(let object1), .sessionToken(let object2)): return object1 == object2
case (.installationId(let object1), .installationId(let object2)): return object1 == object2
case (.mimeType(let object1), .mimeType(let object2)): return object1 == object2
case (.fileSize(let object1), .fileSize(let object2)): return object1 == object2
case (.metadata(let object1), .metadata(let object2)): return object1 == object2
case (.tags(let object1), .tags(let object2)): return object1 == object2
case (.context(let object1), .context(let object2)): return object1.isEqual(object2)
case (.cachePolicy(let object1), .cachePolicy(let object2)): return object1 == object2
case (.serverURL(let object1), .serverURL(let object2)): return object1 == object2
default: return false
}
}
}

Expand All @@ -228,7 +242,7 @@ public struct API {
headers["X-Parse-Client-Version"] = clientVersion()
headers["X-Parse-Request-Id"] = Self.createUniqueRequestId()

options.forEach { (option) in
options.forEach { option in
switch option {
case .usePrimaryKey:
headers["X-Parse-Master-Key"] = Parse.configuration.primaryKey
Expand Down Expand Up @@ -272,11 +286,22 @@ public struct API {
}

internal static func serverURL(options: API.Options) -> URL {
guard let differentServerURLOption = options.first(where: { $0 == .serverURL("") }),
case .serverURL(let differentServerURLString) = differentServerURLOption,
let differentURL = URL(string: differentServerURLString) else {
var optionURL: URL?
// BAKER: Currently have to step through all options and
// break to get the current URL.
for option in options {
switch option {
case .serverURL(let url):
optionURL = URL(string: url)
default:
continue
}
break
}

guard let currentURL = optionURL else {
return Parse.configuration.serverURL
}
return differentURL
return currentURL
}
}
1 change: 1 addition & 0 deletions Sources/ParseSwift/Coding/AnyCodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,6 @@ extension AnyCodable: ExpressibleByBooleanLiteral {}
extension AnyCodable: ExpressibleByIntegerLiteral {}
extension AnyCodable: ExpressibleByFloatLiteral {}
extension AnyCodable: ExpressibleByStringLiteral {}
extension AnyCodable: ExpressibleByStringInterpolation {}
extension AnyCodable: ExpressibleByArrayLiteral {}
extension AnyCodable: ExpressibleByDictionaryLiteral {}
19 changes: 12 additions & 7 deletions Sources/ParseSwift/Coding/ParseEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,8 @@ internal class _ParseEncoder: JSONEncoder, Encoder {
}
valueToEncode = pointer
} else if let object = value as? Objectable {
if !batching || (batching && codingPath.last?.stringValue == "body"),
if !batching ||
(batching && codingPath.last?.stringValue == "body"),
let pointer = try? PointerType(object) {
if let uniquePointer = self.uniquePointer,
uniquePointer.hasSameObjectId(as: pointer) {
Expand Down Expand Up @@ -507,8 +508,8 @@ private struct _ParseEncoderKeyedEncodingContainer<Key: CodingKey>: KeyedEncodin
guard !shouldSkipKey(key) else { return }

var valueToEncode: Encodable = value
if ((value as? Objectable) != nil)
|| ((value as? ParsePointer) != nil) {
if ((value as? Objectable) != nil) ||
((value as? ParsePointer) != nil) {
if let replacedObject = try self.encoder.deepFindAndReplaceParseObjects(value) {
valueToEncode = replacedObject
}
Expand Down Expand Up @@ -964,18 +965,22 @@ extension _ParseEncoder {
// Disambiguation between variable and function is required due to
// issue tracked at: https://bugs.swift.org/browse/SR-1846
let type = Swift.type(of: value)
if type == Date.self || type == NSDate.self {
if type == Date.self ||
type == NSDate.self {
// Respect Date encoding strategy
return try self.box((value as! Date))
} else if type == Data.self || type == NSData.self {
} else if type == Data.self ||
type == NSData.self {
// Respect Data encoding strategy
// swiftlint:disable:next force_cast
return try self.box((value as! Data))
} else if type == URL.self || type == NSURL.self {
} else if type == URL.self ||
type == NSURL.self {
// Encode URLs as single strings.
// swiftlint:disable:next force_cast
return self.box((value as! URL).absoluteString)
} else if type == Decimal.self || type == NSDecimalNumber.self {
} else if type == Decimal.self ||
type == NSDecimalNumber.self {
// JSONSerialization can natively handle NSDecimalNumber.
// swiftlint:disable:next force_cast
return (value as! NSDecimalNumber)
Expand Down
23 changes: 17 additions & 6 deletions Sources/ParseSwift/Extensions/Encodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@

internal extension Encodable {
func isEqual(_ other: Encodable?) -> Bool {
guard let lhsData = try? ParseCoding.parseEncoder().encode(self,
acl: nil),
guard let lhsData = try? ParseCoding
.parseEncoder()
.encode(
self,
acl: nil
),
let lhsString = String(data: lhsData, encoding: .utf8),
let other = other,
let rhsData = try? ParseCoding.parseEncoder().encode(other,
acl: nil),
let rhsString = String(data: rhsData, encoding: .utf8) else {
return false
let rhsData = try? ParseCoding
.parseEncoder()
.encode(
other,
acl: nil
),
let rhsString = String(
data: rhsData,
encoding: .utf8
) else {
return false

Check warning on line 31 in Sources/ParseSwift/Extensions/Encodable.swift

View check run for this annotation

Codecov / codecov/patch

Sources/ParseSwift/Extensions/Encodable.swift#L31

Added line #L31 was not covered by tests
}
return lhsString == rhsString
}
Expand Down
10 changes: 5 additions & 5 deletions Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@

public static func == <U>(lhs: Event<U>, rhs: Event<U>) -> Bool {
switch (lhs, rhs) {
case (.entered(let obj1), .entered(let obj2)): return obj1 == obj2
case (.left(let obj1), .left(let obj2)): return obj1 == obj2
case (.created(let obj1), .created(let obj2)): return obj1 == obj2
case (.updated(let obj1), .updated(let obj2)): return obj1 == obj2
case (.deleted(let obj1), .deleted(let obj2)): return obj1 == obj2
case (.entered(let object1), .entered(let object2)): return object1 == object2
case (.left(let object1), .left(let object2)): return object1 == object2
case (.created(let object1), .created(let object2)): return object1 == object2
case (.updated(let object1), .updated(let object2)): return object1 == object2
case (.deleted(let object1), .deleted(let object2)): return object1 == object2

Check warning on line 52 in Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift

View check run for this annotation

Codecov / codecov/patch

Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift#L48-L52

Added lines #L48 - L52 were not covered by tests
default: return false
}
}
Expand Down
7 changes: 4 additions & 3 deletions Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,8 @@
if isUserWantsToConnect {
self.isDisconnectedByUser = false
}
if self.status == .connected || self.isDisconnectedByUser {
if self.status == .connected ||
self.isDisconnectedByUser {
completion(nil)
return
}
Expand Down Expand Up @@ -769,8 +770,8 @@
}

static func == (lhs: SubscriptionRecord, rhs: SubscriptionRecord) -> Bool {
lhs.messageData == rhs.messageData
&& lhs.queryData == rhs.queryData
lhs.messageData == rhs.messageData &&
lhs.queryData == rhs.queryData

Check warning on line 774 in Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift

View check run for this annotation

Codecov / codecov/patch

Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift#L773-L774

Added lines #L773 - L774 were not covered by tests
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion Sources/ParseSwift/Objects/ParseInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ extension ParseInstallation {

func endpoint(_ method: API.Method) async throws -> API.Endpoint {
try await yieldIfNotInitialized()
if !Parse.configuration.isRequiringCustomObjectIds || method != .POST {
if !Parse.configuration.isRequiringCustomObjectIds ||
method != .POST {
return endpoint
} else {
return .installations
Expand Down
7 changes: 5 additions & 2 deletions Sources/ParseSwift/Objects/ParseObject+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ internal extension ParseObject {
objectsSavedBeforeThisOne: nil,
filesSavedBeforeThisOne: nil)
var waitingToBeSaved = object.unsavedChildren
if isShouldReturnIfChildObjectsFound && waitingToBeSaved.count > 0 {
if isShouldReturnIfChildObjectsFound &&
waitingToBeSaved.count > 0 {
let error = ParseError(code: .otherCause,
message: """
When using transactions, all child ParseObjects have to originally
Expand Down Expand Up @@ -349,7 +350,9 @@ or disable transactions for this call.
}
}
waitingToBeSaved = nextBatch
if waitingToBeSaved.count > 0 && savableObjects.count == 0 && savableFiles.count == 0 {
if waitingToBeSaved.count > 0 &&
savableObjects.count == 0 &&
savableFiles.count == 0 {
throw ParseError(code: .otherCause,
message: "Found a circular dependency in ParseObject.")
}
Expand Down
Loading