diff --git a/CHANGELOG.md b/CHANGELOG.md index 358c52e9f..123e6a08a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,21 @@ # Parse-Swift Changelog ### main -[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.10...main) +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.0...main) * _Contributing to this repo? Add info about your change here to be included in the next release_ +### 1.10.0 +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.9...1.10.0) + +__Improvements__ +- (Breaking Change) Provide ParseObject property, emptyObject, that makes it easy to send only modified keys to the server. This change "might" be breaking depending on your implementation as it requires ParseObjects to now have an empty initializer, init() ([#243](https://github.com/parse-community/Parse-Swift/pull/243)), thanks to [Corey Baker](https://github.com/cbaker6). + __Fixes__ - ParseUser shouldn't send email if it hasn't been modified or else email verification is resent ([#241](https://github.com/parse-community/Parse-Swift/pull/241)), thanks to [Corey Baker](https://github.com/cbaker6). ### 1.9.10 [Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.9...1.9.10) + __Fixes__ - ParseInstallation can't be retreived from Keychain after the first fun ([#236](https://github.com/parse-community/Parse-Swift/pull/236)), thanks to [Corey Baker](https://github.com/cbaker6). 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 e95c47028..c3aea56e2 100644 --- a/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift @@ -39,8 +39,12 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 +} + +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { - //: Custom initializer. init(score: Int) { self.score = score } @@ -62,6 +66,11 @@ struct GameData: ParseObject { //: `ParseBytes` needs to be a part of the original schema //: or else you will need your masterKey to force an upgrade. var bytes: ParseBytes? +} + +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameData { init (bytes: ParseBytes?, polygon: ParsePolygon) { self.bytes = bytes @@ -87,9 +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. + was initialized as immutable. Using `emptyObject` + allows you to only send the updated keys to the + parse server as opposed to the whole object. */ - var changedScore = savedScore + var changedScore = savedScore.emptyObject changedScore.score = 200 changedScore.save { result in switch result { @@ -177,9 +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. + was initialized as immutable. Using `emptyObject` + allows you to only send the updated keys to the + parse server as opposed to the whole object. */ -guard var changedScore = savedScore else { +guard var changedScore = savedScore?.emptyObject else { fatalError() } changedScore.score = 200 diff --git a/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift index 5e4ba6b0d..a3357652a 100644 --- a/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift @@ -94,7 +94,11 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(score: Int) { self.score = score diff --git a/ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift index 0322e9fee..115050a78 100644 --- a/ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift @@ -21,7 +21,11 @@ struct GameScore: ParseObject { var score: Int = 0 var location: ParseGeoPoint? var name: String? +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(name: String, score: Int) { self.name = name diff --git a/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift index 1c17e44f2..c10a70c9a 100644 --- a/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift @@ -22,7 +22,11 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(score: Int) { self.score = score diff --git a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift index 316ffc2f5..18258b7d6 100644 --- a/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift @@ -30,7 +30,11 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int = 0 +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(objectId: String, score: Int) { self.objectId = objectId @@ -64,9 +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. + was initialized as immutable. Using `emptyObject` + allows you to only send the updated keys to the + parse server as opposed to the whole object. */ - var changedScore = savedScore + var changedScore = savedScore.emptyObject changedScore.score = 200 changedScore.save { result in switch result { diff --git a/ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift index 5c5759382..67502511d 100644 --- a/ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift @@ -39,7 +39,11 @@ struct GameScore: ParseObject, Identifiable { var location: ParseGeoPoint? var name: String? var myFiles: [ParseFile]? +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(name: String, score: Int) { self.name = name diff --git a/ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift index f13d0ec7a..329e3fb2b 100644 --- a/ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift @@ -39,7 +39,11 @@ struct GameScore: ParseObject, Identifiable { var score: Int = 0 var location: ParseGeoPoint? var name: String? +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(name: String, score: Int) { self.name = name diff --git a/ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift index 6c24f73c6..ab24881d9 100644 --- a/ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift @@ -29,7 +29,11 @@ struct GameScore: ParseObject { var score: Int = 0 var location: ParseGeoPoint? var name: String? +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(name: String, score: Int) { self.name = name @@ -75,9 +79,7 @@ struct ContentView: View { Text("Not subscribed to a query") } - Spacer() - - Text("Update GameScore in Parse Dashboard to see changes here") + Text("Update GameScore in Parse Dashboard to see changes here:") Button(action: { try? query.unsubscribe() @@ -88,8 +90,8 @@ struct ContentView: View { .foregroundColor(.white) .padding() .cornerRadius(20.0) - .frame(width: 300, height: 50) }) + Spacer() } } } diff --git a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift index d9f3c9670..027558318 100644 --- a/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift @@ -32,7 +32,11 @@ struct User: ParseUser { var score: GameScore? var targetScore: GameScore? var allScores: [GameScore]? +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension User { //: Custom init for signup. init(username: String, password: String, email: String) { self.username = username @@ -51,7 +55,11 @@ struct GameScore: ParseObject { //: Your own properties. var score: Int? = 0 +} +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { //: Custom initializer. init(score: Int) { self.score = score @@ -95,12 +103,15 @@ 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 + parse server as opposed to the whole object. */ -User.current?.customKey = "myCustom" -User.current?.score = GameScore(score: 12) -User.current?.targetScore = GameScore(score: 100) -User.current?.allScores = [GameScore(score: 5), GameScore(score: 8)] -User.current?.save { result in +var currentUser = User.current?.emptyObject +currentUser?.customKey = "myCustom" +currentUser?.score = GameScore(score: 12) +currentUser?.targetScore = GameScore(score: 100) +currentUser?.allScores = [GameScore(score: 5), GameScore(score: 8)] +currentUser?.save { result in switch result { case .success(let updatedUser): @@ -145,7 +156,7 @@ do { //: you should create an instance of your user first. var newUser = User(username: "parse", password: "aPassword*", email: "parse@parse.com") //: Add any other additional information. -newUser.targetScore = .init(score: 40) +newUser.customKey = "mind" newUser.signup { result in switch result { @@ -199,9 +210,10 @@ User.anonymous.login { result in } //: Convert the anonymous user to a real new user. -User.current?.username = "bye" -User.current?.password = "world" -User.current?.signup { result in +var currentUser2 = User.current?.emptyObject +currentUser2?.username = "bye" +currentUser2?.password = "world" +currentUser2?.signup { result in switch result { case .success(let user): diff --git a/ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift index c7c358434..7a303842e 100644 --- a/ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift @@ -33,7 +33,15 @@ struct GameScore: ParseObject { //: Your own properties var score: Int - //: a custom initializer + init() { + self.score = 0 + } +} + +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { + //: Custom initializer. init(score: Int) { self.score = score } diff --git a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift index bf44ff8aa..ea5bb4ab6 100644 --- a/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift @@ -42,8 +42,9 @@ struct Installation: ParseInstallation { designated callbackQueue. If no callbackQueue is specified it returns to main queue. */ -Installation.current?.customKey = "myCustomInstallationKey2" -Installation.current?.save { results in +var currentInstallation = Installation.current +currentInstallation?.customKey = "myCustomInstallationKey2" +currentInstallation?.save { results in switch results { case .success(let updatedInstallation): @@ -56,10 +57,13 @@ Installation.current?.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. + returns to main queue. Using `emptyObject` allows you to only + send the updated keys to the parse server as opposed to the + whole object. */ -Installation.current?.customKey = "updatedValue" -Installation.current?.save { results in +currentInstallation = currentInstallation?.emptyObject +currentInstallation?.customKey = "updatedValue" +currentInstallation?.save { results in switch results { case .success(let updatedInstallation): diff --git a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift index a96639bdc..be7f9da72 100644 --- a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift @@ -21,10 +21,15 @@ struct GameScore: ParseObject { var updatedAt: Date? var ACL: ParseACL? var location: ParseGeoPoint? + //: Your own properties var score: Int? +} - //: A custom initializer. +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { + //: Custom initializer. init(score: Int) { self.score = score } diff --git a/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift index a792853ff..30cd238fc 100644 --- a/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift @@ -24,6 +24,11 @@ struct Book: ParseObject { //: Your own properties. var title: String? +} + +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension Book { init(title: String) { self.title = title @@ -42,6 +47,15 @@ struct Author: ParseObject { var book: Book var otherBooks: [Book]? + init() { + self.name = "hello" + self.book = Book() + } +} + +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension Author { init(name: String, book: Book) { self.name = name self.book = book diff --git a/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift index 5fa5d11b0..d1231d133 100644 --- a/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift @@ -25,8 +25,12 @@ struct GameScore: ParseObject { var score: Int = 0 var profilePicture: ParseFile? var myData: ParseFile? +} - //custom initializer +//: It's recommended to place custom initializers in an extension +//: to preserve the convenience initializer. +extension GameScore { + //: Custom initializer. init(score: Int) { self.score = score } diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index f1a07b7fc..1ab0e483d 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -32,27 +32,43 @@ public protocol ParseObject: Objectable, Deletable, Hashable, CustomDebugStringConvertible, - CustomStringConvertible {} + CustomStringConvertible { + /** + Default initializer of this object. + */ + init() +} // MARK: Default Implementations -extension ParseObject { +public extension ParseObject { /** - Determines if two objects have the same objectId. + 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 + } + /** + Determines if two objects have the same objectId. - parameter as: Object to compare. - - returns: Returns a `true` if the other object has the same `objectId` or `false` if unsuccessful. */ - public func hasSameObjectId(as other: T) -> Bool { + func hasSameObjectId(as other: T) -> Bool { return other.className == className && other.objectId == objectId && objectId != nil } /** - Gets a Pointer referencing this Object. - - returns: Pointer + Gets a Pointer referencing this object. + - returns: Pointer */ - public func toPointer() throws -> Pointer { + func toPointer() throws -> Pointer { return try Pointer(self) } } diff --git a/Sources/ParseSwift/ParseConstants.swift b/Sources/ParseSwift/ParseConstants.swift index 7d8d20b60..aed7969fd 100644 --- a/Sources/ParseSwift/ParseConstants.swift +++ b/Sources/ParseSwift/ParseConstants.swift @@ -10,7 +10,7 @@ import Foundation enum ParseConstants { static let sdk = "swift" - static let version = "1.9.9" + static let version = "1.10.0" static let fileManagementDirectory = "parse/" static let fileManagementPrivateDocumentsDirectory = "Private Documents/" static let fileManagementLibraryDirectory = "Library/" diff --git a/Tests/ParseSwiftTests/IOS13Tests.swift b/Tests/ParseSwiftTests/IOS13Tests.swift index 627032f7c..041280579 100644 --- a/Tests/ParseSwiftTests/IOS13Tests.swift +++ b/Tests/ParseSwiftTests/IOS13Tests.swift @@ -47,6 +47,7 @@ class IOS13Tests: XCTestCase { // swiftlint:disable:this type_body_length var levels: [Level]? //custom initializers + init() {} init (objectId: String?) { self.objectId = objectId } diff --git a/Tests/ParseSwiftTests/ParseEncoderTests/ParseEncoderExtraTests.swift b/Tests/ParseSwiftTests/ParseEncoderTests/ParseEncoderExtraTests.swift index 07eee4b7b..82596cfd3 100644 --- a/Tests/ParseSwiftTests/ParseEncoderTests/ParseEncoderExtraTests.swift +++ b/Tests/ParseSwiftTests/ParseEncoderTests/ParseEncoderExtraTests.swift @@ -21,6 +21,9 @@ class ParseEncoderTests: XCTestCase { var score: Int //: a custom initializer + init() { + self.score = 5 + } init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseLiveQueryTests.swift b/Tests/ParseSwiftTests/ParseLiveQueryTests.swift index 9e4bc9a11..f569da582 100644 --- a/Tests/ParseSwiftTests/ParseLiveQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseLiveQueryTests.swift @@ -23,6 +23,8 @@ class ParseLiveQueryTests: XCTestCase { var score: Int = 0 //custom initializer + init() {} + init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index 7990b9c8b..4bbf08065 100644 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -23,6 +23,9 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le var score: Int = 0 //custom initializers + init() { + self.score = 5 + } init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseObjectCombine.swift b/Tests/ParseSwiftTests/ParseObjectCombine.swift index 54c6b6e63..e67eec57a 100644 --- a/Tests/ParseSwiftTests/ParseObjectCombine.swift +++ b/Tests/ParseSwiftTests/ParseObjectCombine.swift @@ -28,6 +28,7 @@ class ParseObjectCombineTests: XCTestCase { // swiftlint:disable:this type_body_ var player: String? //custom initializers + init() {} init (objectId: String?) { self.objectId = objectId } diff --git a/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift b/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift index 5399d3e8a..80ee964db 100644 --- a/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift @@ -37,6 +37,7 @@ class ParseObjectCustomObjectIdTests: XCTestCase { // swiftlint:disable:this typ var levels: [Level]? //custom initializers + init() {} init (objectId: String?) { self.objectId = objectId } @@ -64,6 +65,9 @@ class ParseObjectCustomObjectIdTests: XCTestCase { // swiftlint:disable:this typ var profilePicture: ParseFile? //: a custom initializer + init() { + self.score = GameScore() + } init(score: GameScore) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseObjectTests.swift b/Tests/ParseSwiftTests/ParseObjectTests.swift index ee3d7be41..4b2adb58c 100644 --- a/Tests/ParseSwiftTests/ParseObjectTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectTests.swift @@ -42,7 +42,9 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length var nextLevel: Level? //custom initializers - init (objectId: String?) { + init() {} + + init(objectId: String?) { self.objectId = objectId } init(score: Int) { @@ -69,6 +71,10 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length var profilePicture: ParseFile? //: a custom initializer + init() { + self.score = GameScore() + } + init(score: GameScore) { self.score = score } @@ -102,6 +108,10 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length var game: GameClass? //: a custom initializer + required init() { + self.score = 5 + } + init(score: Int) { self.score = score } @@ -154,6 +164,10 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length var name = "Hello" //: a custom initializer + required init() { + self.score = GameScoreClass() + } + init(score: GameScoreClass) { self.score = score } @@ -226,6 +240,15 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length wait(for: [expectation2], timeout: 20.0) } + func testEmptyObject() throws { + var score = GameScore(score: 19, name: "fire") + score.objectId = "yolo" + score.createdAt = Date() + let empty = score.emptyObject + XCTAssertTrue(score.hasSameObjectId(as: empty)) + XCTAssertEqual(score.createdAt, empty.createdAt) + } + func testFetchCommand() { var score = GameScore(score: 10) let className = score.className @@ -546,6 +569,49 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) XCTAssertEqual(decoded, expected) } + + func testUpdateCommandEmptyObject() throws { + var score = GameScore(score: 10) + let className = score.className + let objectId = "yarr" + score.objectId = objectId + score.createdAt = Date() + score.updatedAt = score.createdAt + + let command = try score.emptyObject.saveCommand() + XCTAssertNotNil(command) + XCTAssertEqual(command.path.urlComponent, "/classes/\(className)/\(objectId)") + XCTAssertEqual(command.method, API.Method.PUT) + XCTAssertNil(command.params) + + guard let body = command.body else { + XCTFail("Should be able to unwrap") + return + } + + let expected = "{}" + let encoded = try ParseCoding.parseEncoder() + .encode(body, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) + XCTAssertEqual(decoded, expected) + + var empty = score.emptyObject + empty.player = "Jennifer" + let command2 = try empty.saveCommand() + guard let body2 = command2.body else { + XCTFail("Should be able to unwrap") + return + } + let expected2 = "{\"player\":\"Jennifer\"}" + let encoded2 = try ParseCoding.parseEncoder() + .encode(body2, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8)) + XCTAssertEqual(decoded2, expected2) + } #endif func testSave() { // swiftlint:disable:this function_body_length diff --git a/Tests/ParseSwiftTests/ParseOperationCombineTests.swift b/Tests/ParseSwiftTests/ParseOperationCombineTests.swift index d0e224890..bb41e3643 100644 --- a/Tests/ParseSwiftTests/ParseOperationCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseOperationCombineTests.swift @@ -28,6 +28,7 @@ class ParseOperationCombineTests: XCTestCase { // swiftlint:disable:this type_bo var player: String? //custom initializers + init() {} init (objectId: String?) { self.objectId = objectId } diff --git a/Tests/ParseSwiftTests/ParseOperationTests.swift b/Tests/ParseSwiftTests/ParseOperationTests.swift index dfa6ad30c..f4fb13cfd 100644 --- a/Tests/ParseSwiftTests/ParseOperationTests.swift +++ b/Tests/ParseSwiftTests/ParseOperationTests.swift @@ -25,6 +25,10 @@ class ParseOperationTests: XCTestCase { var previous: [Level]? //custom initializers + init() { + self.score = 5 + } + init(score: Int) { self.score = score } @@ -42,6 +46,9 @@ class ParseOperationTests: XCTestCase { var members = [String]() //custom initializers + init() { + self.level = 5 + } init(level: Int) { self.level = level } diff --git a/Tests/ParseSwiftTests/ParsePointerCombineTests.swift b/Tests/ParseSwiftTests/ParsePointerCombineTests.swift index cdb1540ab..8bff44f90 100644 --- a/Tests/ParseSwiftTests/ParsePointerCombineTests.swift +++ b/Tests/ParseSwiftTests/ParsePointerCombineTests.swift @@ -27,6 +27,9 @@ class ParsePointerCombineTests: XCTestCase { var score: Int //: a custom initializer + init() { + self.score = 5 + } init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParsePointerTests.swift b/Tests/ParseSwiftTests/ParsePointerTests.swift index 6bbe1f5f6..337bb8d05 100644 --- a/Tests/ParseSwiftTests/ParsePointerTests.swift +++ b/Tests/ParseSwiftTests/ParsePointerTests.swift @@ -25,6 +25,10 @@ class ParsePointerTests: XCTestCase { var others: [Pointer]? //: a custom initializer + init() { + self.score = 5 + } + init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift index 49e1593f4..a72ad6415 100644 --- a/Tests/ParseSwiftTests/ParseQueryCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryCombineTests.swift @@ -28,6 +28,8 @@ class ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_l var player: String? //custom initializers + init() {} + init (objectId: String?) { self.objectId = objectId } diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index ac8e63f42..832d20106 100644 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -23,6 +23,9 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length var score: Int //: a custom initializer + init() { + self.score = 5 + } init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseQueryViewModelTests.swift b/Tests/ParseSwiftTests/ParseQueryViewModelTests.swift index e1976e479..f4d1d44f0 100644 --- a/Tests/ParseSwiftTests/ParseQueryViewModelTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryViewModelTests.swift @@ -24,6 +24,7 @@ class ParseQueryViewModelTests: XCTestCase { var score: Int = 0 //custom initializer + init() {} init(score: Int) { self.score = score } diff --git a/Tests/ParseSwiftTests/ParseRelationTests.swift b/Tests/ParseSwiftTests/ParseRelationTests.swift index 41097fdce..2cd3016b3 100644 --- a/Tests/ParseSwiftTests/ParseRelationTests.swift +++ b/Tests/ParseSwiftTests/ParseRelationTests.swift @@ -25,6 +25,9 @@ class ParseRelationTests: XCTestCase { var levels: [String]? //custom initializers + init() { + self.score = 5 + } init(score: Int) { self.score = score } @@ -42,6 +45,10 @@ class ParseRelationTests: XCTestCase { var members = [String]() //custom initializers + init() { + self.level = 5 + } + init(level: Int) { self.level = level } diff --git a/Tests/ParseSwiftTests/ParseRoleTests.swift b/Tests/ParseSwiftTests/ParseRoleTests.swift index 14dddc19f..f8395dda1 100644 --- a/Tests/ParseSwiftTests/ParseRoleTests.swift +++ b/Tests/ParseSwiftTests/ParseRoleTests.swift @@ -24,6 +24,10 @@ class ParseRoleTests: XCTestCase { var levels: [String]? //custom initializers + init() { + self.score = 5 + } + init(score: Int) { self.score = score } @@ -76,6 +80,10 @@ class ParseRoleTests: XCTestCase { var members = [String]() //custom initializers + init() { + self.level = 5 + } + init(level: Int) { self.level = level }