UNPKG

@wordpress/core-data

Version:
194 lines (193 loc) 5.63 kB
// packages/core-data/src/queried-data/reducer.js import { combineReducers, keyedReducer } from "@wordpress/data"; import { compose } from "@wordpress/compose"; import { conservativeMapItem, ifMatchingAction, replaceAction } from "../utils/index.mjs"; import { DEFAULT_ENTITY_KEY } from "../entities.mjs"; import getQueryParts from "./get-query-parts.mjs"; function getContextFromAction(action) { const { query } = action; if (!query) { return "default"; } const queryParts = getQueryParts(query); return queryParts.context; } function getMergedItemIds(itemIds = [], nextItemIds, { page = 1, offset, perPage = 10 } = {}) { if (perPage === -1) { return nextItemIds; } const nextItemIdsStartIndex = offset ?? (page - 1) * perPage; const nextItemIdsRange = Math.max(perPage, nextItemIds.length); const size = Math.max( itemIds.length, nextItemIdsStartIndex + nextItemIds.length ); const mergedItemIds = new Array(size); for (let i = 0; i < size; i++) { const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + nextItemIdsRange; if (isInNextItemsRange) { mergedItemIds[i] = nextItemIds[i - nextItemIdsStartIndex]; } else { mergedItemIds[i] = itemIds[i]; } } return mergedItemIds; } function removeEntitiesById(entities, ids) { return Object.fromEntries( Object.entries(entities).filter( ([id]) => !ids.some((itemId) => { if (Number.isInteger(itemId)) { return itemId === +id; } return itemId === id; }) ) ); } function items(state = {}, action) { switch (action.type) { case "RECEIVE_ITEMS": { const context = getContextFromAction(action); const key = action.key || DEFAULT_ENTITY_KEY; const itemsList = Array.isArray(action.items) ? action.items : [action.items]; return { ...state, [context]: { ...state[context], ...Object.fromEntries( itemsList.map((item) => [ item?.[key], conservativeMapItem( state?.[context]?.[item?.[key]], item ) ]) ) } }; } case "REMOVE_ITEMS": return Object.fromEntries( Object.entries(state).map(([itemId, contextState]) => [ itemId, removeEntitiesById(contextState, action.itemIds) ]) ); } return state; } function itemIsComplete(state = {}, action) { switch (action.type) { case "RECEIVE_ITEMS": { const context = getContextFromAction(action); const { query, key = DEFAULT_ENTITY_KEY } = action; const itemsList = Array.isArray(action.items) ? action.items : [action.items]; const queryParts = query ? getQueryParts(query) : {}; const isCompleteQuery = !query || !Array.isArray(queryParts.fields); return { ...state, [context]: { ...state[context], ...itemsList.reduce((result, item) => { const itemId = item?.[key]; result[itemId] = state?.[context]?.[itemId] || isCompleteQuery; return result; }, {}) } }; } case "REMOVE_ITEMS": return Object.fromEntries( Object.entries(state).map(([itemId, contextState]) => [ itemId, removeEntitiesById(contextState, action.itemIds) ]) ); } return state; } var receiveQueries = compose([ // Limit to matching action type so we don't attempt to replace action on // an unhandled action. ifMatchingAction((action) => "query" in action), // Inject query parts into action for use both in `keyedReducer` and reducer. replaceAction((action) => { if (action.query) { return { ...action, ...getQueryParts(action.query) }; } return action; }), keyedReducer("context"), // Queries shape is shared, but keyed by query `stableKey` part. Original // reducer tracks only a single query object. keyedReducer("stableKey") ])((state = {}, action) => { if (action.type !== "RECEIVE_ITEMS") { return state; } if (!Array.isArray(action.items)) { return state; } const key = action.key ?? DEFAULT_ENTITY_KEY; return { itemIds: getMergedItemIds( state.itemIds, action.items.map((item) => item?.[key]).filter(Boolean), { page: action.page, offset: action.offset, perPage: action.perPage } ), meta: action.meta }; }); var queries = (state = {}, action) => { switch (action.type) { case "RECEIVE_ITEMS": return receiveQueries(state, action); case "REMOVE_ITEMS": const removedItems = action.itemIds.reduce((result, itemId) => { result[itemId] = true; return result; }, {}); return Object.fromEntries( Object.entries(state).map( ([queryGroup, contextQueries]) => [ queryGroup, Object.fromEntries( Object.entries(contextQueries).map( ([query, queryItems]) => [ query, { ...queryItems, itemIds: queryItems.itemIds.filter( (queryId) => !removedItems[queryId] ) } ] ) ) ] ) ); default: return state; } }; var reducer_default = combineReducers({ items, itemIsComplete, queries }); export { reducer_default as default, getMergedItemIds, itemIsComplete, items }; //# sourceMappingURL=reducer.mjs.map