Skip to content

feat: add set operation based on KeyPath #403

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

Merged
merged 9 commits into from
Sep 5, 2022
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
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ coverage:
status:
patch:
default:
target: auto
target: 72
changes: false
project:
default:
Expand Down
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Parse-Swift Changelog

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

### 4.10.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.3...4.10.0)

__New features__
- Add a new operation method that allows developers to set a new value to a KeyPath without needing the string version of the key. Also adds the get() method to allow developers to get the unwrapped property of any ParseObject based on its KeyPath ([#403](https://github.com/parse-community/Parse-Swift/pull/403)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add revertKeyPath() and revertObject() methods to ParseObject which allow developers to revert to original values of key paths or objects after mutating ParseObjects that already have an objectId ([#402](https://github.com/parse-community/Parse-Swift/pull/402)), thanks to [Corey Baker](https://github.com/cbaker6).

### 4.9.3
Expand Down
10 changes: 10 additions & 0 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,10 @@
7085DDB326D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
7085DDB426D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
7085DDB526D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };
7087A93C28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */; };
7087A93D28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */; };
7087A93E28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */; };
7087A93F28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */; };
708CADCF2872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
708CADD02872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
708CADD12872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };
Expand Down Expand Up @@ -1269,6 +1273,7 @@
7085DD9326CBF3A70033B977 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = "<group>"; };
7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ParseHealth+combine.swift"; sourceTree = "<group>"; };
7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationCombineTests.swift; sourceTree = "<group>"; };
7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ParseOperation+keyPath.swift"; sourceTree = "<group>"; };
708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroupTests.swift; sourceTree = "<group>"; };
708D035125215F9B00646C70 /* Deletable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deletable.swift; sourceTree = "<group>"; };
709A147C283949D100BF85E5 /* ParseSchema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchema.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2135,6 +2140,7 @@
F97B464024D9C78B00F4A88B /* ParseOperation.swift */,
703B091026BD992E005A112F /* ParseOperation+async.swift */,
7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */,
7087A93B28C558CA00656E93 /* ParseOperation+keyPath.swift */,
91285B1B26990D7F0051B544 /* ParsePolygon.swift */,
705025BC284C610C008D6624 /* ParsePush.swift */,
705025C1284C7841008D6624 /* ParsePush+async.swift */,
Expand Down Expand Up @@ -2697,6 +2703,7 @@
91285B1C26990D7F0051B544 /* ParsePolygon.swift in Sources */,
91BB8FCA2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,
7085DD9426CBF3A70033B977 /* Documentation.docc in Sources */,
7087A93C28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */,
705025EB285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,
705025A928441C96008D6624 /* ParseFieldOptions.swift in Sources */,
F97B45D624D9C6F200F4A88B /* ParseEncoder.swift in Sources */,
Expand Down Expand Up @@ -3006,6 +3013,7 @@
91285B1D26990D7F0051B544 /* ParsePolygon.swift in Sources */,
91BB8FCB2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,
7085DD9526CBF3A70033B977 /* Documentation.docc in Sources */,
7087A93D28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */,
705025EC285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,
705025AA28441C96008D6624 /* ParseFieldOptions.swift in Sources */,
F97B45D724D9C6F200F4A88B /* ParseEncoder.swift in Sources */,
Expand Down Expand Up @@ -3447,6 +3455,7 @@
91679D67268E596300F71809 /* ParseVersion.swift in Sources */,
91285B1F26990D7F0051B544 /* ParsePolygon.swift in Sources */,
91BB8FCD2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,
7087A93F28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */,
705025EE285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,
705025AC28441C96008D6624 /* ParseFieldOptions.swift in Sources */,
7085DD9726CBF3A70033B977 /* Documentation.docc in Sources */,
Expand Down Expand Up @@ -3633,6 +3642,7 @@
91679D66268E596300F71809 /* ParseVersion.swift in Sources */,
91285B1E26990D7F0051B544 /* ParsePolygon.swift in Sources */,
91BB8FCC2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,
7087A93E28C558CA00656E93 /* ParseOperation+keyPath.swift in Sources */,
705025ED285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,
705025AB28441C96008D6624 /* ParseFieldOptions.swift in Sources */,
7085DD9626CBF3A70033B977 /* Documentation.docc in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,11 @@ public extension ParseUser {
completion(result)
}
} catch {
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
let parseError = ParseError(code: .unknownError, message: error.localizedDescription)
completion(.failure(parseError))
}
completion(.failure(parseError))
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Sources/ParseSwift/Documentation.docc/ParseSwift.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ To learn how to use or experiment with ParseSwift, you can run and edit the [Par

- ``ParseSwift/initialize(configuration:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:authentication:)``
- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:migratingFromObjcSDK:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:authentication:)``

9 changes: 4 additions & 5 deletions Sources/ParseSwift/Extensions/URLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,10 @@ internal extension URLSession {
let data = try ParseCoding.jsonEncoder().encode(location)
return try .success(mapper(data))
} catch {
guard let parseError = error as? ParseError else {
return .failure(ParseError(code: .unknownError,
// swiftlint:disable:next line_length
message: "Error decoding parse-server response: \(response) with error: \(String(describing: error))"))
}
let defaultError = ParseError(code: .unknownError,
// swiftlint:disable:next line_length
message: "Error decoding parse-server response: \(response) with error: \(String(describing: error))")
let parseError = error as? ParseError ?? defaultError
return .failure(parseError)
}
}
Expand Down
71 changes: 33 additions & 38 deletions Sources/ParseSwift/Objects/ParseInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

/**
Objects that conform to the `ParseInstallation` protocol have a local representation of an
installation persisted to the Parse cloud. This protocol inherits from the
installation persisted to the Keychain and Parse Server. This protocol inherits from the
`ParseObject` protocol, and retains the same functionality of a `ParseObject`, but also extends
it with installation-specific fields and related immutability and validity
checks.
Expand All @@ -21,16 +21,15 @@ import Foundation
is automatically updated to match the device's time zone
when the `ParseInstallation` is saved, thus these fields might not reflect the
latest device state if the installation has not recently been saved.

`ParseInstallation`s which have a valid `deviceToken` and are saved to
the Parse Server can be used to target push notifications. Use `setDeviceToken` to set the
`deviceToken` properly.

- warning: If the use of badge is desired, it should be retrieved by using UIKit, AppKit, etc. and
stored in `ParseInstallation.badge` before saving/updating the installation.

- warning: Linux developers should set `appName`, `appIdentifier`, and `appVersion`
manually as `ParseSwift` does not have access to Bundle.main.
stored in `ParseInstallation.badge` when saving/updating the installation.
- warning: Linux, Android, and Windows developers should set `appName`,
`appIdentifier`, and `appVersion` manually as `ParseSwift` does not have access
to Bundle.main.
*/
public protocol ParseInstallation: ParseObject {

Expand Down Expand Up @@ -479,13 +478,12 @@ extension ParseInstallation {
try Self.updateKeychainIfNeeded([foundResult])
completion(.success(foundResult))
} catch {
let returnError: ParseError!
if let parseError = error as? ParseError {
returnError = parseError
} else {
returnError = ParseError(code: .unknownError, message: error.localizedDescription)
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
completion(.failure(parseError))
}
completion(.failure(returnError))
}
} else {
completion(result)
Expand Down Expand Up @@ -533,6 +531,7 @@ extension ParseInstallation {
- returns: Returns saved `ParseInstallation`.
- important: If an object saved has the same objectId as current, it will automatically update the current.
*/
@discardableResult
public func save(options: API.Options = []) throws -> Self {
try save(ignoringCustomObjectIdConfig: false,
options: options)
Expand Down Expand Up @@ -560,6 +559,7 @@ extension ParseInstallation {
- note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer
desires a different policy, it should be inserted in `options`.
*/
@discardableResult
public func save(ignoringCustomObjectIdConfig: Bool,
options: API.Options = []) throws -> Self {
var options = options
Expand Down Expand Up @@ -724,12 +724,11 @@ extension ParseInstallation {
completion(result)
}
} catch {
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
completion(.failure(.init(code: .unknownError, message: error.localizedDescription)))
}
completion(.failure(parseError))
}
}
return
Expand Down Expand Up @@ -862,13 +861,12 @@ extension ParseInstallation {
try Self.updateKeychainIfNeeded([self], deleting: true)
completion(.success(()))
} catch {
let returnError: ParseError!
if let parseError = error as? ParseError {
returnError = parseError
} else {
returnError = ParseError(code: .unknownError, message: error.localizedDescription)
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
completion(.failure(parseError))
}
completion(.failure(returnError))
}
case .failure(let error):
completion(.failure(error))
Expand Down Expand Up @@ -937,6 +935,7 @@ public extension Sequence where Element: ParseInstallation {
- note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer
desires a different policy, it should be inserted in `options`.
*/
@discardableResult
func saveAll(batchLimit limit: Int? = nil, // swiftlint:disable:this function_body_length
transaction: Bool = configuration.isUsingTransactions,
ignoringCustomObjectIdConfig: Bool = false,
Expand Down Expand Up @@ -1232,12 +1231,11 @@ public extension Sequence where Element: ParseInstallation {
commands.append(try installation.updateCommand())
}
} catch {
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
completion(.failure(.init(code: .unknownError, message: error.localizedDescription)))
}
completion(.failure(parseError))
}
return
}
Expand Down Expand Up @@ -1275,12 +1273,11 @@ public extension Sequence where Element: ParseInstallation {
}
}
} catch {
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
completion(.failure(.init(code: .unknownError, message: error.localizedDescription)))
}
completion(.failure(parseError))
}
}
}
Expand Down Expand Up @@ -1499,12 +1496,10 @@ public extension Sequence where Element: ParseInstallation {
}
}
} catch {
let defaultError = ParseError(code: .unknownError,
message: error.localizedDescription)
let parseError = error as? ParseError ?? defaultError
callbackQueue.async {
guard let parseError = error as? ParseError else {
completion(.failure(ParseError(code: .unknownError,
message: error.localizedDescription)))
return
}
completion(.failure(parseError))
}
}
Expand Down
Loading