Skip to content

Commit

Permalink
getEntityRecord
Browse files Browse the repository at this point in the history
Updating resolver
  • Loading branch information
ramonjd committed Sep 21, 2023
1 parent c11d0a5 commit 6f0490d
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 56 deletions.
102 changes: 73 additions & 29 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,14 @@ export const getEntityRecord =
( kind, name, key = '', query ) =>
async ( { select, dispatch } ) => {
const configs = await dispatch( getOrLoadEntitiesConfig( kind ) );
// @TODO Create predictable parsing rules for names like post:[key]:revisions.
const splitName = name.split( ':' )[ 0 ];
const entityConfig = configs.find(
( config ) => config.name === name && config.kind === kind
( config ) => config.name === splitName && config.kind === kind
);
const isRevisionEntityRecord =
entityConfig?.supports?.revisions &&
name.split( ':' )?.[ 2 ] === 'revisions';
if ( ! entityConfig || entityConfig?.__experimentalNoFetch ) {
return;
}
Expand All @@ -73,10 +78,12 @@ export const getEntityRecord =

try {
// Entity supports configs,
// use the sync algorithm instead of the old fetch behavior.
// use the sync algorithm instead of the old fetch behavior,
// but not for revisions. @TODO check this.
if (
window.__experimentalEnableSync &&
entityConfig.syncConfig &&
! isRevisionEntityRecord &&
! query
) {
const objectId = entityConfig.getSyncObjectId( key );
Expand Down Expand Up @@ -136,33 +143,71 @@ export const getEntityRecord =
// modifications are relevant to how the data is tracked in state, and not
// for how the request is made to the REST API.

// eslint-disable-next-line @wordpress/no-unused-vars-before-return
const path = addQueryArgs(
entityConfig.baseURL + ( key ? '/' + key : '' ),
{
...entityConfig.baseURLParams,
...query,
}
);
// @TODO this is a mess.
// @TODO Create predictable URL building rules for names like post:[key]:revisions.
// @TODO Possibly `entityConfig.getRevisionsUrl( { name } )?
let path;
if ( isRevisionEntityRecord ) {
const [ , parentKey ] = name.split( ':' );
path = addQueryArgs(
`${ entityConfig.baseURL }/${ parentKey }/revisions${
key ? '/' + key : ''
}`,
{
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
}
);
} else {
path = addQueryArgs(
entityConfig.baseURL + ( key ? '/' + key : '' ),
{
...entityConfig.baseURLParams,
...query,
}
);
}

if ( query !== undefined ) {
query = { ...query, include: [ key ] };
query = isRevisionEntityRecord
? { context: 'view', ...query, include: [ key ] }
: { ...query, include: [ key ] };

// The resolution cache won't consider query as reusable based on the
// fields, so it's tested here, prior to initiating the REST request,
// and without causing `getEntityRecords` resolution to occur.
// @TODO how to handle revisions here?
// @TODO will it know if a new revision has been created?
const hasRecords = select.hasEntityRecords(
kind,
name,
query
);

if ( hasRecords ) {
return;
}
}

const record = await apiFetch( { path } );
dispatch.receiveEntityRecords( kind, name, record, query );
// @TODO just dispatching here to send the action type.
if ( isRevisionEntityRecord ) {
dispatch( {
type: 'RECEIVE_ITEM_REVISIONS',
kind,
name,
items: [ record ],
query: {
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
},
invalidateCache: false,
} );
} else {
dispatch.receiveEntityRecords( kind, name, record, query );
}
}
} finally {
dispatch.__unstableReleaseStoreLock( lock );
Expand Down Expand Up @@ -236,13 +281,11 @@ export const getEntityRecords =
path = addQueryArgs(
`${ entityConfig.baseURL }/${ parentKey }/revisions`,
{
...{
// @TODO Default query params for revisions should be defined in the entity config?
order: 'desc',
orderby: 'date',
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
},
// @TODO Default query params for revisions should be defined in the entity config?
order: 'desc',
orderby: 'date',
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
}
);
Expand Down Expand Up @@ -278,13 +321,11 @@ export const getEntityRecords =
name,
items: records,
query: {
...{
// @TODO Default query params for revisions should be defined in the entity config?
order: 'desc',
orderby: 'date',
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
},
// @TODO Default query params for revisions should be defined in the entity config?
order: 'desc',
orderby: 'date',
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
},
invalidateCache: false,
Expand Down Expand Up @@ -317,13 +358,16 @@ export const getEntityRecords =
dispatch.__unstableReleaseStoreLock( lock );
}
};

// @TODO work out how to invalidate revisions. At the moment, adding a new post revisions doesn't update the state.
getEntityRecords.shouldInvalidate = ( action, kind, name ) => {
const splitName = name.split( ':' )[ 0 ];
return (
( action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS' ) &&
( action.type === 'RECEIVE_ITEMS' ||
action.type === 'REMOVE_ITEMS' ||
action.type === 'RECEIVE_ITEM_REVISIONS' ) &&
action.invalidateCache &&
kind === action.kind &&
name === action.name
splitName === action.name
);
};

Expand Down
80 changes: 53 additions & 27 deletions packages/core-data/src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,14 +321,32 @@ export const getEntityRecord = createSelector(
key: EntityRecordKey,
query?: GetRecordsHttpQuery
): EntityRecord | undefined => {
const queriedState =
state.entities.records?.[ kind ]?.[ name ]?.queriedData;
// @TODO this is a mess.
// @TODO Create predictable parsing rules for names like post:[key]:revisions.
// @TODO update the resolver to fetch the revision item.
const splitName = name?.split( ':' );
const isRevision = splitName?.[ 2 ] === 'revisions';

const queriedState = isRevision
? state.entities.records?.[ kind ]?.[ splitName[ 0 ] ]?.revisions[
splitName[ 1 ]
]
: state.entities.records?.[ kind ]?.[ name ]?.queriedData;
if ( ! queriedState ) {
return undefined;
}
const context = query?.context ?? 'default';

if ( query === undefined ) {
const queryParams = isRevision
? {
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
}
: query;

const context = queryParams?.context ?? 'default';

if ( queryParams === undefined ) {
// If expecting a complete item, validate that completeness.
if ( ! queriedState.itemIsComplete[ context ]?.[ key ] ) {
return undefined;
Expand All @@ -338,9 +356,10 @@ export const getEntityRecord = createSelector(
}

const item = queriedState.items[ context ]?.[ key ];
if ( item && query._fields ) {
if ( item && queryParams._fields ) {
const filteredItem = {};
const fields = getNormalizedCommaSeparable( query._fields ) ?? [];
const fields =
getNormalizedCommaSeparable( queryParams._fields ) ?? [];
for ( let f = 0; f < fields.length; f++ ) {
const field = fields[ f ].split( '.' );
let value = item;
Expand All @@ -355,13 +374,33 @@ export const getEntityRecord = createSelector(
return item;
} ) as GetEntityRecord,
( state: State, kind, name, recordId, query ) => {
const context = query?.context ?? 'default';
// @TODO this is a mess.
// @TODO Create predictable parsing rules for names like post:[key]:revisions.
const splitName = name?.split( ':' );
const isRevision = splitName?.[ 2 ] === 'revisions';
const queryParams = isRevision
? {
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
...query,
}
: query;

const context = queryParams?.context ?? 'default';

return [
state.entities.records?.[ kind ]?.[ name ]?.queriedData?.items[
context
]?.[ recordId ],
state.entities.records?.[ kind ]?.[ name ]?.queriedData
?.itemIsComplete[ context ]?.[ recordId ],
isRevision
? state.entities.records?.[ kind ]?.[ splitName[ 0 ] ]
?.revisions[ splitName[ 1 ] ]?.items[ recordId ]
: state.entities.records?.[ kind ]?.[ name ]?.queriedData
?.items[ context ]?.[ recordId ],
isRevision
? state.entities.records?.[ kind ]?.[ splitName[ 0 ] ]
?.revisions[ splitName[ 1 ] ]?.itemIsComplete[
context
]?.[ recordId ]
: state.entities.records?.[ kind ]?.[ name ]?.queriedData
?.itemIsComplete[ context ]?.[ recordId ],
];
}
) as GetEntityRecord;
Expand Down Expand Up @@ -518,12 +557,13 @@ export const getEntityRecords = ( <
// assigned for the given parameters, then it is known to not exist.
// @TODO this is a mess.
// @TODO Create predictable parsing rules for names like post:[key]:revisions.
const splitName = name.split( ':' );
const splitName = name?.split( ':' );
if ( splitName?.[ 2 ] === 'revisions' ) {
const queriedStateRevisions =
state.entities.records?.[ kind ]?.[ splitName[ 0 ] ]?.revisions[
splitName[ 1 ]
];

if ( ! queriedStateRevisions ) {
return null;
}
Expand All @@ -534,20 +574,6 @@ export const getEntityRecords = ( <
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'view',
};
const test = getQueriedItems(
queriedStateRevisions,
{
...{
// @TODO Default query params for revisions should be defined in the entity config?
order: 'desc',
orderby: 'date',
// @TODO check if this is the default for revisions (should be view?). Is there anything else?
context: 'default',
},
...query,
},
splitName[ 1 ]
);

return getQueriedItems( queriedStateRevisions, {
...query,
Expand Down

0 comments on commit 6f0490d

Please sign in to comment.