UNPKG

@dazejs/framework

Version:

Daze.js - A powerful web framework for Node.js

353 lines (314 loc) 8.02 kB
import { format as dateFormat, getUnixTime } from 'date-fns'; import { BelongsTo, BelongsToMany, HasMany, HasOne, HasRelations } from './relations'; import { Repository } from './repository'; export interface ColumnDescription { type: string; length: number; defaultValue?: string | number | null; secret?: boolean; } export type RelationTypes = 'hasOne' | 'belongsTo' | 'hasMany' | 'belongsToMany' export interface RelationDesc { type: RelationTypes; entityFn: () => any; pivot?: any; foreignKey?: string; localKey?: string; relatedPivotKey?: string; foreignPivotKey?: string; } export class Model<TEntity = any> { /** * table name */ private _table: string; /** * connection name */ private _connection: string; /** * columns map */ private _columns: Map<string, ColumnDescription>; /** * _customColumns */ private _customColumns: string[]; /** * primary key */ private _primaryKey: string; /** * is auto incrementing? */ private _incrementing: boolean; /** * soft delete key * If not defined, delete is forced */ private _softDeleteKey?: string; /** * automatically insert the create timestamp */ private _createTimestampKey?: string; /** * automatically update the update timestamp */ private _updateTimestampKey?: string; /** * relation map */ private _relationMap: Map<string, RelationDesc>; /** * 原始 Entity */ private _originEntity: { new(): TEntity }; /** * 创建模型实例 * @param entity */ constructor(Entity: { new(): TEntity }) { this._originEntity = Entity; this._table = Reflect.getMetadata('table', Entity); this._connection = Reflect.getMetadata('connection', Entity) ?? 'default'; this._columns = Reflect.getMetadata('columns', Entity) ?? new Map(); this._customColumns = Reflect.getMetadata('customColumns', Entity) ?? []; this._primaryKey = Reflect.getMetadata('primaryKey', Entity) ?? 'id'; this._incrementing = Reflect.getMetadata('incrementing', Entity) ?? true; this._softDeleteKey = Reflect.getMetadata('softDeleteKey', Entity); this._createTimestampKey = Reflect.getMetadata('createTimestampKey', Entity); this._updateTimestampKey = Reflect.getMetadata('updateTimestampKey', Entity); this._relationMap = Reflect.getMetadata('relations', Entity) || new Map(); } /** * 创建新的实体实例 * @returns */ createNewEntity() { return new this._originEntity(); } /** * get origin entity * @returns */ getOriginEntity() { return this._originEntity; } /** * get table name */ getTable() { return this._table; } /** * set table name * @param table */ setTable(table: string) { this._table = table; return this; } /** * get connection name * default is `default` */ getConnectionName() { return this._connection ?? 'default'; } /** * get primary key * default id `id` */ getPrimaryKey() { return this._primaryKey ?? 'id'; } /** * get columns map */ getColumns() { return this._columns; } /** * get columns map */ getCustomColumns() { return this._customColumns; } /** * check if is auto incrementing */ isIncrementing() { return !!this._incrementing; } /** * get soft delete key */ getSoftDeleteKey() { return this._softDeleteKey as string; } /** * get soft delete key */ getSoftDeleteDefaultValue() { if (!this._softDeleteKey) return null; return this._columns.get(this._softDeleteKey)?.defaultValue ?? null; } /** * check if is force dlete * if true, soft delete key is undefind */ isForceDelete() { return !this._softDeleteKey; } /** * should update the update timestamp */ hasUpdateTimestamp() { return !!this._updateTimestampKey; } /** * get update timestap key */ getUpdateTimestampKey() { return this._updateTimestampKey; } /** * get fresh date use column type * @param key */ getFreshDateWithColumnKey(key: string) { const type = this.getColumnType(key); return this.getFormatedDate(type); } /** * should insert the create timestamp */ hasCreateTimestamp() { return !!this._createTimestampKey; } /** * get create timestamp key */ getCreateTimestampKey() { return this._createTimestampKey; } /** * create the repository instance */ createRepository(): Repository<TEntity> & TEntity { const repos = new Repository<TEntity>(this); return repos as Repository<TEntity> & TEntity; } /** * 获取字段类型 * @param key */ getColumnType(key: string) { return this._columns.get(key)?.type; } /** * get relation map */ getRelationMap() { return this._relationMap; } /** * get date with database column type * @param type */ getFormatedDate(type = 'int') { switch (type.toLowerCase()) { case 'date': return dateFormat(new Date(), 'yyyy-MM-dd'); case 'time': return dateFormat(new Date(), 'HH:MM:SS'); case 'year': return dateFormat(new Date(), 'yyyy'); case 'datetime': return dateFormat(new Date(), 'yyyy-MM-dd HH:mm:ss'); case 'timestamp': return dateFormat(new Date(), 'yyyy-MM-dd HH:mm:ss'); case 'bigint': return Date.now(); case 'int': default: return getUnixTime(new Date()); } } /** * get realtion instance with relation name * @param relation */ getRelationImp(relation: string): HasRelations | undefined { const relationDesc = this.getRelationMap().get(relation.split('.')[0]); if (!relationDesc) return; if (relationDesc) { const RelationEntity = relationDesc.entityFn(); const model = new Model(RelationEntity); switch (relationDesc.type) { case 'hasOne': return new HasOne( this, model, relationDesc.foreignKey, relationDesc.localKey ); case 'belongsTo': return new BelongsTo( this, model, relationDesc.foreignKey, relationDesc.localKey ); case 'hasMany': return new HasMany( this, model, relationDesc.foreignKey, relationDesc.localKey ); case 'belongsToMany': return new BelongsToMany( this, model, relationDesc.pivot, relationDesc.foreignPivotKey, relationDesc.relatedPivotKey ); default: return; } } return; } /** * convert data to repository instance * @param data */ async resultToRepository(parentRepos: Repository, data: Record<string, any>, isFromCollection = false): Promise<(Repository<TEntity> & TEntity)> { const repos = this.createRepository() .setExists(true) .fill(data); // Eager loading if (!isFromCollection && parentRepos.getWiths().size > 0) { await repos.eagerly(parentRepos.getWiths(), repos); } return repos as (Repository<TEntity> & TEntity); } /**‘ * convert data to repository instance collection */ async resultToRepositories(parentRepos: Repository, results: Record<string, any>[]): Promise<(Repository<TEntity> & TEntity)[]> { const data: Repository<TEntity>[] = []; for (const item of results) { data.push( await this.resultToRepository(parentRepos, item, true) ); } // Eager loading if (parentRepos.getWiths().size > 0) { await parentRepos.eagerlyCollection(parentRepos.getWiths(), data); } return data as (Repository<TEntity> & TEntity)[]; } }