130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
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<T extends Entity<any>> {
|
|
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<this> {
|
|
const uniqKey = entity.data.uniqKey()
|
|
entity._id = await this._storage.save(this.Name(), uniqKey, entity.data.toObject())
|
|
return this
|
|
}
|
|
|
|
async findById(id: string): Promise<T | null> {
|
|
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<string, any>,
|
|
limit?: number,
|
|
order?: Record<string, any>
|
|
): Promise<T[]> {
|
|
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<string, any>, order?: Record<string, any>): Promise<T[]> {
|
|
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<string, any>): Promise<number> {
|
|
return this._storage.count(this.Name(), query)
|
|
}
|
|
|
|
async remove(entity: T, silent = true): Promise<this> {
|
|
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
|
|
}
|
|
}
|