import { remove, at } from 'lodash'; import { ItemSelector } from './interfaces'; import Operation from './Operation'; export default class OperationManager { operationByItemSelector: { [entityType: string]: { [id: string]: Operation // index of operations } } initialOperationItemSelector: ItemSelector allOperations: Array operationsNotResolved: Array // operations require resolving handlers operationsRequireRead: Array constructor(initialOperation: Operation) { this.operationByItemSelector = {}; this.allOperations = []; this.operationsNotResolved = []; this.operationsRequireRead = []; this.initialOperationItemSelector = initialOperation.itemSelector; this.addOperation(initialOperation); } addOperation(newOperation: Operation) { const { itemSelector } = newOperation; const { entityType, id } = itemSelector; // check if already exists in operationsByItemSelector const prevOperation = this.getOperation(newOperation.itemSelector); if (prevOperation) { prevOperation.modify(newOperation.partialAfter); } else { newOperation.connectToOperationManager( // on resolved (operation) => { remove( this.operationsNotResolved, itemSelector => (itemSelector.entityType === operation.itemSelector.entityType) && (itemSelector.id === operation.itemSelector.id) ); }, // on setBefore (on read beforeItem) (operation) => { remove( this.operationsRequireRead, itemSelector => (itemSelector.entityType === operation.itemSelector.entityType) && (itemSelector.id === operation.itemSelector.id) ); } ); if (!this.operationByItemSelector[entityType]) this.operationByItemSelector[entityType] = {}; this.operationByItemSelector[entityType][id] = newOperation; this.allOperations.push(itemSelector); this.operationsNotResolved.push(itemSelector); if (newOperation.requireRead) { this.operationsRequireRead.push(itemSelector); } } } getOperation(itemSelector: ItemSelector): Operation { const { entityType, id } = itemSelector; const opMap = this.operationByItemSelector; return opMap && opMap[entityType] && opMap[entityType][id]; } getInitialOperation(): Operation { return this.getOperation(this.initialOperationItemSelector); } getOperationsRequireRead(): Array { return this.operationsRequireRead.map(itemSelector => this.getOperation(itemSelector)); } getOperationsNotResolved(): Array { return this.operationsNotResolved.map(itemSelector => this.getOperation(itemSelector)); } getAllOperations(): Array { return this.allOperations.map(itemSelector => this.getOperation(itemSelector)); } }