Skip to content

Commit

Permalink
feat: add ParseObjectMutable protocol (#270)
Browse files Browse the repository at this point in the history
* • Updatable

* Requested changes

* Requested changes + Line length

* Requested changes

* Requested changes

Co-authored-by: Corey <coreyearleon@icloud.com>
  • Loading branch information
vdkdamian and cbaker6 committed Oct 31, 2021
1 parent 126f4f6 commit 321905d
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 112 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,8 @@

__Improvements__
- Make ParseUser.current, ParseInstallation.current, ParseConfig.current immutable. This prevents accidently setting to nil. When developers want to make changes, they should make mutable copies, mutate, then save ([#266](https://github.com/parse-community/Parse-Swift/pull/266)), thanks to [Corey Baker](https://github.com/cbaker6).
- 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).


### 2.0.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.2...2.0.3)
Expand Down
Expand Up @@ -30,7 +30,7 @@ do {
}

//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject {
struct GameScore: ParseObject, ParseObjectMutable {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
Expand All @@ -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
Expand Down Expand Up @@ -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 `mutable`
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.mutable
changedScore.score = 200
changedScore.save { result in
switch result {
Expand Down Expand Up @@ -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 `mutable`
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?.mutable else {
fatalError()
}
changedScore.score = 200
Expand Down
Expand Up @@ -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, ParseObjectMutable {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
Expand All @@ -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
Expand Down Expand Up @@ -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 `mutable`
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.mutable
changedScore.score = 200
changedScore.save { result in
switch result {
Expand Down
Expand Up @@ -13,7 +13,7 @@ import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()

struct User: ParseUser {
struct User: ParseUser, ParseObjectMutable {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
Expand All @@ -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
Expand Down Expand Up @@ -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 `mutable` 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?.mutable
currentUser?.customKey = "myCustom"
currentUser?.score = GameScore(score: 12)
currentUser?.targetScore = GameScore(score: 100)
Expand Down Expand Up @@ -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?.mutable
currentUser2?.username = "bye"
currentUser2?.password = "world"
currentUser2?.signup { result in
Expand Down
Expand Up @@ -13,7 +13,7 @@ import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()

struct Installation: ParseInstallation {
struct Installation: ParseInstallation, ParseObjectMutable {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
Expand All @@ -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`.
Expand All @@ -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 `mutable` allows you to only
send the updated keys to the parse server as opposed to the
whole object.
*/
currentInstallation = currentInstallation?.emptyObject
currentInstallation = currentInstallation?.mutable
currentInstallation?.customKey = "updatedValue"
currentInstallation?.save { results in

Expand Down
10 changes: 10 additions & 0 deletions ParseSwift.xcodeproj/project.pbxproj
Expand Up @@ -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 /* 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 */; };
Expand Down Expand Up @@ -961,6 +965,7 @@
91F346B8269B766C005727B6 /* CloudViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudViewModel.swift; sourceTree = "<group>"; };
91F346BD269B77B5005727B6 /* CloudObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudObservable.swift; sourceTree = "<group>"; };
91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudViewModelTests.swift; sourceTree = "<group>"; };
CD1069FF272D481800939151 /* ParseObjectMutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectMutable.swift; sourceTree = "<group>"; };
F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoderExtraTests.swift; sourceTree = "<group>"; };
F97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = "<group>"; };
F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1287,6 +1292,7 @@
F97B45C824D9C6F200F4A88B /* Queryable.swift */,
F97B45C724D9C6F200F4A88B /* Savable.swift */,
70647E9B259E3A9A004C1004 /* ParseType.swift */,
CD1069FF272D481800939151 /* ParseObjectMutable.swift */,
91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */,
91F346BD269B77B5005727B6 /* CloudObservable.swift */,
);
Expand Down Expand Up @@ -2084,6 +2090,7 @@
703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B45E624D9C6F200F4A88B /* Query.swift in Sources */,
CD106A00272D481800939151 /* ParseObjectMutable.swift in Sources */,
703B093526BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,
705D950825BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,
70C5509225B4A99100B5DBC2 /* AddRelation.swift in Sources */,
Expand Down Expand Up @@ -2293,6 +2300,7 @@
703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B45E724D9C6F200F4A88B /* Query.swift in Sources */,
CD106A01272D481800939151 /* ParseObjectMutable.swift in Sources */,
703B093626BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,
705D950925BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,
70C5509325B4A99100B5DBC2 /* AddRelation.swift in Sources */,
Expand Down Expand Up @@ -2597,6 +2605,7 @@
703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */,
CD106A03272D481800939151 /* ParseObjectMutable.swift in Sources */,
703B093826BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,
705D950B25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,
70C5509525B4A99100B5DBC2 /* AddRelation.swift in Sources */,
Expand Down Expand Up @@ -2720,6 +2729,7 @@
703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */,
703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */,
F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */,
CD106A02272D481800939151 /* ParseObjectMutable.swift in Sources */,
703B093726BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,
705D950A25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,
70C5509425B4A99100B5DBC2 /* AddRelation.swift in Sources */,
Expand Down
13 changes: 3 additions & 10 deletions Sources/ParseSwift/Objects/ParseObject.swift
Expand Up @@ -16,19 +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 adds the emptyObject computed property or similar.
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`
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
}
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
Expand Down

0 comments on commit 321905d

Please sign in to comment.