import { merge } from 'lodash'; import { BaseRequestModelInterface } from '../requests'; import { Store } from './store'; import { Keys, Entities, USER_LITERAL } from './entities'; import { Id, HasId, Methods, UserData } from '../types'; export class BaseModel { public _requestModel: BaseRequestModelInterface; public _store: Store; public _storeKey: Keys; private _userPromise: Promise; constructor( requestModel: BaseRequestModelInterface, storeKey: Keys, store: Store, ) { this._requestModel = requestModel; this._storeKey = storeKey; this._store = store; } async create(item: Omit): Promise { const data = await this._requestModel.post(item); this._store.set(this._storeKey, data); return data; } private async _getUser() { if (this._userPromise) { return this._userPromise; } this._userPromise = this._requestModel .request({ method: Methods.GET, url: '/users/me', }) .then((user) => { this._store.set(Keys.userLiteral, { [USER_LITERAL]: user.id }); this._store.set(Keys.users, user); return user.id; }); return this._userPromise; } async getId(potentialId: Id): Promise { if (potentialId === USER_LITERAL) { const me = this._store.get(Keys.userLiteral, USER_LITERAL); if (me && me[USER_LITERAL]) { return me[USER_LITERAL]; } const userId = await this._getUser(); return userId; } return potentialId; } async getLocalById(id: Id): Promise { return this._store.get(this._storeKey, await this.getId(id)); } getLocalFilter( fn: (item: any, index: number, array: any[]) => boolean, ): DataType[] { return this._store.filter(this._storeKey, fn); } getLocalAll(): DataType[] { return this._store.getAll(this._storeKey); } async getById(id: Id): Promise { const actualId = await this.getId(id); if (this._store.has(this._storeKey, actualId)) { return this._store.get(this._storeKey, actualId, { expanded: true }); } const data = await this._requestModel.getById(actualId); this._store.set(this._storeKey, data, { deep: false }); return data; } async getAll(filter?: any): Promise { const data = await this._requestModel.getAll(filter); this._store.setBySchema([Entities[this._storeKey]], data, { deep: false }); return data; } async update(id: Id, item: Partial): Promise { const actualId = await this.getId(id); await this._requestModel.patchById(actualId, item); const oldItem = this._store.get(this._storeKey, actualId); const newItem = merge({}, oldItem, item, { id: actualId }); this._store.set(this._storeKey, newItem); return newItem; } async replace(id: Id, item: DataType): Promise { const actualId = await this.getId(id); await this._requestModel.putById(actualId, item); const newItem = merge({}, item, { id: actualId }); this._store.set(this._storeKey, newItem); return newItem; } async del(id: Id): Promise { const actualId = await this.getId(id); await this._requestModel.deleteById(actualId); this._store.del(this._storeKey, actualId); } }