@@ -47,6 +47,7 @@ export type SaveOptions = FullOptions & {
4747 cascadeSave ?: boolean ;
4848 context ?: AttributeMap ;
4949 batchSize ?: number ;
50+ transaction ?: boolean ;
5051} ;
5152
5253type FetchOptions = {
@@ -1354,6 +1355,29 @@ class ParseObject {
13541355 }
13551356 const controller = CoreManager . getObjectController ( ) ;
13561357 const unsaved = options . cascadeSave !== false ? unsavedChildren ( this ) : null ;
1358+ if (
1359+ unsaved &&
1360+ unsaved . length &&
1361+ options . transaction === true &&
1362+ unsaved . some ( el => el instanceof ParseObject )
1363+ ) {
1364+ saveOptions . transaction = options . transaction ;
1365+ const unsavedFiles : ParseFile [ ] = [ ] ;
1366+ const unsavedObjects : ParseObject [ ] = [ ] ;
1367+ unsaved . forEach ( el => {
1368+ if ( el instanceof ParseFile ) unsavedFiles . push ( el ) ;
1369+ else unsavedObjects . push ( el ) ;
1370+ } ) ;
1371+ unsavedObjects . push ( this ) ;
1372+
1373+ const filePromise = unsavedFiles . length
1374+ ? controller . save ( unsavedFiles , saveOptions )
1375+ : Promise . resolve ( ) ;
1376+
1377+ return filePromise
1378+ . then ( ( ) => controller . save ( unsavedObjects , saveOptions ) )
1379+ . then ( ( savedOjbects : this[ ] ) => savedOjbects . pop ( ) ) ;
1380+ }
13571381 return controller . save ( unsaved , saveOptions ) . then ( ( ) => {
13581382 return controller . save ( this , saveOptions ) ;
13591383 } ) as Promise < ParseObject > as Promise < this> ;
@@ -1770,6 +1794,9 @@ class ParseObject {
17701794 if ( options . hasOwnProperty ( 'sessionToken' ) ) {
17711795 destroyOptions . sessionToken = options . sessionToken ;
17721796 }
1797+ if ( options . hasOwnProperty ( 'transaction' ) && typeof options . transaction === 'boolean' ) {
1798+ destroyOptions . transaction = options . transaction ;
1799+ }
17731800 if ( options . hasOwnProperty ( 'batchSize' ) && typeof options . batchSize === 'number' ) {
17741801 destroyOptions . batchSize = options . batchSize ;
17751802 }
@@ -1805,6 +1832,9 @@ class ParseObject {
18051832 if ( options . hasOwnProperty ( 'sessionToken' ) ) {
18061833 saveOptions . sessionToken = options . sessionToken ;
18071834 }
1835+ if ( options . hasOwnProperty ( 'transaction' ) && typeof options . transaction === 'boolean' ) {
1836+ saveOptions . transaction = options . transaction ;
1837+ }
18081838 if ( options . hasOwnProperty ( 'batchSize' ) && typeof options . batchSize === 'number' ) {
18091839 saveOptions . batchSize = options . batchSize ;
18101840 }
@@ -2322,12 +2352,20 @@ const DefaultController = {
23222352 target : ParseObject | Array < ParseObject > ,
23232353 options : RequestOptions
23242354 ) : Promise < ParseObject | Array < ParseObject > > {
2325- const batchSize =
2355+ if ( options && options . batchSize && options . transaction )
2356+ throw new ParseError (
2357+ ParseError . OTHER_CAUSE ,
2358+ 'You cannot use both transaction and batchSize options simultaneously.'
2359+ ) ;
2360+
2361+ let batchSize =
23262362 options && options . batchSize ? options . batchSize : CoreManager . get ( 'REQUEST_BATCH_SIZE' ) ;
23272363 const localDatastore = CoreManager . getLocalDatastore ( ) ;
23282364
23292365 const RESTController = CoreManager . getRESTController ( ) ;
23302366 if ( Array . isArray ( target ) ) {
2367+ if ( options && options . transaction && target . length > 1 ) batchSize = target . length ;
2368+
23312369 if ( target . length < 1 ) {
23322370 return Promise . resolve ( [ ] ) ;
23332371 }
@@ -2348,21 +2386,20 @@ const DefaultController = {
23482386 let deleteCompleted = Promise . resolve ( ) ;
23492387 const errors = [ ] ;
23502388 batches . forEach ( batch => {
2389+ const requests = batch . map ( obj => {
2390+ return {
2391+ method : 'DELETE' ,
2392+ path : getServerUrlPath ( ) + 'classes/' + obj . className + '/' + obj . _getId ( ) ,
2393+ body : { } ,
2394+ } ;
2395+ } ) ;
2396+ const body =
2397+ options && options . transaction && requests . length > 1
2398+ ? { requests, transaction : true }
2399+ : { requests } ;
2400+
23512401 deleteCompleted = deleteCompleted . then ( ( ) => {
2352- return RESTController . request (
2353- 'POST' ,
2354- 'batch' ,
2355- {
2356- requests : batch . map ( obj => {
2357- return {
2358- method : 'DELETE' ,
2359- path : getServerUrlPath ( ) + 'classes/' + obj . className + '/' + obj . _getId ( ) ,
2360- body : { } ,
2361- } ;
2362- } ) ,
2363- } ,
2364- options
2365- ) . then ( results => {
2402+ return RESTController . request ( 'POST' , 'batch' , body , options ) . then ( results => {
23662403 for ( let i = 0 ; i < results . length ; i ++ ) {
23672404 if ( results [ i ] && results [ i ] . hasOwnProperty ( 'error' ) ) {
23682405 const err = new ParseError ( results [ i ] . error . code , results [ i ] . error . error ) ;
@@ -2402,8 +2439,17 @@ const DefaultController = {
24022439 target : ParseObject | null | Array < ParseObject | ParseFile > ,
24032440 options : RequestOptions
24042441 ) : Promise < ParseObject | Array < ParseObject > | ParseFile | undefined > {
2405- const batchSize =
2442+ if ( options && options . batchSize && options . transaction )
2443+ return Promise . reject (
2444+ new ParseError (
2445+ ParseError . OTHER_CAUSE ,
2446+ 'You cannot use both transaction and batchSize options simultaneously.'
2447+ )
2448+ ) ;
2449+
2450+ let batchSize =
24062451 options && options . batchSize ? options . batchSize : CoreManager . get ( 'REQUEST_BATCH_SIZE' ) ;
2452+
24072453 const localDatastore = CoreManager . getLocalDatastore ( ) ;
24082454 const mapIdForPin = { } ;
24092455
@@ -2437,6 +2483,17 @@ const DefaultController = {
24372483 }
24382484 } ) ;
24392485
2486+ if ( options && options . transaction && pending . length > 1 ) {
2487+ if ( pending . some ( el => ! canBeSerialized ( el ) ) )
2488+ return Promise . reject (
2489+ new ParseError (
2490+ ParseError . OTHER_CAUSE ,
2491+ 'Tried to save a transactional batch containing an object with unserializable attributes.'
2492+ )
2493+ ) ;
2494+ batchSize = pending . length ;
2495+ }
2496+
24402497 return Promise . all ( filesSaved ) . then ( ( ) => {
24412498 let objectError = null ;
24422499 return continueWhile (
@@ -2504,18 +2561,16 @@ const DefaultController = {
25042561 when ( batchReady )
25052562 . then ( ( ) => {
25062563 // Kick off the batch request
2507- return RESTController . request (
2508- 'POST' ,
2509- 'batch' ,
2510- {
2511- requests : batch . map ( obj => {
2512- const params = obj . _getSaveParams ( ) ;
2513- params . path = getServerUrlPath ( ) + params . path ;
2514- return params ;
2515- } ) ,
2516- } ,
2517- options
2518- ) ;
2564+ const requests = batch . map ( obj => {
2565+ const params = obj . _getSaveParams ( ) ;
2566+ params . path = getServerUrlPath ( ) + params . path ;
2567+ return params ;
2568+ } ) ;
2569+ const body =
2570+ options && options . transaction && requests . length > 1
2571+ ? { requests, transaction : true }
2572+ : { requests } ;
2573+ return RESTController . request ( 'POST' , 'batch' , body , options ) ;
25192574 } )
25202575 . then ( batchReturned . resolve , error => {
25212576 batchReturned . reject ( new ParseError ( ParseError . INCORRECT_TYPE , error . message ) ) ;
0 commit comments