import { Repository as TypeormRepository } from 'typeorm' import { Type, Injector, EntityService } from '@notadd/core'; import { Connection, getMetadataArgsStorage, FindOneOptions, FindManyOptions, SaveOptions, DeleteResult, ObjectID, InsertResult, RemoveOptions, EntityManager, UpdateResult, QueryRunner, EntityMetadata, SelectQueryBuilder, DeepPartial, FindConditions } from 'typeorm'; import { MetadataArgsStorage } from 'typeorm/metadata-args/MetadataArgsStorage'; import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity'; import { define, Table, ColumnDefinition, QueryLike, Query, Executable } from './sql-helper'; import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata'; export function createColumn(column: ColumnMetadata): ColumnDefinition { return { name: column.propertyName as Name, dataType: column.type as any } } export function createColumns(columns: ColumnMetadata[]): any { const res = {}; columns.map(column => { Reflect.set(res, column.propertyName, createColumn(column)) }) return res; } export function createTable(metadata: EntityMetadata): Table { return define({ name: metadata.tableName as Name, schema: metadata.schema || '', columns: createColumns(metadata.columns) }) } export function isExecutable(val: any): val is Executable { return val && Reflect.has(val, 'toQuery') } export class Repository implements TypeormRepository{ manager: EntityManager; metadata: EntityMetadata; queryRunner?: QueryRunner; entityService: EntityService; get table() { return createTable(this.metadata) } constructor(public repository: TypeormRepository, public injector: Injector, public entity: Type) { this.entityService = this.injector.get(EntityService) this.metadata = this.repository.metadata; this.manager = this.repository.manager; this.queryRunner = this.repository.queryRunner; } createQueryBuilder(alias?: string | undefined, queryRunner?: QueryRunner): SelectQueryBuilder { return this.manager.createQueryBuilder(this.entity, alias || this.entity.name, queryRunner || this.queryRunner); } get target() { return this.entity; } sql(sqlLike: QueryLike | Query): Promise { if (isExecutable(sqlLike)) { return this.sql(sqlLike.toQuery()) } else { return this.query(sqlLike.text, sqlLike.values) } } hasId(entity: Entity): boolean { return this.repository.hasId(entity) } getId(entity: Entity) { return this.repository.getId(entity) } create(): Entity; create(entityLikeArray: DeepPartial[]): Entity[]; create(entityLike: DeepPartial): Entity; create(entityLike?: any) { if (entityLike) { return this.repository.create(entityLike) } else { return this.repository.create() } } createAsync(): Promise; createAsync(entityLikeArray: DeepPartial[]): Promise; createAsync(entityLike: DeepPartial): Promise; async createAsync(entityLike?: any) { if (Array.isArray(entityLike)) { return await Promise.all(entityLike.map(it => this.createAsync(it))) } else if (entityLike) { return this.entityService.create(entityLike, this.target) } else { return this.entityService.create(entityLike, this.target) } } merge(mergeIntoEntity: Entity, ...entityLikes: DeepPartial[]): Entity { return this.repository.merge(mergeIntoEntity, ...entityLikes) } async preload(entityLike: DeepPartial): Promise { entityLike = await this.entityService.create(entityLike as any, this.entity) as any; return this.repository.preload(entityLike) } save>(entities: T[], options: SaveOptions & { reload: false; }): Promise; save>(entities: T[], options?: SaveOptions | undefined): Promise<(T & Entity)[]>; save>(entity: T, options: SaveOptions & { reload: false; }): Promise; save>(entity: T, options?: SaveOptions | undefined): Promise; async save(entity: any, options?: any) { const type = entity.constructor if (type) { if (type.name === 'Object') { // entity = await this.createAsync(entity as any) } } return this.repository.save(entity, options) } remove(entities: Entity[], options?: RemoveOptions | undefined): Promise; remove(entity: Entity, options?: RemoveOptions | undefined): Promise; remove(entity: any, options?: any): Promise { if (Array.isArray(entity)) { return this.repository.remove(entity, options) } else { return this.repository.remove(entity, options) } } softRemove>(entities: T[], options: SaveOptions & { reload: false; }): Promise; softRemove>(entities: T[], options?: SaveOptions | undefined): Promise<(T & Entity)[]>; softRemove>(entity: T, options: SaveOptions & { reload: false; }): Promise; softRemove>(entity: T, options?: SaveOptions | undefined): Promise; softRemove(entity: any, options?: any) { return this.repository.softRemove(entity, options) } recover>(entities: T[], options: SaveOptions & { reload: false; }): Promise; recover>(entities: T[], options?: SaveOptions | undefined): Promise<(T & Entity)[]>; recover>(entity: T, options: SaveOptions & { reload: false; }): Promise; recover>(entity: T, options?: SaveOptions | undefined): Promise; recover(entity: any, options?: any) { return this.repository.recover(entity, options) } async insert(entity: QueryDeepPartialEntity | QueryDeepPartialEntity[]): Promise { const type = entity.constructor if (type) { if (type.name === 'Object') { // entity = await this.createAsync(entity as any) } } return this.repository.insert(entity) } update(criteria: string | number | string[] | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions, partialEntity: QueryDeepPartialEntity): Promise { return this.repository.update(criteria, partialEntity) } delete(criteria: string | number | string[] | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions): Promise { return this.repository.delete(criteria) } softDelete(criteria: string | number | string[] | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions): Promise { return this.repository.softDelete(criteria) } restore(criteria: string | number | string[] | number[] | Date | Date[] | ObjectID | ObjectID[] | FindConditions): Promise { return this.repository.restore(criteria) } count(options?: FindManyOptions | undefined): Promise; count(conditions?: FindConditions | undefined): Promise; count(conditions?: any) { return this.repository.count(conditions) } find(options?: FindManyOptions | undefined): Promise; find(conditions?: FindConditions | undefined): Promise; find(conditions?: any): any { return this.repository.find(conditions) } findAndCount(options?: FindManyOptions | undefined): Promise<[Entity[], number]>; findAndCount(conditions?: FindConditions | undefined): Promise<[Entity[], number]>; findAndCount(conditions?: any) { return this.repository.findAndCount(conditions) } findByIds(ids: any[], options?: FindManyOptions | undefined): Promise; findByIds(ids: any[], conditions?: FindConditions | undefined): Promise; findByIds(ids: any, conditions?: any) { return this.repository.findByIds(conditions) } findOne(id?: string | number | Date | ObjectID | undefined, options?: FindOneOptions | undefined): Promise; findOne(options?: FindOneOptions | undefined): Promise; findOne(conditions?: FindConditions | undefined, options?: FindOneOptions | undefined): Promise; findOne(id?: any,conditions?: any, options?: any) { return this.repository.findOne(id,conditions) } findOneOrFail(id?: string | number | Date | ObjectID | undefined, options?: FindOneOptions | undefined): Promise; findOneOrFail(options?: FindOneOptions | undefined): Promise; findOneOrFail(conditions?: FindConditions | undefined, options?: FindOneOptions | undefined): Promise; findOneOrFail(id?: any,conditions?: any, options?: any) { return this.repository.findOneOrFail(id,conditions) } query(query: string, parameters?: any[] | undefined): Promise { return this.repository.query(query, parameters) } clear(): Promise { return this.repository.clear() } increment(conditions: FindConditions, propertyPath: string, value: string | number): Promise { return this.repository.increment(conditions, propertyPath, value) } decrement(conditions: FindConditions, propertyPath: string, value: string | number): Promise { return this.repository.decrement(conditions, propertyPath, value) } } export function createRepository(entity: Type, injector: Injector) { const connection = injector.get(Connection) const store: MetadataArgsStorage = getMetadataArgsStorage() const table = store.tables.find(table => table.target === entity); let repository: TypeormRepository; if (table) { repository = connection.getRepository(entity) } else { repository = connection.getTreeRepository(entity) } return new Repository(repository, injector, entity) }