From a470285e8fb2e3493403aca96f0b514d650fdcb8 Mon Sep 17 00:00:00 2001 From: Damian Van de Kauter Date: Sat, 30 Oct 2021 12:46:23 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=E2=80=A2=20Updatable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contents.swift | 24 ++------- .../Contents.swift | 20 ++----- .../Contents.swift | 22 ++------ .../Contents.swift | 20 ++----- ParseSwift.xcodeproj/project.pbxproj | 10 ++++ .../Objects/ParseObject+updatable.swift | 52 +++++++++++++++++++ Sources/ParseSwift/Objects/ParseObject.swift | 13 ----- 7 files changed, 77 insertions(+), 84 deletions(-) create mode 100644 Sources/ParseSwift/Objects/ParseObject+updatable.swift diff --git a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift index e935e3c25..ac907ed2d 100644 --- a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift @@ -30,7 +30,7 @@ do { } //: Create your own value typed `ParseObject`. -struct GameScore: ParseObject { +struct GameScore: ParseObject, Updatable { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -39,20 +39,6 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 - - /*: - It's recommended the developer adds the emptyObject computed property or similar. - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an - empty object and updating a subset of the fields reduces the amount of data sent between - client and server when using `save` and `saveAll` to update objects. - */ - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } } //: It's recommended to place custom initializers in an extension @@ -110,11 +96,11 @@ score.save { result in assert(savedScore.score == 10) /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `emptyObject` + was initialized as immutable. Using `updatable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ - var changedScore = savedScore.emptyObject + var changedScore = savedScore.updatable changedScore.score = 200 changedScore.save { result in switch result { @@ -202,11 +188,11 @@ assert(savedScore?.updatedAt != nil) assert(savedScore?.score == 10) /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `emptyObject` + was initialized as immutable. Using `updatable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -guard var changedScore = savedScore?.emptyObject else { +guard var changedScore = savedScore?.updatable else { fatalError() } changedScore.score = 200 diff --git a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift index 2946927d3..a3b21a224 100644 --- a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift @@ -21,7 +21,7 @@ npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey - initializeParseCustomObjectId() //: Create your own value typed `ParseObject`. -struct GameScore: ParseObject { +struct GameScore: ParseObject, Updatable { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -30,20 +30,6 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 - - /*: - It's recommended the developer adds the emptyObject computed property or similar. - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an - empty object and updating a subset of the fields reduces the amount of data sent between - client and server when using `save` and `saveAll` to update objects. - */ - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } } //: It's recommended to place custom initializers in an extension @@ -82,11 +68,11 @@ score.save { result in print("Saved score: \(savedScore)") /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `emptyObject` + was initialized as immutable. Using `updatable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ - var changedScore = savedScore.emptyObject + var changedScore = savedScore.updatable changedScore.score = 200 changedScore.save { result in switch result { diff --git a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift index b554f0c62..82fb6ee96 100644 --- a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift @@ -13,7 +13,7 @@ import ParseSwift PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct User: ParseUser { +struct User: ParseUser, Updatable { //: These are required for `ParseObject`. var objectId: String? var createdAt: Date? @@ -32,20 +32,6 @@ struct User: ParseUser { var score: GameScore? var targetScore: GameScore? var allScores: [GameScore]? - - /*: - It's recommended the developer adds the emptyObject computed property or similar. - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an - empty object and updating a subset of the fields reduces the amount of data sent between - client and server when using `save` and `saveAll` to update objects. - */ - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } } //: It's recommended to place custom initializers in an extension @@ -117,10 +103,10 @@ User.login(username: "hello", password: "world") { result in Asynchrounously - Performs work on background queue and returns to specified callbackQueue. If no callbackQueue is specified it returns to main queue. - Using `emptyObject` allows you to only send the updated keys to the + Using `updatable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -var currentUser = User.current?.emptyObject +var currentUser = User.current?.updatable currentUser?.customKey = "myCustom" currentUser?.score = GameScore(score: 12) currentUser?.targetScore = GameScore(score: 100) @@ -224,7 +210,7 @@ User.anonymous.login { result in } //: Convert the anonymous user to a real new user. -var currentUser2 = User.current?.emptyObject +var currentUser2 = User.current?.updatable currentUser2?.username = "bye" currentUser2?.password = "world" currentUser2?.signup { result in diff --git a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift index 035eb198b..ccaf64f4f 100644 --- a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift @@ -13,7 +13,7 @@ import ParseSwift PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct Installation: ParseInstallation { +struct Installation: ParseInstallation, Updatable { //: These are required for `ParseObject`. var objectId: String? var createdAt: Date? @@ -35,20 +35,6 @@ struct Installation: ParseInstallation { //: Your custom keys var customKey: String? - - /*: - It's recommended the developer adds the emptyObject computed property or similar. - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an - empty object and updating a subset of the fields reduces the amount of data sent between - client and server when using `save` and `saveAll` to update objects. - */ - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } } /*: Save your first `customKey` value to your `ParseInstallation`. @@ -71,11 +57,11 @@ currentInstallation?.save { results in /*: Update your `ParseInstallation` `customKey` value. Performs work on background queue and returns to designated on designated callbackQueue. If no callbackQueue is specified it - returns to main queue. Using `emptyObject` allows you to only + returns to main queue. Using `updatable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -currentInstallation = currentInstallation?.emptyObject +currentInstallation = currentInstallation?.updatable currentInstallation?.customKey = "updatedValue" currentInstallation?.save { results in diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index d4bcbe907..66bf3d10b 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -587,6 +587,10 @@ 91F346C3269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; 91F346C4269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; 91F346C5269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; + CD106A00272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; + CD106A01272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; + CD106A02272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; + CD106A03272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; F971F4F624DE381A006CB79B /* ParseEncoderExtraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */; }; F97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; F97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; @@ -961,6 +965,7 @@ 91F346B8269B766C005727B6 /* CloudViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudViewModel.swift; sourceTree = ""; }; 91F346BD269B77B5005727B6 /* CloudObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudObservable.swift; sourceTree = ""; }; 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudViewModelTests.swift; sourceTree = ""; }; + CD1069FF272D481800939151 /* ParseObject+updatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseObject+updatable.swift"; sourceTree = ""; }; F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoderExtraTests.swift; sourceTree = ""; }; F97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; @@ -1531,6 +1536,7 @@ F97B45C624D9C6F200F4A88B /* ParseObject.swift */, 7028373326BD8883007688C9 /* ParseObject+async.swift */, 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */, + CD1069FF272D481800939151 /* ParseObject+updatable.swift */, 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */, 70C5503725B406B800B5DBC2 /* ParseSession.swift */, F97B45C424D9C6F200F4A88B /* ParseUser.swift */, @@ -2084,6 +2090,7 @@ 703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B45E624D9C6F200F4A88B /* Query.swift in Sources */, + CD106A00272D481800939151 /* ParseObject+updatable.swift in Sources */, 703B093526BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950825BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509225B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2293,6 +2300,7 @@ 703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B45E724D9C6F200F4A88B /* Query.swift in Sources */, + CD106A01272D481800939151 /* ParseObject+updatable.swift in Sources */, 703B093626BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950925BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509325B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2597,6 +2605,7 @@ 703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */, + CD106A03272D481800939151 /* ParseObject+updatable.swift in Sources */, 703B093826BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950B25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509525B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2720,6 +2729,7 @@ 703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */, + CD106A02272D481800939151 /* ParseObject+updatable.swift in Sources */, 703B093726BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950A25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509425B4A99100B5DBC2 /* AddRelation.swift in Sources */, diff --git a/Sources/ParseSwift/Objects/ParseObject+updatable.swift b/Sources/ParseSwift/Objects/ParseObject+updatable.swift new file mode 100644 index 000000000..4a530eef1 --- /dev/null +++ b/Sources/ParseSwift/Objects/ParseObject+updatable.swift @@ -0,0 +1,52 @@ +// +// ParseObject+updatable.swift +// ParseSwift +// +// Created by Damian Van de Kauter on 30/10/2021. +// Copyright © 2021 Parse Community. All rights reserved. +// + +import Foundation + +/** + The **Updatable** protocol adds an empty version of the respective object. This can be used when you only need to update a + a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating + a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + to update objects. + + **Example use case:** + ~~~~ + var user = User.current?.updatable + user?.customKey = "newValue" + + do { + try await user?.save() + } catch { + // Handle error + } + ~~~~ + + - warning: Using the **Updatable** protocol requires the developer to use an **init()** without declaring custom properties. + You can still use non-optional properties if you add them to your **init()** method and give them a default value. + If you need a custom **init()**, you can't use the **Updatable** protocol. +*/ +public protocol Updatable: ParseObject { + init() + + var updatable: Self { get } +} + +public extension Updatable { + + /** + An empty version of the respective object that allows you to update a + a subset of the fields of an object as oppose to updating every field of an object. + - note: You need to use this to create a mutable copy of your **ParseObject**. + */ + var updatable: Self { + var object = self + object.objectId = objectId + object.createdAt = createdAt + return object + } +} diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index c3086129c..b69b26697 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -16,19 +16,6 @@ import Foundation If you are using value types the the compiler will assist you with conforming to `ParseObject` protocol. If you are thinking of using reference types, see the warning. - It's recommended the developer adds the emptyObject computed property or similar. - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating - a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` - to update objects. You should add the following properties in your `ParseObject`'s: - - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } - - important: It is recommended that all added properties be optional properties so they can eventually be used as Parse `Pointer`'s. If a developer really wants to have a required key, they should require it on the server-side or create methods to check the respective properties on the client-side before saving objects. See From ae2a05a15a0f5abcac216790d13e63d004badb7d Mon Sep 17 00:00:00 2001 From: Damian Van de Kauter Date: Sun, 31 Oct 2021 00:31:01 +0200 Subject: [PATCH 2/5] Requested changes --- CHANGELOG.md | 4 + .../Contents.swift | 10 +-- .../Contents.swift | 6 +- .../Contents.swift | 8 +- .../Contents.swift | 6 +- ParseSwift.xcodeproj/project.pbxproj | 20 ++--- .../Objects/ParseObject+updatable.swift | 52 ------------- Sources/ParseSwift/Objects/ParseObject.swift | 6 ++ .../Protocols/ParseObjectMutable.swift | 76 +++++++++++++++++++ Tests/ParseSwiftTests/ParseObjectTests.swift | 25 ++---- 10 files changed, 117 insertions(+), 96 deletions(-) delete mode 100644 Sources/ParseSwift/Objects/ParseObject+updatable.swift create mode 100644 Sources/ParseSwift/Protocols/ParseObjectMutable.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cd83b734..084b59d8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ### main +__Improvements__ + - Added the ParseObjectMutable protocol to make emptyObject more developer friendly ([#270](https://github.com/parse-community/Parse-Swift/pull/270)), thanks to [Damian Van de Kauter](https://github.com/novemTeam). + + [Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.3...main) * _Contributing to this repo? Add info about your change here to be included in the next release_ diff --git a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift index ac907ed2d..7ba394815 100644 --- a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift @@ -30,7 +30,7 @@ do { } //: Create your own value typed `ParseObject`. -struct GameScore: ParseObject, Updatable { +struct GameScore: ParseObjectMutable { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -96,11 +96,11 @@ score.save { result in assert(savedScore.score == 10) /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `updatable` + was initialized as immutable. Using `mutable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ - var changedScore = savedScore.updatable + var changedScore = savedScore.mutable changedScore.score = 200 changedScore.save { result in switch result { @@ -188,11 +188,11 @@ assert(savedScore?.updatedAt != nil) assert(savedScore?.score == 10) /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `updatable` + was initialized as immutable. Using `mutable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -guard var changedScore = savedScore?.updatable else { +guard var changedScore = savedScore?.mutable else { fatalError() } changedScore.score = 200 diff --git a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift index a3b21a224..39a2ca239 100644 --- a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift @@ -21,7 +21,7 @@ npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey - initializeParseCustomObjectId() //: Create your own value typed `ParseObject`. -struct GameScore: ParseObject, Updatable { +struct GameScore: ParseObjectMutable { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -68,11 +68,11 @@ score.save { result in print("Saved score: \(savedScore)") /*: To modify, need to make it a var as the value type - was initialized as immutable. Using `updatable` + was initialized as immutable. Using `mutable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ - var changedScore = savedScore.updatable + var changedScore = savedScore.mutable changedScore.score = 200 changedScore.save { result in switch result { diff --git a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift index 82fb6ee96..21f560add 100644 --- a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift @@ -13,7 +13,7 @@ import ParseSwift PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct User: ParseUser, Updatable { +struct User: ParseUserMutable { //: These are required for `ParseObject`. var objectId: String? var createdAt: Date? @@ -103,10 +103,10 @@ User.login(username: "hello", password: "world") { result in Asynchrounously - Performs work on background queue and returns to specified callbackQueue. If no callbackQueue is specified it returns to main queue. - Using `updatable` allows you to only send the updated keys to the + Using `mutable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -var currentUser = User.current?.updatable +var currentUser = User.current?.mutable currentUser?.customKey = "myCustom" currentUser?.score = GameScore(score: 12) currentUser?.targetScore = GameScore(score: 100) @@ -210,7 +210,7 @@ User.anonymous.login { result in } //: Convert the anonymous user to a real new user. -var currentUser2 = User.current?.updatable +var currentUser2 = User.current?.mutable currentUser2?.username = "bye" currentUser2?.password = "world" currentUser2?.signup { result in diff --git a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift index ccaf64f4f..fe6e0eafb 100644 --- a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift @@ -13,7 +13,7 @@ import ParseSwift PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct Installation: ParseInstallation, Updatable { +struct Installation: ParseInstallationMutable { //: These are required for `ParseObject`. var objectId: String? var createdAt: Date? @@ -57,11 +57,11 @@ currentInstallation?.save { results in /*: Update your `ParseInstallation` `customKey` value. Performs work on background queue and returns to designated on designated callbackQueue. If no callbackQueue is specified it - returns to main queue. Using `updatable` allows you to only + returns to main queue. Using `mutable` allows you to only send the updated keys to the parse server as opposed to the whole object. */ -currentInstallation = currentInstallation?.updatable +currentInstallation = currentInstallation?.mutable currentInstallation?.customKey = "updatedValue" currentInstallation?.save { results in diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 66bf3d10b..b70c9304d 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -587,10 +587,10 @@ 91F346C3269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; 91F346C4269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; 91F346C5269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; }; - CD106A00272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; - CD106A01272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; - CD106A02272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; - CD106A03272D481800939151 /* ParseObject+updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObject+updatable.swift */; }; + CD106A00272D481800939151 /* ParseObjectMutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObjectMutable.swift */; }; + CD106A01272D481800939151 /* ParseObjectMutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObjectMutable.swift */; }; + CD106A02272D481800939151 /* ParseObjectMutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObjectMutable.swift */; }; + CD106A03272D481800939151 /* ParseObjectMutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD1069FF272D481800939151 /* ParseObjectMutable.swift */; }; F971F4F624DE381A006CB79B /* ParseEncoderExtraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */; }; F97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; F97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; @@ -965,7 +965,7 @@ 91F346B8269B766C005727B6 /* CloudViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudViewModel.swift; sourceTree = ""; }; 91F346BD269B77B5005727B6 /* CloudObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudObservable.swift; sourceTree = ""; }; 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudViewModelTests.swift; sourceTree = ""; }; - CD1069FF272D481800939151 /* ParseObject+updatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseObject+updatable.swift"; sourceTree = ""; }; + CD1069FF272D481800939151 /* ParseObjectMutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectMutable.swift; sourceTree = ""; }; F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoderExtraTests.swift; sourceTree = ""; }; F97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; @@ -1292,6 +1292,7 @@ F97B45C824D9C6F200F4A88B /* Queryable.swift */, F97B45C724D9C6F200F4A88B /* Savable.swift */, 70647E9B259E3A9A004C1004 /* ParseType.swift */, + CD1069FF272D481800939151 /* ParseObjectMutable.swift */, 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */, 91F346BD269B77B5005727B6 /* CloudObservable.swift */, ); @@ -1536,7 +1537,6 @@ F97B45C624D9C6F200F4A88B /* ParseObject.swift */, 7028373326BD8883007688C9 /* ParseObject+async.swift */, 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */, - CD1069FF272D481800939151 /* ParseObject+updatable.swift */, 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */, 70C5503725B406B800B5DBC2 /* ParseSession.swift */, F97B45C424D9C6F200F4A88B /* ParseUser.swift */, @@ -2090,7 +2090,7 @@ 703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B45E624D9C6F200F4A88B /* Query.swift in Sources */, - CD106A00272D481800939151 /* ParseObject+updatable.swift in Sources */, + CD106A00272D481800939151 /* ParseObjectMutable.swift in Sources */, 703B093526BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950825BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509225B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2300,7 +2300,7 @@ 703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B45E724D9C6F200F4A88B /* Query.swift in Sources */, - CD106A01272D481800939151 /* ParseObject+updatable.swift in Sources */, + CD106A01272D481800939151 /* ParseObjectMutable.swift in Sources */, 703B093626BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950925BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509325B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2605,7 +2605,7 @@ 703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */, - CD106A03272D481800939151 /* ParseObject+updatable.swift in Sources */, + CD106A03272D481800939151 /* ParseObjectMutable.swift in Sources */, 703B093826BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950B25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509525B4A99100B5DBC2 /* AddRelation.swift in Sources */, @@ -2729,7 +2729,7 @@ 703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */, 703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */, F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */, - CD106A02272D481800939151 /* ParseObject+updatable.swift in Sources */, + CD106A02272D481800939151 /* ParseObjectMutable.swift in Sources */, 703B093726BF43D9005A112F /* ParseAnonymous+async.swift in Sources */, 705D950A25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */, 70C5509425B4A99100B5DBC2 /* AddRelation.swift in Sources */, diff --git a/Sources/ParseSwift/Objects/ParseObject+updatable.swift b/Sources/ParseSwift/Objects/ParseObject+updatable.swift deleted file mode 100644 index 4a530eef1..000000000 --- a/Sources/ParseSwift/Objects/ParseObject+updatable.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// ParseObject+updatable.swift -// ParseSwift -// -// Created by Damian Van de Kauter on 30/10/2021. -// Copyright © 2021 Parse Community. All rights reserved. -// - -import Foundation - -/** - The **Updatable** protocol adds an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating - a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` - to update objects. - - **Example use case:** - ~~~~ - var user = User.current?.updatable - user?.customKey = "newValue" - - do { - try await user?.save() - } catch { - // Handle error - } - ~~~~ - - - warning: Using the **Updatable** protocol requires the developer to use an **init()** without declaring custom properties. - You can still use non-optional properties if you add them to your **init()** method and give them a default value. - If you need a custom **init()**, you can't use the **Updatable** protocol. -*/ -public protocol Updatable: ParseObject { - init() - - var updatable: Self { get } -} - -public extension Updatable { - - /** - An empty version of the respective object that allows you to update a - a subset of the fields of an object as oppose to updating every field of an object. - - note: You need to use this to create a mutable copy of your **ParseObject**. - */ - var updatable: Self { - var object = self - object.objectId = objectId - object.createdAt = createdAt - return object - } -} diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index b69b26697..154bdbef6 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -16,6 +16,12 @@ import Foundation If you are using value types the the compiler will assist you with conforming to `ParseObject` protocol. If you are thinking of using reference types, see the warning. + It's recommended the developer uses the ParseObjectMutable protocol. + Gets an empty version of the respective object. This can be used when you only need to update a + a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating + a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + to update objects. + - important: It is recommended that all added properties be optional properties so they can eventually be used as Parse `Pointer`'s. If a developer really wants to have a required key, they should require it on the server-side or create methods to check the respective properties on the client-side before saving objects. See diff --git a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift new file mode 100644 index 000000000..ad924fc71 --- /dev/null +++ b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift @@ -0,0 +1,76 @@ +// +// ParseObjectMutable.swift +// ParseSwift +// +// Created by Damian Van de Kauter on 30/10/2021. +// Copyright © 2021 Parse Community. All rights reserved. +// + +import Foundation + +/** + The **ParseObjectMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a + a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating + a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + to update objects. + + **Example use case:** + ~~~~ + var user = User.current?.mutable + user?.customKey = "newValue" + + do { + try await user?.save() + } catch { + // Handle error + } + ~~~~ + + - warning: Using the **ParseObjectMutable** protocol requires the developer to use an **init()** without declaring custom properties. + You can still use non-optional properties if you add them to your **init()** method and give them a default value. + If you need a custom **init()**, you can't use the **ParseObjectMutable** protocol. +*/ +public protocol ParseObjectMutable: ParseObject { + init() + + var mutable: Self { get } +} + +public extension ParseObjectMutable { + + /** + An empty version of the respective object that allows you to update a + a subset of the fields of an object as oppose to updating every field of an object. + - note: You need to use this to create a mutable copy of your **ParseObject**. + */ + var mutable: Self { + var object = self + object.objectId = objectId + object.createdAt = createdAt + return object + } +} + +/** + The **ParseInstallationMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a + a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating + a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + to update objects. + + It combines the **ParseInstallation** protocol and the **ParseObjectMutable** protocol. +*/ +public protocol ParseInstallationMutable: ParseInstallation, ParseObjectMutable { + init() +} + +/** + The **ParseUserMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a + a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating + a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + to update objects. + + It combines the **ParseUser** protocol and the **ParseObjectMutable** protocol. +*/ +public protocol ParseUserMutable: ParseUser, ParseObjectMutable { + init() +} diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index 69a271e96..214b59c8b 100644 --- a/Tests/ParseSwiftTests/ParseObjectTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectTests.swift @@ -27,7 +27,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length } } - struct GameScore: ParseObject { + struct GameScore: ParseObjectMutable { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -55,19 +55,6 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length self.score = score self.player = name } - - /** - Gets an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. - - note: Using an empty object and updating a subset of the fields reduces the amount of data sent between - client and server when using `save` and `saveAll` to update objects. - */ - var emptyObject: Self { - var object = Self() - object.objectId = objectId - object.createdAt = createdAt - return object - } } struct Game: ParseObject { @@ -253,11 +240,11 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length wait(for: [expectation2], timeout: 20.0) } - func testEmptyObject() throws { + func testParseObjectMutable() throws { var score = GameScore(score: 19, name: "fire") score.objectId = "yolo" score.createdAt = Date() - let empty = score.emptyObject + let empty = score.mutable XCTAssertTrue(score.hasSameObjectId(as: empty)) XCTAssertEqual(score.createdAt, empty.createdAt) } @@ -583,7 +570,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length XCTAssertEqual(decoded, expected) } - func testUpdateCommandEmptyObject() throws { + func testUpdateCommandParseObjectMutable() throws { var score = GameScore(score: 10) let className = score.className let objectId = "yarr" @@ -591,7 +578,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length score.createdAt = Date() score.updatedAt = score.createdAt - let command = try score.emptyObject.saveCommand() + let command = try score.mutable.saveCommand() XCTAssertNotNil(command) XCTAssertEqual(command.path.urlComponent, "/classes/\(className)/\(objectId)") XCTAssertEqual(command.method, API.Method.PUT) @@ -610,7 +597,7 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) XCTAssertEqual(decoded, expected) - var empty = score.emptyObject + var empty = score.mutable empty.player = "Jennifer" let command2 = try empty.saveCommand() guard let body2 = command2.body else { From 170cab228f2ae237864dd7cb52313955c29c394c Mon Sep 17 00:00:00 2001 From: Damian Van de Kauter Date: Sun, 31 Oct 2021 09:54:26 +0100 Subject: [PATCH 3/5] Requested changes + Line length --- Sources/ParseSwift/Objects/ParseObject.swift | 2 +- .../Protocols/ParseObjectMutable.swift | 72 +++++++------------ Sources/ParseSwift/Types/ParseError.swift | 24 +++---- 3 files changed, 38 insertions(+), 60 deletions(-) diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 154bdbef6..61daa7b17 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -16,7 +16,7 @@ import Foundation If you are using value types the the compiler will assist you with conforming to `ParseObject` protocol. If you are thinking of using reference types, see the warning. - It's recommended the developer uses the ParseObjectMutable protocol. + It's recommended the developer conforms to the `ParseObjectMutable` protocol. Gets an empty version of the respective object. This can be used when you only need to update a a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` diff --git a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift index ad924fc71..816f588da 100644 --- a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift +++ b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift @@ -9,68 +9,46 @@ import Foundation /** - The **ParseObjectMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating - a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` + The `ParseObjectMutable` protocol adds an empty version of the respective object. + This can be used when you only need to update a subset of the fields of an object + as oppose to updating every field of an object. + Using an empty object and updating a subset of the fields reduces the amount of data + sent between client and server when using `save` and `saveAll` to update objects. **Example use case:** - ~~~~ - var user = User.current?.mutable - user?.customKey = "newValue" - - do { - try await user?.save() - } catch { - // Handle error - } - ~~~~ - - - warning: Using the **ParseObjectMutable** protocol requires the developer to use an **init()** without declaring custom properties. + ```` + var user = User.current?.mutable + user?.customKey = "newValue" + + do { + try await user?.save() + } catch { + // Handle error + } + ```` + + - warning: Using the `ParseObjectMutable` protocol requires the developer to + use an **init()** without declaring custom properties. You can still use non-optional properties if you add them to your **init()** method and give them a default value. - If you need a custom **init()**, you can't use the **ParseObjectMutable** protocol. + If you need a custom **init()**, you can't use the `ParseObjectMutable` protocol. */ public protocol ParseObjectMutable: ParseObject { init() - var mutable: Self { get } -} - -public extension ParseObjectMutable { - /** An empty version of the respective object that allows you to update a a subset of the fields of an object as oppose to updating every field of an object. - - note: You need to use this to create a mutable copy of your **ParseObject**. + - note: You need to use this to create a mutable copy of your `ParseObject`. */ + var mutable: Self { get } +} + +public extension ParseObjectMutable { var mutable: Self { - var object = self + var object = Self() object.objectId = objectId object.createdAt = createdAt return object } } - -/** - The **ParseInstallationMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating - a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` - to update objects. - - It combines the **ParseInstallation** protocol and the **ParseObjectMutable** protocol. -*/ -public protocol ParseInstallationMutable: ParseInstallation, ParseObjectMutable { - init() -} - -/** - The **ParseUserMutable** protocol adds an empty version of the respective object. This can be used when you only need to update a - a subset of the fields of an object as oppose to updating every field of an object. Using an empty object and updating - a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` - to update objects. - - It combines the **ParseUser** protocol and the **ParseObjectMutable** protocol. -*/ -public protocol ParseUserMutable: ParseUser, ParseObjectMutable { - init() -} diff --git a/Sources/ParseSwift/Types/ParseError.swift b/Sources/ParseSwift/Types/ParseError.swift index e0e0844de..66dd0635a 100644 --- a/Sources/ParseSwift/Types/ParseError.swift +++ b/Sources/ParseSwift/Types/ParseError.swift @@ -421,11 +421,11 @@ public extension Error { Returns the respective `ParseError` if the given `ParseError` code is equal to the error. **Example use case:** - ~~~ + ```` if let parseError = error.equalsTo(.objectNotFound) { print(parseError.description) } - ~~~ + ```` - parameter errorCode: A `ParseError` code to compare to. - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil. @@ -442,11 +442,11 @@ public extension Error { Validates if the given `ParseError` code is equal to the error. **Example use case:** - ~~~ + ```` if error.equalsTo(.objectNotFound) { //Do stuff } - ~~~ + ```` - parameter errorCode: A `ParseError` code to compare to. - returns: A boolean indicating whether or not the `Error` is the `errorCode`. @@ -462,11 +462,11 @@ public extension Error { Returns the respective `ParseError` if the `Error` is contained in the array of `ParseError` codes. **Example use case:** - ~~~ + ```` if let parseError = error.containedIn([.objectNotFound, .invalidQuery]) { print(parseError.description) } - ~~~ + ```` - parameter errorCodes: An array of zero or more of `ParseError` codes to compare to. - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil. @@ -483,11 +483,11 @@ public extension Error { Returns the respective `ParseError` if the `Error` is contained in the list of `ParseError` codes. **Example use case:** - ~~~ + ```` if let parseError = error.containedIn(.objectNotFound, .invalidQuery) { print(parseError.description) } - ~~~ + ```` - parameter errorCodes: A variadic amount of zero or more of `ParseError` codes to compare to. - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil. @@ -500,11 +500,11 @@ public extension Error { Validates if the given `ParseError` codes contains the error. **Example use case:** - ~~~ + ```` if error.containedIn([.objectNotFound, .invalidQuery]) { //Do stuff } - ~~~ + ```` - parameter errorCodes: An array of zero or more of `ParseError` codes to compare to. - returns: A boolean indicating whether or not the `Error` is contained in the `errorCodes`. @@ -520,11 +520,11 @@ public extension Error { Validates if the given `ParseError` codes contains the error. **Example use case:** - ~~~ + ```` if error.containedIn(.objectNotFound, .invalidQuery) { //Do stuff } - ~~~ + ```` - parameter errorCodes: A variadic amount of zero or more of `ParseError` codes to compare to. - returns: A boolean indicating whether or not the `Error` is contained in the `errorCodes`. From a7f6d9993f372a461def259ae8958b171dd6629b Mon Sep 17 00:00:00 2001 From: Damian Van de Kauter Date: Sun, 31 Oct 2021 14:28:45 +0100 Subject: [PATCH 4/5] Requested changes --- .../Protocols/ParseObjectMutable.swift | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift index 816f588da..cc8a1a2b8 100644 --- a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift +++ b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift @@ -9,15 +9,36 @@ import Foundation /** - The `ParseObjectMutable` protocol adds an empty version of the respective object. + The `ParseObjectMutable` protocol creates an empty copy of the respective object. This can be used when you only need to update a subset of the fields of an object as oppose to updating every field of an object. - Using an empty object and updating a subset of the fields reduces the amount of data + Using the mutable copy and updating a subset of the fields reduces the amount of data sent between client and server when using `save` and `saveAll` to update objects. - **Example use case:** + **Example use case for User:** ```` + struct User: ParseUser, ParseObjectMutable { + //: These are required by `ParseObject`. + var objectId: String? + var createdAt: Date? + var updatedAt: Date? + var ACL: ParseACL? + + //: These are required by `ParseUser`. + var username: String? + var email: String? + var emailVerified: Bool? + var password: String? + var authData: [String: [String: String]?]? + + //: Your custom keys. + var customKey: String? + var score: GameScore? + var targetScore: GameScore? + var allScores: [GameScore]? + } + var user = User.current?.mutable user?.customKey = "newValue" @@ -27,19 +48,56 @@ import Foundation // Handle error } ```` + + **Example use case for GameScore:** + ```` + struct GameScore: ParseObject, ParseObjectMutable { + //: These are required by ParseObject + var objectId: String? + var createdAt: Date? + var updatedAt: Date? + var ACL: ParseACL? + + //: Your own properties. + var score: Int = 0 + } + + let score = GameScore(score: 10) + + score.save { result in + switch result { + case .success(let savedScore): + var changedScore = savedScore.mutable + changedScore.score = 200 + changedScore.save { result in + switch result { + case .success(let savedChangedScore): + print("Successfully saved: \(savedChangedScore)") + + case .failure(let error): + assertionFailure("Error saving: \(error)") + } + } + case .failure(let error): + assertionFailure("Error saving: \(error)") + } + } + ```` - warning: Using the `ParseObjectMutable` protocol requires the developer to - use an **init()** without declaring custom properties. - You can still use non-optional properties if you add them to your **init()** method and give them a default value. - If you need a custom **init()**, you can't use the `ParseObjectMutable` protocol. + initialize all of the `ParseObject` properties. This can be accomplished by making all properties + optional or setting default values for non-optional properties. + This also allows your objects to be used as Parse `Pointer`‘s. + It's recommended to place custom initializers in an extension + to preserve the convenience initializer. */ public protocol ParseObjectMutable: ParseObject { init() /** - An empty version of the respective object that allows you to update a + An empty copy of the respective object that allows you to update a a subset of the fields of an object as oppose to updating every field of an object. - - note: You need to use this to create a mutable copy of your `ParseObject`. + - note: It is recommended to use this to create a mutable copy of your `ParseObject`. */ var mutable: Self { get } } From 6b21e2800707624840719963cd2d2a111599539b Mon Sep 17 00:00:00 2001 From: Damian Van de Kauter Date: Sun, 31 Oct 2021 21:46:21 +0100 Subject: [PATCH 5/5] Requested changes --- .../Protocols/ParseObjectMutable.swift | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift index cc8a1a2b8..392c1bac3 100644 --- a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift +++ b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift @@ -16,7 +16,7 @@ import Foundation sent between client and server when using `save` and `saveAll` to update objects. - **Example use case for User:** + **Example use case for `ParseUser`:** ```` struct User: ParseUser, ParseObjectMutable { //: These are required by `ParseObject`. @@ -49,7 +49,7 @@ import Foundation } ```` - **Example use case for GameScore:** + **Example use case for a general `ParseObject`:** ```` struct GameScore: ParseObject, ParseObjectMutable { //: These are required by ParseObject @@ -61,26 +61,26 @@ import Foundation //: Your own properties. var score: Int = 0 } + //: It's recommended to place custom initializers in an extension + //: to preserve the convenience initializer. + extension GameScore { + + init(score: Int) { + self.score = score + } + + init(objectId: String?) { + self.objectId = objectId + } + } - let score = GameScore(score: 10) + var newScore = GameScore(score: 10).mutable + newScore.score = 200 - score.save { result in - switch result { - case .success(let savedScore): - var changedScore = savedScore.mutable - changedScore.score = 200 - changedScore.save { result in - switch result { - case .success(let savedChangedScore): - print("Successfully saved: \(savedChangedScore)") - - case .failure(let error): - assertionFailure("Error saving: \(error)") - } - } - case .failure(let error): - assertionFailure("Error saving: \(error)") - } + do { + try await newScore.save() + } catch { + // Handle error } ````