import { Count, HandlerSetter, ItemSelector } from 'interfaces'; // import { cloneDeep } from 'lodash'; import Operation from '../Operation'; import checkCondition from './checkCondition'; export default function getCreatedAtHandlers( parentEntityType: string, propKey: string, propValue: Count ): {selfHandlerSetters: Array, childHandlerSetters: Array} { // ---------- selfHandler ---------- const selfHandlerSetter: HandlerSetter = { handlerHolder: 'SELF', // 'SELF' = parent onAdd: [{ updatingParentType: null, operationModifier: (parentOperation: Operation) => { // so, selfOperation = parentOperation parentOperation.modify({ [propKey]: 0 }); } }], onUpdate: [], onDelete: [] }; // ---------- childHandler ---------- const { childEntityType, conditions } = propValue; // checking 단계에서는 parent를 읽지 않은 상태이므로 parentOperations 대신 parentItemSelectors를 받는다. const checkNeedUpdatingParents = (childOperation: Operation, beforeParentItemSelectors: ItemSelector[], afterParentItemSelectors: ItemSelector[] ) => { let needUpdate: boolean = false; const deltas = {}; beforeParentItemSelectors.forEach(s => deltas[s.id] = 0); afterParentItemSelectors.forEach(s => deltas[s.id] = 0); const isBeforeChildOnCondition = checkCondition(childOperation.before, conditions); if (isBeforeChildOnCondition) { beforeParentItemSelectors.forEach(s => deltas[s.id] -= 1); } const isAfterChildOnCondition = checkCondition(childOperation.after, conditions); if (isAfterChildOnCondition) { afterParentItemSelectors.forEach(s => deltas[s.id] += 1); } Object.keys(deltas).forEach(parentId => { if (deltas[parentId] !== 0) needUpdate = true; }); return needUpdate; } const updateCountOfParentOperations = ( childOperation: Operation, beforeParentOperations: Array, afterParentOperations: Array ) => { const isBeforeChildOnCondition = checkCondition(childOperation.before, conditions); if (isBeforeChildOnCondition) { beforeParentOperations.forEach((parentOperation) => { parentOperation.addNumToProp(propKey, -1); }); } const isAfterChildOnCondition = checkCondition(childOperation.after, conditions); if (isAfterChildOnCondition) { afterParentOperations.forEach((parentOperation) => { parentOperation.addNumToProp(propKey, 1); }); } }; const childHandlerSetter: HandlerSetter = { handlerHolder: childEntityType, onAdd: [{ checkNeedUpdatingParents, updatingParentType: parentEntityType, operationModifier: ( childOperation: Operation, beforeParentOperations: Array, afterParentOperations: Array ) => { updateCountOfParentOperations(childOperation, beforeParentOperations, afterParentOperations); } }], onUpdate: [{ checkNeedUpdatingParents, updatingParentType: parentEntityType, operationModifier: ( childOperation: Operation, beforeParentOperations: Array, afterParentOperations: Array ) => { updateCountOfParentOperations(childOperation, beforeParentOperations, afterParentOperations); } }], onDelete: [{ checkNeedUpdatingParents, updatingParentType: parentEntityType, operationModifier: ( childOperation: Operation, beforeParentOperations: Array, afterParentOperations: Array ) => { updateCountOfParentOperations(childOperation, beforeParentOperations, afterParentOperations); } }] }; return { selfHandlerSetters: [selfHandlerSetter], childHandlerSetters: [childHandlerSetter] }; }