diff --git a/CHANGELOG.md b/CHANGELOG.md index 083378037..e0564e930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ Now `EntityManager` now simply use them from the connection. * refactored how query runner works, removed query runner provider * fixed some issues with sqlite, sqlite now strongly works on a single connection +* `Connection` how has `createQueryRunner` that can be used to control database connection and its transaction state ### BUG FIXES diff --git a/src/commands/QueryCommand.ts b/src/commands/QueryCommand.ts index e25caa814..83162c52c 100644 --- a/src/commands/QueryCommand.ts +++ b/src/commands/QueryCommand.ts @@ -31,7 +31,7 @@ export class QueryCommand { let queryRunner: QueryRunner|undefined = undefined; try { - queryRunner = await connection.driver.createQueryRunner(); + queryRunner = await connection.createQueryRunner(); const queryResult = await queryRunner.query(argv._[1]); connection.logger.log("info", "Query executed. Result: " + JSON.stringify(queryResult)); diff --git a/src/connection/Connection.ts b/src/connection/Connection.ts index 4ba63b352..a52740ec7 100644 --- a/src/connection/Connection.ts +++ b/src/connection/Connection.ts @@ -206,7 +206,7 @@ export class Connection { * Can be used only after connection to the database is established. */ async dropDatabase(): Promise { - const queryRunner = await this.driver.createQueryRunner(); + const queryRunner = await this.createQueryRunner(); await queryRunner.clearDatabase(); await queryRunner.release(); } @@ -312,7 +312,7 @@ export class Connection { if (queryRunner && queryRunner.isReleased) throw new QueryRunnerProviderAlreadyReleasedError(); - const usedQueryRunner = queryRunner || this.driver.createQueryRunner(); + const usedQueryRunner = queryRunner || this.createQueryRunner(); const transactionEntityManager = new EntityManagerFactory().create(this, usedQueryRunner); try { @@ -343,7 +343,7 @@ export class Connection { if (queryRunner && queryRunner.isReleased) throw new QueryRunnerProviderAlreadyReleasedError(); - const usedQueryRunner = queryRunner || this.driver.createQueryRunner(); + const usedQueryRunner = queryRunner || this.createQueryRunner(); try { return await usedQueryRunner.query(query, parameters); // await is needed here because we are using finally @@ -382,6 +382,15 @@ export class Connection { } } + /** + * Creates a query runner used for perform queries on a single database connection. + * Using query runners you can control your queries to execute using single database connection and + * manually control your database transaction. + */ + createQueryRunner(): QueryRunner { + return this.driver.createQueryRunner(); + } + /** * Creates a new entity manager with a single opened connection to the database. * This may be useful if you want to perform all db queries within one connection. @@ -389,7 +398,7 @@ export class Connection { */ createIsolatedManager(queryRunner?: QueryRunner): EntityManager { if (!queryRunner) - queryRunner = this.driver.createQueryRunner(); + queryRunner = this.createQueryRunner(); return new EntityManagerFactory().create(this, queryRunner); } @@ -401,7 +410,7 @@ export class Connection { */ createIsolatedRepository(entityClassOrName: ObjectType|string, queryRunner?: QueryRunner): Repository { if (!queryRunner) - queryRunner = this.driver.createQueryRunner(); + queryRunner = this.createQueryRunner(); return new RepositoryFactory().createRepository(this, this.getMetadata(entityClassOrName), queryRunner); } @@ -413,7 +422,7 @@ export class Connection { */ createIsolatedSpecificRepository(entityClassOrName: ObjectType|string, queryRunner?: QueryRunner): SpecificRepository { if (!queryRunner) - queryRunner = this.driver.createQueryRunner(); + queryRunner = this.createQueryRunner(); return new RepositoryFactory().createSpecificRepository(this, this.getMetadata(entityClassOrName), queryRunner); } diff --git a/src/entity-manager/EntityManager.ts b/src/entity-manager/EntityManager.ts index 9049fa98d..1db7db32e 100644 --- a/src/entity-manager/EntityManager.ts +++ b/src/entity-manager/EntityManager.ts @@ -568,7 +568,7 @@ export class EntityManager { */ async clear(entityClass: ObjectType|string): Promise { const metadata = this.connection.getMetadata(entityClass); - const queryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { return await queryRunner.truncate(metadata.tableName); // await is needed here because we are using finally @@ -735,7 +735,7 @@ export class EntityManager { */ protected async saveOne(target: Function|string, entity: any, options?: SaveOptions): Promise { const metadata = this.connection.getMetadata(target); - const queryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { const transactionEntityManager = this.connection.createIsolatedManager(queryRunner); // transactionEntityManager.data = @@ -757,7 +757,7 @@ export class EntityManager { */ protected async removeOne(target: Function|string, entity: any, options?: RemoveOptions): Promise { const metadata = this.connection.getMetadata(target); - const queryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const queryRunner = this.queryRunner || this.connection.createQueryRunner(); try { const transactionEntityManager = this.connection.createIsolatedManager(queryRunner); diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index 00ea2877b..faed392ff 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -22,7 +22,7 @@ export class MigrationExecutor { // ------------------------------------------------------------------------- constructor(protected connection: Connection, queryRunner?: QueryRunner) { - this.queryRunner = queryRunner || connection.driver.createQueryRunner(); + this.queryRunner = queryRunner || connection.createQueryRunner(); } // ------------------------------------------------------------------------- diff --git a/src/query-builder/QueryBuilder.ts b/src/query-builder/QueryBuilder.ts index 3b860c3c2..3941a97ec 100644 --- a/src/query-builder/QueryBuilder.ts +++ b/src/query-builder/QueryBuilder.ts @@ -1746,7 +1746,7 @@ export class QueryBuilder { return this.queryRunner; } else { // means its empty - return this.connection.driver.createQueryRunner(); + return this.connection.createQueryRunner(); } } diff --git a/src/repository/SpecificRepository.ts b/src/repository/SpecificRepository.ts index 8d162d7d1..3e6e97be1 100644 --- a/src/repository/SpecificRepository.ts +++ b/src/repository/SpecificRepository.ts @@ -70,7 +70,7 @@ export class SpecificRepository { } - const usedQueryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const usedQueryRunner = this.queryRunner || this.connection.createQueryRunner(); await usedQueryRunner.update(table, values, conditions); if (!this.queryRunner) // means created by this method await usedQueryRunner.release(); @@ -117,7 +117,7 @@ export class SpecificRepository { conditions[relation.joinColumns[0].referencedColumn!.databaseName] = entityId; } - const usedQueryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const usedQueryRunner = this.queryRunner || this.connection.createQueryRunner(); await usedQueryRunner.update(table, values, conditions); if (!this.queryRunner) // means created by this method await usedQueryRunner.release(); @@ -150,7 +150,7 @@ export class SpecificRepository { if (!relation.isManyToMany) throw new Error(`Only many-to-many relation supported for this operation. However ${this.metadata.name}#${propertyPath} relation type is ${relation.relationType}`); - const usedQueryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const usedQueryRunner = this.queryRunner || this.connection.createQueryRunner(); const insertPromises = relatedEntityIds.map(relatedEntityId => { const values: any = {}; if (relation.isOwning) { @@ -196,7 +196,7 @@ export class SpecificRepository { if (!relation.isManyToMany) throw new Error(`Only many-to-many relation supported for this operation. However ${this.metadata.name}#${propertyPath} relation type is ${relation.relationType}`); - const usedQueryRunner = this.queryRunner || this.connection.driver.createQueryRunner(); + const usedQueryRunner = this.queryRunner || this.connection.createQueryRunner(); try { const insertPromises = entityIds.map(entityId => { const values: any = {}; diff --git a/src/schema-builder/RdbmsSchemaBuilder.ts b/src/schema-builder/RdbmsSchemaBuilder.ts index 42531e54c..3dcbd289d 100644 --- a/src/schema-builder/RdbmsSchemaBuilder.ts +++ b/src/schema-builder/RdbmsSchemaBuilder.ts @@ -57,7 +57,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder { * Creates complete schemas for the given entity metadatas. */ async build(): Promise { - this.queryRunner = await this.connection.driver.createQueryRunner(); + this.queryRunner = await this.connection.createQueryRunner(); this.tableSchemas = await this.loadTableSchemas(); await this.queryRunner.startTransaction(); diff --git a/test/functional/connection/connection.ts b/test/functional/connection/connection.ts index e470a41c2..b0cf44b1e 100644 --- a/test/functional/connection/connection.ts +++ b/test/functional/connection/connection.ts @@ -220,7 +220,7 @@ describe("Connection", () => { afterEach(() => closeTestingConnections(connections)); it("database should be empty after schema sync", () => Promise.all(connections.map(async connection => { await connection.syncSchema(true); - const queryRunner = connection.driver.createQueryRunner(); + const queryRunner = connection.createQueryRunner(); let schema = await queryRunner.loadTableSchemas(["view"]); await queryRunner.release(); expect(schema.some(table => table.name === "view")).to.be.false; @@ -304,7 +304,7 @@ describe("Connection", () => { const commentRepo = connection.getRepository(CommentV1); await commentRepo.save(comment); - const queryRunner = connection.driver.createQueryRunner(); + const queryRunner = connection.createQueryRunner(); const rows = await queryRunner.query(`select * from "${schemaName}"."comment" where id = $1`, [comment.id]); await queryRunner.release(); expect(rows[0]["context"]).to.be.eq(comment.context); diff --git a/test/functional/json/jsonb.ts b/test/functional/json/jsonb.ts index 262f22ad7..066222851 100644 --- a/test/functional/json/jsonb.ts +++ b/test/functional/json/jsonb.ts @@ -16,7 +16,7 @@ describe("jsonb type", () => { it("should make correct schema with Postgres' jsonb type", () => Promise.all(connections.map(async connection => { await connection.syncSchema(true); - const queryRunner = connection.driver.createQueryRunner(); + const queryRunner = connection.createQueryRunner(); let schema = await queryRunner.loadTableSchema("record"); await queryRunner.release(); expect(schema).not.to.be.empty; diff --git a/test/functional/uuid/uuid.ts b/test/functional/uuid/uuid.ts index dd332dec2..0f1d9ad5c 100644 --- a/test/functional/uuid/uuid.ts +++ b/test/functional/uuid/uuid.ts @@ -22,7 +22,7 @@ describe("uuid type", () => { it("should make correct schema with Postgres' uuid type", () => Promise.all(connections.map(async connection => { await connection.syncSchema(true); - const queryRunner = connection.driver.createQueryRunner(); + const queryRunner = connection.createQueryRunner(); let schema = await queryRunner.loadTableSchema("record"); await queryRunner.release(); expect(schema).not.to.be.empty;