import { Entity } from './entity' import { Storage } from './storage' /** @public */ export class ErrFoundNotUniqEntity extends Error {} /** @public */ export class ErrEntityNotFound extends Error {} /** @public */ export abstract class Repo> { protected _storage: Storage protected _entity: T protected _limit = 0 protected _offset = 0 protected _transformer: (obj: any) => any /** * Возвращает объект соотв. сущности, например new App() */ abstract Entity(): T /** * Возвращает название коллекции/таблицы/... хранящей записи соотв. сущностей */ abstract Name(): string constructor(storage: Storage, transformer?: (obj: any) => any) { this._storage = storage this._entity = this.Entity() this.setTransformer(transformer) } setTransformer(transformer?: (obj: any) => any): this { if (transformer) { this._transformer = transformer } else { this._transformer = function (object: any): any { const entity = this.Entity() entity.data.fromObject(object) entity._id = object._id return entity } } return this } get storage(): Storage { return this._storage } async save(entity: T): Promise { const uniqKey = entity.data.uniqKey() entity._id = await this._storage.save(this.Name(), uniqKey, entity.data.toObject()) return this } async findById(id: string): Promise { const uniqKey = this.Entity().data.uniqKey() const cursor = await this._storage.find(this.Name(), { [uniqKey]: id }) const entryList = await cursor.toArray() if (entryList.length > 1) { throw new ErrFoundNotUniqEntity( `found few (${entryList.length}) entries in ${this.Name()} for id ${id}` ) } if (entryList.length === 0) { throw new ErrEntityNotFound(`not found entry in [${this.Name()}] for id [${id}]`) } return this._transformer(entryList[0]) } /** * * @protected */ async _findByParams( parameters: Record, limit?: number, order?: Record ): Promise { const cursor = await this._storage.find(this.Name(), parameters) if (limit && limit > 0) await cursor.limit(limit) if (order) await cursor.sort(order) const data = await cursor.toArray() const list = [] for (const item of data) { list.push(this._transformer(item)) } return list } async findMany(parameters: Record, order?: Record): Promise { const cursor = await this._storage.find(this.Name(), parameters) if (this._offset > 0) await cursor.skip(this._offset) if (this._limit > 0) await cursor.limit(this._limit) if (order) await cursor.sort(order) const data = await cursor.toArray() const list = [] for (const item of data) { list.push(this._transformer(item)) } return list } shift(limit = 0, offset = 0) { this._limit = limit this._offset = offset return this } async count(query?: Record): Promise { return this._storage.count(this.Name(), query) } async remove(entity: T, silent = true): Promise { const idName = entity.data.uniqKey() const id = entity.getUniqKey() const ok = await this._storage.remove(this.Name(), idName, id) if (!silent && !ok) throw new ErrEntityNotFound(`can not remove entry in ${this.Name()} for id ${id}`) return this } }