@mikro-orm/migrations
Version:
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.
81 lines (80 loc) • 3.21 kB
JavaScript
import { Utils } from '@mikro-orm/core';
/** Executes individual migration files within optional transaction contexts. */
export class MigrationRunner {
driver;
options;
config;
#connection;
#helper;
#masterTransaction;
#runSchema;
constructor(driver, options, config) {
this.driver = driver;
this.options = options;
this.config = config;
this.#connection = this.driver.getConnection();
this.#helper = this.driver.getPlatform().getSchemaHelper();
}
async run(migration, method, afterRun) {
migration.reset();
if (!this.options.transactional || !migration.isTransactional()) {
// Without a pinned transaction the set/reset statements may land on different pooled
// connections than the DDL, so refuse rather than silently running in the default schema.
if (this.#runSchema) {
throw new Error('Runtime schema (migrations.schema / migrator.up({ schema })) is only supported with transactional migrations');
}
const queries = await this.getQueries(migration, method);
await Utils.runSerial(queries, sql => this.driver.execute(sql));
await afterRun?.();
}
else {
await this.#connection.transactional(async (tx) => {
migration.setTransactionContext(tx);
try {
const queries = await this.getQueries(migration, method);
await Utils.runSerial(queries, sql => this.driver.execute(sql, undefined, 'all', tx));
await afterRun?.(tx);
}
finally {
await this.resetSessionSchema(tx);
}
}, { ctx: this.#masterTransaction });
}
}
async resetSessionSchema(ctx) {
if (!this.#runSchema) {
return;
}
const sql = this.#helper.getResetSchemaSQL(this.config.get('dbName'));
/* v8 ignore next 3 */
if (!sql) {
return;
}
// best-effort — surfacing a reset failure would mask the real migration error
await this.driver.execute(sql, undefined, 'all', ctx).catch(() => void 0);
}
setMasterMigration(trx) {
this.#masterTransaction = trx;
}
unsetMasterMigration() {
this.#masterTransaction = undefined;
}
setRunSchema(schema) {
this.#runSchema = this.#helper.resolveMigrationSchema(schema);
}
unsetRunSchema() {
this.#runSchema = undefined;
}
async getQueries(migration, method) {
await migration[method]();
const charset = this.config.get('charset');
let queries = migration.getQueries();
queries.unshift(...this.#helper.getSchemaBeginning(charset, this.options.disableForeignKeys).split('\n'));
if (this.#runSchema) {
queries.unshift(this.#helper.getSetSchemaSQL(this.#runSchema));
}
queries.push(...this.#helper.getSchemaEnd(this.options.disableForeignKeys).split('\n'));
queries = queries.filter(sql => typeof sql !== 'string' || sql.trim().length > 0);
return queries;
}
}