@riao/dbal
Version:
181 lines • 8.22 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MigrationRunner = void 0;
const fs = require("fs");
const path_1 = require("path");
const ts_import_ts_1 = require("ts-import-ts");
const _001_create_migration_table_1 = require("./migrations/001-create-migration-table");
const migration_package_1 = require("./migration-package");
const _002_add_migration_package_column_1 = require("./migrations/002-add-migration-package-column");
/**
* Runs migrations
*/
class MigrationRunner {
constructor(db) {
this.db = db;
}
/**
* Run migrations
* @deprecated This method will change parameters in a future release.
* Switch to runWithOptions() to prepare for this change.
*
* @param migrations (Optional) Folder to find migrations in. Default is
* db.getMigraitonDirectory()
* @param log (Optional) Log function. Defaults to console.log
* @param direction (Optional) Run migrations up or down?
* @param steps (Optional) Run a certain number of steps?
*/
run(migrations,
/* eslint-disable-next-line no-console */
log = console.log, direction = 'up', steps) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.runWithOptions({
migrations,
log,
direction,
steps,
});
});
}
runWithOptions(options) {
return __awaiter(this, void 0, void 0, function* () {
const name = options.package || this.db.name || 'database';
let migrations = options.migrations || this.db.getMigrationsDirectory();
// eslint-disable-next-line no-console
const optionsLog = options.log || console.log;
const log = (...args) => {
optionsLog(`[${name}]\t`, ...args);
};
const direction = options.direction || 'up';
let steps = options.steps;
const pkg = options.package || null;
if (steps === -1) {
steps = undefined;
}
if (steps !== undefined && steps < 0) {
throw new Error('Steps must be a positive integer, or -1 for all.');
}
// Create migration table, if not existing
yield this.runRiaoDbalMigrations();
// Query migrations that have already run
const repo = this.db.getQueryRepository();
const alreadyRanMigrations = yield repo.find({
columns: ['name'],
table: 'riao_migration',
where: { package: pkg ? pkg : null },
});
const alreadyRanNames = alreadyRanMigrations.map((migration) => migration.name);
if (typeof migrations === 'string') {
// Get migration files in folder
migrations = this.loadMigrationsFromDirectory(migrations);
}
const migrationNames = Object.keys(migrations);
if (!migrationNames.length) {
log('No migrations found!');
return;
}
// Check which migrations need to run
let migrationsToRun;
if (direction === 'up') {
migrationsToRun = migrationNames.filter((file) => !alreadyRanNames.includes(file));
}
else {
migrationsToRun = alreadyRanNames.reverse();
}
if (!migrationsToRun.length) {
log('All migrations have already run');
return;
}
log(`Discovered ${migrationsToRun.length} ` +
'pending migrations in this direction.');
if (steps !== undefined) {
migrationsToRun = migrationsToRun.slice(0, steps);
}
log(`Running ${migrationsToRun.length} migrations...`);
// Run each migration
for (const name of migrationsToRun) {
// Run the migration
log(direction.toLocaleUpperCase() + ' | ', name);
const migration = migrations[name];
if (migration instanceof migration_package_1.MigrationPackage) {
log('Importing packaged migrations for ' +
migration.name +
'...');
const importedMigrationTypes = yield migration.getMigrations();
const PackagedMigrations = Object.keys(importedMigrationTypes).reduce((obj, key) => {
const migrationType = importedMigrationTypes[key];
obj[key] = new migrationType(this.db);
return obj;
}, {});
yield this.runWithOptions(Object.assign(Object.assign({}, options), { steps: undefined, migrations: PackagedMigrations, package: migration.package }));
continue;
}
yield migration[direction]();
// Save the migration record
if (direction === 'up') {
yield repo.insert({
table: 'riao_migration',
records: { name, package: pkg ? pkg : null },
});
}
else {
yield repo.delete({
table: 'riao_migration',
where: { name, package: pkg ? pkg : null },
});
}
}
log('Rebuilding Schema...');
yield this.db.buildSchema();
log('Migrations Complete!');
});
}
getMigrationName(filename) {
return (0, path_1.basename)(filename.toLowerCase(), (0, path_1.extname)(filename));
}
loadMigration(dir, filename) {
const path = (0, path_1.join)(dir, filename);
const migrationType = (0, ts_import_ts_1.tsimport)(path);
const migration = new migrationType(this.db);
return migration;
}
loadMigrationsFromDirectory(dir) {
return fs
.readdirSync(dir)
.filter((filename) => /\.ts$/.test(filename))
.map((filename) => ({
name: this.getMigrationName(filename),
migration: this.loadMigration(dir, filename),
}))
.reduce((obj, item) => {
obj[item.name] = item.migration;
return obj;
}, {});
}
runRiaoDbalMigrations() {
return __awaiter(this, void 0, void 0, function* () {
// Create table, if not existing
const createMigrationTable = new _001_create_migration_table_1.CreateMigrationTable(this.db);
yield createMigrationTable.up();
// Check if `package` column exists, and if not, add it
const columns = yield this.db
.getSchemaQueryRepository()
.getColumns({ table: 'riao_migration' });
if (!columns.find((col) => col.name === 'package')) {
const addMigrationPackageColumn = new _002_add_migration_package_column_1.AddMigrationPackageColumn(this.db);
yield addMigrationPackageColumn.up();
}
});
}
}
exports.MigrationRunner = MigrationRunner;
//# sourceMappingURL=migration-runner.js.map