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: Retrieve the pagination totals in the getEntityRecords calls #55164

Merged
merged 4 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
31 changes: 31 additions & 0 deletions docs/reference-guides/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,36 @@ _Returns_

- `EntityRecord[] | null`: Records.

### getEntityRecordsTotalItems

Returns the Entity's total available records for a given query (ignoring pagination).

_Parameters_

- _state_ `State`: State tree
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _query_ `GetRecordsHttpQuery`: Optional terms query. If requesting specific fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".

_Returns_

- `number | null`: number | null.

### getEntityRecordsTotalPages

Returns the number of available pages for the given query.

_Parameters_

- _state_ `State`: State tree
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _query_ `GetRecordsHttpQuery`: Optional terms query. If requesting specific fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".

_Returns_

- `number | null`: number | null.

### getLastEntityDeleteError

Returns the specified entity record's last delete error.
Expand Down Expand Up @@ -630,6 +660,7 @@ _Parameters_
- _query_ `?Object`: Query Object.
- _invalidateCache_ `?boolean`: Should invalidate query caches.
- _edits_ `?Object`: Edits to reset.
- _meta_ `?Object`: Meta information about pagination.

_Returns_

Expand Down
4 changes: 4 additions & 0 deletions packages/core-data/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

## Enhancements

- Add `getEntityRecordsTotalItems` and `getEntityRecordsTotalPages` selectors. [#55164](https://github.com/WordPress/gutenberg/pull/55164).

## 6.20.0 (2023-10-05)

## 6.19.0 (2023-09-20)
Expand Down
31 changes: 31 additions & 0 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ _Parameters_
- _query_ `?Object`: Query Object.
- _invalidateCache_ `?boolean`: Should invalidate query caches.
- _edits_ `?Object`: Edits to reset.
- _meta_ `?Object`: Meta information about pagination.

_Returns_

Expand Down Expand Up @@ -535,6 +536,36 @@ _Returns_

- `EntityRecord[] | null`: Records.

### getEntityRecordsTotalItems

Returns the Entity's total available records for a given query (ignoring pagination).

_Parameters_

- _state_ `State`: State tree
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _query_ `GetRecordsHttpQuery`: Optional terms query. If requesting specific fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".

_Returns_

- `number | null`: number | null.

### getEntityRecordsTotalPages

Returns the number of available pages for the given query.

_Parameters_

- _state_ `State`: State tree
- _kind_ `string`: Entity kind.
- _name_ `string`: Entity name.
- _query_ `GetRecordsHttpQuery`: Optional terms query. If requesting specific fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".

_Returns_

- `number | null`: number | null.

### getLastEntityDeleteError

Returns the specified entity record's last delete error.
Expand Down
8 changes: 5 additions & 3 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export function addEntities( entities ) {
* @param {?Object} query Query Object.
* @param {?boolean} invalidateCache Should invalidate query caches.
* @param {?Object} edits Edits to reset.
* @param {?Object} meta Meta information about pagination.
* @return {Object} Action object.
*/
export function receiveEntityRecords(
Expand All @@ -88,7 +89,8 @@ export function receiveEntityRecords(
records,
query,
invalidateCache = false,
edits
edits,
meta
) {
// Auto drafts should not have titles, but some plugins rely on them so we can't filter this
// on the server.
Expand All @@ -102,9 +104,9 @@ export function receiveEntityRecords(
}
let action;
if ( query ) {
action = receiveQueriedItems( records, query, edits );
action = receiveQueriedItems( records, query, edits, meta );
} else {
action = receiveItems( records, edits );
action = receiveItems( records, edits, meta );
}

return {
Expand Down
2 changes: 2 additions & 0 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const rootEntitiesConfig = [
plural: 'mediaItems',
label: __( 'Media' ),
rawAttributes: [ 'caption', 'title', 'description' ],
supportsPagination: true,
},
{
name: 'taxonomy',
Expand Down Expand Up @@ -326,6 +327,7 @@ async function loadPostTypeEntities() {
},
syncObjectType: 'postType/' + postType.name,
getSyncObjectId: ( id ) => id,
supportsPagination: true,
};
} );
}
Expand Down
4 changes: 4 additions & 0 deletions packages/core-data/src/hooks/test/use-entity-records.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ describe( 'useEntityRecords', () => {
hasResolved: false,
isResolving: false,
status: 'IDLE',
totalItems: null,
totalPages: null,
} );

// Fetch request should have been issued
Expand All @@ -65,6 +67,8 @@ describe( 'useEntityRecords', () => {
hasResolved: true,
isResolving: false,
status: 'SUCCESS',
totalItems: null,
totalPages: null,
} );
} );
} );
38 changes: 38 additions & 0 deletions packages/core-data/src/hooks/use-entity-records.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import { addQueryArgs } from '@wordpress/url';
import deprecated from '@wordpress/deprecated';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
Expand All @@ -28,6 +29,16 @@ interface EntityRecordsResolution< RecordType > {

/** Resolution status */
status: Status;

/**
* The total number of available items (if not paginated).
*/
totalItems: number | null;

/**
* The total number of pages.
*/
totalPages: number | null;
}

const EMPTY_ARRAY = [];
Expand Down Expand Up @@ -97,8 +108,35 @@ export default function useEntityRecords< RecordType >(
[ kind, name, queryAsString, options.enabled ]
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed that this hook is using a special useQuerySelect. That felt a bit too magic to me, I'd have preferred as simple useSelect I think but it's not that important.

const { totalItems, totalPages } = useSelect(
( select ) => {
if ( ! options.enabled ) {
return {
// Avoiding returning a new reference on every execution.
youknowriad marked this conversation as resolved.
Show resolved Hide resolved
totalItems: null,
totalPages: null,
};
}
return {
totalItems: select( coreStore ).getEntityRecordsTotalItems(
kind,
name,
queryArgs
),
totalPages: select( coreStore ).getEntityRecordsTotalPages(
kind,
name,
queryArgs
),
};
},
[ kind, name, queryAsString, options.enabled ]
);

return {
records,
totalItems,
totalPages,
...rest,
};
}
Expand Down
9 changes: 6 additions & 3 deletions packages/core-data/src/queried-data/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
*
* @param {Array} items Items received.
* @param {?Object} edits Optional edits to reset.
* @param {?Object} meta Meta information about pagination.
*
* @return {Object} Action object.
*/
export function receiveItems( items, edits ) {
export function receiveItems( items, edits, meta ) {
return {
type: 'RECEIVE_ITEMS',
items: Array.isArray( items ) ? items : [ items ],
persistedEdits: edits,
meta,
};
}

Expand Down Expand Up @@ -41,12 +43,13 @@ export function removeItems( kind, name, records, invalidateCache = false ) {
* @param {Array} items Queried items received.
* @param {?Object} query Optional query object.
* @param {?Object} edits Optional edits to reset.
* @param {?Object} meta Meta information about pagination.
*
* @return {Object} Action object.
*/
export function receiveQueriedItems( items, query = {}, edits ) {
export function receiveQueriedItems( items, query = {}, edits, meta ) {
return {
...receiveItems( items, edits ),
...receiveItems( items, edits, meta ),
query,
};
}
27 changes: 17 additions & 10 deletions packages/core-data/src/queried-data/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,19 +222,22 @@ const receiveQueries = compose( [
// Queries shape is shared, but keyed by query `stableKey` part. Original
// reducer tracks only a single query object.
onSubKey( 'stableKey' ),
] )( ( state = null, action ) => {
] )( ( state = {}, action ) => {
ntsekouras marked this conversation as resolved.
Show resolved Hide resolved
const { type, page, perPage, key = DEFAULT_ENTITY_KEY } = action;

if ( type !== 'RECEIVE_ITEMS' ) {
return state;
}

return getMergedItemIds(
state || [],
action.items.map( ( item ) => item[ key ] ),
page,
perPage
);
return {
itemIds: getMergedItemIds(
state?.itemIds || [],
action.items.map( ( item ) => item[ key ] ),
page,
perPage
),
meta: action.meta,
};
} );

/**
Expand Down Expand Up @@ -263,9 +266,13 @@ const queries = ( state = {}, action ) => {
Object.entries( contextQueries ).map(
( [ query, queryItems ] ) => [
query,
queryItems.filter(
( queryId ) => ! removedItems[ queryId ]
),
{
...queryItems,
itemIds: queryItems.itemIds.filter(
( queryId ) =>
! removedItems[ queryId ]
),
},
]
)
),
Expand Down
14 changes: 13 additions & 1 deletion packages/core-data/src/queried-data/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function getQueriedItemsUncached( state, query ) {
let itemIds;

if ( state.queries?.[ context ]?.[ stableKey ] ) {
itemIds = state.queries[ context ][ stableKey ];
itemIds = state.queries[ context ][ stableKey ].itemIds;
}

if ( ! itemIds ) {
Expand Down Expand Up @@ -118,3 +118,15 @@ export const getQueriedItems = createSelector( ( state, query = {} ) => {
queriedItemsCache.set( query, items );
return items;
} );

export function getQueriedTotalItems( state, query = {} ) {
const { stableKey, context } = getQueryParts( query );

return state.queries?.[ context ]?.[ stableKey ]?.meta?.totalItems ?? null;
}

export function getQueriedTotalPages( state, query = {} ) {
const { stableKey, context } = getQueryParts( query );

return state.queries?.[ context ]?.[ stableKey ]?.meta?.totalPages ?? null;
}
18 changes: 9 additions & 9 deletions packages/core-data/src/queried-data/test/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe( 'reducer', () => {
default: { 1: true },
},
queries: {
default: { 's=a': [ 1 ] },
default: { 's=a': { itemIds: [ 1 ] } },
},
} );
} );
Expand Down Expand Up @@ -200,8 +200,8 @@ describe( 'reducer', () => {
},
queries: {
default: {
'': [ 1, 2, 3, 4 ],
's=a': [ 1, 3 ],
'': { itemIds: [ 1, 2, 3, 4 ] },
's=a': { itemIds: [ 1, 3 ] },
},
},
} );
Expand All @@ -218,8 +218,8 @@ describe( 'reducer', () => {
},
queries: {
default: {
'': [ 1, 2, 4 ],
's=a': [ 1 ],
'': { itemIds: [ 1, 2, 4 ] },
's=a': { itemIds: [ 1 ] },
},
},
} );
Expand All @@ -238,8 +238,8 @@ describe( 'reducer', () => {
},
queries: {
default: {
'': [ 'foo//bar1', 'foo//bar2', 'foo//bar3' ],
's=2': [ 'foo//bar2' ],
'': { itemIds: [ 'foo//bar1', 'foo//bar2', 'foo//bar3' ] },
's=2': { itemIds: [ 'foo//bar2' ] },
},
},
} );
Expand All @@ -258,8 +258,8 @@ describe( 'reducer', () => {
},
queries: {
default: {
'': [ 'foo//bar1', 'foo//bar3' ],
's=2': [],
'': { itemIds: [ 'foo//bar1', 'foo//bar3' ] },
's=2': { itemIds: [] },
},
},
} );
Expand Down
Loading
Loading