@ngrx/entity
Version:
Common utilities for entity reducers
456 lines (444 loc) • 15.9 kB
JavaScript
import { createSelector } from '@ngrx/store';
import { isDevMode } from '@angular/core';
function getInitialEntityState() {
return {
ids: [],
entities: {},
};
}
function createInitialStateFactory() {
function getInitialState(additionalState = {}) {
return Object.assign(getInitialEntityState(), additionalState);
}
return { getInitialState };
}
function createSelectorsFactory() {
function getSelectors(selectState) {
const selectIds = (state) => state.ids;
const selectEntities = (state) => state.entities;
const selectAll = createSelector(selectIds, selectEntities, (ids, entities) => ids.map((id) => entities[id]));
const selectTotal = createSelector(selectIds, (ids) => ids.length);
if (!selectState) {
return {
selectIds,
selectEntities,
selectAll,
selectTotal,
};
}
return {
selectIds: createSelector(selectState, selectIds),
selectEntities: createSelector(selectState, selectEntities),
selectAll: createSelector(selectState, selectAll),
selectTotal: createSelector(selectState, selectTotal),
};
}
return { getSelectors };
}
var DidMutate;
(function (DidMutate) {
DidMutate[DidMutate["EntitiesOnly"] = 0] = "EntitiesOnly";
DidMutate[DidMutate["Both"] = 1] = "Both";
DidMutate[DidMutate["None"] = 2] = "None";
})(DidMutate || (DidMutate = {}));
function createStateOperator(mutator) {
return function operation(arg, state) {
const clonedEntityState = {
ids: [...state.ids],
entities: { ...state.entities },
};
const didMutate = mutator(arg, clonedEntityState);
if (didMutate === DidMutate.Both) {
return Object.assign({}, state, clonedEntityState);
}
if (didMutate === DidMutate.EntitiesOnly) {
return {
...state,
entities: clonedEntityState.entities,
};
}
return state;
};
}
function selectIdValue(entity, selectId) {
const key = selectId(entity);
if (isDevMode() && key === undefined) {
console.warn('@ngrx/entity: The entity passed to the `selectId` implementation returned undefined.', 'You should probably provide your own `selectId` implementation.', 'The entity that was passed:', entity, 'The `selectId` implementation:', selectId.toString());
}
return key;
}
function createUnsortedStateAdapter(selectId) {
function addOneMutably(entity, state) {
const key = selectIdValue(entity, selectId);
if (key in state.entities) {
return DidMutate.None;
}
state.ids.push(key);
state.entities[key] = entity;
return DidMutate.Both;
}
function addManyMutably(entities, state) {
let didMutate = false;
for (const entity of entities) {
didMutate = addOneMutably(entity, state) !== DidMutate.None || didMutate;
}
return didMutate ? DidMutate.Both : DidMutate.None;
}
function setAllMutably(entities, state) {
state.ids = [];
state.entities = {};
addManyMutably(entities, state);
return DidMutate.Both;
}
function setOneMutably(entity, state) {
const key = selectIdValue(entity, selectId);
if (key in state.entities) {
state.entities[key] = entity;
return DidMutate.EntitiesOnly;
}
state.ids.push(key);
state.entities[key] = entity;
return DidMutate.Both;
}
function setManyMutably(entities, state) {
const didMutateSetOne = entities.map((entity) => setOneMutably(entity, state));
switch (true) {
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.Both):
return DidMutate.Both;
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.EntitiesOnly):
return DidMutate.EntitiesOnly;
default:
return DidMutate.None;
}
}
function removeOneMutably(key, state) {
return removeManyMutably([key], state);
}
function removeManyMutably(keysOrPredicate, state) {
const keys = keysOrPredicate instanceof Array
? keysOrPredicate
: state.ids.filter((key) => keysOrPredicate(state.entities[key]));
const didMutate = keys
.filter((key) => key in state.entities)
.map((key) => delete state.entities[key]).length > 0;
if (didMutate) {
state.ids = state.ids.filter((id) => id in state.entities);
}
return didMutate ? DidMutate.Both : DidMutate.None;
}
function removeAll(state) {
return Object.assign({}, state, {
ids: [],
entities: {},
});
}
function takeNewKey(keys, update, state) {
const original = state.entities[update.id];
const updated = Object.assign({}, original, update.changes);
const newKey = selectIdValue(updated, selectId);
const hasNewKey = newKey !== update.id;
if (hasNewKey) {
keys[update.id] = newKey;
delete state.entities[update.id];
}
state.entities[newKey] = updated;
return hasNewKey;
}
function updateOneMutably(update, state) {
return updateManyMutably([update], state);
}
function updateManyMutably(updates, state) {
const newKeys = {};
updates = updates.filter((update) => update.id in state.entities);
const didMutateEntities = updates.length > 0;
if (didMutateEntities) {
const didMutateIds = updates.filter((update) => takeNewKey(newKeys, update, state)).length >
0;
if (didMutateIds) {
state.ids = state.ids.map((id) => newKeys[id] || id);
return DidMutate.Both;
}
else {
return DidMutate.EntitiesOnly;
}
}
return DidMutate.None;
}
function mapMutably(map, state) {
const changes = state.ids.reduce((changes, id) => {
const change = map(state.entities[id]);
if (change !== state.entities[id]) {
changes.push({ id, changes: change });
}
return changes;
}, []);
const updates = changes.filter(({ id }) => id in state.entities);
return updateManyMutably(updates, state);
}
function mapOneMutably({ map, id }, state) {
const entity = state.entities[id];
if (!entity) {
return DidMutate.None;
}
const updatedEntity = map(entity);
return updateOneMutably({
id: id,
changes: updatedEntity,
}, state);
}
function upsertOneMutably(entity, state) {
return upsertManyMutably([entity], state);
}
function upsertManyMutably(entities, state) {
const added = [];
const updated = [];
for (const entity of entities) {
const id = selectIdValue(entity, selectId);
if (id in state.entities) {
updated.push({ id, changes: entity });
}
else {
added.push(entity);
}
}
const didMutateByUpdated = updateManyMutably(updated, state);
const didMutateByAdded = addManyMutably(added, state);
switch (true) {
case didMutateByAdded === DidMutate.None &&
didMutateByUpdated === DidMutate.None:
return DidMutate.None;
case didMutateByAdded === DidMutate.Both ||
didMutateByUpdated === DidMutate.Both:
return DidMutate.Both;
default:
return DidMutate.EntitiesOnly;
}
}
return {
removeAll,
addOne: createStateOperator(addOneMutably),
addMany: createStateOperator(addManyMutably),
setAll: createStateOperator(setAllMutably),
setOne: createStateOperator(setOneMutably),
setMany: createStateOperator(setManyMutably),
updateOne: createStateOperator(updateOneMutably),
updateMany: createStateOperator(updateManyMutably),
upsertOne: createStateOperator(upsertOneMutably),
upsertMany: createStateOperator(upsertManyMutably),
removeOne: createStateOperator(removeOneMutably),
removeMany: createStateOperator(removeManyMutably),
map: createStateOperator(mapMutably),
mapOne: createStateOperator(mapOneMutably),
};
}
function createSortedStateAdapter(selectId, sort) {
const { removeOne, removeMany, removeAll } = createUnsortedStateAdapter(selectId);
function addOneMutably(entity, state) {
return addManyMutably([entity], state);
}
function addManyMutably(newModels, state) {
const models = newModels.filter((model) => !(selectIdValue(model, selectId) in state.entities));
if (models.length === 0) {
return DidMutate.None;
}
else {
merge(models, state);
return DidMutate.Both;
}
}
function setAllMutably(models, state) {
state.entities = {};
state.ids = [];
addManyMutably(models, state);
return DidMutate.Both;
}
function setOneMutably(entity, state) {
const id = selectIdValue(entity, selectId);
if (id in state.entities) {
state.ids = state.ids.filter((val) => val !== id);
merge([entity], state);
return DidMutate.Both;
}
else {
return addOneMutably(entity, state);
}
}
function setManyMutably(entities, state) {
const didMutateSetOne = entities.map((entity) => setOneMutably(entity, state));
switch (true) {
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.Both):
return DidMutate.Both;
case didMutateSetOne.some((didMutate) => didMutate === DidMutate.EntitiesOnly):
return DidMutate.EntitiesOnly;
default:
return DidMutate.None;
}
}
function updateOneMutably(update, state) {
return updateManyMutably([update], state);
}
function takeUpdatedModel(models, update, state) {
if (!(update.id in state.entities)) {
return false;
}
const original = state.entities[update.id];
const updated = Object.assign({}, original, update.changes);
const newKey = selectIdValue(updated, selectId);
delete state.entities[update.id];
models.push(updated);
return newKey !== update.id;
}
function updateManyMutably(updates, state) {
const models = [];
const didMutateIds = updates.filter((update) => takeUpdatedModel(models, update, state))
.length > 0;
if (models.length === 0) {
return DidMutate.None;
}
else {
const originalIds = state.ids;
const updatedIndexes = [];
state.ids = state.ids.filter((id, index) => {
if (id in state.entities) {
return true;
}
else {
updatedIndexes.push(index);
return false;
}
});
merge(models, state);
if (!didMutateIds &&
updatedIndexes.every((i) => state.ids[i] === originalIds[i])) {
return DidMutate.EntitiesOnly;
}
else {
return DidMutate.Both;
}
}
}
function mapMutably(updatesOrMap, state) {
const updates = state.ids.reduce((changes, id) => {
const change = updatesOrMap(state.entities[id]);
if (change !== state.entities[id]) {
changes.push({ id, changes: change });
}
return changes;
}, []);
return updateManyMutably(updates, state);
}
function mapOneMutably({ map, id }, state) {
const entity = state.entities[id];
if (!entity) {
return DidMutate.None;
}
const updatedEntity = map(entity);
return updateOneMutably({
id: id,
changes: updatedEntity,
}, state);
}
function upsertOneMutably(entity, state) {
return upsertManyMutably([entity], state);
}
function upsertManyMutably(entities, state) {
const added = [];
const updated = [];
for (const entity of entities) {
const id = selectIdValue(entity, selectId);
if (id in state.entities) {
updated.push({ id, changes: entity });
}
else {
added.push(entity);
}
}
const didMutateByUpdated = updateManyMutably(updated, state);
const didMutateByAdded = addManyMutably(added, state);
switch (true) {
case didMutateByAdded === DidMutate.None &&
didMutateByUpdated === DidMutate.None:
return DidMutate.None;
case didMutateByAdded === DidMutate.Both ||
didMutateByUpdated === DidMutate.Both:
return DidMutate.Both;
default:
return DidMutate.EntitiesOnly;
}
}
function merge(models, state) {
models.sort(sort);
const ids = [];
let i = 0;
let j = 0;
while (i < models.length && j < state.ids.length) {
const model = models[i];
const modelId = selectIdValue(model, selectId);
const entityId = state.ids[j];
const entity = state.entities[entityId];
if (sort(model, entity) <= 0) {
ids.push(modelId);
i++;
}
else {
ids.push(entityId);
j++;
}
}
if (i < models.length) {
state.ids = ids.concat(models.slice(i).map(selectId));
}
else {
state.ids = ids.concat(state.ids.slice(j));
}
models.forEach((model, i) => {
state.entities[selectId(model)] = model;
});
}
return {
removeOne,
removeMany,
removeAll,
addOne: createStateOperator(addOneMutably),
updateOne: createStateOperator(updateOneMutably),
upsertOne: createStateOperator(upsertOneMutably),
setAll: createStateOperator(setAllMutably),
setOne: createStateOperator(setOneMutably),
setMany: createStateOperator(setManyMutably),
addMany: createStateOperator(addManyMutably),
updateMany: createStateOperator(updateManyMutably),
upsertMany: createStateOperator(upsertManyMutably),
map: createStateOperator(mapMutably),
mapOne: createStateOperator(mapOneMutably),
};
}
function createEntityAdapter(options = {}) {
const { selectId, sortComparer } = {
selectId: options.selectId ?? ((entity) => entity.id),
sortComparer: options.sortComparer ?? false,
};
const stateFactory = createInitialStateFactory();
const selectorsFactory = createSelectorsFactory();
const stateAdapter = sortComparer
? createSortedStateAdapter(selectId, sortComparer)
: createUnsortedStateAdapter(selectId);
return {
selectId,
sortComparer,
...stateFactory,
...selectorsFactory,
...stateAdapter,
};
}
class Dictionary {
}
/**
* DO NOT EDIT
*
* This file is automatically generated at build
*/
/**
* Generated bundle index. Do not edit.
*/
export { Dictionary, createEntityAdapter };
//# sourceMappingURL=ngrx-entity.mjs.map