diff --git a/.codecov.yml b/.codecov.yml index fd2c86e08..c25410f92 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -6,7 +6,7 @@ coverage: status: patch: default: - target: auto + target: 58 changes: false project: default: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2dca3637e..4342d652f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ on: env: CI_XCODE_OLDEST: '/Applications/Xcode_12.5.1.app/Contents/Developer' CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer' - CI_XCODE_LATEST: '/Applications/Xcode_14.0.app/Contents/Developer' + CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer' jobs: xcode-test-ios: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 69f87ec91..537c293af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,7 +4,7 @@ on: types: [published] env: CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer' - CI_XCODE_LATEST: '/Applications/Xcode_14.0.app/Contents/Developer' + CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer' jobs: cocoapods: diff --git a/CHANGELOG.md b/CHANGELOG.md index 85963f5eb..2f1637abe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,15 @@ # Parse-Swift Changelog ### main -[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.1...main), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/main/documentation/parseswift) +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.2...main), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/main/documentation/parseswift) * _Contributing to this repo? Add info about your change here to be included in the next release_ +### 4.14.2 +[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.1...4.14.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.2/documentation/parseswift) + +__Fixes__ +- Addressed an issue that prevented updating ParseObjects with saveAll ([#423](https://github.com/parse-community/Parse-Swift/pull/423)), thanks to [Corey Baker](https://github.com/cbaker6). + ### 4.14.1 [Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.0...4.14.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.1/documentation/parseswift) diff --git a/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift index 96199c7cb..07fb6c4c3 100644 --- a/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift @@ -118,7 +118,7 @@ do { //: There may be cases where you want to set/forceSet a value to null //: instead of unsetting let setToNullOperation = savedScore - .operation.set(("name", \.name), value: nil) + .operation.set(("name", \.name), to: nil) do { let updatedScore = try setToNullOperation.save() print("Updated score: \(updatedScore). Check the new score on Parse Dashboard.") diff --git a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift index 181c03f50..7b72f640e 100644 --- a/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift @@ -55,9 +55,10 @@ do { try score.location = ParseGeoPoint(latitude: 40.0, longitude: -30.0) } -/*: Save asynchronously (preferred way) - performs work on background - queue and returns to specified callbackQueue. - If no callbackQueue is specified it returns to main queue. +/*: + Save asynchronously (preferred way) - performs work on background + queue and returns to specified callbackQueue. + If no callbackQueue is specified it returns to main queue. */ score.save { result in switch result { @@ -107,8 +108,9 @@ do { } } -/*: If you only want to query for points in descending order, use the order enum. -Notice the "var", the query has to be mutable since it is a value type. +/*: + If you only want to query for points in descending order, use the order enum. + Notice the "var", the query has to be mutable since it is a value type. */ var querySorted = query querySorted.order([.descending("points")]) diff --git a/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift index c5e0b9e29..901148f2e 100644 --- a/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift @@ -108,7 +108,7 @@ author.save { result in assert(savedAuthorAndBook.createdAt != nil) assert(savedAuthorAndBook.updatedAt != nil) - print("Saved \(savedAuthorAndBook)") + print("Saved: \(savedAuthorAndBook)") case .failure(let error): assertionFailure("Error saving: \(error)") } @@ -132,7 +132,7 @@ author2.save { result in Notice the pointer objects have not been updated on the client.If you want the latest pointer objects, fetch and include them. */ - print("Saved \(savedAuthorAndBook)") + print("Saved: \(savedAuthorAndBook)") case .failure(let error): assertionFailure("Error saving: \(error)") @@ -243,7 +243,7 @@ do { assert(updatedBook.updatedAt != nil) assert(updatedBook.relatedBook != nil) - print("Saved \(updatedBook)") + print("Saved: \(updatedBook)") case .failure(let error): assertionFailure("Error saving: \(error)") } @@ -323,12 +323,12 @@ author4.otherBooks = [otherBook3, otherBook4] assert(savedAuthorAndBook.createdAt != nil) assert(savedAuthorAndBook.updatedAt != nil) assert(savedAuthorAndBook.otherBooks?.count == 2) - + author4 = savedAuthorAndBook /*: Notice the pointer objects have not been updated on the client.If you want the latest pointer objects, fetch and include them. */ - print("Saved \(savedAuthorAndBook)") + print("Saved: \(savedAuthorAndBook)") case .failure(let error): assertionFailure("Error saving: \(error)") } @@ -339,5 +339,37 @@ author4.otherBooks = [otherBook3, otherBook4] } } +//: Batching saves by updating an already saved object. +author4.fetch { result in + switch result { + case .success(var fetchedAuthor): + print("The latest author: \(fetchedAuthor)") + fetchedAuthor.name = "R.L. Stine" + [fetchedAuthor].saveAll { result in + switch result { + case .success(let savedAuthorsAndBook): + savedAuthorsAndBook.forEach { eachResult in + switch eachResult { + case .success(let savedAuthorAndBook): + assert(savedAuthorAndBook.objectId != nil) + assert(savedAuthorAndBook.createdAt != nil) + assert(savedAuthorAndBook.updatedAt != nil) + assert(savedAuthorAndBook.otherBooks?.count == 2) + + print("Updated: \(savedAuthorAndBook)") + case .failure(let error): + assertionFailure("Error saving: \(error)") + } + } + + case .failure(let error): + assertionFailure("Error saving: \(error)") + } + } + case .failure(let error): + assertionFailure("Error fetching: \(error)") + } +} + PlaygroundPage.current.finishExecution() //: [Next](@next) diff --git a/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift index 0b718f45b..e898209a3 100644 --- a/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift @@ -74,9 +74,10 @@ let profilePic = ParseFile(name: "profile.svg", cloudURL: linkToFile) //: Set the picture as part of your ParseObject score.profilePicture = profilePic -/*: Save asynchronously (preferred way) - Performs work on background - queue and returns to specified callbackQueue. - If no callbackQueue is specified it returns to main queue. +/*: + Save asynchronously (preferred way) - Performs work on background + queue and returns to specified callbackQueue. + If no callbackQueue is specified it returns to main queue. */ score.save { result in switch result { @@ -121,7 +122,8 @@ score.save { result in } } -/*: Files can also be saved from data. Below is how to do it synchronously, but async is similar to above +/*: + Files can also be saved from data. Below is how to do it synchronously, but async is similar to above Create a new `ParseFile` for your data. */ let sampleData = "Hello World".data(using: .utf8)! @@ -153,7 +155,8 @@ do { print("The file is now saved at: \(fetchedFile.localURL!)") print("The full details of your data ParseFile are: \(fetchedFile)") - /*: If you want to use the data from the file to display the text file or image, you need to retreive + /*: + If you want to use the data from the file to display the text file or image, you need to retreive the data from the file. */ guard let dataFromParseFile = try? Data(contentsOf: fetchedFile.localURL!) else { @@ -179,7 +182,8 @@ do { fatalError("Error saving: \(error)") } -/*: Files can also be saved from files located on your device by using: +/*: + Files can also be saved from files located on your device by using: let localFile = ParseFile(name: "hello.txt", localURL: URL). */ diff --git a/Sources/ParseSwift/API/API+Command+async.swift b/Sources/ParseSwift/API/API+Command+async.swift index 138ad0140..2c1159295 100644 --- a/Sources/ParseSwift/API/API+Command+async.swift +++ b/Sources/ParseSwift/API/API+Command+async.swift @@ -15,6 +15,7 @@ import FoundationNetworking internal extension API.Command { // MARK: Asynchronous Execution func executeAsync(options: API.Options, + batching: Bool = false, callbackQueue: DispatchQueue, notificationQueue: DispatchQueue? = nil, childObjects: [String: PointerType]? = nil, @@ -24,6 +25,7 @@ internal extension API.Command { downloadProgress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? = nil) async throws -> U { try await withCheckedThrowingContinuation { continuation in self.executeAsync(options: options, + batching: batching, callbackQueue: callbackQueue, notificationQueue: notificationQueue, childObjects: childObjects, diff --git a/Sources/ParseSwift/API/API+Command.swift b/Sources/ParseSwift/API/API+Command.swift index 80cd1d083..951955882 100644 --- a/Sources/ParseSwift/API/API+Command.swift +++ b/Sources/ParseSwift/API/API+Command.swift @@ -55,7 +55,10 @@ internal extension API { childFiles: [UUID: ParseFile]? = nil, uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil, stream: InputStream) throws { - switch self.prepareURLRequest(options: options, childObjects: childObjects, childFiles: childFiles) { + switch self.prepareURLRequest(options: options, + batching: false, + childObjects: childObjects, + childFiles: childFiles) { case .success(let urlRequest): if method == .POST || method == .PUT || method == .PATCH { @@ -80,6 +83,7 @@ internal extension API { } func execute(options: API.Options, + batching: Bool = false, notificationQueue: DispatchQueue? = nil, childObjects: [String: PointerType]? = nil, childFiles: [UUID: ParseFile]? = nil, @@ -94,6 +98,7 @@ internal extension API { let group = DispatchGroup() group.enter() self.executeAsync(options: options, + batching: batching, callbackQueue: synchronizationQueue, notificationQueue: notificationQueue, childObjects: childObjects, @@ -115,6 +120,7 @@ internal extension API { // MARK: Asynchronous Execution // swiftlint:disable:next function_body_length cyclomatic_complexity func executeAsync(options: API.Options, + batching: Bool = false, callbackQueue: DispatchQueue, notificationQueue: DispatchQueue? = nil, childObjects: [String: PointerType]? = nil, @@ -131,6 +137,7 @@ internal extension API { if !path.urlComponent.contains("/files/") { // All ParseObjects use the shared URLSession switch self.prepareURLRequest(options: options, + batching: batching, childObjects: childObjects, childFiles: childFiles) { case .success(let urlRequest): @@ -156,6 +163,7 @@ internal extension API { // ParseFiles are handled with a dedicated URLSession if method == .POST || method == .PUT || method == .PATCH { switch self.prepareURLRequest(options: options, + batching: batching, childObjects: childObjects, childFiles: childFiles) { @@ -187,6 +195,7 @@ internal extension API { } else if method == .DELETE { switch self.prepareURLRequest(options: options, + batching: batching, childObjects: childObjects, childFiles: childFiles) { case .success(let urlRequest): @@ -213,6 +222,7 @@ internal extension API { if parseURL != nil { switch self.prepareURLRequest(options: options, + batching: batching, childObjects: childObjects, childFiles: childFiles) { @@ -266,6 +276,7 @@ internal extension API { // MARK: URL Preperation func prepareURLRequest(options: API.Options, + batching: Bool = false, childObjects: [String: PointerType]? = nil, childFiles: [UUID: ParseFile]? = nil) -> Result { let params = self.params?.getURLQueryItems() @@ -299,7 +310,9 @@ internal extension API { } else { guard let bodyData = try? ParseCoding .parseEncoder() - .encode(urlBody, collectChildren: false, + .encode(urlBody, + batching: batching, + collectChildren: false, objectsSavedBeforeThisOne: childObjects, filesSavedBeforeThisOne: childFiles) else { return .failure(ParseError(code: .unknownError, @@ -393,14 +406,16 @@ internal extension API.Command { // MARK: Saving ParseObjects static func save(_ object: T, original data: Data?, - ignoringCustomObjectIdConfig: Bool) throws -> API.Command where T: ParseObject { - if Parse.configuration.isAllowingCustomObjectIds + ignoringCustomObjectIdConfig: Bool, + batching: Bool = false) throws -> API.Command where T: ParseObject { + if Parse.configuration.isRequiringCustomObjectIds && object.objectId == nil && !ignoringCustomObjectIdConfig { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") } if object.isSaved { // MARK: Should be switched to "update" when server supports PATCH. - return try replace(object, original: data) + return try replace(object, + original: data) } return create(object) } @@ -420,7 +435,8 @@ internal extension API.Command { mapper: mapper) } - static func replace(_ object: T, original data: Data?) throws -> API.Command where T: ParseObject { + static func replace(_ object: T, + original data: Data?) throws -> API.Command where T: ParseObject { guard object.objectId != nil else { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") @@ -446,7 +462,8 @@ internal extension API.Command { mapper: mapper) } - static func update(_ object: T, original data: Data?) throws -> API.Command where T: ParseObject { + static func update(_ object: T, + original data: Data?) throws -> API.Command where T: ParseObject { guard object.objectId != nil else { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") @@ -504,8 +521,10 @@ internal extension API.Command where T: ParseObject { guard let body = command.body else { return nil } - return API.Command(method: command.method, path: .any(path), - body: body, mapper: command.mapper) + return API.Command(method: command.method, + path: .any(path), + body: body, + mapper: command.mapper) } let mapper = { (data: Data) -> [Result] in diff --git a/Sources/ParseSwift/API/API+NonParseBodyCommand.swift b/Sources/ParseSwift/API/API+NonParseBodyCommand.swift index 97225d177..0d6c4d09d 100644 --- a/Sources/ParseSwift/API/API+NonParseBodyCommand.swift +++ b/Sources/ParseSwift/API/API+NonParseBodyCommand.swift @@ -170,7 +170,7 @@ internal extension API.NonParseBodyCommand { } let path = Parse.configuration.mountPath + objectable.endpoint.urlComponent - let encoded = try ParseCoding.parseEncoder().encode(object) + let encoded = try ParseCoding.parseEncoder().encode(object, batching: true) let body = try ParseCoding.jsonDecoder().decode(AnyCodable.self, from: encoded) return API.BatchCommand(method: method, path: .any(path), diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index c6d763532..75b92a2a6 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -104,8 +104,12 @@ public struct ParseEncoder { self.outputFormatting = outputFormatting } - func encode(_ value: Encodable) throws -> Data { - let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: SkipKeys.none.keys()) + func encode(_ value: Encodable, batching: Bool = false) throws -> Data { + var keysToSkip = SkipKeys.none.keys() + if batching { + keysToSkip = SkipKeys.object.keys() + } + let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip) if let dateEncodingStrategy = dateEncodingStrategy { encoder.dateEncodingStrategy = dateEncodingStrategy } @@ -113,6 +117,7 @@ public struct ParseEncoder { encoder.outputFormatting = outputFormatting } return try encoder.encodeObject(value, + batching: batching, collectChildren: false, uniquePointer: nil, objectsSavedBeforeThisOne: nil, @@ -147,7 +152,7 @@ public struct ParseEncoder { unique: PointerType?, unsavedChildren: [Encodable]) { let keysToSkip: Set! - if !Parse.configuration.isAllowingCustomObjectIds { + if !Parse.configuration.isRequiringCustomObjectIds { keysToSkip = SkipKeys.object.keys() } else { keysToSkip = SkipKeys.customObjectId.keys() @@ -168,11 +173,12 @@ public struct ParseEncoder { // swiftlint:disable large_tuple internal func encode(_ value: ParseEncodable, + batching: Bool = false, collectChildren: Bool, objectsSavedBeforeThisOne: [String: PointerType]?, filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) { let keysToSkip: Set! - if !Parse.configuration.isAllowingCustomObjectIds { + if !Parse.configuration.isRequiringCustomObjectIds { keysToSkip = SkipKeys.object.keys() } else { keysToSkip = SkipKeys.customObjectId.keys() @@ -185,6 +191,7 @@ public struct ParseEncoder { encoder.outputFormatting = outputFormatting } return try encoder.encodeObject(value, + batching: batching, collectChildren: collectChildren, uniquePointer: nil, objectsSavedBeforeThisOne: objectsSavedBeforeThisOne, @@ -201,6 +208,7 @@ internal class _ParseEncoder: JSONEncoder, Encoder { var uniqueFiles = Set() var newObjects = [Encodable]() var collectChildren = false + var batching = false var objectsSavedBeforeThisOne: [String: PointerType]? var filesSavedBeforeThisOne: [UUID: ParseFile]? /// The encoder's storage. @@ -248,23 +256,26 @@ internal class _ParseEncoder: JSONEncoder, Encoder { @available(*, unavailable) override func encode(_ value: T) throws -> Data { - throw ParseError(code: .unknownError, message: "This method should not be used. Either use the JSONEncoder or if you are encoding a ParseObject use \"encodeObject\"") + throw ParseError(code: .unknownError, + message: "This method should not be used. Either use the JSONEncoder or if you are encoding a ParseObject use \"encodeObject\"") } func encodeObject(_ value: Encodable, + batching: Bool = false, collectChildren: Bool, uniquePointer: PointerType?, objectsSavedBeforeThisOne: [String: PointerType]?, filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) { let encoder = _ParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) - encoder.collectChildren = collectChildren encoder.outputFormatting = outputFormatting encoder.dateEncodingStrategy = dateEncodingStrategy encoder.dataEncodingStrategy = dataEncodingStrategy encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy encoder.keyEncodingStrategy = keyEncodingStrategy encoder.userInfo = userInfo + encoder.collectChildren = collectChildren + encoder.batching = batching encoder.objectsSavedBeforeThisOne = objectsSavedBeforeThisOne encoder.filesSavedBeforeThisOne = filesSavedBeforeThisOne encoder.uniquePointer = uniquePointer @@ -342,7 +353,8 @@ internal class _ParseEncoder: JSONEncoder, Encoder { } valueToEncode = pointer } else if let object = value as? Objectable { - if let pointer = try? PointerType(object) { + if !batching || (batching && codingPath.last?.stringValue == "body"), + let pointer = try? PointerType(object) { if let uniquePointer = self.uniquePointer, uniquePointer.hasSameObjectId(as: pointer) { throw ParseError(code: .unknownError, diff --git a/Sources/ParseSwift/Documentation.docc/ParseSwift.md b/Sources/ParseSwift/Documentation.docc/ParseSwift.md index d8b904f4b..58a52a331 100644 --- a/Sources/ParseSwift/Documentation.docc/ParseSwift.md +++ b/Sources/ParseSwift/Documentation.docc/ParseSwift.md @@ -12,6 +12,7 @@ To learn how to use or experiment with ParseSwift, you can run and edit the [Par ### Configure SDK - ``ParseSwift/initialize(configuration:)`` +- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:requiringCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:primitiveStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)`` - ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)`` - ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:migratingFromObjcSDK:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)`` - ``ParseSwift/configuration`` diff --git a/Sources/ParseSwift/Objects/ParseInstallation+async.swift b/Sources/ParseSwift/Objects/ParseInstallation+async.swift index 7cc5b2ff3..40e673c21 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation+async.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation+async.swift @@ -36,16 +36,16 @@ public extension ParseInstallation { /** Saves the `ParseInstallation` *asynchronously*. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns saved `ParseInstallation`. - throws: An error of type `ParseError`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -180,7 +180,7 @@ public extension Sequence where Element: ParseInstallation { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns an array of Result enums with the object if a save was successful or a @@ -190,10 +190,10 @@ public extension Sequence where Element: ParseInstallation { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -424,6 +424,7 @@ internal extension Sequence where Element: ParseInstallation { let saved = try await API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) diff --git a/Sources/ParseSwift/Objects/ParseInstallation+combine.swift b/Sources/ParseSwift/Objects/ParseInstallation+combine.swift index 4345b2330..981ab5dd3 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation+combine.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation+combine.swift @@ -38,15 +38,15 @@ public extension ParseInstallation { Saves the `ParseInstallation` *asynchronously* and publishes when complete. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -176,7 +176,7 @@ public extension Sequence where Element: ParseInstallation { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces an an array of Result enums with the object if a save was @@ -185,10 +185,10 @@ public extension Sequence where Element: ParseInstallation { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using diff --git a/Sources/ParseSwift/Objects/ParseInstallation.swift b/Sources/ParseSwift/Objects/ParseInstallation.swift index bc4c8e415..694c890cf 100644 --- a/Sources/ParseSwift/Objects/ParseInstallation.swift +++ b/Sources/ParseSwift/Objects/ParseInstallation.swift @@ -172,7 +172,7 @@ extension ParseInstallation { } func endpoint(_ method: API.Method) -> API.Endpoint { - if !Parse.configuration.isAllowingCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { return endpoint } else { return .installations @@ -615,16 +615,16 @@ extension ParseInstallation { Saves the `ParseInstallation` *synchronously* and throws an error if there is an issue. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - returns: Returns saved `ParseInstallation`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using @@ -667,17 +667,17 @@ extension ParseInstallation { Saves the `ParseInstallation` *asynchronously* and executes the given callback block. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: The block to execute. It should have the following argument signature: `(Result)`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using @@ -891,7 +891,7 @@ extension ParseInstallation { } func saveCommand(ignoringCustomObjectIdConfig: Bool = false) throws -> API.Command { - if Parse.configuration.isAllowingCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig { + if Parse.configuration.isRequiringCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") } if isSaved { @@ -1064,7 +1064,7 @@ public extension Sequence where Element: ParseInstallation { is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`. Defaults to 50. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that @@ -1076,10 +1076,10 @@ public extension Sequence where Element: ParseInstallation { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1150,6 +1150,7 @@ public extension Sequence where Element: ParseInstallation { let currentBatch = try API.Command .batch(commands: $0, transaction: transaction) .execute(options: options, + batching: true, childObjects: childObjects, childFiles: childFiles) returnBatch.append(contentsOf: currentBatch) @@ -1166,7 +1167,7 @@ public extension Sequence where Element: ParseInstallation { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. @@ -1176,10 +1177,10 @@ public extension Sequence where Element: ParseInstallation { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1488,6 +1489,7 @@ public extension Sequence where Element: ParseInstallation { API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) { results in diff --git a/Sources/ParseSwift/Objects/ParseObject+async.swift b/Sources/ParseSwift/Objects/ParseObject+async.swift index bc43c7be0..de7f30c4b 100644 --- a/Sources/ParseSwift/Objects/ParseObject+async.swift +++ b/Sources/ParseSwift/Objects/ParseObject+async.swift @@ -35,7 +35,7 @@ public extension ParseObject { /** Saves the `ParseObject` *asynchronously*. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns the saved `ParseObject`. @@ -135,7 +135,7 @@ public extension Sequence where Element: ParseObject { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns an array of Result enums with the object if a save was successful or a @@ -144,10 +144,10 @@ public extension Sequence where Element: ParseObject { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -452,6 +452,7 @@ internal extension Sequence where Element: ParseObject { let saved = try await API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) diff --git a/Sources/ParseSwift/Objects/ParseObject+combine.swift b/Sources/ParseSwift/Objects/ParseObject+combine.swift index cb41326dc..337ae6694 100644 --- a/Sources/ParseSwift/Objects/ParseObject+combine.swift +++ b/Sources/ParseSwift/Objects/ParseObject+combine.swift @@ -36,14 +36,14 @@ public extension ParseObject { /** Saves the `ParseObject` *asynchronously* and publishes when complete. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -141,7 +141,7 @@ public extension Sequence where Element: ParseObject { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces an an array of Result enums with the object if a save was @@ -149,10 +149,10 @@ public extension Sequence where Element: ParseObject { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 58a8b490b..84db2f227 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -378,7 +378,7 @@ transactions for this call. - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns an array of Result enums with the object if a save was successful or a @@ -387,10 +387,10 @@ transactions for this call. - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -460,6 +460,7 @@ transactions for this call. let currentBatch = try API.Command .batch(commands: $0, transaction: transaction) .execute(options: options, + batching: true, childObjects: childObjects, childFiles: childFiles) returnBatch.append(contentsOf: currentBatch) @@ -475,7 +476,7 @@ transactions for this call. - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. @@ -484,10 +485,10 @@ transactions for this call. - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -790,6 +791,7 @@ transactions for this call. API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) { results in @@ -1131,16 +1133,16 @@ extension ParseObject { /** Saves the `ParseObject` *synchronously* and throws an error if there is an issue. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - returns: Returns saved `ParseObject`. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1181,16 +1183,16 @@ extension ParseObject { Saves the `ParseObject` *asynchronously* and executes the given callback block. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: The block to execute. It should have the following argument signature: `(Result)`. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using diff --git a/Sources/ParseSwift/Objects/ParseUser+async.swift b/Sources/ParseSwift/Objects/ParseUser+async.swift index 9f442d984..c1fe81df1 100644 --- a/Sources/ParseSwift/Objects/ParseUser+async.swift +++ b/Sources/ParseSwift/Objects/ParseUser+async.swift @@ -228,16 +228,16 @@ public extension ParseUser { /** Saves the `ParseUser` *asynchronously*. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns the saved `ParseUser`. - throws: An error of type `ParseError`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -353,7 +353,7 @@ public extension Sequence where Element: ParseUser { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: Returns an array of Result enums with the object if a save was successful or a @@ -363,10 +363,10 @@ public extension Sequence where Element: ParseUser { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -599,6 +599,7 @@ internal extension Sequence where Element: ParseUser { let saved = try await API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) diff --git a/Sources/ParseSwift/Objects/ParseUser+combine.swift b/Sources/ParseSwift/Objects/ParseUser+combine.swift index 2c40c32ed..0a2297ac5 100644 --- a/Sources/ParseSwift/Objects/ParseUser+combine.swift +++ b/Sources/ParseSwift/Objects/ParseUser+combine.swift @@ -218,15 +218,15 @@ public extension ParseUser { Saves the `ParseUser` *asynchronously* and publishes when complete. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces a single value and then finishes or fails. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -338,7 +338,7 @@ public extension Sequence where Element: ParseUser { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - returns: A publisher that eventually produces an an array of Result enums with the object if a save was @@ -347,10 +347,10 @@ public extension Sequence where Element: ParseUser { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 4eae6c16f..6d6c3e763 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -89,7 +89,7 @@ extension ParseUser { } func endpoint(_ method: API.Method) -> API.Endpoint { - if !Parse.configuration.isAllowingCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { return endpoint } else { return .users @@ -1030,16 +1030,16 @@ extension ParseUser { Saves the `ParseUser` *synchronously* and throws an error if there is an issue. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - throws: An error of type `ParseError`. - returns: Returns saved `ParseUser`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1082,17 +1082,17 @@ extension ParseUser { Saves the `ParseUser` *asynchronously* and executes the given callback block. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. - parameter completion: The block to execute. It should have the following argument signature: `(Result)`. - important: If an object saved has the same objectId as current, it will automatically update the current. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1300,7 +1300,7 @@ extension ParseUser { } func saveCommand(ignoringCustomObjectIdConfig: Bool = false) throws -> API.Command { - if Parse.configuration.isAllowingCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig { + if Parse.configuration.isRequiringCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig { throw ParseError(code: .missingObjectId, message: "objectId must not be nil") } if isSaved { @@ -1497,7 +1497,7 @@ public extension Sequence where Element: ParseUser { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. @@ -1507,10 +1507,10 @@ public extension Sequence where Element: ParseUser { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1580,6 +1580,7 @@ public extension Sequence where Element: ParseUser { let currentBatch = try API.Command .batch(commands: $0, transaction: transaction) .execute(options: options, + batching: true, childObjects: childObjects, childFiles: childFiles) returnBatch.append(contentsOf: currentBatch) @@ -1596,7 +1597,7 @@ public extension Sequence where Element: ParseUser { - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that prevents the transaction from completing, then none of the objects are committed to the Parse Server database. - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId` - when `ParseConfiguration.isAllowingCustomObjectIds = true` to allow for mixed + when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed `objectId` environments. Defaults to false. - parameter options: A set of header options sent to the server. Defaults to an empty set. - parameter callbackQueue: The queue to return to after completion. Default value of .main. @@ -1606,10 +1607,10 @@ public extension Sequence where Element: ParseUser { - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else the transactions can fail. - - warning: If you are using `ParseConfiguration.isAllowingCustomObjectIds = true` + - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true` and plan to generate all of your `objectId`'s on the client-side then you should leave `ignoringCustomObjectIdConfig = false`. Setting - `ParseConfiguration.isAllowingCustomObjectIds = true` and + `ParseConfiguration.isRequiringCustomObjectIds = true` and `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s and the server will generate an `objectId` only when the client does not provide one. This can increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using @@ -1915,6 +1916,7 @@ public extension Sequence where Element: ParseUser { API.Command .batch(commands: batch, transaction: transaction) .executeAsync(options: options, + batching: true, callbackQueue: callbackQueue, childObjects: childObjects, childFiles: childFiles) { results in diff --git a/Sources/ParseSwift/Parse.swift b/Sources/ParseSwift/Parse.swift index 65619ab78..cdf961312 100644 --- a/Sources/ParseSwift/Parse.swift +++ b/Sources/ParseSwift/Parse.swift @@ -17,11 +17,11 @@ internal func initialize(applicationId: String, masterKey: String? = nil, serverURL: URL, liveQueryServerURL: URL? = nil, - allowingCustomObjectIds: Bool = false, + requiringCustomObjectIds: Bool = false, usingTransactions: Bool = false, usingEqualQueryConstraint: Bool = false, usingPostForQuery: Bool = false, - keyValueStore: ParsePrimitiveStorable? = nil, + primitiveStore: ParsePrimitiveStorable? = nil, requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, cacheMemoryCapacity: Int = 512_000, cacheDiskCapacity: Int = 10_000_000, @@ -39,11 +39,11 @@ internal func initialize(applicationId: String, masterKey: masterKey, serverURL: serverURL, liveQueryServerURL: liveQueryServerURL, - allowingCustomObjectIds: allowingCustomObjectIds, + requiringCustomObjectIds: requiringCustomObjectIds, usingTransactions: usingTransactions, usingEqualQueryConstraint: usingEqualQueryConstraint, usingPostForQuery: usingPostForQuery, - keyValueStore: keyValueStore, + primitiveStore: primitiveStore, requestCachePolicy: requestCachePolicy, cacheMemoryCapacity: cacheMemoryCapacity, cacheDiskCapacity: cacheDiskCapacity, @@ -183,13 +183,13 @@ public func initialize(configuration: ParseConfiguration) { specified when using the SDK on a server. - parameter serverURL: The server URL to connect to Parse Server. - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. - - parameter allowingCustomObjectIds: Allows objectIds to be created on the client. + - parameter requiringCustomObjectIds: Requires `objectId`'s to be created on the client side for each object. Must be enabled on the server to work. - parameter usingTransactions: Use transactions when saving/updating multiple objects. - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls. Defaults to **false**. - - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore` + - parameter primitiveStore: A key/value store that conforms to the `ParseKeyValueStore` protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this this is the only store available since there is no Keychain. Linux, Android, and Windows users should replace this store with an encrypted one. @@ -226,11 +226,11 @@ public func initialize( masterKey: String? = nil, serverURL: URL, liveQueryServerURL: URL? = nil, - allowingCustomObjectIds: Bool = false, + requiringCustomObjectIds: Bool = false, usingTransactions: Bool = false, usingEqualQueryConstraint: Bool = false, usingPostForQuery: Bool = false, - keyValueStore: ParsePrimitiveStorable? = nil, + primitiveStore: ParsePrimitiveStorable? = nil, requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, cacheMemoryCapacity: Int = 512_000, cacheDiskCapacity: Int = 10_000_000, @@ -248,11 +248,11 @@ public func initialize( masterKey: masterKey, serverURL: serverURL, liveQueryServerURL: liveQueryServerURL, - allowingCustomObjectIds: allowingCustomObjectIds, + requiringCustomObjectIds: requiringCustomObjectIds, usingTransactions: usingTransactions, usingEqualQueryConstraint: usingEqualQueryConstraint, usingPostForQuery: usingPostForQuery, - keyValueStore: keyValueStore, + primitiveStore: primitiveStore, requestCachePolicy: requestCachePolicy, cacheMemoryCapacity: cacheMemoryCapacity, cacheDiskCapacity: cacheDiskCapacity, @@ -274,7 +274,98 @@ public func initialize( specified when using the SDK on a server. - parameter serverURL: The server URL to connect to Parse Server. - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. - - parameter allowingCustomObjectIds: Allows objectIds to be created on the client. + - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client + side for each object. Must be enabled on the server to work. + - parameter usingTransactions: Use transactions when saving/updating multiple objects. + - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. + - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls. + Defaults to **false**. + - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore` + protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this + this is the only store available since there is no Keychain. Linux, Android, and Windows users should + replace this store with an encrypted one. + - parameter requestCachePolicy: The default caching policy for all http requests that determines + when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data) + for more info. + - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB. + - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB. + - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain) + for more info. Defaults to **false**. + - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time. + Defaults to **false**. + - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's + [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders) + for more info. + - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server. + Defaults to 5. + - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s. + Allows for direct uploads to other file storage providers. + - parameter authentication: A callback block that will be used to receive/accept/decline network challenges. + Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges. + It should have the following argument signature: `(challenge: URLAuthenticationChallenge, + completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`. + See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details. + - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client. + - note: Setting `usingPostForQuery` to **true** will require all queries to access the server instead of following the `requestCachePolicy`. + - warning: `usingTransactions` is experimental. + - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in + situtations when apps do not have credentials to setup a Keychain. + */ +@available(*, deprecated, message: "Change: allowingCustomObjectIds->requiringCustomObjectIds and keyValueStore->primitiveStore") +public func initialize( + applicationId: String, + clientKey: String? = nil, + masterKey: String? = nil, + serverURL: URL, + liveQueryServerURL: URL? = nil, + allowingCustomObjectIds: Bool, + usingTransactions: Bool = false, + usingEqualQueryConstraint: Bool = false, + usingPostForQuery: Bool = false, + keyValueStore: ParsePrimitiveStorable? = nil, + requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, + cacheMemoryCapacity: Int = 512_000, + cacheDiskCapacity: Int = 10_000_000, + usingDataProtectionKeychain: Bool = false, + deletingKeychainIfNeeded: Bool = false, + httpAdditionalHeaders: [AnyHashable: Any]? = nil, + maxConnectionAttempts: Int = 5, + parseFileTransfer: ParseFileTransferable? = nil, + authentication: ((URLAuthenticationChallenge, + (URLSession.AuthChallengeDisposition, + URLCredential?) -> Void) -> Void)? = nil +) { + initialize(applicationId: applicationId, + clientKey: clientKey, + masterKey: masterKey, + serverURL: serverURL, + liveQueryServerURL: liveQueryServerURL, + requiringCustomObjectIds: allowingCustomObjectIds, + usingTransactions: usingTransactions, + usingEqualQueryConstraint: usingEqualQueryConstraint, + usingPostForQuery: usingPostForQuery, + primitiveStore: keyValueStore, + requestCachePolicy: requestCachePolicy, + cacheMemoryCapacity: cacheMemoryCapacity, + cacheDiskCapacity: cacheDiskCapacity, + usingDataProtectionKeychain: usingDataProtectionKeychain, + deletingKeychainIfNeeded: deletingKeychainIfNeeded, + httpAdditionalHeaders: httpAdditionalHeaders, + maxConnectionAttempts: maxConnectionAttempts, + parseFileTransfer: parseFileTransfer, + authentication: authentication) +} + +/** + Configure the Parse Swift client. This should only be used when starting your app. Typically in the + `application(... didFinishLaunchingWithOptions launchOptions...)`. + - parameter applicationId: The application id for your Parse application. + - parameter clientKey: The client key for your Parse application. + - parameter masterKey: The master key for your Parse application. This key should only be + specified when using the SDK on a server. + - parameter serverURL: The server URL to connect to Parse Server. + - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. + - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client side for each object. Must be enabled on the server to work. - parameter usingTransactions: Use transactions when saving/updating multiple objects. - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. @@ -328,7 +419,7 @@ public func initialize( requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, cacheMemoryCapacity: Int = 512_000, cacheDiskCapacity: Int = 10_000_000, - migratingFromObjcSDK: Bool = false, + migratingFromObjcSDK: Bool, usingDataProtectionKeychain: Bool = false, deletingKeychainIfNeeded: Bool = false, httpAdditionalHeaders: [AnyHashable: Any]? = nil, @@ -343,11 +434,11 @@ public func initialize( masterKey: masterKey, serverURL: serverURL, liveQueryServerURL: liveQueryServerURL, - allowingCustomObjectIds: allowingCustomObjectIds, + requiringCustomObjectIds: allowingCustomObjectIds, usingTransactions: usingTransactions, usingEqualQueryConstraint: usingEqualQueryConstraint, usingPostForQuery: usingPostForQuery, - keyValueStore: keyValueStore, + primitiveStore: keyValueStore, requestCachePolicy: requestCachePolicy, cacheMemoryCapacity: cacheMemoryCapacity, cacheDiskCapacity: cacheDiskCapacity, diff --git a/Sources/ParseSwift/ParseConstants.swift b/Sources/ParseSwift/ParseConstants.swift index 0335f55a5..8f54a5856 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 = "4.14.1" + static let version = "4.14.2" static let fileManagementDirectory = "parse/" static let fileManagementPrivateDocumentsDirectory = "Private Documents/" static let fileManagementLibraryDirectory = "Library/" diff --git a/Sources/ParseSwift/Protocols/Objectable.swift b/Sources/ParseSwift/Protocols/Objectable.swift index 62643b97e..a3839f4d3 100644 --- a/Sources/ParseSwift/Protocols/Objectable.swift +++ b/Sources/ParseSwift/Protocols/Objectable.swift @@ -74,7 +74,7 @@ extension Objectable { /// Specifies if a `ParseObject` has been saved. public var isSaved: Bool { - if !Parse.configuration.isAllowingCustomObjectIds { + if !Parse.configuration.isRequiringCustomObjectIds { return objectId != nil } else { return objectId != nil && createdAt != nil @@ -86,7 +86,7 @@ extension Objectable { } func endpoint(_ method: API.Method) -> API.Endpoint { - if !Parse.configuration.isAllowingCustomObjectIds || method != .POST { + if !Parse.configuration.isRequiringCustomObjectIds || method != .POST { return endpoint } else { return .objects(className: className) diff --git a/Sources/ParseSwift/Types/ParseConfiguration.swift b/Sources/ParseSwift/Types/ParseConfiguration.swift index 1283fd87f..31c67d433 100644 --- a/Sources/ParseSwift/Types/ParseConfiguration.swift +++ b/Sources/ParseSwift/Types/ParseConfiguration.swift @@ -40,8 +40,14 @@ public struct ParseConfiguration { /// The live query server URL to connect to Parse Server. public internal(set) var liveQuerysServerURL: URL? - /// Allows objectIds to be created on the client. - public internal(set) var isAllowingCustomObjectIds = false + /// Requires `objectId`'s to be created on the client. + public internal(set) var isRequiringCustomObjectIds = false + + /// Requires `objectId`'s to be created on the client. + @available(*, deprecated, renamed: "isRequiringCustomObjectIds") + public var isAllowingCustomObjectIds: Bool { + isRequiringCustomObjectIds + } /// Use transactions when saving/updating multiple objects. /// - warning: This is experimental. @@ -117,13 +123,13 @@ public struct ParseConfiguration { specified when using the SDK on a server. - parameter serverURL: The server URL to connect to Parse Server. - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. - - parameter allowingCustomObjectIds: Allows objectIds to be created on the client. + - parameter requiringCustomObjectIds: Requires `objectId`'s to be created on the client side for each object. Must be enabled on the server to work. - parameter usingTransactions: Use transactions when saving/updating multiple objects. - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls. Defaults to **false**. - - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore` + - parameter primitiveStore: A key/value store that conforms to the `ParsePrimitiveStorable` protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this this is the only store available since there is no Keychain. Linux, Android, and Windows users should replace this store with an encrypted one. @@ -162,11 +168,11 @@ public struct ParseConfiguration { webhookKey: String? = nil, serverURL: URL, liveQueryServerURL: URL? = nil, - allowingCustomObjectIds: Bool = false, + requiringCustomObjectIds: Bool = false, usingTransactions: Bool = false, usingEqualQueryConstraint: Bool = false, usingPostForQuery: Bool = false, - keyValueStore: ParsePrimitiveStorable? = nil, + primitiveStore: ParsePrimitiveStorable? = nil, requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, cacheMemoryCapacity: Int = 512_000, cacheDiskCapacity: Int = 10_000_000, @@ -183,7 +189,7 @@ public struct ParseConfiguration { self.masterKey = masterKey self.serverURL = serverURL self.liveQuerysServerURL = liveQueryServerURL - self.isAllowingCustomObjectIds = allowingCustomObjectIds + self.isRequiringCustomObjectIds = requiringCustomObjectIds self.isUsingTransactions = usingTransactions self.isUsingEqualQueryConstraint = usingEqualQueryConstraint self.isUsingPostForQuery = usingPostForQuery @@ -199,7 +205,99 @@ public struct ParseConfiguration { self.httpAdditionalHeaders = httpAdditionalHeaders self.maxConnectionAttempts = maxConnectionAttempts self.parseFileTransfer = parseFileTransfer ?? ParseFileDefaultTransfer() - ParseStorage.shared.use(keyValueStore ?? InMemoryKeyValueStore()) + ParseStorage.shared.use(primitiveStore ?? InMemoryKeyValueStore()) + } + + /** + Create a Parse Swift configuration. + - parameter applicationId: The application id for your Parse application. + - parameter clientKey: The client key for your Parse application. + - parameter masterKey: The master key for your Parse application. This key should only be + specified when using the SDK on a server. + - parameter serverURL: The server URL to connect to Parse Server. + - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. + - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client + side for each object. Must be enabled on the server to work. + - parameter usingTransactions: Use transactions when saving/updating multiple objects. + - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. + - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls. + Defaults to **false**. + - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore` + protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this + this is the only store available since there is no Keychain. Linux, Android, and Windows users should + replace this store with an encrypted one. + - parameter requestCachePolicy: The default caching policy for all http requests that determines + when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data) + for more info. + - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB. + - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB. + - parameter migratingFromObjcSDK: If your app previously used the iOS Objective-C SDK, setting this value + to **true** will attempt to migrate relevant data stored in the Keychain to ParseSwift. Defaults to **false**. + - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain) + for more info. Defaults to **false**. + - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time. + Defaults to **false**. + - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's + [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders) + for more info. + - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server. + Defaults to 5. + - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s. + Allows for direct uploads to other file storage providers. + - parameter authentication: A callback block that will be used to receive/accept/decline network challenges. + Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges. + It should have the following argument signature: `(challenge: URLAuthenticationChallenge, + completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`. + See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details. + - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client. + - note: Setting `usingPostForQuery` to **true** will require all queries to access the server instead of following the `requestCachePolicy`. + - warning: `usingTransactions` is experimental. + - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in + situtations when apps do not have credentials to setup a Keychain. + */ + @available(*, deprecated, message: "Change: allowingCustomObjectIds->requiringCustomObjectIds and keyValueStore->primitiveStore") + public init(applicationId: String, + clientKey: String? = nil, + masterKey: String? = nil, + webhookKey: String? = nil, + serverURL: URL, + liveQueryServerURL: URL? = nil, + allowingCustomObjectIds: Bool, + usingTransactions: Bool = false, + usingEqualQueryConstraint: Bool = false, + usingPostForQuery: Bool = false, + keyValueStore: ParseKeyValueStore? = nil, + requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, + cacheMemoryCapacity: Int = 512_000, + cacheDiskCapacity: Int = 10_000_000, + usingDataProtectionKeychain: Bool = false, + deletingKeychainIfNeeded: Bool = false, + httpAdditionalHeaders: [AnyHashable: Any]? = nil, + maxConnectionAttempts: Int = 5, + parseFileTransfer: ParseFileTransferable? = nil, + authentication: ((URLAuthenticationChallenge, + (URLSession.AuthChallengeDisposition, + URLCredential?) -> Void) -> Void)? = nil) { + self.init(applicationId: applicationId, + clientKey: clientKey, + masterKey: masterKey, + webhookKey: webhookKey, + serverURL: serverURL, + liveQueryServerURL: liveQueryServerURL, + requiringCustomObjectIds: allowingCustomObjectIds, + usingTransactions: usingTransactions, + usingEqualQueryConstraint: usingEqualQueryConstraint, + usingPostForQuery: usingPostForQuery, + primitiveStore: keyValueStore, + requestCachePolicy: requestCachePolicy, + cacheMemoryCapacity: cacheMemoryCapacity, + cacheDiskCapacity: cacheDiskCapacity, + usingDataProtectionKeychain: usingDataProtectionKeychain, + deletingKeychainIfNeeded: deletingKeychainIfNeeded, + httpAdditionalHeaders: httpAdditionalHeaders, + maxConnectionAttempts: maxConnectionAttempts, + parseFileTransfer: parseFileTransfer ?? ParseFileDefaultTransfer(), + authentication: authentication) } /** @@ -210,7 +308,7 @@ public struct ParseConfiguration { specified when using the SDK on a server. - parameter serverURL: The server URL to connect to Parse Server. - parameter liveQueryServerURL: The live query server URL to connect to Parse Server. - - parameter allowingCustomObjectIds: Allows objectIds to be created on the client. + - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client side for each object. Must be enabled on the server to work. - parameter usingTransactions: Use transactions when saving/updating multiple objects. - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying. @@ -264,7 +362,7 @@ public struct ParseConfiguration { requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy, cacheMemoryCapacity: Int = 512_000, cacheDiskCapacity: Int = 10_000_000, - migratingFromObjcSDK: Bool = false, + migratingFromObjcSDK: Bool, usingDataProtectionKeychain: Bool = false, deletingKeychainIfNeeded: Bool = false, httpAdditionalHeaders: [AnyHashable: Any]? = nil, @@ -279,11 +377,11 @@ public struct ParseConfiguration { webhookKey: webhookKey, serverURL: serverURL, liveQueryServerURL: liveQueryServerURL, - allowingCustomObjectIds: allowingCustomObjectIds, + requiringCustomObjectIds: allowingCustomObjectIds, usingTransactions: usingTransactions, usingEqualQueryConstraint: usingEqualQueryConstraint, usingPostForQuery: usingPostForQuery, - keyValueStore: keyValueStore, + primitiveStore: keyValueStore, requestCachePolicy: requestCachePolicy, cacheMemoryCapacity: cacheMemoryCapacity, cacheDiskCapacity: cacheDiskCapacity, diff --git a/Sources/ParseSwift/Types/Pointer.swift b/Sources/ParseSwift/Types/Pointer.swift index 14fdd228a..1a4d8acfc 100644 --- a/Sources/ParseSwift/Types/Pointer.swift +++ b/Sources/ParseSwift/Types/Pointer.swift @@ -33,14 +33,14 @@ public struct Pointer: ParsePointer, ParseTypeable, Fetchable, H internal let __type: String = "Pointer" // swiftlint:disable:this identifier_name /** - The id of the object. + The class name of the object. */ - public var objectId: String + public var className: String /** - The class name of the object. + The id of the object. */ - public var className: String + public var objectId: String /** Create a Pointer type. @@ -148,10 +148,9 @@ public extension Pointer { } internal struct PointerType: ParsePointer, Codable { - var __type: String = "Pointer" // swiftlint:disable:this identifier_name - var objectId: String var className: String + var objectId: String init(_ target: Objectable) throws { self.objectId = try getObjectId(target: target) diff --git a/Tests/ParseSwiftTests/InitializeSDKTests.swift b/Tests/ParseSwiftTests/InitializeSDKTests.swift index c1a347adc..16ea70e83 100644 --- a/Tests/ParseSwiftTests/InitializeSDKTests.swift +++ b/Tests/ParseSwiftTests/InitializeSDKTests.swift @@ -226,7 +226,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let currentInstallation = Installation.current else { @@ -299,7 +299,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let installation = Installation.current else { XCTFail("Should have installation") @@ -335,7 +335,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let installation = Installation.current else { XCTFail("Should have installation") @@ -371,7 +371,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let installation = Installation.current else { XCTFail("Should have installation") @@ -408,7 +408,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let installation = Installation.current else { XCTFail("Should have installation") @@ -444,7 +444,7 @@ class InitializeSDKTests: XCTestCase { clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - keyValueStore: memory, + primitiveStore: memory, testing: true) guard let installation = Installation.current else { XCTFail("Should have installation") diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index c51b382ef..1da900c4e 100644 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -73,27 +73,60 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le try ParseStorage.shared.deleteAll() } + func testEncodeEmbeddedSavedObjectWithBatching() throws { + var score = GameScore(points: 10) + score.objectId = "yolo" + score.createdAt = Date() + score.updatedAt = Date() + var game = Game2() + game.createdAt = Date() + game.updatedAt = Date() + game.objectId = "brave" + score.other = game + let command = try score.saveCommand() + let batch = API.Command + .batch(commands: [command], transaction: false) + // swiftlint:disable:next line_length + let expected = "{\"body\":{\"requests\":[{\"body\":{\"other\":{\"__type\":\"Pointer\",\"className\":\"Game2\",\"objectId\":\"brave\"},\"points\":10},\"method\":\"PUT\",\"path\":\"\\/1\\/classes\\/GameScore\\/yolo\"}],\"transaction\":false},\"method\":\"POST\",\"path\":\"\\/batch\"}" + let encoded = try ParseCoding.parseEncoder().encode(batch, + batching: true) + let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) + XCTAssertEqual(decoded, expected) + } + + func testEncodeMutltipleEmbeddedSavedObjectWithBatching() throws { + var score = GameScore(points: 10) + score.objectId = "yolo" + score.createdAt = Date() + score.updatedAt = Date() + var game = Game2() + game.createdAt = Date() + game.updatedAt = Date() + game.objectId = "brave" + score.other = game + let command = try score.saveCommand() + let batch = API.Command + .batch(commands: [command, command], transaction: false) + // swiftlint:disable:next line_length + let expected = "{\"body\":{\"requests\":[{\"body\":{\"other\":{\"__type\":\"Pointer\",\"className\":\"Game2\",\"objectId\":\"brave\"},\"points\":10},\"method\":\"PUT\",\"path\":\"\\/1\\/classes\\/GameScore\\/yolo\"},{\"body\":{\"other\":{\"__type\":\"Pointer\",\"className\":\"Game2\",\"objectId\":\"brave\"},\"points\":10},\"method\":\"PUT\",\"path\":\"\\/1\\/classes\\/GameScore\\/yolo\"}],\"transaction\":false},\"method\":\"POST\",\"path\":\"\\/batch\"}" + let encoded = try ParseCoding.parseEncoder().encode(batch, + batching: true) + let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) + XCTAssertEqual(decoded, expected) + } + func testSaveAllCommand() throws { let score = GameScore(points: 10) let score2 = GameScore(points: 20) - var scoreOnServer = score - scoreOnServer.objectId = "yarr" - scoreOnServer.createdAt = Date() - scoreOnServer.ACL = nil - - var scoreOnServer2 = score2 - scoreOnServer2.objectId = "yolo" - scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date()) - scoreOnServer2.ACL = nil - let objects = [score, score2] let commands = try objects.map { try $0.saveCommand() } let body = BatchCommand(requests: commands, transaction: false) // swiftlint:disable:next line_length let expected = "{\"requests\":[{\"body\":{\"points\":10},\"method\":\"POST\",\"path\":\"\\/classes\\/GameScore\"},{\"body\":{\"points\":20},\"method\":\"POST\",\"path\":\"\\/classes\\/GameScore\"}],\"transaction\":false}" let encoded = try ParseCoding.parseEncoder() - .encode(body, collectChildren: false, + .encode(body, + collectChildren: false, objectsSavedBeforeThisOne: nil, filesSavedBeforeThisOne: nil).encoded let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) @@ -523,6 +556,9 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le score.objectId = "yarr" score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date()) score.ACL = nil + var game = Game2() + game.objectId = "brave" + score.other = game var score2 = GameScore(points: 20) score2.objectId = "yolo" @@ -1086,6 +1122,21 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le callbackQueue: .main) } + func testSaveAlreadySavedEncode() throws { + var score = GameScore(points: 10) + var game = Game2() + game.objectId = "brave" + score.other = game + // swiftlint:disable:next line_length + let expected = "{\"other\":{\"__type\":\"Pointer\",\"className\":\"Game2\",\"objectId\":\"brave\"},\"points\":10}" + let encoded = try ParseCoding.parseEncoder() + .encode(score, collectChildren: false, + objectsSavedBeforeThisOne: nil, + filesSavedBeforeThisOne: nil).encoded + let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8)) + XCTAssertEqual(decoded, expected) + } + func testSaveAllAsyncPointerArray() { var score = GameScore(points: 10) score.otherArray = [Game2()] diff --git a/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift b/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift index 86af471bb..6beda702b 100644 --- a/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift @@ -127,7 +127,7 @@ class ParseObjectCustomObjectIdTests: XCTestCase { // swiftlint:disable:this typ clientKey: "clientKey", masterKey: "masterKey", serverURL: url, - allowingCustomObjectIds: true, + requiringCustomObjectIds: true, testing: true) } diff --git a/Tests/ParseSwiftTests/ParseRoleTests.swift b/Tests/ParseSwiftTests/ParseRoleTests.swift index 7d5235209..8e31daee5 100644 --- a/Tests/ParseSwiftTests/ParseRoleTests.swift +++ b/Tests/ParseSwiftTests/ParseRoleTests.swift @@ -452,7 +452,7 @@ class ParseRoleTests: XCTestCase { acl.publicWrite = false acl.publicRead = true - Parse.configuration.isAllowingCustomObjectIds = true + Parse.configuration.isRequiringCustomObjectIds = true var role = try Role(name: "Administrator", acl: acl) role.createdAt = Date() role.updatedAt = Date() @@ -495,7 +495,7 @@ class ParseRoleTests: XCTestCase { acl.publicWrite = false acl.publicRead = true - Parse.configuration.isAllowingCustomObjectIds = true + Parse.configuration.isRequiringCustomObjectIds = true var role = try Role(name: "Administrator", acl: acl) role.createdAt = Date() role.updatedAt = Date() @@ -575,7 +575,7 @@ class ParseRoleTests: XCTestCase { acl.publicWrite = false acl.publicRead = true - Parse.configuration.isAllowingCustomObjectIds = true + Parse.configuration.isRequiringCustomObjectIds = true var role = try Role(name: "Administrator", acl: acl) role.createdAt = Date() role.updatedAt = Date() @@ -609,7 +609,9 @@ class ParseRoleTests: XCTestCase { acl.publicWrite = false acl.publicRead = true - Parse.configuration.isAllowingCustomObjectIds = true + Parse.configuration.isRequiringCustomObjectIds = true + XCTAssertEqual(Parse.configuration.isAllowingCustomObjectIds, + Parse.configuration.isRequiringCustomObjectIds) var role = try Role(name: "Administrator", acl: acl) role.createdAt = Date() role.updatedAt = Date()