mirror of
https://github.com/typeorm/typeorm.git
synced 2025-12-08 21:26:23 +00:00
fixed issues with query runner manager and repo instances
This commit is contained in:
parent
e7c516e7f4
commit
555cd69f46
@ -29,6 +29,7 @@ import {DriverFactory} from "../driver/DriverFactory";
|
||||
import {ConnectionMetadataBuilder} from "./ConnectionMetadataBuilder";
|
||||
import {QueryRunner} from "../query-runner/QueryRunner";
|
||||
import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder";
|
||||
import {SqliteDriver} from "../driver/sqlite/SqliteDriver";
|
||||
|
||||
/**
|
||||
* Connection is a single database ORM connection to a specific DBMS database.
|
||||
@ -269,7 +270,7 @@ export class Connection {
|
||||
* Gets repository for the given entity.
|
||||
*/
|
||||
getRepository<Entity>(target: ObjectType<Entity>|string): Repository<Entity> {
|
||||
return this.getMetadata(target).repository;
|
||||
return this.manager.getRepository(target);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -277,17 +278,7 @@ export class Connection {
|
||||
* Only tree-type entities can have a TreeRepository, like ones decorated with @ClosureEntity decorator.
|
||||
*/
|
||||
getTreeRepository<Entity>(target: ObjectType<Entity>|string): TreeRepository<Entity> {
|
||||
if (this.driver instanceof MongoDriver)
|
||||
throw new Error(`You cannot use getTreeRepository for MongoDB connections.`);
|
||||
|
||||
if (!this.hasMetadata(target))
|
||||
throw new RepositoryNotFoundError(this.name, target);
|
||||
|
||||
const repository = this.getMetadata(target).repository;
|
||||
if (!(repository instanceof TreeRepository))
|
||||
throw new RepositoryNotTreeError(target);
|
||||
|
||||
return repository;
|
||||
return this.manager.getTreeRepository(target);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,10 +289,7 @@ export class Connection {
|
||||
if (!(this.driver instanceof MongoDriver))
|
||||
throw new Error(`You can use getMongoRepository only for MongoDB connections.`);
|
||||
|
||||
if (!this.hasMetadata(target))
|
||||
throw new RepositoryNotFoundError(this.name, target);
|
||||
|
||||
return this.getMetadata(target).repository as MongoRepository<Entity>;
|
||||
return this.manager.getRepository(target) as MongoRepository<Entity>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -315,32 +303,8 @@ export class Connection {
|
||||
* Wraps given function execution (and all operations made there) into a transaction.
|
||||
* All database operations must be executed using provided entity manager.
|
||||
*/
|
||||
async transaction(runInTransaction: (entityManger: EntityManager) => Promise<any>, queryRunner?: QueryRunner): Promise<any> {
|
||||
if (this instanceof MongoEntityManager)
|
||||
throw new Error(`Transactions aren't supported by MongoDB.`);
|
||||
|
||||
if (queryRunner && queryRunner.isReleased)
|
||||
throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
|
||||
const usedQueryRunner = queryRunner || this.createQueryRunner();
|
||||
const transactionEntityManager = new EntityManagerFactory().create(this, usedQueryRunner);
|
||||
|
||||
try {
|
||||
await usedQueryRunner.startTransaction();
|
||||
const result = await runInTransaction(transactionEntityManager);
|
||||
await usedQueryRunner.commitTransaction();
|
||||
return result;
|
||||
|
||||
} catch (err) {
|
||||
try { // we throw original error even if rollback thrown an error
|
||||
await usedQueryRunner.rollbackTransaction();
|
||||
} catch (rollbackError) { }
|
||||
throw err;
|
||||
|
||||
} finally {
|
||||
if (!queryRunner) // if we used a new query runner provider then release it
|
||||
await usedQueryRunner.release();
|
||||
}
|
||||
async transaction(runInTransaction: (entityManger: EntityManager) => Promise<any>): Promise<any> {
|
||||
return this.manager.transaction(runInTransaction);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,26 +370,31 @@ export class Connection {
|
||||
* This may be useful if you want to perform all db queries within one connection.
|
||||
* After finishing with entity manager, don't forget to release it (to release database connection back to pool).
|
||||
*/
|
||||
createIsolatedManager(queryRunner?: QueryRunner): EntityManager {
|
||||
if (queryRunner && queryRunner.manager && queryRunner.manager !== this.manager)
|
||||
return queryRunner.manager;
|
||||
createIsolatedManager(): EntityManager {
|
||||
if (this.driver instanceof MongoDriver)
|
||||
throw new Error(`You can use createIsolatedManager only for non MongoDB connections.`);
|
||||
|
||||
if (!queryRunner)
|
||||
queryRunner = this.createQueryRunner();
|
||||
// sqlite has a single query runner and does not support isolated managers
|
||||
if (this.driver instanceof SqliteDriver)
|
||||
return this.manager;
|
||||
|
||||
Object.assign(queryRunner, { manager: new EntityManagerFactory().create(this, queryRunner) });
|
||||
return queryRunner.manager;
|
||||
return new EntityManagerFactory().create(this, this.driver.createQueryRunner());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new repository with a single opened connection to the database.
|
||||
* This may be useful if you want to perform all db queries within one connection.
|
||||
* After finishing with entity manager, don't forget to release it (to release database connection back to pool).
|
||||
* After finishing with repository, don't forget to release its query runner (to release database connection back to pool).
|
||||
*/
|
||||
createIsolatedRepository<Entity>(entityClassOrName: ObjectType<Entity>|string, queryRunner?: QueryRunner): Repository<Entity> {
|
||||
if (!queryRunner)
|
||||
queryRunner = this.createQueryRunner();
|
||||
return new RepositoryFactory().create(this, this.getMetadata(entityClassOrName), queryRunner);
|
||||
createIsolatedRepository<Entity>(entityClassOrName: ObjectType<Entity>|string): Repository<Entity> {
|
||||
if (this.driver instanceof MongoDriver)
|
||||
throw new Error(`You can use createIsolatedRepository only for non MongoDB connections.`);
|
||||
|
||||
// sqlite has a single query runner and does not support isolated repositories
|
||||
if (this.driver instanceof SqliteDriver)
|
||||
return this.manager.getRepository(entityClassOrName);
|
||||
|
||||
return this.createIsolatedManager().getRepository(entityClassOrName);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@ -465,7 +434,6 @@ export class Connection {
|
||||
protected buildMetadatas(): void {
|
||||
|
||||
const connectionMetadataBuilder = new ConnectionMetadataBuilder(this);
|
||||
const repositoryFactory = new RepositoryFactory();
|
||||
const entityMetadataValidator = new EntityMetadataValidator();
|
||||
|
||||
// create subscribers instances if they are not disallowed from high-level (for example they can disallowed from migrations run process)
|
||||
@ -482,11 +450,6 @@ export class Connection {
|
||||
const migrations = connectionMetadataBuilder.buildMigrations(this.options.migrations || []);
|
||||
Object.assign(this, { migrations: migrations });
|
||||
|
||||
// initialize repositories for all entity metadatas
|
||||
this.entityMetadatas.forEach(metadata => {
|
||||
metadata.repository = repositoryFactory.create(this, metadata);
|
||||
});
|
||||
|
||||
// validate all created entity metadatas to make sure user created entities are valid and correct
|
||||
entityMetadataValidator.validateMany(this.entityMetadatas);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import {ObjectLiteral} from "../common/ObjectLiteral";
|
||||
import {ColumnType} from "./types/ColumnTypes";
|
||||
import {MappedColumnTypes} from "./types/MappedColumnTypes";
|
||||
import {SchemaBuilder} from "../schema-builder/SchemaBuilder";
|
||||
import {EntityManager} from "../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "./types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -12,6 +12,7 @@ import {MongoConnectionOptions} from "./MongoConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {MongoSchemaBuilder} from "../../schema-builder/MongoSchemaBuilder";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -54,11 +54,6 @@ export class MongoQueryRunner implements QueryRunner {
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -83,7 +78,6 @@ export class MongoQueryRunner implements QueryRunner {
|
||||
|
||||
constructor(connection: Connection, databaseConnection: Db) {
|
||||
this.connection = connection;
|
||||
this.manager = connection.manager;
|
||||
this.databaseConnection = databaseConnection;
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
|
||||
import {MysqlConnectionOptions} from "./MysqlConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -23,16 +23,16 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: MysqlDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -72,9 +72,9 @@ export class MysqlQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: MysqlDriver) {
|
||||
constructor(driver: MysqlDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -12,6 +12,7 @@ import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
|
||||
import {OracleConnectionOptions} from "./OracleConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -25,16 +25,16 @@ export class OracleQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: OracleDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -74,9 +74,9 @@ export class OracleQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: OracleDriver) {
|
||||
constructor(driver: OracleDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -14,6 +14,7 @@ import {PostgresConnectionOptions} from "./PostgresConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -23,16 +23,16 @@ export class PostgresQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: PostgresDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -77,9 +77,9 @@ export class PostgresQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: PostgresDriver) {
|
||||
constructor(driver: PostgresDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -12,6 +12,7 @@ import {SqliteConnectionOptions} from "./SqliteConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {QueryRunner} from "../../query-runner/QueryRunner";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -27,16 +27,16 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: SqliteDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -66,9 +66,9 @@ export class SqliteQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: SqliteDriver) {
|
||||
constructor(driver: SqliteDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -13,6 +13,7 @@ import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
|
||||
import {SqlServerConnectionOptions} from "./SqlServerConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
@ -112,7 +113,7 @@ export class SqlServerDriver implements Driver {
|
||||
varchar: { length: 255 },
|
||||
nvarchar: { length: 255 }
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -23,16 +23,16 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: SqlServerDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -76,9 +76,9 @@ export class SqlServerQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: SqlServerDriver) {
|
||||
constructor(driver: SqlServerDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -10,6 +10,7 @@ import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
|
||||
import {WebSqlConnectionOptions} from "./WebSqlConnectionOptions";
|
||||
import {MappedColumnTypes} from "../types/MappedColumnTypes";
|
||||
import {ColumnType} from "../types/ColumnTypes";
|
||||
import {EntityManager} from "../../entity-manager/EntityManager";
|
||||
import {DataTypeDefaults} from "../types/DataTypeDefaults";
|
||||
|
||||
/**
|
||||
|
||||
@ -27,16 +27,16 @@ export class WebsqlQueryRunner implements QueryRunner {
|
||||
// Public Implemented Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Database driver used by connection.
|
||||
*/
|
||||
driver: WebsqlDriver;
|
||||
|
||||
/**
|
||||
* Connection used by this query runner.
|
||||
*/
|
||||
connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
@ -76,9 +76,9 @@ export class WebsqlQueryRunner implements QueryRunner {
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
constructor(protected driver: WebsqlDriver) {
|
||||
constructor(driver: WebsqlDriver) {
|
||||
this.driver = driver;
|
||||
this.connection = driver.connection;
|
||||
this.manager = driver.connection.manager;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -22,6 +22,12 @@ import {AbstractRepository} from "../repository/AbstractRepository";
|
||||
import {CustomRepositoryCannotInheritRepositoryError} from "../error/CustomRepositoryCannotInheritRepositoryError";
|
||||
import {QueryRunner} from "../query-runner/QueryRunner";
|
||||
import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder";
|
||||
import {EntityMetadata} from "../metadata/EntityMetadata";
|
||||
import {MongoDriver} from "../driver/mongodb/MongoDriver";
|
||||
import {RepositoryNotFoundError} from "../error/RepositoryNotFoundError";
|
||||
import {RepositoryNotTreeError} from "../error/RepositoryNotTreeError";
|
||||
import {RepositoryFactory} from "../repository/RepositoryFactory";
|
||||
import {EntityManagerFactory} from "./EntityManagerFactory";
|
||||
|
||||
/**
|
||||
* Entity manager supposed to work with any entity, automatically find its repository and call its methods,
|
||||
@ -36,23 +42,29 @@ export class EntityManager {
|
||||
/**
|
||||
* Connection used by this entity manager.
|
||||
*/
|
||||
connection: Connection;
|
||||
readonly connection: Connection;
|
||||
|
||||
/**
|
||||
* Custom query runner to be used for operations in this entity manager.
|
||||
* Used only in non-global entity manager.
|
||||
*/
|
||||
readonly queryRunner?: QueryRunner;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Custom query runner to be used for operations in this entity manager.
|
||||
*/
|
||||
protected queryRunner?: QueryRunner;
|
||||
|
||||
/**
|
||||
* Stores temporarily user data.
|
||||
* Useful for sharing data with subscribers.
|
||||
*/
|
||||
protected data: ObjectLiteral = {};
|
||||
|
||||
/**
|
||||
* Once created and then reused by en repositories.
|
||||
*/
|
||||
protected repositories: { metadata: EntityMetadata, repository: Repository<any> }[] = [];
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
@ -72,7 +84,35 @@ export class EntityManager {
|
||||
* All database operations must be executed using provided entity manager.
|
||||
*/
|
||||
async transaction(runInTransaction: (entityManger: EntityManager) => Promise<any>): Promise<any> {
|
||||
return this.connection.transaction(runInTransaction, this.queryRunner);
|
||||
|
||||
if (this.connection.driver instanceof MongoDriver)
|
||||
throw new Error(`Transactions aren't supported by MongoDB.`);
|
||||
|
||||
if (this.queryRunner && this.queryRunner.isReleased)
|
||||
throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
|
||||
if (this.queryRunner && this.queryRunner.isTransactionActive)
|
||||
throw new Error(`Cannot start transaction because its already started`);
|
||||
|
||||
const usedQueryRunner = this.queryRunner || this.connection.createQueryRunner();
|
||||
const transactionEntityManager = new EntityManagerFactory().create(this.connection, usedQueryRunner);
|
||||
|
||||
try {
|
||||
await usedQueryRunner.startTransaction();
|
||||
const result = await runInTransaction(transactionEntityManager);
|
||||
await usedQueryRunner.commitTransaction();
|
||||
return result;
|
||||
|
||||
} catch (err) {
|
||||
try { // we throw original error even if rollback thrown an error
|
||||
await usedQueryRunner.rollbackTransaction();
|
||||
} catch (rollbackError) { }
|
||||
throw err;
|
||||
|
||||
} finally {
|
||||
if (!this.queryRunner) // if we used a new query runner provider then release it
|
||||
await usedQueryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,8 +295,15 @@ export class EntityManager {
|
||||
|
||||
return Promise.resolve().then(async () => { // we MUST call "fake" resolve here to make sure all properties of lazily loaded properties are resolved.
|
||||
|
||||
// todo: use transaction instead if possible
|
||||
await this.transaction(async transactionEntityManager => {
|
||||
if (options && options.data)
|
||||
transactionEntityManager.data = options.data;
|
||||
|
||||
});
|
||||
|
||||
const queryRunner = this.queryRunner || this.connection.createQueryRunner();
|
||||
const transactionEntityManager = this.connection.createIsolatedManager(queryRunner);
|
||||
const transactionEntityManager = new EntityManagerFactory().create(this.connection, queryRunner);
|
||||
if (options && options.data)
|
||||
transactionEntityManager.data = options.data;
|
||||
|
||||
@ -453,7 +500,7 @@ export class EntityManager {
|
||||
return Promise.resolve().then(async () => { // we MUST call "fake" resolve here to make sure all properties of lazily loaded properties are resolved.
|
||||
|
||||
const queryRunner = this.queryRunner || this.connection.createQueryRunner();
|
||||
const transactionEntityManager = this.connection.createIsolatedManager(queryRunner);
|
||||
const transactionEntityManager = new EntityManagerFactory().create(this.connection, queryRunner);
|
||||
if (options && options.data)
|
||||
transactionEntityManager.data = options.data;
|
||||
|
||||
@ -720,17 +767,27 @@ export class EntityManager {
|
||||
* 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<Entity>(entityClassOrName: ObjectType<Entity>|string): Repository<Entity> {
|
||||
getRepository<Entity>(target: ObjectType<Entity>|string): Repository<Entity> {
|
||||
|
||||
// if single db connection is used then create its own repository with reused query runner
|
||||
if (this.queryRunner) {
|
||||
if (this.queryRunner.isReleased)
|
||||
throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
if (!this.connection.hasMetadata(target))
|
||||
throw new RepositoryNotFoundError(this.connection.name, target);
|
||||
|
||||
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunner);
|
||||
const metadata = this.connection.getMetadata(target);
|
||||
let repository = this.repositories.find(repo => repo.metadata === metadata);
|
||||
if (!repository) {
|
||||
repository = { metadata: metadata, repository: new RepositoryFactory().create(this, metadata, this.queryRunner) };
|
||||
this.repositories.push(repository);
|
||||
}
|
||||
|
||||
return this.connection.getRepository<Entity>(entityClassOrName as any);
|
||||
// if single db connection is used then create its own repository with reused query runner
|
||||
// if (this.queryRunner) {
|
||||
// if (this.queryRunner.isReleased)
|
||||
// throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
//
|
||||
// return this.connection.createIsolatedRepository(target, this.queryRunner);
|
||||
// }
|
||||
|
||||
return repository.repository;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -739,17 +796,15 @@ export class EntityManager {
|
||||
* 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<Entity>(entityClassOrName: ObjectType<Entity>|string): TreeRepository<Entity> {
|
||||
getTreeRepository<Entity>(target: ObjectType<Entity>|string): TreeRepository<Entity> {
|
||||
if (this.connection.driver instanceof MongoDriver)
|
||||
throw new Error(`You cannot use getTreeRepository for MongoDB connections.`);
|
||||
|
||||
// if single db connection is used then create its own repository with reused query runner
|
||||
if (this.queryRunner) {
|
||||
if (this.queryRunner.isReleased)
|
||||
throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
const repository = this.getRepository(target);
|
||||
if (!(repository instanceof TreeRepository))
|
||||
throw new RepositoryNotTreeError(target);
|
||||
|
||||
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunner) as TreeRepository<Entity>;
|
||||
}
|
||||
|
||||
return this.connection.getTreeRepository<Entity>(entityClassOrName as any);
|
||||
return repository;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -772,7 +827,7 @@ export class EntityManager {
|
||||
if (this.queryRunner.isReleased)
|
||||
throw new QueryRunnerProviderAlreadyReleasedError();
|
||||
|
||||
return this.connection.createIsolatedRepository(entityClassOrName, this.queryRunner) as MongoRepository<Entity>;
|
||||
return this.connection.createIsolatedRepository(entityClassOrName) as MongoRepository<Entity>;
|
||||
}
|
||||
|
||||
return this.connection.getMongoRepository<Entity>(entityClassOrName as any);
|
||||
|
||||
@ -58,6 +58,17 @@ export class MongoEntityManager extends EntityManager {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Overridden Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets query runner used to execute queries.
|
||||
*/
|
||||
get queryRunner(): MongoQueryRunner {
|
||||
return (this.connection.driver as MongoDriver).queryRunner!;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Overridden Methods
|
||||
// -------------------------------------------------------------------------
|
||||
@ -495,13 +506,6 @@ export class MongoEntityManager extends EntityManager {
|
||||
// Protected Methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Gets query runner used to execute queries.
|
||||
*/
|
||||
protected get queryRunner(): MongoQueryRunner {
|
||||
return (this.connection.driver as MongoDriver).queryRunner!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts FindManyOptions to mongodb query.
|
||||
*/
|
||||
|
||||
@ -25,11 +25,6 @@ export class EntityMetadata {
|
||||
// Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Repository used for this entity metadata.
|
||||
*/
|
||||
repository: Repository<any>;
|
||||
|
||||
/**
|
||||
* Used to wrap lazy relations.
|
||||
*/
|
||||
|
||||
@ -19,11 +19,6 @@ export interface QueryRunner {
|
||||
*/
|
||||
readonly connection: Connection;
|
||||
|
||||
/**
|
||||
* Entity manager isolated for this query runner.
|
||||
*/
|
||||
readonly manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Indicates if connection for this query runner is released.
|
||||
* Once its released, query runner cannot run queries anymore.
|
||||
|
||||
@ -42,13 +42,13 @@ import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder";
|
||||
export class MongoRepository<Entity extends ObjectLiteral> extends Repository<Entity> {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods Set Dynamically
|
||||
// Public Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Entity Manager used by this repository.
|
||||
*/
|
||||
protected manager: MongoEntityManager;
|
||||
readonly manager: MongoEntityManager;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Overridden Methods
|
||||
|
||||
@ -15,25 +15,23 @@ import {SelectQueryBuilder} from "../query-builder/SelectQueryBuilder";
|
||||
export class Repository<Entity extends ObjectLiteral> {
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Protected Methods Set Dynamically
|
||||
// Public Properties
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// todo: wny not to make them public?
|
||||
|
||||
/**
|
||||
* Entity Manager used by this repository.
|
||||
*/
|
||||
protected manager: EntityManager;
|
||||
readonly manager: EntityManager;
|
||||
|
||||
/**
|
||||
* Entity metadata of the entity current repository manages.
|
||||
*/
|
||||
protected metadata: EntityMetadata;
|
||||
readonly metadata: EntityMetadata;
|
||||
|
||||
/**
|
||||
* Query runner provider used for this repository.
|
||||
*/
|
||||
protected queryRunner?: QueryRunner;
|
||||
readonly queryRunner?: QueryRunner;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public Methods
|
||||
|
||||
@ -5,6 +5,7 @@ import {Repository} from "./Repository";
|
||||
import {MongoDriver} from "../driver/mongodb/MongoDriver";
|
||||
import {MongoRepository} from "./MongoRepository";
|
||||
import {QueryRunner} from "../query-runner/QueryRunner";
|
||||
import {EntityManager} from "../entity-manager/EntityManager";
|
||||
|
||||
/**
|
||||
* Factory used to create different types of repositories.
|
||||
@ -18,29 +19,33 @@ export class RepositoryFactory {
|
||||
/**
|
||||
* Creates a repository.
|
||||
*/
|
||||
create(connection: Connection, metadata: EntityMetadata, queryRunner?: QueryRunner): Repository<any> {
|
||||
create(manager: EntityManager, metadata: EntityMetadata, queryRunner?: QueryRunner): Repository<any> {
|
||||
|
||||
if (metadata.isClosure) {
|
||||
// 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
|
||||
const repository = new TreeRepository<any>();
|
||||
(repository as any)["manager"] = connection.manager;
|
||||
(repository as any)["metadata"] = metadata;
|
||||
(repository as any)["queryRunner"] = queryRunner;
|
||||
Object.assign(repository, {
|
||||
manager: manager,
|
||||
metadata: metadata,
|
||||
queryRunner: queryRunner,
|
||||
});
|
||||
return repository;
|
||||
|
||||
} else {
|
||||
// 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
|
||||
let repository: Repository<any>;
|
||||
if (connection.driver instanceof MongoDriver) {
|
||||
if (manager.connection.driver instanceof MongoDriver) {
|
||||
repository = new MongoRepository();
|
||||
} else {
|
||||
repository = new Repository<any>();
|
||||
}
|
||||
(repository as any)["manager"] = connection.manager;
|
||||
(repository as any)["metadata"] = metadata;
|
||||
(repository as any)["queryRunner"] = queryRunner;
|
||||
Object.assign(repository, {
|
||||
manager: manager,
|
||||
metadata: metadata,
|
||||
queryRunner: queryRunner,
|
||||
});
|
||||
|
||||
return repository;
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
import {Entity} from "../../../../../src/decorator/entity/Entity";
|
||||
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
|
||||
import {Column} from "../../../../../src/decorator/columns/Column";
|
||||
|
||||
@Entity()
|
||||
export class Post {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
title: string;
|
||||
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
import "reflect-metadata";
|
||||
import {createTestingConnections, closeTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
|
||||
import {Connection} from "../../../../src/connection/Connection";
|
||||
import {Post} from "./entity/Post";
|
||||
import {expect} from "chai";
|
||||
|
||||
describe("transaction > single query runner", () => {
|
||||
|
||||
let connections: Connection[];
|
||||
before(async () => connections = await createTestingConnections({
|
||||
entities: [__dirname + "/entity/*{.js,.ts}"],
|
||||
schemaCreate: true,
|
||||
dropSchemaOnConnection: true,
|
||||
}));
|
||||
beforeEach(() => reloadTestingDatabases(connections));
|
||||
after(() => closeTestingConnections(connections));
|
||||
|
||||
it("should execute all operations in the method in a transaction", () => Promise.all(connections.map(async connection => {
|
||||
return connection.transaction(async transactionalEntityManager => {
|
||||
const originalQueryRunner = transactionalEntityManager.queryRunner;
|
||||
|
||||
expect(originalQueryRunner).to.exist;
|
||||
expect(transactionalEntityManager.getRepository(Post).queryRunner).to.exist;
|
||||
transactionalEntityManager.getRepository(Post).queryRunner!.should.be.equal(originalQueryRunner);
|
||||
transactionalEntityManager.getRepository(Post).manager.should.be.equal(transactionalEntityManager);
|
||||
});
|
||||
|
||||
})));
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user