Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Remove the "throwing" actions in favor of a throwOnError option
  • Loading branch information
adamziel committed Mar 16, 2022
commit 90eac4af3f7c6e1f2516f8729a64909208392995
14 changes: 2 additions & 12 deletions docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ _Parameters_
- _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 promise.
- _options.throwOnError_ `[boolean]`: Whether to re-throw exceptions. If false, dispatching this action always resolves successfully and. never rejects.

### editEntityRecord

Expand Down Expand Up @@ -734,18 +735,7 @@ _Parameters_
- _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 promise.

### throwingDeleteEntityRecord

Undocumented declaration.

### throwingSaveEditedEntityRecord

Undocumented declaration.

### throwingSaveEntityRecord

Undocumented declaration.
- _options.throwOnError_ `[boolean]`: Whether to re-throw exceptions. If false, dispatching this action always resolves successfully and. never rejects.

### undo

Expand Down
1 change: 1 addition & 0 deletions packages/core-data/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- Learn how to maintain this file at https://github.com/WordPress/gutenberg/tree/HEAD/packages#maintaining-changelogs. -->

## Unreleased
– The saveEntityRecord, saveEditedEntityRecord, and deleteEntityRecord actions now accept an optional throwOnError option (defaults to false). When set to true, any exceptions occurring when the action was executing are re-thrown, causing dispatch().saveEntityRecord() to reject with an error. ([#39258](https://github.com/WordPress/gutenberg/pull/39258))

## 4.2.0 (2022-03-11)

Expand Down
14 changes: 2 additions & 12 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ _Parameters_
- _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 promise.
- _options.throwOnError_ `[boolean]`: Whether to re-throw exceptions. If false, dispatching this action always resolves successfully and. never rejects.

### editEntityRecord

Expand Down Expand Up @@ -237,18 +238,7 @@ _Parameters_
- _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 promise.

### throwingDeleteEntityRecord

Undocumented declaration.

### throwingSaveEditedEntityRecord

Undocumented declaration.

### throwingSaveEntityRecord

Undocumented declaration.
- _options.throwOnError_ `[boolean]`: Whether to re-throw exceptions. If false, dispatching this action always resolves successfully and. never rejects.

### undo

Expand Down
124 changes: 39 additions & 85 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,22 +209,26 @@ export function receiveEmbedPreview( url, preview ) {
/**
* Action triggered to delete an entity record.
*
* @param {string} kind Kind of the deleted entity record.
* @param {string} name Name of the deleted entity record.
* @param {string} recordId Record ID of the deleted entity record.
* @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 promise.
* @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 promise.
* @param {boolean} [options.throwOnError=false] Whether to re-throw exceptions.
* If false, dispatching this action
* always resolves successfully and.
* never rejects.
*/
export const deleteEntityRecord = (
kind,
name,
recordId,
query,
{ __unstableFetch = apiFetch } = {}
{ __unstableFetch = apiFetch, throwOnError = false } = {}
) => async ( { dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
const entityConfig = find( configs, { kind, name } );
Expand Down Expand Up @@ -273,6 +277,10 @@ export const deleteEntityRecord = (
error,
} );

if ( error && throwOnError ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if error is undefined or null or 0 or any falsy value? Even though it's an edge case, it should still throw such error 😅. I guess we'll need a flag like hasError to determine if it reaches the catch clause or not.
(Would be awesome if there's a test case for it too, but it's a nitpick.)

throw error;
}

return deletedRecord;
} finally {
dispatch.__unstableReleaseStoreLock( lock );
Expand Down Expand Up @@ -386,20 +394,28 @@ 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 {Function} [options.__unstableFetch] Internal use only. Function to
* call instead of `apiFetch()`.
* Must return a promise.
* @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 promise.
* @param {boolean} [options.throwOnError=false] Whether to re-throw exceptions.
* If false, dispatching this action
* always resolves successfully and.
* never rejects.
*/
export const saveEntityRecord = (
kind,
name,
record,
{ isAutosave = false, __unstableFetch = apiFetch } = {}
{
isAutosave = false,
__unstableFetch = apiFetch,
throwOnError = false,
} = {}
) => async ( { select, resolveSelect, dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
const entityConfig = find( configs, { kind, name } );
Expand Down Expand Up @@ -578,6 +594,10 @@ export const saveEntityRecord = (
isAutosave,
} );

if ( error && throwOnError ) {
throw error;
}

return updatedRecord;
} finally {
dispatch.__unstableReleaseStoreLock( lock );
Expand Down Expand Up @@ -759,69 +779,3 @@ export function receiveAutosaves( postId, autosaves ) {
autosaves: castArray( autosaves ),
};
}

export const throwingSaveEntityRecord = ( ...args ) => async ( {
dispatch,
select,
} ) => {
const [ kind, name, record ] = args;
const recordId = await dispatch( getRecordPk( kind, name, record ) );

const result = await dispatch( saveEntityRecord( ...args ) );
if ( ! result ) {
if ( recordId ) {
const error = select.getLastEntitySaveError( kind, name, recordId );
throw error;
} else {
throw new Error( 'Something went wrong' );
}
}

const resultId = await dispatch( getRecordPk( kind, name, result ) );
const error = select.getLastEntitySaveError( kind, name, resultId );

if ( error ) {
throw error;
}
return result;
};

export const throwingSaveEditedEntityRecord = ( ...args ) => async ( {
dispatch,
select,
} ) => {
const result = await dispatch( saveEditedEntityRecord( ...args ) );

const [ kind, name, id ] = args;
const error = select.getLastEntitySaveError( kind, name, id );

if ( error || ! result ) {
throw error;
}
return result;
};

export const throwingDeleteEntityRecord = ( ...args ) => async ( {
dispatch,
select,
} ) => {
const result = await dispatch( deleteEntityRecord( ...args ) );

const [ kind, name, id ] = args;
const error = select.getLastEntityDeleteError( kind, name, id );

if ( error || ! result ) {
throw error;
}
return result;
};

const getRecordPk = ( kind, name, record ) => async ( { dispatch } ) => {
const entities = await dispatch( getKindEntities( kind ) );
const entity = find( entities, { kind, name } );
if ( ! entity || entity?.__experimentalNoFetch ) {
return;
}
const entityIdKey = entity.key || DEFAULT_ENTITY_KEY;
return record[ entityIdKey ];
};
Loading