From ad13069f137188dd23a2def2d998580d44a80ab5 Mon Sep 17 00:00:00 2001 From: Leonardo Falk Date: Thu, 10 Oct 2019 15:23:27 -0300 Subject: [PATCH] feat: export Migration Execution API from main package (fixes #4880) --- src/index.ts | 2 + src/migration/MigrationExecutor.ts | 87 +++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 71829638a7c..5fb9d8c44e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -139,6 +139,8 @@ export {DeleteResult} from "./query-builder/result/DeleteResult"; export {QueryRunner} from "./query-runner/QueryRunner"; export {EntityManager} from "./entity-manager/EntityManager"; export {MongoEntityManager} from "./entity-manager/MongoEntityManager"; +export {Migration} from "./migration/Migration"; +export {MigrationExecutor} from "./migration/MigrationExecutor"; export {MigrationInterface} from "./migration/MigrationInterface"; export {DefaultNamingStrategy} from "./naming-strategy/DefaultNamingStrategy"; export {NamingStrategyInterface} from "./naming-strategy/NamingStrategyInterface"; diff --git a/src/migration/MigrationExecutor.ts b/src/migration/MigrationExecutor.ts index aef39b06705..bae2314b0a7 100644 --- a/src/migration/MigrationExecutor.ts +++ b/src/migration/MigrationExecutor.ts @@ -51,6 +51,78 @@ export class MigrationExecutor { // Public Methods // ------------------------------------------------------------------------- + /** + * Tries to execute a single migration given. + */ + public async executeMigration(migration: Migration): Promise { + return this.withQueryRunner(async (queryRunner) => { + await this.createMigrationsTableIfNotExist(queryRunner); + await (migration.instance as any).up(queryRunner); + await this.insertExecutedMigration(queryRunner, migration); + + return migration; + }); + } + + /** + * Returns an array of all migrations. + */ + public async getAllMigrations(): Promise { + return Promise.resolve(this.getMigrations()); + } + + /** + * Returns an array of all executed migrations. + */ + public async getExecutedMigrations(): Promise { + return this.withQueryRunner(async queryRunner => { + await this.createMigrationsTableIfNotExist(queryRunner); + + return await this.loadExecutedMigrations(queryRunner); + }); + } + + /** + * Returns an array of all pending migrations. + */ + public async getPendingMigrations(): Promise { + const allMigrations = await this.getAllMigrations(); + const executedMigrations = await this.getExecutedMigrations(); + + return allMigrations.filter(migration => + executedMigrations.find( + executedMigration => + executedMigration.name === migration.name + ) + ); + } + + /** + * Inserts an executed migration. + */ + public insertMigration(migration: Migration): Promise { + return new Promise((resolve, reject) => { + this.withQueryRunner(queryRunner => { + this.insertExecutedMigration(queryRunner, migration) + .then(resolve) + .catch(reject); + }); + }); + } + + /** + * Deletes an executed migration. + */ + public deleteMigration(migration: Migration): Promise { + return new Promise((resolve, reject) => { + this.withQueryRunner(queryRunner => { + this.deleteExecutedMigration(queryRunner, migration) + .then(resolve) + .catch(reject); + }); + }); + } + /** * Lists all migrations and whether they have been executed or not * returns true if there are unapplied migrations @@ -333,8 +405,9 @@ export class MigrationExecutor { const migrations = this.connection.migrations.map(migration => { const migrationClassName = migration.name || (migration.constructor as any).name; const migrationTimestamp = parseInt(migrationClassName.substr(-13)); - if (!migrationTimestamp) + if (!migrationTimestamp || isNaN(migrationTimestamp)) { throw new Error(`${migrationClassName} migration name is wrong. Migration class name should have a JavaScript timestamp appended.`); + } return new Migration(undefined, migrationTimestamp, migrationClassName, migration); }); @@ -421,4 +494,16 @@ export class MigrationExecutor { } } + + protected async withQueryRunner(callback: (queryRunner: QueryRunner) => T) { + const queryRunner = this.queryRunner || this.connection.createQueryRunner("master"); + + try { + return callback(queryRunner); + } finally { + if (!this.queryRunner) { + await queryRunner.release(); + } + } + } }