@@ -83,6 +83,22 @@ public extension ParseObject {
8383// MARK: Batch Support
8484public extension Sequence where Element: ParseObject {
8585
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+
86102 /**
87103 Saves a collection of objects *synchronously* all at once and throws an error if necessary.
88104 - 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 {
113129 desires a different policy, it should be inserted in `options`.
114130 */
115131 func saveAll( batchLimit limit: Int ? = nil , // swiftlint:disable:this function_body_length
116- transaction: Bool = false ,
132+ transaction: Bool = ParseSwift . configuration . useTransactions ,
117133 isIgnoreCustomObjectIdConfig: Bool = false ,
118134 options: API . Options = [ ] ) throws -> [ ( Result < Self . Element , ParseError > ) ] {
119135 var options = options
@@ -126,7 +142,9 @@ public extension Sequence where Element: ParseObject {
126142 for object in objects {
127143 let group = DispatchGroup ( )
128144 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
130148 //If an error occurs, everything should be skipped
131149 if parseError != nil {
132150 error = parseError
@@ -163,12 +181,8 @@ public extension Sequence where Element: ParseObject {
163181
164182 var returnBatch = [ ( Result < Self . Element , ParseError > ) ] ( )
165183 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)
172186 let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
173187 try batches. forEach {
174188 let currentBatch = try API . Command < Self . Element , Self . Element >
@@ -212,7 +226,7 @@ public extension Sequence where Element: ParseObject {
212226 */
213227 func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity
214228 batchLimit limit: Int ? = nil ,
215- transaction: Bool = false ,
229+ transaction: Bool = ParseSwift . configuration . useTransactions ,
216230 isIgnoreCustomObjectIdConfig: Bool = false ,
217231 options: API . Options = [ ] ,
218232 callbackQueue: DispatchQueue = . main,
@@ -236,7 +250,9 @@ public extension Sequence where Element: ParseObject {
236250 for object in objects {
237251 let group = DispatchGroup ( )
238252 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
240256 //If an error occurs, everything should be skipped
241257 if parseError != nil {
242258 error = parseError
@@ -279,12 +295,8 @@ public extension Sequence where Element: ParseObject {
279295 let commands = try map {
280296 try $0. saveCommand ( isIgnoreCustomObjectIdConfig: isIgnoreCustomObjectIdConfig)
281297 }
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)
288300 let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
289301 var completed = 0
290302 for batch in batches {
@@ -447,18 +459,14 @@ public extension Sequence where Element: ParseObject {
447459 desires a different policy, it should be inserted in `options`.
448460 */
449461 func deleteAll( batchLimit limit: Int ? = nil ,
450- transaction: Bool = false ,
462+ transaction: Bool = ParseSwift . configuration . useTransactions ,
451463 options: API . Options = [ ] ) throws -> [ ( Result < Void , ParseError > ) ] {
452464 var options = options
453465 options. insert ( . cachePolicy( . reloadIgnoringLocalCacheData) )
454466 var returnBatch = [ ( Result < Void , ParseError > ) ] ( )
455467 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)
462470 let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
463471 try batches. forEach {
464472 let currentBatch = try API . Command < Self . Element , ( Result < Void , ParseError > ) >
@@ -497,7 +505,7 @@ public extension Sequence where Element: ParseObject {
497505 */
498506 func deleteAll(
499507 batchLimit limit: Int ? = nil ,
500- transaction: Bool = false ,
508+ transaction: Bool = ParseSwift . configuration . useTransactions ,
501509 options: API . Options = [ ] ,
502510 callbackQueue: DispatchQueue = . main,
503511 completion: @escaping ( Result < [ ( Result < Void , ParseError > ) ] , ParseError > ) -> Void
@@ -507,12 +515,8 @@ public extension Sequence where Element: ParseObject {
507515 options. insert ( . cachePolicy( . reloadIgnoringLocalCacheData) )
508516 var returnBatch = [ ( Result < Void , ParseError > ) ] ( )
509517 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)
516520 let batches = BatchUtils . splitArray ( commands, valuesPerSegment: batchLimit)
517521 var completed = 0
518522 for batch in batches {
@@ -755,6 +759,7 @@ extension ParseObject {
755759
756760 // swiftlint:disable:next function_body_length
757761 internal func ensureDeepSave( options: API . Options = [ ] ,
762+ isShouldReturnIfChildObjectsFound: Bool = false ,
758763 completion: @escaping ( [ String : PointerType ] ,
759764 [ UUID : ParseFile ] , ParseError ? ) -> Void ) {
760765 let uuid = UUID ( )
@@ -779,7 +784,16 @@ extension ParseObject {
779784 filesSavedBeforeThisOne: nil )
780785
781786 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+ }
783797 while waitingToBeSaved. count > 0 {
784798 var savableObjects = [ ParseType] ( )
785799 var savableFiles = [ ParseFile] ( )
@@ -848,7 +862,7 @@ extension ParseObject {
848862// MARK: Savable Encodable Version
849863internal extension ParseType {
850864 func saveAll( objects: [ ParseType ] ,
851- transaction: Bool = ParseSwift . configuration. useTransactionsInternally ,
865+ transaction: Bool = ParseSwift . configuration. useTransactions ,
852866 options: API . Options = [ ] ) throws -> [ ( Result < PointerType , ParseError > ) ] {
853867 try API . NonParseBodyCommand < AnyCodable , PointerType >
854868 . batch ( objects: objects,
0 commit comments