diff --git a/CHANGELOG.md b/CHANGELOG.md index 60b1f88a7..8ccca6287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) 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 92b3d8370..49968d6ff 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, ParseObjectMutable { //: These are required by ParseObject 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 `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 { @@ -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 diff --git a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift index f17298579..b61e9e575 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, ParseObjectMutable { //: These are required by ParseObject 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 `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 { diff --git a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift index 5ee1e4666..5b7197f4b 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, ParseObjectMutable { //: These are required by `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 `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) @@ -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 diff --git a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift index 429b5b733..54b661277 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, ParseObjectMutable { //: These are required by `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 `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 diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index d4bcbe907..b70c9304d 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 /* 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 */; }; @@ -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 /* 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 = ""; }; @@ -1287,6 +1292,7 @@ F97B45C824D9C6F200F4A88B /* Queryable.swift */, F97B45C724D9C6F200F4A88B /* Savable.swift */, 70647E9B259E3A9A004C1004 /* ParseType.swift */, + CD1069FF272D481800939151 /* ParseObjectMutable.swift */, 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */, 91F346BD269B77B5005727B6 /* CloudObservable.swift */, ); @@ -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 */, @@ -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 */, @@ -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 */, @@ -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 */, diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index c3086129c..61daa7b17 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -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 diff --git a/Sources/ParseSwift/Protocols/ParseObjectMutable.swift b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift new file mode 100644 index 000000000..392c1bac3 --- /dev/null +++ b/Sources/ParseSwift/Protocols/ParseObjectMutable.swift @@ -0,0 +1,112 @@ +// +// 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 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 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 for `ParseUser`:** + ```` + 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" + + do { + try await user?.save() + } catch { + // Handle error + } + ```` + + **Example use case for a general `ParseObject`:** + ```` + 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 + } + //: 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 + } + } + + var newScore = GameScore(score: 10).mutable + newScore.score = 200 + + do { + try await newScore.save() + } catch { + // Handle error + } + ```` + + - warning: Using the `ParseObjectMutable` protocol requires the developer to + 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 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: It is recommended to use this to create a mutable copy of your `ParseObject`. + */ + var mutable: Self { get } +} + +public extension ParseObjectMutable { + var mutable: Self { + var object = Self() + object.objectId = objectId + object.createdAt = createdAt + return object + } +} 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`. diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index 476c657b2..a7e2b338f 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: ParseObject, ParseObjectMutable { //: These are required by ParseObject 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 {