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

Use consistent terminology across @wordpress/core-data #39349

Merged
merged 14 commits into from
Mar 14, 2022
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
47 changes: 39 additions & 8 deletions docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,22 @@ _Returns_

### getEntitiesByKind

Returns whether the entities for the give kind are loaded.
> **Deprecated** since WordPress 6.0. Use getEntitiesConfig instead

Returns the loaded entities for the given kind.

_Parameters_

- _state_ `Object`: Data state.
- _kind_ `string`: Entity kind.

_Returns_

- `Array<Object>`: Array of entities with config matching kind.

### getEntitiesConfig

Returns the loaded entities for the given kind.

_Parameters_

Expand All @@ -161,7 +176,9 @@ _Returns_

### getEntity

Returns the entity object given its kind and name.
> **Deprecated** since WordPress 6.0. Use getEntityConfig instead

Returns the entity config given its kind and name.

_Parameters_

Expand All @@ -171,7 +188,21 @@ _Parameters_

_Returns_

- `Object`: Entity
- `Object`: Entity config

### getEntityConfig

Returns the entity config given its kind and name.

_Parameters_

- _state_ `Object`: Data state.
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.

_Returns_

- `Object`: Entity config

### getEntityRecord

Expand Down Expand Up @@ -530,9 +561,9 @@ Action triggered to delete an entity record.

_Parameters_

- _kind_ `string`: Kind of the deleted entity.
- _name_ `string`: Name of the deleted entity.
- _recordId_ `string`: Record ID of the deleted entity.
- _kind_ `string`: Kind of the deleted entity record.
- _name_ `string`: Name of the deleted entity record.
- _recordId_ `string`: Record ID of the deleted entity record.
- _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.
Expand Down Expand Up @@ -613,8 +644,8 @@ Returns an action object used in signalling that entity records have been receiv

_Parameters_

- _kind_ `string`: Kind of the received entity.
- _name_ `string`: Name of the received entity.
- _kind_ `string`: Kind of the received entity record.
- _name_ `string`: Name of the received entity record.
- _records_ `Array|Object`: Records received.
- _query_ `?Object`: Query Object.
- _invalidateCache_ `?boolean`: Should invalidate query caches.
Expand Down
47 changes: 39 additions & 8 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ Action triggered to delete an entity record.

_Parameters_

- _kind_ `string`: Kind of the deleted entity.
- _name_ `string`: Name of the deleted entity.
- _recordId_ `string`: Record ID of the deleted entity.
- _kind_ `string`: Kind of the deleted entity record.
- _name_ `string`: Name of the deleted entity record.
- _recordId_ `string`: Record ID of the deleted entity record.
- _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.
Expand Down Expand Up @@ -147,8 +147,8 @@ Returns an action object used in signalling that entity records have been receiv

_Parameters_

- _kind_ `string`: Kind of the received entity.
- _name_ `string`: Name of the received entity.
- _kind_ `string`: Kind of the received entity record.
- _name_ `string`: Name of the received entity record.
- _records_ `Array|Object`: Records received.
- _query_ `?Object`: Query Object.
- _invalidateCache_ `?boolean`: Should invalidate query caches.
Expand Down Expand Up @@ -393,7 +393,22 @@ _Returns_

### getEntitiesByKind

Returns whether the entities for the give kind are loaded.
> **Deprecated** since WordPress 6.0. Use getEntitiesConfig instead

Returns the loaded entities for the given kind.

_Parameters_

- _state_ `Object`: Data state.
- _kind_ `string`: Entity kind.

_Returns_

- `Array<Object>`: Array of entities with config matching kind.

### getEntitiesConfig

Returns the loaded entities for the given kind.

_Parameters_

Expand All @@ -406,7 +421,23 @@ _Returns_

### getEntity

Returns the entity object given its kind and name.
> **Deprecated** since WordPress 6.0. Use getEntityConfig instead

Returns the entity config given its kind and name.

_Parameters_

- _state_ `Object`: Data state.
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.

_Returns_

- `Object`: Entity config

### getEntityConfig

Returns the entity config given its kind and name.

_Parameters_

Expand All @@ -416,7 +447,7 @@ _Parameters_

_Returns_

- `Object`: Entity
- `Object`: Entity config

### getEntityRecord

Expand Down
52 changes: 26 additions & 26 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import deprecated from '@wordpress/deprecated';
* Internal dependencies
*/
import { receiveItems, removeItems, receiveQueriedItems } from './queried-data';
import { getKindEntities, DEFAULT_ENTITY_KEY } from './entities';
import { getOrLoadEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
import { createBatch } from './batch';
import { STORE_NAME } from './name';

Expand Down Expand Up @@ -66,8 +66,8 @@ export function addEntities( entities ) {
/**
* Returns an action object used in signalling that entity records have been received.
*
* @param {string} kind Kind of the received entity.
* @param {string} name Name of the received entity.
* @param {string} kind Kind of the received entity record.
* @param {string} name Name of the received entity record.
* @param {Array|Object} records Records received.
* @param {?Object} query Query Object.
* @param {?boolean} invalidateCache Should invalidate query caches.
Expand Down Expand Up @@ -209,9 +209,9 @@ 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 {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.
Expand All @@ -226,17 +226,17 @@ export const deleteEntityRecord = (
query,
{ __unstableFetch = apiFetch } = {}
) => async ( { dispatch } ) => {
const entities = await dispatch( getKindEntities( kind ) );
const entity = find( entities, { kind, name } );
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
const entityConfig = find( configs, { kind, name } );
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if there's a reason we dispatch this action here but rely on the getEntityConfig selector for editEntityRecord, and dispatch again on saveEntityRecord

when deleting and saving we will try and fetch more entity configs if we can't find the given one, but on edit we give up immediately.

Copy link
Contributor Author

@adamziel adamziel Mar 11, 2022

Choose a reason for hiding this comment

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

My guess is that by the time we edit an entity record, it must have been resolved, which means that the loading already happened in a different code path. Definitely confusing, though. It would be easier to read if we relied on getOrLoad in editEntityRecord too, even if only for consistency. Let's save it for another PR.

let error;
let deletedRecord = false;
if ( ! entity || entity?.__experimentalNoFetch ) {
if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
return;
}

const lock = await dispatch.__unstableAcquireStoreLock(
STORE_NAME,
[ 'entities', 'data', kind, name, recordId ],
[ 'entities', 'records', kind, name, recordId ],
{ exclusive: true }
);

Expand All @@ -249,7 +249,7 @@ export const deleteEntityRecord = (
} );

try {
let path = `${ entity.baseURL }/${ recordId }`;
let path = `${ entityConfig.baseURL }/${ recordId }`;

if ( query ) {
path = addQueryArgs( path, query );
Expand Down Expand Up @@ -299,13 +299,13 @@ export const editEntityRecord = (
edits,
options = {}
) => ( { select, dispatch } ) => {
const entity = select.getEntity( kind, name );
if ( ! entity ) {
const entityConfig = select.getEntityConfig( kind, name );
Copy link
Member

Choose a reason for hiding this comment

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

my goodness this line's change alone makes this PR worthwhile.

if ( ! entityConfig ) {
throw new Error(
`The entity being edited (${ kind }, ${ name }) does not have a loaded config.`
);
}
const { transientEdits = {}, mergedEdits = {} } = entity;
const { transientEdits = {}, mergedEdits = {} } = entityConfig;
const record = select.getRawEntityRecord( kind, name, recordId );
const editedRecord = select.getEditedEntityRecord( kind, name, recordId );

Expand Down Expand Up @@ -401,17 +401,17 @@ export const saveEntityRecord = (
record,
{ isAutosave = false, __unstableFetch = apiFetch } = {}
) => async ( { select, resolveSelect, dispatch } ) => {
const entities = await dispatch( getKindEntities( kind ) );
const entity = find( entities, { kind, name } );
if ( ! entity || entity?.__experimentalNoFetch ) {
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
const entityConfig = find( configs, { kind, name } );
if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
return;
}
const entityIdKey = entity.key || DEFAULT_ENTITY_KEY;
const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
const recordId = record[ entityIdKey ];

const lock = await dispatch.__unstableAcquireStoreLock(
STORE_NAME,
[ 'entities', 'data', kind, name, recordId || uuid() ],
[ 'entities', 'records', kind, name, recordId || uuid() ],
{ exclusive: true }
);

Expand Down Expand Up @@ -446,7 +446,7 @@ export const saveEntityRecord = (
let updatedRecord;
let error;
try {
const path = `${ entity.baseURL }${
const path = `${ entityConfig.baseURL }${
recordId ? '/' + recordId : ''
}`;
const persistedRecord = select.getRawEntityRecord(
Expand Down Expand Up @@ -543,10 +543,10 @@ export const saveEntityRecord = (
}
} else {
let edits = record;
if ( entity.__unstablePrePersist ) {
if ( entityConfig.__unstablePrePersist ) {
edits = {
...edits,
...entity.__unstablePrePersist(
...entityConfig.__unstablePrePersist(
persistedRecord,
edits
),
Expand Down Expand Up @@ -659,12 +659,12 @@ export const saveEditedEntityRecord = (
if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
return;
}
const entities = await dispatch( getKindEntities( kind ) );
const entity = find( entities, { kind, name } );
if ( ! entity ) {
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
const entityConfig = find( configs, { kind, name } );
if ( ! entityConfig ) {
return;
}
const entityIdKey = entity.key || DEFAULT_ENTITY_KEY;
const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;

const edits = select.getEntityRecordNonTransientEdits(
kind,
Expand Down
44 changes: 28 additions & 16 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const DEFAULT_ENTITY_KEY = 'id';

const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ];

export const defaultEntities = [
export const rootEntitiesConfig = [
{
label: __( 'Base' ),
name: '__unstableBase',
Expand Down Expand Up @@ -164,9 +164,9 @@ export const defaultEntities = [
},
];

export const kinds = [
{ name: 'postType', loadEntities: loadPostTypeEntities },
{ name: 'taxonomy', loadEntities: loadTaxonomyEntities },
export const additionalEntityConfigLoaders = [
{ kind: 'postType', loadEntities: loadPostTypeEntities },
{ kind: 'taxonomy', loadEntities: loadTaxonomyEntities },
];

/**
Expand Down Expand Up @@ -257,6 +257,15 @@ async function loadTaxonomyEntities() {
/**
* Returns the entity's getter method name given its kind and name.
*
* @example
* ```js
* const nameSingular = getMethodName( 'root', 'theme', 'get' );
* // nameSingular is getRootTheme
*
* const namePlural = getMethodName( 'root', 'theme', 'set' );
* // namePlural is setRootThemes
* ```
*
* @param {string} kind Entity kind.
* @param {string} name Entity name.
* @param {string} prefix Function prefix.
Expand All @@ -270,13 +279,13 @@ export const getMethodName = (
prefix = 'get',
usePlural = false
) => {
const entity = find( defaultEntities, { kind, name } );
const entityConfig = find( rootEntitiesConfig, { kind, name } );
const kindPrefix = kind === 'root' ? '' : upperFirst( camelCase( kind ) );
const nameSuffix =
upperFirst( camelCase( name ) ) + ( usePlural ? 's' : '' );
const suffix =
usePlural && entity.plural
? upperFirst( camelCase( entity.plural ) )
usePlural && entityConfig.plural
? upperFirst( camelCase( entityConfig.plural ) )
: nameSuffix;
return `${ prefix }${ kindPrefix }${ suffix }`;
};
Expand All @@ -288,19 +297,22 @@ export const getMethodName = (
*
* @return {Array} Entities
*/
export const getKindEntities = ( kind ) => async ( { select, dispatch } ) => {
let entities = select.getEntitiesByKind( kind );
if ( entities && entities.length !== 0 ) {
return entities;
export const getOrLoadEntitiesConfig = ( kind ) => async ( {
select,
dispatch,
} ) => {
let configs = select.getEntitiesConfig( kind );
if ( configs && configs.length !== 0 ) {
return configs;
}

const kindConfig = find( kinds, { name: kind } );
if ( ! kindConfig ) {
const loader = find( additionalEntityConfigLoaders, { kind } );
if ( ! loader ) {
return [];
}

entities = await kindConfig.loadEntities();
dispatch( addEntities( entities ) );
configs = await loader.loadEntities();
dispatch( addEntities( configs ) );

return entities;
return configs;
};
Loading