import {Connection} from "../connection/Connection"; import {FindOptions} from "../find-options/FindOptions"; import {ObjectType} from "../common/ObjectType"; import {BaseEntityManager} from "./BaseEntityManager"; import {QueryRunnerProviderAlreadyReleasedError} from "../query-runner/error/QueryRunnerProviderAlreadyReleasedError"; import {QueryRunnerProvider} from "../query-runner/QueryRunnerProvider"; import {ObjectLiteral} from "../common/ObjectLiteral"; /** * Entity manager supposed to work with any entity, automatically find its repository and call its methods, * whatever entity type are you passing. */ export class EntityManager extends BaseEntityManager { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor(connection: Connection, queryRunnerProvider?: QueryRunnerProvider) { super(connection, queryRunnerProvider); } // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(entity: Entity): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(targetOrEntity: Function, entity: Entity): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(targetOrEntity: string, entity: Entity): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(entities: Entity[]): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(targetOrEntity: Function, entities: Entity[]): Promise; /** * Persists (saves) all given entities in the database. * If entities do not exist in the database then inserts, otherwise updates. */ persist(targetOrEntity: string, entities: Entity[]): Promise; /** * Persists (saves) a given entity in the database. */ persist(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise { const target = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Function|string; const entity = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Entity|Entity[]; if (typeof target === "string") { return this.getRepository(target).persist(entity); } else { if (target instanceof Array) { return this.getRepository(target[0].constructor).persist(entity as Entity[]); } else { return this.getRepository(target.constructor).persist(entity as Entity); } } } /** * Removes a given entity from the database. */ remove(entity: Entity): Promise; /** * Removes a given entity from the database. */ remove(targetOrEntity: Function, entity: Entity): Promise; /** * Removes a given entity from the database. */ remove(targetOrEntity: string, entity: Entity): Promise; /** * Removes a given entity from the database. */ remove(entity: Entity[]): Promise; /** * Removes a given entity from the database. */ remove(targetOrEntity: Function, entity: Entity[]): Promise; /** * Removes a given entity from the database. */ remove(targetOrEntity: string, entity: Entity[]): Promise; /** * Removes a given entity from the database. */ remove(targetOrEntity: (Entity|Entity[])|Function|string, maybeEntity?: Entity|Entity[]): Promise { const target = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Function|string; const entity = arguments.length === 2 ? maybeEntity as Entity|Entity[] : targetOrEntity as Entity|Entity[]; if (typeof target === "string") { return this.getRepository(target).remove(entity); } else { if (target instanceof Array) { return this.getRepository(target[0].constructor).remove(entity as Entity[]); } else { return this.getRepository(target.constructor).remove(entity as Entity); } } } /** * Finds entities that match given conditions. */ find(entityClass: ObjectType): Promise; /** * Finds entities that match given conditions. */ find(entityClass: ObjectType, conditions: ObjectLiteral): Promise; /** * Finds entities that match given conditions. */ find(entityClass: ObjectType, options: FindOptions): Promise; /** * Finds entities that match given conditions. */ find(entityClass: ObjectType, conditions: ObjectLiteral, options: FindOptions): Promise; /** * Finds entities that match given conditions. */ find(entityClass: ObjectType, conditionsOrFindOptions?: ObjectLiteral|FindOptions, options?: FindOptions): Promise { if (conditionsOrFindOptions && options) { return this.getRepository(entityClass).find(conditionsOrFindOptions, options); } else if (conditionsOrFindOptions) { return this.getRepository(entityClass).find(conditionsOrFindOptions); } else { return this.getRepository(entityClass).find(); } } /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (maxResults, firstResult) options. */ findAndCount(entityClass: ObjectType): Promise<[ Entity[], number ]>; /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (maxResults, firstResult) options. */ findAndCount(entityClass: ObjectType, conditions: ObjectLiteral): Promise<[ Entity[], number ]>; /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (maxResults, firstResult) options. */ findAndCount(entityClass: ObjectType, options: FindOptions): Promise<[ Entity[], number ]>; /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (maxResults, firstResult) options. */ findAndCount(entityClass: ObjectType, conditions: ObjectLiteral, options: FindOptions): Promise<[ Entity[], number ]>; /** * Finds entities that match given conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (maxResults, firstResult) options. */ findAndCount(entityClass: ObjectType, conditionsOrFindOptions?: ObjectLiteral|FindOptions, options?: FindOptions): Promise<[Entity[], number]> { if (conditionsOrFindOptions && options) { return this.getRepository(entityClass).findAndCount(conditionsOrFindOptions, options); } else if (conditionsOrFindOptions) { return this.getRepository(entityClass).findAndCount(conditionsOrFindOptions); } else { return this.getRepository(entityClass).findAndCount(); } } /** * Finds first entity that matches given conditions. */ findOne(entityClass: ObjectType): Promise; /** * Finds first entity that matches given conditions. */ findOne(entityClass: ObjectType, conditions: ObjectLiteral): Promise; /** * Finds first entity that matches given conditions. */ findOne(entityClass: ObjectType, options: FindOptions): Promise; /** * Finds first entity that matches given conditions. */ findOne(entityClass: ObjectType, conditions: ObjectLiteral, options: FindOptions): Promise; /** * Finds first entity that matches given conditions. */ findOne(entityClass: ObjectType, conditionsOrFindOptions?: ObjectLiteral|FindOptions, options?: FindOptions): Promise { if (conditionsOrFindOptions && options) { return this.getRepository(entityClass).findOne(conditionsOrFindOptions, options); } else if (conditionsOrFindOptions) { return this.getRepository(entityClass).findOne(conditionsOrFindOptions); } else { return this.getRepository(entityClass).findOne(); } } /** * Finds entity with given id. */ findOneById(entityClass: ObjectType, id: any, options?: FindOptions): Promise { return this.getRepository(entityClass).findOneById(id, options); } /** * Executes raw SQL query and returns raw database results. */ async query(query: string): Promise { if (this.queryRunnerProvider && this.queryRunnerProvider.isReleased) throw new QueryRunnerProviderAlreadyReleasedError(); const queryRunnerProvider = this.queryRunnerProvider || new QueryRunnerProvider(this.connection.driver); const queryRunner = await queryRunnerProvider.provide(); try { return await queryRunner.query(query); // await is needed here because we are using finally } finally { await queryRunnerProvider.release(queryRunner); } } /** * Wraps given function execution (and all operations made there) in a transaction. * All database operations must be executed using provided entity manager. */ async transaction(runInTransaction: (entityManger: EntityManager) => Promise): Promise { if (this.queryRunnerProvider && this.queryRunnerProvider.isReleased) throw new QueryRunnerProviderAlreadyReleasedError(); const queryRunnerProvider = this.queryRunnerProvider || new QueryRunnerProvider(this.connection.driver, true); const queryRunner = await queryRunnerProvider.provide(); const transactionEntityManager = new EntityManager(this.connection, queryRunnerProvider); try { await queryRunner.beginTransaction(); const result = await runInTransaction(transactionEntityManager); await queryRunner.commitTransaction(); return result; } catch (err) { await queryRunner.rollbackTransaction(); throw err; } finally { await queryRunnerProvider.release(queryRunner); if (!this.queryRunnerProvider) // if we used a new query runner provider then release it await queryRunnerProvider.releaseReused(); } } }