@wordpress/core-data
Version:
Access to and manipulation of core WordPress entities.
194 lines (193 loc) • 5.63 kB
JavaScript
// 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