UNPKG

chrono-forge

Version:

A comprehensive framework for building resilient Temporal workflows, advanced state management, and real-time streaming activities in TypeScript. Designed for a seamless developer experience with powerful abstractions, dynamic orchestration, and full cont

153 lines (152 loc) 6.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleDeleteEntities = exports.handleUpdateEntities = exports.createUpdateStatement = exports.normalizeEntities = exports.initialState = exports.defaultState = void 0; exports.reducer = reducer; const normalizr_1 = require("normalizr"); const immutability_helper_1 = __importDefault(require("immutability-helper")); const actions_1 = require("./actions"); exports.defaultState = {}; exports.initialState = {}; const normalizeEntities = (data, entitySchema) => { const schema = typeof entitySchema === 'string' ? (0, actions_1.getSchema)(entitySchema) : entitySchema; const { entities } = (0, normalizr_1.normalize)(data, Array.isArray(data) ? [schema] : schema); return entities; }; exports.normalizeEntities = normalizeEntities; const createUpdateStatement = (state, normalizedEntities) => Object.entries(normalizedEntities).reduce((acc, [entityName, entityGroup]) => { acc[entityName] = state[entityName] ? Object.entries(entityGroup).reduce((subAcc, [entityId, entityData]) => { subAcc[entityId] = state[entityName][entityId] ? { $merge: entityData } : { $set: entityData }; return subAcc; }, {}) : { $set: entityGroup }; return acc; }, {}); exports.createUpdateStatement = createUpdateStatement; const handleUpdateEntities = (state, entities, strategy = '$merge') => Object.entries(entities).reduce((acc, [entityName, entityGroup]) => { switch (strategy) { case '$replace': acc[entityName] = replaceStrategy(entityGroup); break; case '$set': acc[entityName] = setStrategy(entityGroup, state[entityName]); break; case '$merge': acc[entityName] = mergeStrategy(state, entityName, entityGroup); break; case '$unset': acc[entityName] = unsetStrategy(entityGroup); break; case '$push': case '$unshift': acc[entityName] = arrayOperation(state[entityName], entityGroup, strategy); break; case '$splice': acc[entityName] = spliceStrategy(entityGroup); break; case '$apply': acc[entityName] = applyStrategy(entityGroup); break; default: throw new Error(`Invalid strategy: ${strategy}`); } return acc; }, {}); exports.handleUpdateEntities = handleUpdateEntities; const handleDeleteEntities = (state, entities) => Object.fromEntries(Object.entries(entities).map(([entityName, entityGroup]) => { const entityIds = Object.keys(entityGroup); return [ entityName, { $unset: entityIds } ]; })); exports.handleDeleteEntities = handleDeleteEntities; const replaceStrategy = (entityGroup) => Object.entries(entityGroup).reduce((acc, [entityId, entityData]) => { acc[entityId] = { $set: entityData }; return acc; }, {}); const setStrategy = (entityGroup, stateArray) => Object.entries(entityGroup).reduce((acc, [entityId, entityData]) => { acc[entityId] = acc[entityId] || {}; Object.entries(entityData).forEach(([fieldName, fieldValue]) => { if (fieldValue === entityId) { return; } acc[entityId][fieldName] = { $set: fieldValue }; }); return acc; }, {}); const mergeStrategy = (state, entityName, entityGroup) => ({ ...(0, exports.createUpdateStatement)(state, { [entityName]: entityGroup })[entityName] }); const unsetStrategy = (entityGroup) => { return Object.entries(entityGroup).reduce((acc, [entityId, entityData]) => { acc[entityId] = acc[entityId] || {}; acc[entityId].$unset = acc[entityId].$unset || []; acc[entityId].$unset = [ ...acc[entityId].$unset, ...Object.entries(entityData) .filter(([_, value]) => value !== entityId) .map(([key]) => key) ]; return acc; }, {}); }; const arrayOperation = (entityState, entityGroup, operation) => Object.entries(entityGroup).reduce((acc, [entityId, entity]) => { Object.entries(entity).forEach(([fieldName, value]) => { if (entityId === value) { return; } const currentArray = entityState[entityId][fieldName] ?? []; if (!Array.isArray(currentArray)) { throw new Error(`Expected array for ${operation} operation on entityId '${entityId}.${fieldName}'`); } acc[entityId] = acc[entityId] || {}; acc[entityId][fieldName] = { [operation]: Array.isArray(value) ? value : [value] }; }); return acc; }, {}); const spliceStrategy = (entityGroup) => Object.fromEntries(Object.entries(entityGroup).map(([entityId, entity]) => [ entityId, Object.fromEntries(Object.entries(entity) .filter(([_, value]) => value !== entityId) .map(([fieldName, value]) => { if (!Array.isArray(value)) { throw new Error(`Expected array for $splice operation on entityId '${entityId}.${fieldName}'`); } return [fieldName, { $splice: value }]; })) ])); const applyStrategy = (entityGroup) => Object.fromEntries(Object.entries(entityGroup).map(([entityId, entity]) => [ entityId, typeof entity === 'function' ? { $apply: entity } : Object.fromEntries(Object.entries(entity) .filter(([_, value]) => value !== entityId) .map(([key, value]) => [key, { $apply: value }])) ])); function reducer(state = exports.initialState, action) { const { entities = {}, strategy } = action; switch (action.type) { case actions_1.UPDATE_ENTITIES: case actions_1.UPDATE_ENTITIES_PARTIAL: { return (0, immutability_helper_1.default)(state, (0, exports.handleUpdateEntities)(state, entities, strategy)); } case actions_1.DELETE_ENTITIES: { return (0, immutability_helper_1.default)(state, (0, exports.handleDeleteEntities)(state, entities)); } case actions_1.SET_STATE: { return (0, immutability_helper_1.default)(state, { $set: entities }); } default: { return state; } } } exports.default = reducer;