Skip to content

Commit 632a132

Browse files
committed
feat: export Migration Execution API from main package (fixes typeorm#4880)
1 parent 488d210 commit 632a132

File tree

2 files changed

+67
-6
lines changed

2 files changed

+67
-6
lines changed

src/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ export {DeleteResult} from "./query-builder/result/DeleteResult";
138138
export {QueryRunner} from "./query-runner/QueryRunner";
139139
export {EntityManager} from "./entity-manager/EntityManager";
140140
export {MongoEntityManager} from "./entity-manager/MongoEntityManager";
141-
export {MigrationInterface} from "./migration/MigrationInterface";
141+
export {Migration} from "./migration/Migration";
142+
export {MigrationExecutor} from "./migration/MigrationExecutor";
143+
export {MigrationInterface } from "./migration/MigrationInterface";
142144
export {DefaultNamingStrategy} from "./naming-strategy/DefaultNamingStrategy";
143145
export {NamingStrategyInterface} from "./naming-strategy/NamingStrategyInterface";
144146
export {Repository} from "./repository/Repository";

src/migration/MigrationExecutor.ts

+64-5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,40 @@ export class MigrationExecutor {
4848
// Public Methods
4949
// -------------------------------------------------------------------------
5050

51+
public async executeMigration(migration: Migration): Promise<Migration> {
52+
return this.withQueryRunner(async (queryRunner) => {
53+
await this.createMigrationsTableIfNotExist(queryRunner);
54+
await (migration.instance as any).up(queryRunner);
55+
await this.insertExecutedMigration(queryRunner, migration);
56+
57+
return migration;
58+
})
59+
}
60+
61+
public async getAllMigrations(): Promise<Migration[]> {
62+
return this.getMigrations()
63+
}
64+
65+
public async getExecutedMigrations(): Promise<Migration[]> {
66+
return this.withQueryRunner(async queryRunner => {
67+
await this.createMigrationsTableIfNotExist(queryRunner);
68+
69+
return await this.loadExecutedMigrations(queryRunner);
70+
});
71+
}
72+
73+
public async getPendingMigrations(): Promise<Migration[]> {
74+
const allMigrations = await this.getAllMigrations();
75+
const executedMigrations = await this.getExecutedMigrations();
76+
77+
return allMigrations.filter(migration =>
78+
executedMigrations.find(
79+
executedMigration =>
80+
executedMigration.name === migration.name
81+
)
82+
);
83+
}
84+
5185
/**
5286
* Lists all migrations and whether they have been executed or not
5387
* returns true if there are unapplied migrations
@@ -315,9 +349,11 @@ export class MigrationExecutor {
315349
protected getMigrations(): Migration[] {
316350
const migrations = this.connection.migrations.map(migration => {
317351
const migrationClassName = (migration.constructor as any).name;
318-
const migrationTimestamp = parseInt(migrationClassName.substr(-13));
319-
if (!migrationTimestamp)
352+
const migrationTimestamp = parseInt(migrationClassName.substr(-13), 10);
353+
354+
if (!migrationTimestamp || isNaN(migrationTimestamp)) {
320355
throw new Error(`${migrationClassName} migration name is wrong. Migration class name should have a JavaScript timestamp appended.`);
356+
}
321357

322358
return new Migration(undefined, migrationTimestamp, migrationClassName, migration);
323359
});
@@ -342,6 +378,12 @@ export class MigrationExecutor {
342378
return sortedMigrations.length > 0 ? sortedMigrations[0] : undefined;
343379
}
344380

381+
public insertMigration(migration: Migration) {
382+
return this.withQueryRunner(async queryRunner => {
383+
return await this.insertExecutedMigration(queryRunner, migration)
384+
})
385+
}
386+
345387
/**
346388
* Inserts new executed migration's data into migrations table.
347389
*/
@@ -354,9 +396,9 @@ export class MigrationExecutor {
354396
values["timestamp"] = migration.timestamp;
355397
values["name"] = migration.name;
356398
}
357-
if (this.connection.driver instanceof MongoDriver) {
399+
if (this.connection.driver instanceof MongoDriver) {
358400
const mongoRunner = queryRunner as MongoQueryRunner;
359-
mongoRunner.databaseConnection.db(this.connection.driver.database!).collection(this.migrationsTableName).insert(values);
401+
mongoRunner.databaseConnection.db(this.connection.driver.database!).collection(this.migrationsTableName).insert(values);
360402
} else {
361403
const qb = queryRunner.manager.createQueryBuilder();
362404
await qb.insert()
@@ -366,6 +408,12 @@ export class MigrationExecutor {
366408
}
367409
}
368410

411+
public deleteMigration(migration: Migration) {
412+
return this.withQueryRunner(async queryRunner => {
413+
return await this.deleteExecutedMigration(queryRunner, migration);
414+
})
415+
}
416+
369417
/**
370418
* Delete previously executed migration's data from the migrations table.
371419
*/
@@ -382,7 +430,7 @@ export class MigrationExecutor {
382430

383431
if (this.connection.driver instanceof MongoDriver) {
384432
const mongoRunner = queryRunner as MongoQueryRunner;
385-
mongoRunner.databaseConnection.db(this.connection.driver.database!).collection(this.migrationsTableName).deleteOne(conditions);
433+
mongoRunner.databaseConnection.db(this.connection.driver.database!).collection(this.migrationsTableName).deleteOne(conditions);
386434
} else {
387435
const qb = queryRunner.manager.createQueryBuilder();
388436
await qb.delete()
@@ -395,4 +443,15 @@ export class MigrationExecutor {
395443

396444
}
397445

446+
private async withQueryRunner<T extends any>(callback: (queryRunner: QueryRunner) => T) {
447+
const queryRunner = this.queryRunner || this.connection.createQueryRunner("master");
448+
449+
try {
450+
return callback(queryRunner)
451+
} finally {
452+
if (!this.queryRunner) {
453+
queryRunner.release()
454+
}
455+
}
456+
}
398457
}

0 commit comments

Comments
 (0)