Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core Data: Add __experimentalBatch() #28210

Merged
merged 1 commit into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/designers-developers/developers/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ _Parameters_
- _name_ `string`: Name of the deleted entity.
- _recordId_ `string`: Record ID of the deleted entity.
- _query_ `?Object`: Special query parameters for the DELETE API call.
- _options_ `[Object]`: Delete options.
- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.

<a name="editEntityRecord" href="#editEntityRecord">#</a> **editEntityRecord**

Expand Down Expand Up @@ -697,6 +699,7 @@ _Parameters_
- _record_ `Object`: Record to be saved.
- _options_ `Object`: Saving options.
- _options.isAutosave_ `[boolean]`: Whether this is an autosave.
- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.

<a name="undo" href="#undo">#</a> **undo**

Expand Down
3 changes: 3 additions & 0 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ _Parameters_
- _name_ `string`: Name of the deleted entity.
- _recordId_ `string`: Record ID of the deleted entity.
- _query_ `?Object`: Special query parameters for the DELETE API call.
- _options_ `[Object]`: Delete options.
- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.

<a name="editEntityRecord" href="#editEntityRecord">#</a> **editEntityRecord**

Expand Down Expand Up @@ -230,6 +232,7 @@ _Parameters_
- _record_ `Object`: Record to be saved.
- _options_ `Object`: Saving options.
- _options.isAutosave_ `[boolean]`: Whether this is an autosave.
- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.

<a name="undo" href="#undo">#</a> **undo**

Expand Down
146 changes: 126 additions & 20 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { v4 as uuid } from 'uuid';
* WordPress dependencies
*/
import { controls } from '@wordpress/data';
import { apiFetch } from '@wordpress/data-controls';
import { apiFetch, __unstableAwaitPromise } from '@wordpress/data-controls';
import { addQueryArgs } from '@wordpress/url';

/**
Expand All @@ -20,6 +20,8 @@ import {
__unstableAcquireStoreLock,
__unstableReleaseStoreLock,
} from './locks';
import { createBatch } from './batch';
import { getDispatch } from './controls';

/**
* Returns an action object used in signalling that authors have been received.
Expand Down Expand Up @@ -154,12 +156,23 @@ export function receiveEmbedPreview( url, preview ) {
/**
* Action triggered to delete an entity record.
*
* @param {string} kind Kind of the deleted entity.
* @param {string} name Name of the deleted entity.
* @param {string} recordId Record ID of the deleted entity.
* @param {?Object} query Special query parameters for the DELETE API call.
* @param {string} kind Kind of the deleted entity.
* @param {string} name Name of the deleted entity.
* @param {string} recordId Record ID of the deleted entity.
* @param {?Object} query Special query parameters for the
* DELETE API call.
* @param {Object} [options] Delete options.
* @param {Function} [options.__unstableFetch] Internal use only. Function to
* call instead of `apiFetch()`.
* Must return a control descriptor.
*/
export function* deleteEntityRecord( kind, name, recordId, query ) {
export function* deleteEntityRecord(
kind,
name,
recordId,
query,
{ __unstableFetch = null } = {}
) {
const entities = yield getKindEntities( kind );
const entity = find( entities, { kind, name } );
let error;
Expand Down Expand Up @@ -188,10 +201,17 @@ export function* deleteEntityRecord( kind, name, recordId, query ) {
path = addQueryArgs( path, query );
}

deletedRecord = yield apiFetch( {
const options = {
path,
method: 'DELETE',
} );
};
if ( __unstableFetch ) {
deletedRecord = yield __unstableAwaitPromise(
__unstableFetch( options )
);
} else {
deletedRecord = yield apiFetch( options );
}

yield removeItems( kind, name, recordId, true );
} catch ( _error ) {
Expand Down Expand Up @@ -329,17 +349,21 @@ export function __unstableCreateUndoLevel() {
/**
* Action triggered to save an entity record.
*
* @param {string} kind Kind of the received entity.
* @param {string} name Name of the received entity.
* @param {Object} record Record to be saved.
* @param {Object} options Saving options.
* @param {boolean} [options.isAutosave=false] Whether this is an autosave.
* @param {string} kind Kind of the received entity.
* @param {string} name Name of the received entity.
* @param {Object} record Record to be saved.
* @param {Object} options Saving options.
* @param {boolean} [options.isAutosave=false] Whether this is an autosave.
* @param {Function} [options.__unstableFetch] Internal use only. Function to
* call instead of `apiFetch()`.
* Must return a control
* descriptor.
*/
export function* saveEntityRecord(
kind,
name,
record,
{ isAutosave = false } = { isAutosave: false }
{ isAutosave = false, __unstableFetch = null } = {}
) {
const entities = yield getKindEntities( kind );
const entity = find( entities, { kind, name } );
Expand Down Expand Up @@ -441,11 +465,18 @@ export function* saveEntityRecord(
: data.status,
}
);
updatedRecord = yield apiFetch( {
const options = {
path: `${ path }/autosaves`,
method: 'POST',
data,
} );
};
if ( __unstableFetch ) {
updatedRecord = yield __unstableAwaitPromise(
noisysocks marked this conversation as resolved.
Show resolved Hide resolved
__unstableFetch( options )
);
} else {
updatedRecord = yield apiFetch( options );
}
// An autosave may be processed by the server as a regular save
// when its update is requested by the author and the post had
// draft or auto-draft status.
Expand Down Expand Up @@ -510,12 +541,18 @@ export function* saveEntityRecord(
),
};
}

updatedRecord = yield apiFetch( {
const options = {
path,
method: recordId ? 'PUT' : 'POST',
data: edits,
} );
};
if ( __unstableFetch ) {
updatedRecord = yield __unstableAwaitPromise(
__unstableFetch( options )
);
} else {
updatedRecord = yield apiFetch( options );
}
yield receiveEntityRecords(
kind,
name,
Expand Down Expand Up @@ -543,6 +580,75 @@ export function* saveEntityRecord(
}
}

/**
* Runs multiple core-data actions at the same time using one API request.
*
* Example:
*
* ```
* const [ savedRecord, updatedRecord, deletedRecord ] =
* await dispatch( 'core' ).__experimentalBatch( [
* ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
* ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
* ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
* ] );
* ```
*
* @param {Array} requests Array of functions which are invoked simultaneously.
* Each function is passed an object containing
* `saveEntityRecord`, `saveEditedEntityRecord`, and
* `deleteEntityRecord`.
*
* @return {Promise} A promise that resolves to an array containing the return
* values of each function given in `requests`.
*/
export function* __experimentalBatch( requests ) {
const batch = createBatch();
const dispatch = yield getDispatch();
const api = {
saveEntityRecord( kind, name, record, options ) {
return batch.add( ( add ) =>
dispatch( 'core' ).saveEntityRecord( kind, name, record, {
...options,
__unstableFetch: add,
} )
);
},
saveEditedEntityRecord( kind, name, recordId, options ) {
return batch.add( ( add ) =>
dispatch( 'core' ).saveEditedEntityRecord(
kind,
name,
recordId,
{
...options,
__unstableFetch: add,
}
)
);
},
deleteEntityRecord( kind, name, recordId, query, options ) {
return batch.add( ( add ) =>
dispatch( 'core' ).deleteEntityRecord(
kind,
name,
recordId,
query,
{
...options,
__unstableFetch: add,
}
)
);
},
};
const resultPromises = requests.map( ( request ) => request( api ) );
const [ , ...results ] = yield __unstableAwaitPromise(
Promise.all( [ batch.run(), ...resultPromises ] )
);
return results;
}

/**
* Action triggered to save an entity record's edits.
*
Expand Down Expand Up @@ -571,7 +677,7 @@ export function* saveEditedEntityRecord( kind, name, recordId, options ) {
recordId
);
const record = { id: recordId, ...edits };
yield* saveEntityRecord( kind, name, record, options );
return yield* saveEntityRecord( kind, name, record, options );
}

/**
Expand Down
Loading