@@ -83,6 +83,22 @@ public extension ParseObject {
83
83
// MARK: Batch Support
84
84
public extension Sequence where Element: ParseObject {
85
85
86
+ internal func canSendTransactions( _ isUsingTransactions: Bool ,
87
+ objectCount: Int ,
88
+ batchLimit: Int ) throws {
89
+ if isUsingTransactions {
90
+ if objectCount > batchLimit {
91
+ let error = ParseError ( code: . unknownError,
92
+ message: """
93
+ The amount of objects ( \( objectCount) ) can't exceed the batch size( \( batchLimit) ).
94
+ Either decrease the amount of objects, increase the batch size, or disable
95
+ transactions for this call.
96
+ """ )
97
+ throw error
98
+ }
99
+ }
100
+ }
101
+
86
102
/**
87
103
Saves a collection of objects *synchronously* all at once and throws an error if necessary.
88
104
- parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.
@@ -113,7 +129,7 @@ public extension Sequence where Element: ParseObject {
113
129
desires a different policy, it should be inserted in `options`.
114
130
*/
115
131
func saveAll( batchLimit limit: Int ? = nil , // swiftlint:disable:this function_body_length
116
- transaction: Bool = false ,
132
+ transaction: Bool = ParseSwift . configuration . useTransactions ,
117
133
isIgnoreCustomObjectIdConfig: Bool = false ,
118
134
options: API . Options = [ ] ) throws -> [ ( Result < Self . Element , ParseError > ) ] {
119
135
var options = options
@@ -126,7 +142,9 @@ public extension Sequence where Element: ParseObject {
126
142
for object in objects {
127
143
let group = DispatchGroup ( )
128
144
group. enter ( )
129
- object. ensureDeepSave ( options: options) { ( savedChildObjects, savedChildFiles, parseError) -> Void in
145
+ object. ensureDeepSave ( options: options,
146
+ // swiftlint:disable:next line_length
147
+ isShouldReturnIfChildObjectsFound: true ) { ( savedChildObjects, savedChildFiles, parseError) -> Void in
130
148
//If an error occurs, everything should be skipped
131
149
if parseError != nil {
132
150
error = parseError
@@ -163,12 +181,8 @@ public extension Sequence where Element: ParseObject {
163
181
164
182
var returnBatch = [ ( Result < Self . Element , ParseError > ) ] ( )
165
183
let commands = try map { try $0. saveCommand ( isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig) }
166
- let batchLimit : Int !
167
- if transaction {
168
- batchLimit = commands. count
169
- } else {
170
- batchLimit = limit ?? ParseConstants . batchLimit
171
- }
184
+ let batchLimit = limit != nil ? limit! : ParseConstants . batchLimit
185
+ try canSendTransactions ( transaction, objectCount: commands. count, batchLimit: batchLimit)
172
186
let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
173
187
try batches. forEach {
174
188
let currentBatch = try API . Command < Self . Element , Self . Element >
@@ -212,7 +226,7 @@ public extension Sequence where Element: ParseObject {
212
226
*/
213
227
func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity
214
228
batchLimit limit: Int ? = nil ,
215
- transaction: Bool = false ,
229
+ transaction: Bool = ParseSwift . configuration . useTransactions ,
216
230
isIgnoreCustomObjectIdConfig: Bool = false ,
217
231
options: API . Options = [ ] ,
218
232
callbackQueue: DispatchQueue = . main,
@@ -236,7 +250,9 @@ public extension Sequence where Element: ParseObject {
236
250
for object in objects {
237
251
let group = DispatchGroup ( )
238
252
group. enter ( )
239
- object. ensureDeepSave ( options: options) { ( savedChildObjects, savedChildFiles, parseError) -> Void in
253
+ object. ensureDeepSave ( options: options,
254
+ // swiftlint:disable:next line_length
255
+ isShouldReturnIfChildObjectsFound: true ) { ( savedChildObjects, savedChildFiles, parseError) -> Void in
240
256
//If an error occurs, everything should be skipped
241
257
if parseError != nil {
242
258
error = parseError
@@ -279,12 +295,8 @@ public extension Sequence where Element: ParseObject {
279
295
let commands = try map {
280
296
try $0. saveCommand ( isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
281
297
}
282
- let batchLimit : Int !
283
- if transaction {
284
- batchLimit = commands. count
285
- } else {
286
- batchLimit = limit ?? ParseConstants . batchLimit
287
- }
298
+ let batchLimit = limit != nil ? limit! : ParseConstants . batchLimit
299
+ try canSendTransactions ( transaction, objectCount: commands. count, batchLimit: batchLimit)
288
300
let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
289
301
var completed = 0
290
302
for batch in batches {
@@ -447,18 +459,14 @@ public extension Sequence where Element: ParseObject {
447
459
desires a different policy, it should be inserted in `options`.
448
460
*/
449
461
func deleteAll( batchLimit limit: Int ? = nil ,
450
- transaction: Bool = false ,
462
+ transaction: Bool = ParseSwift . configuration . useTransactions ,
451
463
options: API . Options = [ ] ) throws -> [ ( Result < Void , ParseError > ) ] {
452
464
var options = options
453
465
options. insert ( . cachePolicy( . reloadIgnoringLocalCacheData) )
454
466
var returnBatch = [ ( Result < Void , ParseError > ) ] ( )
455
467
let commands = try map { try $0. deleteCommand ( ) }
456
- let batchLimit : Int !
457
- if transaction {
458
- batchLimit = commands. count
459
- } else {
460
- batchLimit = limit ?? ParseConstants . batchLimit
461
- }
468
+ let batchLimit = limit != nil ? limit! : ParseConstants . batchLimit
469
+ try canSendTransactions ( transaction, objectCount: commands. count, batchLimit: batchLimit)
462
470
let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
463
471
try batches. forEach {
464
472
let currentBatch = try API . Command < Self . Element , ( Result < Void , ParseError > ) >
@@ -497,7 +505,7 @@ public extension Sequence where Element: ParseObject {
497
505
*/
498
506
func deleteAll(
499
507
batchLimit limit: Int ? = nil ,
500
- transaction: Bool = false ,
508
+ transaction: Bool = ParseSwift . configuration . useTransactions ,
501
509
options: API . Options = [ ] ,
502
510
callbackQueue: DispatchQueue = . main,
503
511
completion: @escaping ( Result < [ ( Result < Void , ParseError > ) ] , ParseError > ) -> Void
@@ -507,12 +515,8 @@ public extension Sequence where Element: ParseObject {
507
515
options. insert ( . cachePolicy( . reloadIgnoringLocalCacheData) )
508
516
var returnBatch = [ ( Result < Void , ParseError > ) ] ( )
509
517
let commands = try map ( { try $0. deleteCommand ( ) } )
510
- let batchLimit : Int !
511
- if transaction {
512
- batchLimit = commands. count
513
- } else {
514
- batchLimit = limit ?? ParseConstants . batchLimit
515
- }
518
+ let batchLimit = limit != nil ? limit! : ParseConstants . batchLimit
519
+ try canSendTransactions ( transaction, objectCount: commands. count, batchLimit: batchLimit)
516
520
let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
517
521
var completed = 0
518
522
for batch in batches {
@@ -755,6 +759,7 @@ extension ParseObject {
755
759
756
760
// swiftlint:disable:next function_body_length
757
761
internal func ensureDeepSave( options: API . Options = [ ] ,
762
+ isShouldReturnIfChildObjectsFound: Bool = false ,
758
763
completion: @escaping ( [ String : PointerType ] ,
759
764
[ UUID : ParseFile ] , ParseError ? ) -> Void ) {
760
765
let uuid = UUID ( )
@@ -779,7 +784,16 @@ extension ParseObject {
779
784
filesSavedBeforeThisOne: nil )
780
785
781
786
var waitingToBeSaved = object. unsavedChildren
782
-
787
+ if isShouldReturnIfChildObjectsFound && waitingToBeSaved. count > 0 {
788
+ let error = ParseError ( code: . unknownError,
789
+ message: """
790
+ When using transactions, all child ParseObjects have to originally
791
+ be saved to the Parse Server. Either save all child objects first
792
+ or disable transactions for this call.
793
+ """ )
794
+ completion ( [ String: PointerType] ( ) , [ UUID: ParseFile] ( ) , error)
795
+ return
796
+ }
783
797
while waitingToBeSaved. count > 0 {
784
798
var savableObjects = [ ParseType] ( )
785
799
var savableFiles = [ ParseFile] ( )
@@ -848,7 +862,7 @@ extension ParseObject {
848
862
// MARK: Savable Encodable Version
849
863
internal extension ParseType {
850
864
func saveAll( objects: [ ParseType ] ,
851
- transaction: Bool = ParseSwift . configuration. useTransactionsInternally ,
865
+ transaction: Bool = ParseSwift . configuration. useTransactions ,
852
866
options: API . Options = [ ] ) throws -> [ ( Result < PointerType , ParseError > ) ] {
853
867
try API . NonParseBodyCommand < AnyCodable , PointerType >
854
868
. batch ( objects: objects,
0 commit comments