Skip to content

Commit 3ed5c85

Browse files
committed
Allow mixed custom objectId environment
1 parent f584819 commit 3ed5c85

9 files changed

+932
-54
lines changed

Sources/ParseSwift/API/API+Commands.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,9 @@ internal extension API.Command {
344344
}
345345

346346
// MARK: Saving ParseObjects
347-
static func save<T>(_ object: T) throws -> API.Command<T, T> where T: ParseObject {
348-
if ParseSwift.configuration.allowCustomObjectId && object.objectId == nil {
347+
static func save<T>(_ object: T,
348+
isIgnoreCustomObjectIdConfig: Bool) throws -> API.Command<T, T> where T: ParseObject {
349+
if ParseSwift.configuration.allowCustomObjectId && object.objectId == nil && !isIgnoreCustomObjectIdConfig {
349350
throw ParseError(code: .missingObjectId, message: "objectId must not be nil")
350351
}
351352
if object.isSaved {

Sources/ParseSwift/Objects/ParseInstallation+combine.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ public extension ParseInstallation {
4242
- returns: A publisher that eventually produces a single value and then finishes or fails.
4343
- important: If an object saved has the same objectId as current, it will automatically update the current.
4444
*/
45-
func savePublisher(options: API.Options = []) -> Future<Self, ParseError> {
45+
func savePublisher(isIgnoreCustomObjectIdConfig: Bool = false,
46+
options: API.Options = []) -> Future<Self, ParseError> {
4647
Future { promise in
47-
self.save(options: options,
48+
self.save(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig,
49+
options: options,
4850
completion: promise)
4951
}
5052
}
@@ -102,10 +104,12 @@ public extension Sequence where Element: ParseInstallation {
102104
*/
103105
func saveAllPublisher(batchLimit limit: Int? = nil,
104106
transaction: Bool = false,
107+
isIgnoreCustomObjectIdConfig: Bool = false,
105108
options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {
106109
Future { promise in
107110
self.saveAll(batchLimit: limit,
108111
transaction: transaction,
112+
isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig,
109113
options: options,
110114
completion: promise)
111115
}

Sources/ParseSwift/Objects/ParseInstallation.swift

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,32 @@ extension ParseInstallation {
426426
- important: If an object saved has the same objectId as current, it will automatically update the current.
427427
*/
428428
public func save(options: API.Options = []) throws -> Self {
429+
try save(isIgnoreCustomObjectIdConfig: false,
430+
options: options)
431+
}
432+
433+
/**
434+
Saves the `ParseInstallation` *synchronously* and throws an error if there's an issue.
435+
436+
- parameter isIgnoreCustomObjectIdConfig: Ignore checking for `objectId`
437+
when `ParseConfiguration.allowCustomObjectId = true` to allow for mixed
438+
`objectId` environments. Defaults to false.
439+
- parameter options: A set of header options sent to the server. Defaults to an empty set.
440+
- throws: An error of type `ParseError`.
441+
- returns: Returns saved `ParseInstallation`.
442+
- important: If an object saved has the same objectId as current, it will automatically update the current.
443+
- warning: If you are using `ParseConfiguration.allowCustomObjectId = true`
444+
and plan to generate all of your `objectId`'s on the client-side then you should leave
445+
`isIgnoreCustomObjectIdConfig = false`. Setting
446+
`ParseConfiguration.allowCustomObjectId = true` and
447+
`isIgnoreCustomObjectIdConfig = true` means the client will generate `objectId`'s
448+
and the server will generate an `objectId` only when the client does not provide one. This can lead
449+
to collisions of `objectId`'s as the client and server `objectId`'s may be generated using
450+
different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the
451+
client-side checks are disabled. Developers are responsible for handling such cases.
452+
*/
453+
public func save(isIgnoreCustomObjectIdConfig: Bool,
454+
options: API.Options = []) throws -> Self {
429455
var options = options
430456
options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))
431457
var childObjects: [String: PointerType]?
@@ -445,7 +471,7 @@ extension ParseInstallation {
445471
throw error
446472
}
447473

448-
let result: Self = try saveCommand()
474+
let result: Self = try saveCommand(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
449475
.execute(options: options,
450476
callbackQueue: .main,
451477
childObjects: childObjects,
@@ -457,13 +483,26 @@ extension ParseInstallation {
457483
/**
458484
Saves the `ParseInstallation` *asynchronously* and executes the given callback block.
459485

486+
- parameter isIgnoreCustomObjectIdConfig: Ignore checking for `objectId`
487+
when `ParseConfiguration.allowCustomObjectId = true` to allow for mixed
488+
`objectId` environments. Defaults to false.
460489
- parameter options: A set of header options sent to the server. Defaults to an empty set.
461490
- parameter callbackQueue: The queue to return to after completion. Default value of .main.
462491
- parameter completion: The block to execute.
463492
It should have the following argument signature: `(Result<Self, ParseError>)`.
464493
- important: If an object saved has the same objectId as current, it will automatically update the current.
494+
- warning: If you are using `ParseConfiguration.allowCustomObjectId = true`
495+
and plan to generate all of your `objectId`'s on the client-side then you should leave
496+
`isIgnoreCustomObjectIdConfig = false`. Setting
497+
`ParseConfiguration.allowCustomObjectId = true` and
498+
`isIgnoreCustomObjectIdConfig = true` means the client will generate `objectId`'s
499+
and the server will generate an `objectId` only when the client does not provide one. This can lead
500+
to collisions of `objectId`'s as the client and server `objectId`'s may be generated using
501+
different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the
502+
client-side checks are disabled. Developers are responsible for handling such cases.
465503
*/
466504
public func save(
505+
isIgnoreCustomObjectIdConfig: Bool = false,
467506
options: API.Options = [],
468507
callbackQueue: DispatchQueue = .main,
469508
completion: @escaping (Result<Self, ParseError>) -> Void
@@ -473,7 +512,7 @@ extension ParseInstallation {
473512
self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, error) in
474513
guard let parseError = error else {
475514
do {
476-
try self.saveCommand()
515+
try self.saveCommand(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
477516
.executeAsync(options: options,
478517
callbackQueue: callbackQueue,
479518
childObjects: savedChildObjects,
@@ -515,8 +554,8 @@ extension ParseInstallation {
515554
}
516555
}
517556

518-
func saveCommand() throws -> API.Command<Self, Self> {
519-
if ParseSwift.configuration.allowCustomObjectId && objectId == nil {
557+
func saveCommand(isIgnoreCustomObjectIdConfig: Bool = false) throws -> API.Command<Self, Self> {
558+
if ParseSwift.configuration.allowCustomObjectId && objectId == nil && !isIgnoreCustomObjectIdConfig {
520559
throw ParseError(code: .missingObjectId, message: "objectId must not be nil")
521560
}
522561
if isSaved {
@@ -643,6 +682,9 @@ public extension Sequence where Element: ParseInstallation {
643682
- parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.
644683
is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.
645684
Defaults to 50.
685+
- parameter isIgnoreCustomObjectIdConfig: Ignore checking for `objectId`
686+
when `ParseConfiguration.allowCustomObjectId = true` to allow for mixed
687+
`objectId` environments. Defaults to false.
646688
- parameter options: A set of header options sent to the server. Defaults to an empty set.
647689
- parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that
648690
prevents the transaction from completing, then none of the objects are committed to the Parse Server database.
@@ -653,9 +695,19 @@ public extension Sequence where Element: ParseInstallation {
653695
- warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the
654696
objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else
655697
the transactions can fail.
698+
- warning: If you are using `ParseConfiguration.allowCustomObjectId = true`
699+
and plan to generate all of your `objectId`'s on the client-side then you should leave
700+
`isIgnoreCustomObjectIdConfig = false`. Setting
701+
`ParseConfiguration.allowCustomObjectId = true` and
702+
`isIgnoreCustomObjectIdConfig = true` means the client will generate `objectId`'s
703+
and the server will generate an `objectId` only when the client does not provide one. This can lead
704+
to collisions of `objectId`'s as the client and server `objectId`'s may be generated using
705+
different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the
706+
client-side checks are disabled. Developers are responsible for handling such cases.
656707
*/
657708
func saveAll(batchLimit limit: Int? = nil, // swiftlint:disable:this function_body_length
658709
transaction: Bool = false,
710+
isIgnoreCustomObjectIdConfig: Bool = false,
659711
options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {
660712
var options = options
661713
options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))
@@ -703,7 +755,9 @@ public extension Sequence where Element: ParseInstallation {
703755
}
704756

705757
var returnBatch = [(Result<Self.Element, ParseError>)]()
706-
let commands = try map { try $0.saveCommand() }
758+
let commands = try map {
759+
try $0.saveCommand(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
760+
}
707761
let batchLimit: Int!
708762
if transaction {
709763
batchLimit = commands.count
@@ -731,6 +785,9 @@ public extension Sequence where Element: ParseInstallation {
731785
Defaults to 50.
732786
- parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that
733787
prevents the transaction from completing, then none of the objects are committed to the Parse Server database.
788+
- parameter isIgnoreCustomObjectIdConfig: Ignore checking for `objectId`
789+
when `ParseConfiguration.allowCustomObjectId = true` to allow for mixed
790+
`objectId` environments. Defaults to false.
734791
- parameter options: A set of header options sent to the server. Defaults to an empty set.
735792
- parameter callbackQueue: The queue to return to after completion. Default value of .main.
736793
- parameter completion: The block to execute.
@@ -739,10 +796,20 @@ public extension Sequence where Element: ParseInstallation {
739796
- warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the
740797
objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else
741798
the transactions can fail.
799+
- warning: If you are using `ParseConfiguration.allowCustomObjectId = true`
800+
and plan to generate all of your `objectId`'s on the client-side then you should leave
801+
`isIgnoreCustomObjectIdConfig = false`. Setting
802+
`ParseConfiguration.allowCustomObjectId = true` and
803+
`isIgnoreCustomObjectIdConfig = true` means the client will generate `objectId`'s
804+
and the server will generate an `objectId` only when the client does not provide one. This can lead
805+
to collisions of `objectId`'s as the client and server `objectId`'s may be generated using
806+
different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the
807+
client-side checks are disabled. Developers are responsible for handling such cases.
742808
*/
743809
func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity
744810
batchLimit limit: Int? = nil,
745811
transaction: Bool = false,
812+
isIgnoreCustomObjectIdConfig: Bool = false,
746813
options: API.Options = [],
747814
callbackQueue: DispatchQueue = .main,
748815
completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void
@@ -805,7 +872,9 @@ public extension Sequence where Element: ParseInstallation {
805872

806873
do {
807874
var returnBatch = [(Result<Self.Element, ParseError>)]()
808-
let commands = try map { try $0.saveCommand() }
875+
let commands = try map {
876+
try $0.saveCommand(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
877+
}
809878
let batchLimit: Int!
810879
if transaction {
811880
batchLimit = commands.count

Sources/ParseSwift/Objects/ParseObject+combine.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ public extension ParseObject {
3939
- returns: A publisher that eventually produces a single value and then finishes or fails.
4040
- important: If an object saved has the same objectId as current, it will automatically update the current.
4141
*/
42-
func savePublisher(options: API.Options = []) -> Future<Self, ParseError> {
42+
func savePublisher(isIgnoreCustomObjectIdConfig: Bool = false,
43+
options: API.Options = []) -> Future<Self, ParseError> {
4344
Future { promise in
44-
self.save(options: options,
45+
self.save(isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig,
46+
options: options,
4547
completion: promise)
4648
}
4749
}
@@ -89,19 +91,33 @@ public extension Sequence where Element: ParseObject {
8991
Defaults to 50.
9092
- parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that
9193
prevents the transaction from completing, then none of the objects are committed to the Parse Server database.
94+
- parameter isIgnoreCustomObjectIdConfig: Ignore checking for `objectId`
95+
when `ParseConfiguration.allowCustomObjectId = true` to allow for mixed
96+
`objectId` environments. Defaults to false.
9297
- parameter options: A set of header options sent to the server. Defaults to an empty set.
9398
- returns: A publisher that eventually produces a single value and then finishes or fails.
9499
- important: If an object saved has the same objectId as current, it will automatically update the current.
95100
- warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the
96101
objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else
97102
the transactions can fail.
103+
- warning: If you are using `ParseConfiguration.allowCustomObjectId = true`
104+
and plan to generate all of your `objectId`'s on the client-side then you should leave
105+
`isIgnoreCustomObjectIdConfig = false`. Setting
106+
`ParseConfiguration.allowCustomObjectId = true` and
107+
`isIgnoreCustomObjectIdConfig = true` means the client will generate `objectId`'s
108+
and the server will generate an `objectId` only when the client does not provide one. This can lead
109+
to collisions of `objectId`'s as the client and server `objectId`'s may be generated using
110+
different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the
111+
client-side checks are disabled. Developers are responsible for handling such cases.
98112
*/
99113
func saveAllPublisher(batchLimit limit: Int? = nil,
100114
transaction: Bool = false,
115+
isIgnoreCustomObjectIdConfig: Bool = false,
101116
options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {
102117
Future { promise in
103118
self.saveAll(batchLimit: limit,
104119
transaction: transaction,
120+
isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig,
105121
options: options,
106122
completion: promise)
107123
}

0 commit comments

Comments
 (0)