anydb-sql-migrations
Version:
Database migrations for anydb-sql
137 lines (136 loc) • 5.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var Promise = require("bluebird");
var _ = require("lodash");
var fs = require("fs");
var path = require("path");
function create(db, tasks) {
var list = [];
var migrations = db.define({
name: '_migrations',
columns: {
version: { dataType: db.dialect() === 'mysql' ? 'varchar(255)' : 'text', notNull: true, primaryKey: true }
}
});
function runMigration(migfn) {
return db.transaction(function (tx) {
return migrations.create().ifNotExists().execWithin(tx)
.then(function (_) { return migfn(tx); })
.thenReturn();
});
}
function defineMigration(name, fns) {
if (_.find(list, function (m) { return m.name == name; }) != null)
return;
list.push({ name: name, up: fns.up, down: fns.down });
}
function getMigrationList(tx) {
return migrations.select()
.order(migrations.version.descending)
.allWithin(tx)
.then(function (migs) {
var alreadyExecuted = migs.map(function (m) { return m.version; });
return _(list).sortBy(function (m) { return m.name; }).filter(function (m) { return !_.includes(alreadyExecuted, m.name); }).value();
});
}
function unmigrate() {
}
function add(tx, name) {
return migrations.insert({ version: name }).execWithin(tx);
}
function remove(tx, name) {
return migrations.where({ version: name }).delete().execWithin(tx);
}
function runSingle(tx, type, m) {
return type == 'up' ?
m.up(tx).then(function () { return add(tx, m.name); }) :
m.down(tx).then(function () { return remove(tx, m.name); });
}
function migrate(opts) {
if (opts === void 0) { opts = {}; }
return runMigration(function (tx) { return getMigrationList(tx).then(function (migrations) { return migrations.reduce(function (acc, m) { return acc.then(function (_) { return runSingle(tx, "up", m); })
.then(function (_) { return !opts.silent && console.log("Completed:", m.name); })
.thenReturn(); }, Promise.resolve()); }); });
}
function undoLast() {
return runMigration(function (tx) { return migrations.select()
.order(migrations.version.descending)
.getWithin(tx).then(function (mig) {
if (!mig)
throw new Error("No migrations available to rollback");
var undoMigration = _.find(list, function (item) { return item.name == mig.version; });
return runSingle(tx, "down", undoMigration);
}); });
}
function undoAll() {
return runMigration(function (tx) { return migrations.select()
.order(migrations.version.descending)
.allWithin(tx).then(function (migrations) {
if (!migrations.length) {
throw new Error("No migrations available to rollback");
}
return Promise.each(migrations, function (mig) {
var task = _.find(list, function (item) { return item.name == mig.version; });
return runSingle(tx, "down", task);
});
}); });
}
function loadFromPath(location) {
fs.readdirSync(location)
.filter(function (file) { return (/\.js$/.test(file)); })
.forEach(function (file) { return defineMigration(file.replace(/\.js$/, ''), require(path.resolve(location, file))); });
}
function check(f) {
return runMigration(function (tx) { return getMigrationList(tx).then(f); });
}
function run() {
var args = require('yargs').argv;
if (args.check)
return check(function (migrations) {
if (migrations.length) {
console.log("Migrations to run");
migrations.forEach(function (item) { return console.log("-", item.name); });
process.exit(1);
}
else {
console.log("No pending migrations");
process.exit(0);
}
});
else if (args.execute)
return migrate().done(function (_) { return process.exit(0); }, function (e) {
console.error(e.stack);
process.exit(1);
});
else if (args.rollback) {
return undoLast().done(function (_) { return process.exit(0); }, function (e) {
if (e.message == 'No migrations available to rollback') {
console.error(e.message);
}
else {
console.error(e.stack);
}
process.exit(1);
});
}
else if (args.drop) {
return undoAll().done(function (_) { return process.exit(0); }, function (e) {
if (e.message == 'No migrations available to rollback') {
console.error(e.message);
}
else {
console.error(e.stack);
}
process.exit(1);
});
}
console.error("Add a --check, --execute, --drop or --rollback argument");
process.exit(1);
}
if (typeof tasks === 'string')
loadFromPath(tasks);
else
tasks.forEach(function (task) { return defineMigration(task.name, task); });
return { run: run, check: check, migrate: migrate, undoLast: undoLast, drop: undoAll };
}
exports.create = create;