import { State } from '../state'; import { Preprocessors } from '../common.interfaces'; import { CompositeFilterDescriptor } from '../filtering/filter-descriptor.interface'; import { DataResult } from '../data-result.interface'; import { filterBy } from '../filtering/filter-expression.factory'; import { process } from '../array.operators'; import { DataSource, IdType } from './data-source'; import cloneDeep from 'lodash/cloneDeep'; import { toJS, comparer } from 'mobx'; export class InMemoryDataSource implements DataSource { idSelector?: (row: T) => TId; private data: T[]; private preprocessors: Preprocessors; private cached?: { state: State; result: DataResult; }; constructor(data: T[], idSelector?: (row: T) => TId, preprocessors: Preprocessors = {}) { this.data = cloneDeep(toJS(data)); this.idSelector = idSelector; this.preprocessors = preprocessors; } getData(state: State) { const { skip, take, sort, filter, group } = state; const sortedAndFiltered = this.cached && comparer.structural(this.cached.state, { sort, filter }) ? this.cached.result : process(this.data, { sort, filter }, this.preprocessors); this.cached = { state: { sort, filter }, result: sortedAndFiltered, }; const { data } = process(sortedAndFiltered.data, { skip, take, group }, this.preprocessors); const { total } = sortedAndFiltered; return Promise.resolve({ total, data: cloneDeep(data), } as DataResult); } addData(row: T, index?: number) { if (index !== undefined) { this.data.splice(index, 0, cloneDeep(row)); } else { this.data.push(cloneDeep(row)); } this.cached = undefined; return Promise.resolve(cloneDeep(row)); } async updateData(id: TId, changes: Partial) { if (!this.idSelector) { throw 'missing idSelector'; } const row = this.data.find(row => this.idSelector!(row) === id); if (row) { Object.assign(row, changes); this.cached = undefined; } return Promise.resolve(); } async removeData(id: TId) { if (!this.idSelector) { throw 'missing idSelector'; } const index = this.data.findIndex(row => this.idSelector!(row) === id); if (index !== -1) { const row = this.data[index]; this.data.splice(index, 1); this.cached = undefined; return Promise.resolve(row); } } getFilteredPersistentItems(filter: CompositeFilterDescriptor) { const set = new Set(this.data); const inFilter = filterBy(this.data, filter, this.preprocessors); inFilter.forEach(dataItem => set.delete(dataItem)); return cloneDeep(Array.from(set)); } }