import ModelComponent from "./ModelComponent"; import Model from "./Model"; import ModelQuery, {ModelQueryResult, SelectFields} from "./ModelQuery"; import {Request} from "express"; import {Type} from "../Utils"; export default class ModelFactory { private static readonly factories: { [modelType: string]: ModelFactory } = {}; public static register(modelType: Type) { if (this.factories[modelType.name]) throw new Error(`Factory for type ${modelType.name} already defined.`); this.factories[modelType.name] = new ModelFactory(modelType); } public static get(modelType: Type): ModelFactory { const factory = this.factories[modelType.name]; if (!factory) throw new Error(`No factory registered for ${modelType.name}.`); return factory; } private readonly modelType: Type; private readonly components: ModelComponentFactory[] = []; protected constructor(modelType: Type) { this.modelType = modelType; } public addComponent(modelComponentFactory: ModelComponentFactory) { this.components.push(modelComponentFactory); } public create(data: any): T { const model = new this.modelType(this, data); for (const component of this.components) { model.addComponent(new component(model)); } model.updateWithData(data); return model; } public get table(): string { // @ts-ignore return this.modelType.table; } public select(...fields: SelectFields): ModelQuery { return ModelQuery.select(this, ...fields); } public update(data: { [key: string]: any }): ModelQuery { return ModelQuery.update(this, data); } public delete(): ModelQuery { return ModelQuery.delete(this); } public getPrimaryKeyFields(): string[] { return ['id']; } public getPrimaryKey(modelData: any): any[] { return this.getPrimaryKeyFields().map(f => modelData[f]); } public getPrimaryKeyString(modelData: any): string { return this.getPrimaryKey(modelData).join(','); } public async getById(...id: any): Promise { let query = this.select(); const primaryKeyFields = this.getPrimaryKeyFields(); for (let i = 0; i < primaryKeyFields.length; i++) { query = query.where(primaryKeyFields[i], id[i]); } return query.first(); } public async paginate(request: Request, perPage: number = 20, query?: ModelQuery): Promise> { let page = request.params.page ? parseInt(request.params.page) : 1; if (!query) query = this.select(); if (request.params.sortBy) { const dir = request.params.sortDirection; query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined); } else { query = query.sortBy('id'); } return await query.paginate(page, perPage); } } export type ModelComponentFactory = new (model: T) => ModelComponent;