UNPKG

typeorm

Version:

Data-Mapper ORM for TypeScript and ES2021+. Supports MySQL/MariaDB, PostgreSQL, MS SQL Server, Oracle, SAP HANA, SQLite, MongoDB databases.

854 lines (852 loc) • 37.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EntityManager = void 0; const EntityNotFoundError_1 = require("../error/EntityNotFoundError"); const QueryRunnerProviderAlreadyReleasedError_1 = require("../error/QueryRunnerProviderAlreadyReleasedError"); const NoNeedToReleaseEntityManagerError_1 = require("../error/NoNeedToReleaseEntityManagerError"); const MongoRepository_1 = require("../repository/MongoRepository"); const TreeRepository_1 = require("../repository/TreeRepository"); const Repository_1 = require("../repository/Repository"); const FindOptionsUtils_1 = require("../find-options/FindOptionsUtils"); const PlainObjectToNewEntityTransformer_1 = require("../query-builder/transformer/PlainObjectToNewEntityTransformer"); const PlainObjectToDatabaseEntityTransformer_1 = require("../query-builder/transformer/PlainObjectToDatabaseEntityTransformer"); const error_1 = require("../error"); const AbstractRepository_1 = require("../repository/AbstractRepository"); const EntityPersistExecutor_1 = require("../persistence/EntityPersistExecutor"); const ObjectUtils_1 = require("../util/ObjectUtils"); const globals_1 = require("../globals"); const InstanceChecker_1 = require("../util/InstanceChecker"); const SqlTagUtils_1 = require("../util/SqlTagUtils"); const OrmUtils_1 = require("../util/OrmUtils"); /** * Entity manager supposed to work with any entity, automatically find its repository and call its methods, * whatever entity type are you passing. */ class EntityManager { // ------------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------------- constructor(connection, queryRunner) { this["@instanceof"] = Symbol.for("EntityManager"); // ------------------------------------------------------------------------- // Protected Properties // ------------------------------------------------------------------------- /** * Once created and then reused by repositories. * Created as a future replacement for the #repositories to provide a bit more perf optimization. */ this.repositories = new Map(); /** * Once created and then reused by repositories. */ this.treeRepositories = []; /** * Plain to object transformer used in create and merge operations. */ this.plainObjectToEntityTransformer = new PlainObjectToNewEntityTransformer_1.PlainObjectToNewEntityTransformer(); this.connection = connection; if (queryRunner) { this.queryRunner = queryRunner; // dynamic: this.queryRunner = manager; ObjectUtils_1.ObjectUtils.assign(this.queryRunner, { manager: this }); } } /** * Wraps given function execution (and all operations made there) in a transaction. * All database operations must be executed using provided entity manager. */ async transaction(isolationOrRunInTransaction, runInTransactionParam) { const isolation = typeof isolationOrRunInTransaction === "string" ? isolationOrRunInTransaction : undefined; const runInTransaction = typeof isolationOrRunInTransaction === "function" ? isolationOrRunInTransaction : runInTransactionParam; if (!runInTransaction) { throw new error_1.TypeORMError(`Transaction method requires callback in second parameter if isolation level is supplied.`); } if (this.queryRunner && this.queryRunner.isReleased) throw new QueryRunnerProviderAlreadyReleasedError_1.QueryRunnerProviderAlreadyReleasedError(); // if query runner is already defined in this class, it means this entity manager was already created for a single connection // if its not defined we create a new query runner - single connection where we'll execute all our operations const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { await queryRunner.startTransaction(isolation); const result = await runInTransaction(queryRunner.manager); await queryRunner.commitTransaction(); return result; } catch (err) { try { // we throw original error even if rollback thrown an error await queryRunner.rollbackTransaction(); } catch (rollbackError) { } throw err; } finally { if (!this.queryRunner) // if we used a new query runner provider then release it await queryRunner.release(); } } /** * Executes raw SQL query and returns raw database results. * * @see [Official docs](https://typeorm.io/docs/Working%20with%20Entity%20Manager/entity-manager-api/) for examples. */ async query(query, parameters) { return this.connection.query(query, parameters, this.queryRunner); } /** * Tagged template function that executes raw SQL query and returns raw database results. * Template expressions are automatically transformed into database parameters. * Raw query execution is supported only by relational databases (MongoDB is not supported). * Note: Don't call this as a regular function, it is meant to be used with backticks to tag a template literal. * Example: entityManager.sql`SELECT * FROM table_name WHERE id = ${id}` */ async sql(strings, ...values) { const { query, parameters } = (0, SqlTagUtils_1.buildSqlTag)({ driver: this.connection.driver, strings: strings, expressions: values, }); return await this.query(query, parameters); } /** * Creates a new query builder that can be used to build a SQL query. */ createQueryBuilder(entityClass, alias, queryRunner) { if (alias) { return this.connection.createQueryBuilder(entityClass, alias, queryRunner || this.queryRunner); } else { return this.connection.createQueryBuilder(entityClass || queryRunner || this.queryRunner); } } /** * Checks if entity has an id by its Function type or schema name. */ hasId(targetOrEntity, maybeEntity) { const target = arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor; const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; const metadata = this.connection.getMetadata(target); return metadata.hasId(entity); } /** * Gets entity mixed id. */ getId(targetOrEntity, maybeEntity) { const target = arguments.length === 2 ? targetOrEntity : targetOrEntity.constructor; const entity = arguments.length === 2 ? maybeEntity : targetOrEntity; const metadata = this.connection.getMetadata(target); return metadata.getEntityIdMixedMap(entity); } /** * Creates a new entity instance or instances. * Can copy properties from the given object into new entities. */ create(entityClass, plainObjectOrObjects) { const metadata = this.connection.getMetadata(entityClass); if (!plainObjectOrObjects) return metadata.create(this.queryRunner); if (Array.isArray(plainObjectOrObjects)) return plainObjectOrObjects.map((plainEntityLike) => this.create(entityClass, plainEntityLike)); const mergeIntoEntity = metadata.create(this.queryRunner); this.plainObjectToEntityTransformer.transform(mergeIntoEntity, plainObjectOrObjects, metadata, true); return mergeIntoEntity; } /** * Merges two entities into one new entity. */ merge(entityClass, mergeIntoEntity, ...entityLikes) { // todo: throw exception if entity manager is released const metadata = this.connection.getMetadata(entityClass); entityLikes.forEach((object) => this.plainObjectToEntityTransformer.transform(mergeIntoEntity, object, metadata)); return mergeIntoEntity; } /** * Creates a new entity from the given plain javascript object. If entity already exist in the database, then * it loads it (and everything related to it), replaces all values with the new ones from the given object * and returns this new entity. This new entity is actually a loaded from the db entity with all properties * replaced from the new object. */ async preload(entityClass, entityLike) { const metadata = this.connection.getMetadata(entityClass); const plainObjectToDatabaseEntityTransformer = new PlainObjectToDatabaseEntityTransformer_1.PlainObjectToDatabaseEntityTransformer(this.connection.manager); const transformedEntity = await plainObjectToDatabaseEntityTransformer.transform(entityLike, metadata); if (transformedEntity) return this.merge(entityClass, transformedEntity, entityLike); return undefined; } /** * Saves a given entity in the database. */ save(targetOrEntity, maybeEntityOrOptions, maybeOptions) { // normalize mixed parameters let target = arguments.length > 1 && (typeof targetOrEntity === "function" || InstanceChecker_1.InstanceChecker.isEntitySchema(targetOrEntity) || typeof targetOrEntity === "string") ? targetOrEntity : undefined; const entity = target ? maybeEntityOrOptions : targetOrEntity; const options = target ? maybeOptions : maybeEntityOrOptions; if (InstanceChecker_1.InstanceChecker.isEntitySchema(target)) target = target.options.name; // if user passed empty array of entities then we don't need to do anything if (Array.isArray(entity) && entity.length === 0) return Promise.resolve(entity); // execute save operation return new EntityPersistExecutor_1.EntityPersistExecutor(this.connection, this.queryRunner, "save", target, entity, options) .execute() .then(() => entity); } /** * Removes a given entity from the database. */ remove(targetOrEntity, maybeEntityOrOptions, maybeOptions) { // normalize mixed parameters const target = arguments.length > 1 && (typeof targetOrEntity === "function" || InstanceChecker_1.InstanceChecker.isEntitySchema(targetOrEntity) || typeof targetOrEntity === "string") ? targetOrEntity : undefined; const entity = target ? maybeEntityOrOptions : targetOrEntity; const options = target ? maybeOptions : maybeEntityOrOptions; // if user passed empty array of entities then we don't need to do anything if (Array.isArray(entity) && entity.length === 0) return Promise.resolve(entity); // execute save operation return new EntityPersistExecutor_1.EntityPersistExecutor(this.connection, this.queryRunner, "remove", target, entity, options) .execute() .then(() => entity); } /** * Records the delete date of one or many given entities. */ softRemove(targetOrEntity, maybeEntityOrOptions, maybeOptions) { // normalize mixed parameters let target = arguments.length > 1 && (typeof targetOrEntity === "function" || InstanceChecker_1.InstanceChecker.isEntitySchema(targetOrEntity) || typeof targetOrEntity === "string") ? targetOrEntity : undefined; const entity = target ? maybeEntityOrOptions : targetOrEntity; const options = target ? maybeOptions : maybeEntityOrOptions; if (InstanceChecker_1.InstanceChecker.isEntitySchema(target)) target = target.options.name; // if user passed empty array of entities then we don't need to do anything if (Array.isArray(entity) && entity.length === 0) return Promise.resolve(entity); // execute soft-remove operation return new EntityPersistExecutor_1.EntityPersistExecutor(this.connection, this.queryRunner, "soft-remove", target, entity, options) .execute() .then(() => entity); } /** * Recovers one or many given entities. */ recover(targetOrEntity, maybeEntityOrOptions, maybeOptions) { // normalize mixed parameters let target = arguments.length > 1 && (typeof targetOrEntity === "function" || InstanceChecker_1.InstanceChecker.isEntitySchema(targetOrEntity) || typeof targetOrEntity === "string") ? targetOrEntity : undefined; const entity = target ? maybeEntityOrOptions : targetOrEntity; const options = target ? maybeOptions : maybeEntityOrOptions; if (InstanceChecker_1.InstanceChecker.isEntitySchema(target)) target = target.options.name; // if user passed empty array of entities then we don't need to do anything if (Array.isArray(entity) && entity.length === 0) return Promise.resolve(entity); // execute recover operation return new EntityPersistExecutor_1.EntityPersistExecutor(this.connection, this.queryRunner, "recover", target, entity, options) .execute() .then(() => entity); } /** * Inserts a given entity into the database. * Unlike save method executes a primitive operation without cascades, relations and other operations included. * Executes fast and efficient INSERT query. * Does not check if entity exist in the database, so query will fail if duplicate entity is being inserted. * You can execute bulk inserts using this method. */ async insert(target, entity) { return this.createQueryBuilder() .insert() .into(target) .values(entity) .execute(); } async upsert(target, entityOrEntities, conflictPathsOrOptions) { const metadata = this.connection.getMetadata(target); let options; if (Array.isArray(conflictPathsOrOptions)) { options = { conflictPaths: conflictPathsOrOptions, }; } else { options = conflictPathsOrOptions; } let entities; if (!Array.isArray(entityOrEntities)) { entities = [entityOrEntities]; } else { entities = entityOrEntities; } const conflictColumns = metadata.mapPropertyPathsToColumns(Array.isArray(options.conflictPaths) ? options.conflictPaths : Object.keys(options.conflictPaths)); const overwriteColumns = metadata.columns.filter((col) => !conflictColumns.includes(col) && entities.some((entity) => typeof col.getEntityValue(entity) !== "undefined")); return this.createQueryBuilder() .insert() .into(target) .values(entities) .orUpdate([...conflictColumns, ...overwriteColumns].map((col) => col.databaseName), conflictColumns.map((col) => col.databaseName), { skipUpdateIfNoValuesChanged: options.skipUpdateIfNoValuesChanged, indexPredicate: options.indexPredicate, upsertType: options.upsertType || this.connection.driver.supportedUpsertTypes[0], }) .execute(); } /** * Updates entity partially. Entity can be found by a given condition(s). * Unlike save method executes a primitive operation without cascades, relations and other operations included. * Executes fast and efficient UPDATE query. * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ update(target, criteria, partialEntity) { // if user passed empty criteria or empty list of criterias, then throw an error if (OrmUtils_1.OrmUtils.isCriteriaNullOrEmpty(criteria)) { return Promise.reject(new error_1.TypeORMError(`Empty criteria(s) are not allowed for the update method.`)); } if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) { return this.createQueryBuilder() .update(target) .set(partialEntity) .whereInIds(criteria) .execute(); } else { return this.createQueryBuilder() .update(target) .set(partialEntity) .where(criteria) .execute(); } } /** * Updates all entities of target type, setting fields from supplied partial entity. * This is a primitive operation without cascades, relations or other operations included. * Executes fast and efficient UPDATE query without WHERE clause. * * WARNING! This method updates ALL rows in the target table. */ updateAll(target, partialEntity) { return this.createQueryBuilder() .update(target) .set(partialEntity) .execute(); } /** * Deletes entities by a given condition(s). * Unlike save method executes a primitive operation without cascades, relations and other operations included. * Executes fast and efficient DELETE query. * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ delete(targetOrEntity, criteria) { // if user passed empty criteria or empty list of criterias, then throw an error if (OrmUtils_1.OrmUtils.isCriteriaNullOrEmpty(criteria)) { return Promise.reject(new error_1.TypeORMError(`Empty criteria(s) are not allowed for the delete method.`)); } if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) { return this.createQueryBuilder() .delete() .from(targetOrEntity) .whereInIds(criteria) .execute(); } else { return this.createQueryBuilder() .delete() .from(targetOrEntity) .where(criteria) .execute(); } } /** * Deletes all entities of target type. * This is a primitive operation without cascades, relations or other operations included. * Executes fast and efficient DELETE query without WHERE clause. * * WARNING! This method deletes ALL rows in the target table. */ deleteAll(targetOrEntity) { return this.createQueryBuilder().delete().from(targetOrEntity).execute(); } /** * Records the delete date of entities by a given condition(s). * Unlike save method executes a primitive operation without cascades, relations and other operations included. * Executes fast and efficient UPDATE query. * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ softDelete(targetOrEntity, criteria) { // if user passed empty criteria or empty list of criterias, then throw an error if (OrmUtils_1.OrmUtils.isCriteriaNullOrEmpty(criteria)) { return Promise.reject(new error_1.TypeORMError(`Empty criteria(s) are not allowed for the softDelete method.`)); } if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) { return this.createQueryBuilder() .softDelete() .from(targetOrEntity) .whereInIds(criteria) .execute(); } else { return this.createQueryBuilder() .softDelete() .from(targetOrEntity) .where(criteria) .execute(); } } /** * Restores entities by a given condition(s). * Unlike save method executes a primitive operation without cascades, relations and other operations included. * Executes fast and efficient UPDATE query. * Does not check if entity exist in the database. * Condition(s) cannot be empty. */ restore(targetOrEntity, criteria) { // if user passed empty criteria or empty list of criterias, then throw an error if (OrmUtils_1.OrmUtils.isCriteriaNullOrEmpty(criteria)) { return Promise.reject(new error_1.TypeORMError(`Empty criteria(s) are not allowed for the restore method.`)); } if (OrmUtils_1.OrmUtils.isPrimitiveCriteria(criteria)) { return this.createQueryBuilder() .restore() .from(targetOrEntity) .whereInIds(criteria) .execute(); } else { return this.createQueryBuilder() .restore() .from(targetOrEntity) .where(criteria) .execute(); } } /** * Checks whether any entity exists with the given options. */ exists(entityClass, options) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, FindOptionsUtils_1.FindOptionsUtils.extractFindManyOptionsAlias(options) || metadata.name) .setFindOptions(options || {}) .getExists(); } /** * Checks whether any entity exists with the given conditions. */ async existsBy(entityClass, where) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where }) .getExists(); } /** * Counts entities that match given options. * Useful for pagination. */ count(entityClass, options) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, FindOptionsUtils_1.FindOptionsUtils.extractFindManyOptionsAlias(options) || metadata.name) .setFindOptions(options || {}) .getCount(); } /** * Counts entities that match given conditions. * Useful for pagination. */ countBy(entityClass, where) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where }) .getCount(); } /** * Return the SUM of a column */ sum(entityClass, columnName, where) { return this.callAggregateFun(entityClass, "SUM", columnName, where); } /** * Return the AVG of a column */ average(entityClass, columnName, where) { return this.callAggregateFun(entityClass, "AVG", columnName, where); } /** * Return the MIN of a column */ minimum(entityClass, columnName, where) { return this.callAggregateFun(entityClass, "MIN", columnName, where); } /** * Return the MAX of a column */ maximum(entityClass, columnName, where) { return this.callAggregateFun(entityClass, "MAX", columnName, where); } async callAggregateFun(entityClass, fnName, columnName, where = {}) { const metadata = this.connection.getMetadata(entityClass); const column = metadata.columns.find((item) => item.propertyPath === columnName); if (!column) { throw new error_1.TypeORMError(`Column "${columnName}" was not found in table "${metadata.name}"`); } const result = await this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where }) .select(`${fnName}(${this.connection.driver.escape(column.databaseName)})`, fnName) .getRawOne(); return result[fnName] === null ? null : parseFloat(result[fnName]); } /** * Finds entities that match given find options. */ async find(entityClass, options) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, FindOptionsUtils_1.FindOptionsUtils.extractFindManyOptionsAlias(options) || metadata.name) .setFindOptions(options || {}) .getMany(); } /** * Finds entities that match given find options. */ async findBy(entityClass, where) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where: where }) .getMany(); } /** * Finds entities that match given find options. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ findAndCount(entityClass, options) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, FindOptionsUtils_1.FindOptionsUtils.extractFindManyOptionsAlias(options) || metadata.name) .setFindOptions(options || {}) .getManyAndCount(); } /** * Finds entities that match given WHERE conditions. * Also counts all entities that match given conditions, * but ignores pagination settings (from and take options). */ findAndCountBy(entityClass, where) { const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where }) .getManyAndCount(); } /** * Finds entities with ids. * Optionally find options or conditions can be applied. * * @deprecated use `findBy` method instead in conjunction with `In` operator, for example: * * .findBy({ * id: In([1, 2, 3]) * }) */ async findByIds(entityClass, ids) { // if no ids passed, no need to execute a query - just return an empty array of values if (!ids.length) return Promise.resolve([]); const metadata = this.connection.getMetadata(entityClass); return this.createQueryBuilder(entityClass, metadata.name) .andWhereInIds(ids) .getMany(); } /** * Finds first entity by a given find options. * If entity was not found in the database - returns null. */ async findOne(entityClass, options) { const metadata = this.connection.getMetadata(entityClass); // prepare alias for built query let alias = metadata.name; if (options && options.join) { alias = options.join.alias; } if (!options.where) { throw new Error(`You must provide selection conditions in order to find a single row.`); } // create query builder and apply find options return this.createQueryBuilder(entityClass, alias) .setFindOptions({ ...options, take: 1, }) .getOne(); } /** * Finds first entity that matches given where condition. * If entity was not found in the database - returns null. */ async findOneBy(entityClass, where) { const metadata = this.connection.getMetadata(entityClass); // create query builder and apply find options return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ where, take: 1, }) .getOne(); } /** * Finds first entity that matches given id. * If entity was not found in the database - returns null. * * @deprecated use `findOneBy` method instead in conjunction with `In` operator, for example: * * .findOneBy({ * id: 1 // where "id" is your primary column name * }) */ async findOneById(entityClass, id) { const metadata = this.connection.getMetadata(entityClass); // create query builder and apply find options return this.createQueryBuilder(entityClass, metadata.name) .setFindOptions({ take: 1, }) .whereInIds(metadata.ensureEntityIdMap(id)) .getOne(); } /** * Finds first entity by a given find options. * If entity was not found in the database - rejects with error. */ async findOneOrFail(entityClass, options) { return this.findOne(entityClass, options).then((value) => { if (value === null) { return Promise.reject(new EntityNotFoundError_1.EntityNotFoundError(entityClass, options)); } return Promise.resolve(value); }); } /** * Finds first entity that matches given where condition. * If entity was not found in the database - rejects with error. */ async findOneByOrFail(entityClass, where) { return this.findOneBy(entityClass, where).then((value) => { if (value === null) { return Promise.reject(new EntityNotFoundError_1.EntityNotFoundError(entityClass, where)); } return Promise.resolve(value); }); } /** * Clears all the data from the given table (truncates/drops it). * * Note: this method uses TRUNCATE and may not work as you expect in transactions on some platforms. * @see https://stackoverflow.com/a/5972738/925151 */ async clear(entityClass) { const metadata = this.connection.getMetadata(entityClass); const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { return await queryRunner.clearTable(metadata.tablePath); // await is needed here because we are using finally } finally { if (!this.queryRunner) await queryRunner.release(); } } /** * Increments some column by provided value of the entities matched given conditions. */ async increment(entityClass, conditions, propertyPath, value) { const metadata = this.connection.getMetadata(entityClass); const column = metadata.findColumnWithPropertyPath(propertyPath); if (!column) throw new error_1.TypeORMError(`Column ${propertyPath} was not found in ${metadata.targetName} entity.`); if (isNaN(Number(value))) throw new error_1.TypeORMError(`Value "${value}" is not a number.`); // convert possible embedded path "social.likes" into object { social: { like: () => value } } const values = propertyPath .split(".") .reduceRight((value, key) => ({ [key]: value }), () => this.connection.driver.escape(column.databaseName) + " + " + value); return this.createQueryBuilder(entityClass, "entity") .update(entityClass) .set(values) .where(conditions) .execute(); } /** * Decrements some column by provided value of the entities matched given conditions. */ async decrement(entityClass, conditions, propertyPath, value) { const metadata = this.connection.getMetadata(entityClass); const column = metadata.findColumnWithPropertyPath(propertyPath); if (!column) throw new error_1.TypeORMError(`Column ${propertyPath} was not found in ${metadata.targetName} entity.`); if (isNaN(Number(value))) throw new error_1.TypeORMError(`Value "${value}" is not a number.`); // convert possible embedded path "social.likes" into object { social: { like: () => value } } const values = propertyPath .split(".") .reduceRight((value, key) => ({ [key]: value }), () => this.connection.driver.escape(column.databaseName) + " - " + value); return this.createQueryBuilder(entityClass, "entity") .update(entityClass) .set(values) .where(conditions) .execute(); } /** * Gets repository for the given entity class or name. * If single database connection mode is used, then repository is obtained from the * repository aggregator, where each repository is individually created for this entity manager. * When single database connection is not used, repository is being obtained from the connection. */ getRepository(target) { // find already created repository instance and return it if found const repoFromMap = this.repositories.get(target); if (repoFromMap) return repoFromMap; // if repository was not found then create it, store its instance and return it if (this.connection.driver.options.type === "mongodb") { const newRepository = new MongoRepository_1.MongoRepository(target, this, this.queryRunner); this.repositories.set(target, newRepository); return newRepository; } else { const newRepository = new Repository_1.Repository(target, this, this.queryRunner); this.repositories.set(target, newRepository); return newRepository; } } /** * Gets tree repository for the given entity class or name. * If single database connection mode is used, then repository is obtained from the * repository aggregator, where each repository is individually created for this entity manager. * When single database connection is not used, repository is being obtained from the connection. */ getTreeRepository(target) { // tree tables aren't supported by some drivers (mongodb) if (this.connection.driver.treeSupport === false) throw new error_1.TreeRepositoryNotSupportedError(this.connection.driver); // find already created repository instance and return it if found const repository = this.treeRepositories.find((repository) => repository.target === target); if (repository) return repository; // check if repository is real tree repository const newRepository = new TreeRepository_1.TreeRepository(target, this, this.queryRunner); this.treeRepositories.push(newRepository); return newRepository; } /** * Gets mongodb repository for the given entity class. */ getMongoRepository(target) { return this.connection.getMongoRepository(target); } /** * Creates a new repository instance out of a given Repository and * sets current EntityManager instance to it. Used to work with custom repositories * in transactions. */ withRepository(repository) { const repositoryConstructor = repository.constructor; const { target, manager, queryRunner, ...otherRepositoryProperties } = repository; return Object.assign(new repositoryConstructor(repository.target, this), { ...otherRepositoryProperties, }); } /** * Gets custom entity repository marked with @EntityRepository decorator. * * @deprecated use Repository.extend to create custom repositories */ getCustomRepository(customRepository) { const entityRepositoryMetadataArgs = (0, globals_1.getMetadataArgsStorage)().entityRepositories.find((repository) => { return (repository.target === (typeof customRepository === "function" ? customRepository : customRepository.constructor)); }); if (!entityRepositoryMetadataArgs) throw new error_1.CustomRepositoryNotFoundError(customRepository); const entityMetadata = entityRepositoryMetadataArgs.entity ? this.connection.getMetadata(entityRepositoryMetadataArgs.entity) : undefined; const entityRepositoryInstance = new entityRepositoryMetadataArgs.target(this, entityMetadata); // NOTE: dynamic access to protected properties. We need this to prevent unwanted properties in those classes to be exposed, // however we need these properties for internal work of the class if (entityRepositoryInstance instanceof AbstractRepository_1.AbstractRepository) { if (!entityRepositoryInstance["manager"]) entityRepositoryInstance["manager"] = this; } else { if (!entityMetadata) throw new error_1.CustomRepositoryCannotInheritRepositoryError(customRepository); entityRepositoryInstance["manager"] = this; entityRepositoryInstance["metadata"] = entityMetadata; } return entityRepositoryInstance; } /** * Releases all resources used by entity manager. * This is used when entity manager is created with a single query runner, * and this single query runner needs to be released after job with entity manager is done. */ async release() { if (!this.queryRunner) throw new NoNeedToReleaseEntityManagerError_1.NoNeedToReleaseEntityManagerError(); return this.queryRunner.release(); } } exports.EntityManager = EntityManager; //# sourceMappingURL=EntityManager.js.map