@@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid';
88 * WordPress dependencies
99 */
1010import { controls } from '@wordpress/data' ;
11- import { apiFetch } from '@wordpress/data-controls' ;
11+ import { apiFetch , __unstableAwaitPromise } from '@wordpress/data-controls' ;
1212import { addQueryArgs } from '@wordpress/url' ;
1313
1414/**
@@ -20,6 +20,8 @@ import {
2020 __unstableAcquireStoreLock ,
2121 __unstableReleaseStoreLock ,
2222} from './locks' ;
23+ import { createBatch } from './batch' ;
24+ import { getDispatch } from './controls' ;
2325
2426/**
2527 * Returns an action object used in signalling that authors have been received.
@@ -154,12 +156,23 @@ export function receiveEmbedPreview( url, preview ) {
154156/**
155157 * Action triggered to delete an entity record.
156158 *
157- * @param {string } kind Kind of the deleted entity.
158- * @param {string } name Name of the deleted entity.
159- * @param {string } recordId Record ID of the deleted entity.
160- * @param {?Object } query Special query parameters for the DELETE API call.
159+ * @param {string } kind Kind of the deleted entity.
160+ * @param {string } name Name of the deleted entity.
161+ * @param {string } recordId Record ID of the deleted entity.
162+ * @param {?Object } query Special query parameters for the
163+ * DELETE API call.
164+ * @param {Object } [options] Delete options.
165+ * @param {Function } [options.__unstableFetch] Internal use only. Function to
166+ * call instead of `apiFetch()`.
167+ * Must return a control descriptor.
161168 */
162- export function * deleteEntityRecord ( kind , name , recordId , query ) {
169+ export function * deleteEntityRecord (
170+ kind ,
171+ name ,
172+ recordId ,
173+ query ,
174+ { __unstableFetch = null } = { }
175+ ) {
163176 const entities = yield getKindEntities ( kind ) ;
164177 const entity = find ( entities , { kind, name } ) ;
165178 let error ;
@@ -188,10 +201,17 @@ export function* deleteEntityRecord( kind, name, recordId, query ) {
188201 path = addQueryArgs ( path , query ) ;
189202 }
190203
191- deletedRecord = yield apiFetch ( {
204+ const options = {
192205 path,
193206 method : 'DELETE' ,
194- } ) ;
207+ } ;
208+ if ( __unstableFetch ) {
209+ deletedRecord = yield __unstableAwaitPromise (
210+ __unstableFetch ( options )
211+ ) ;
212+ } else {
213+ deletedRecord = yield apiFetch ( options ) ;
214+ }
195215
196216 yield removeItems ( kind , name , recordId , true ) ;
197217 } catch ( _error ) {
@@ -329,17 +349,21 @@ export function __unstableCreateUndoLevel() {
329349/**
330350 * Action triggered to save an entity record.
331351 *
332- * @param {string } kind Kind of the received entity.
333- * @param {string } name Name of the received entity.
334- * @param {Object } record Record to be saved.
335- * @param {Object } options Saving options.
336- * @param {boolean } [options.isAutosave=false] Whether this is an autosave.
352+ * @param {string } kind Kind of the received entity.
353+ * @param {string } name Name of the received entity.
354+ * @param {Object } record Record to be saved.
355+ * @param {Object } options Saving options.
356+ * @param {boolean } [options.isAutosave=false] Whether this is an autosave.
357+ * @param {Function } [options.__unstableFetch] Internal use only. Function to
358+ * call instead of `apiFetch()`.
359+ * Must return a control
360+ * descriptor.
337361 */
338362export function * saveEntityRecord (
339363 kind ,
340364 name ,
341365 record ,
342- { isAutosave = false } = { isAutosave : false }
366+ { isAutosave = false , __unstableFetch = null } = { }
343367) {
344368 const entities = yield getKindEntities ( kind ) ;
345369 const entity = find ( entities , { kind, name } ) ;
@@ -441,11 +465,18 @@ export function* saveEntityRecord(
441465 : data . status ,
442466 }
443467 ) ;
444- updatedRecord = yield apiFetch ( {
468+ const options = {
445469 path : `${ path } /autosaves` ,
446470 method : 'POST' ,
447471 data,
448- } ) ;
472+ } ;
473+ if ( __unstableFetch ) {
474+ updatedRecord = yield __unstableAwaitPromise (
475+ __unstableFetch ( options )
476+ ) ;
477+ } else {
478+ updatedRecord = yield apiFetch ( options ) ;
479+ }
449480 // An autosave may be processed by the server as a regular save
450481 // when its update is requested by the author and the post had
451482 // draft or auto-draft status.
@@ -510,12 +541,18 @@ export function* saveEntityRecord(
510541 ) ,
511542 } ;
512543 }
513-
514- updatedRecord = yield apiFetch ( {
544+ const options = {
515545 path,
516546 method : recordId ? 'PUT' : 'POST' ,
517547 data : edits ,
518- } ) ;
548+ } ;
549+ if ( __unstableFetch ) {
550+ updatedRecord = yield __unstableAwaitPromise (
551+ __unstableFetch ( options )
552+ ) ;
553+ } else {
554+ updatedRecord = yield apiFetch ( options ) ;
555+ }
519556 yield receiveEntityRecords (
520557 kind ,
521558 name ,
@@ -543,6 +580,75 @@ export function* saveEntityRecord(
543580 }
544581}
545582
583+ /**
584+ * Runs multiple core-data actions at the same time using one API request.
585+ *
586+ * Example:
587+ *
588+ * ```
589+ * const [ savedRecord, updatedRecord, deletedRecord ] =
590+ * await dispatch( 'core' ).__experimentalBatch( [
591+ * ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
592+ * ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
593+ * ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
594+ * ] );
595+ * ```
596+ *
597+ * @param {Array } requests Array of functions which are invoked simultaneously.
598+ * Each function is passed an object containing
599+ * `saveEntityRecord`, `saveEditedEntityRecord`, and
600+ * `deleteEntityRecord`.
601+ *
602+ * @return {Promise } A promise that resolves to an array containing the return
603+ * values of each function given in `requests`.
604+ */
605+ export function * __experimentalBatch ( requests ) {
606+ const batch = createBatch ( ) ;
607+ const dispatch = yield getDispatch ( ) ;
608+ const api = {
609+ saveEntityRecord ( kind , name , record , options ) {
610+ return batch . add ( ( add ) =>
611+ dispatch ( 'core' ) . saveEntityRecord ( kind , name , record , {
612+ ...options ,
613+ __unstableFetch : add ,
614+ } )
615+ ) ;
616+ } ,
617+ saveEditedEntityRecord ( kind , name , recordId , options ) {
618+ return batch . add ( ( add ) =>
619+ dispatch ( 'core' ) . saveEditedEntityRecord (
620+ kind ,
621+ name ,
622+ recordId ,
623+ {
624+ ...options ,
625+ __unstableFetch : add ,
626+ }
627+ )
628+ ) ;
629+ } ,
630+ deleteEntityRecord ( kind , name , recordId , query , options ) {
631+ return batch . add ( ( add ) =>
632+ dispatch ( 'core' ) . deleteEntityRecord (
633+ kind ,
634+ name ,
635+ recordId ,
636+ query ,
637+ {
638+ ...options ,
639+ __unstableFetch : add ,
640+ }
641+ )
642+ ) ;
643+ } ,
644+ } ;
645+ const resultPromises = requests . map ( ( request ) => request ( api ) ) ;
646+ const [ , ...results ] = yield __unstableAwaitPromise (
647+ Promise . all ( [ batch . run ( ) , ...resultPromises ] )
648+ ) ;
649+ return results ;
650+ }
651+
546652/**
547653 * Action triggered to save an entity record's edits.
548654 *
@@ -571,7 +677,7 @@ export function* saveEditedEntityRecord( kind, name, recordId, options ) {
571677 recordId
572678 ) ;
573679 const record = { id : recordId , ...edits } ;
574- yield * saveEntityRecord ( kind , name , record , options ) ;
680+ return yield * saveEntityRecord ( kind , name , record , options ) ;
575681}
576682
577683/**
0 commit comments