@golemio/db-migrate
Version:
Database migration framework for node.js
118 lines (103 loc) • 4.2 kB
JavaScript
;
const Promise = require('bluebird');
const State = require('../../state');
const log = require('db-migrate-shared').log;
const Learn = require('../../learn');
const Chain = require('../../chain');
const StateTravel = require('../../methods/v2/statetravel');
const Migrate = require('../../methods/v2/migrate');
const TranslateState = require('../../methods/v2/translatestate');
const AddConventions = require('../../methods/v2/conventions');
const util = require('util');
const execUnit = {
_extend: (context, type) => {
return {
atomic: function (actions) {
const action = actions[type];
const reverse = actions[type === 'up' ? 'up' : 'down'];
if (!action || !reverse) {
return Promise.reject(new Error('invalid operation'));
}
return action().catch(() => reverse());
}
};
},
up: async function (context, driver, file) {
const _file = file.get();
const chain = new Chain(context._driver, file, driver, context.internals, context._pdriver);
if (!_file._meta.noDefaultColumn) {
chain.addChain(AddConventions);
}
chain.addChain(Learn);
chain.addChain(StateTravel);
chain.addChain(Migrate);
await State.startMigration(context._pdriver, file, context.internals);
// startMigration - needs secondary instance since we can not afford to
// loose state and the transaction start will include these for roll back
// we will disable them probably at all from DDL when the driver does not
// explicitly signal DDL transaction support (like crdb)
try {
await _file.migrate(chain, {
options: context.internals.safeOptions,
seedLink: context.seedLink,
dbm: context.internals.safeOptions.dbmigrate
});
} catch (err) {
context.internals.rollback = true;
// transfer last state
chain.transferInt();
log.error(
'An error occured. No alternative failure strategy defined. Rolling back!',
err
);
await execUnit.down(context, driver, file);
throw err;
}
await Promise.promisify(context.writeMigrationRecord.bind(context))(file);
return State.endMigration(context._pdriver, file, context.internals);
// end migration, same as start migration
},
fix: async function (context, driver, file) {
const _file = file.get();
const chain = new Chain(context._driver, file, driver, context.internals, context._pdriver);
if (!_file._meta.noDefaultColumn) {
chain.addChain(AddConventions);
}
chain.addChain(Learn);
chain.addChain(StateTravel);
await State.startMigration(context._pdriver, file, context.internals);
// startMigration - needs secondary instance since we can not afford to
// loose state and the transaction start will include these for roll back
// we will disable them probably at all from DDL when the driver does not
// explicitly signal DDL transaction support (like crdb)
try {
await _file.migrate(chain, {
options: context.internals.safeOptions,
seedLink: context.seedLink,
dbm: context.internals.safeOptions.dbmigrate
});
} catch (err) {
context.internals.rollback = true;
// transfer last state
chain.transferInt();
log.error(
'An error occured. No alternative failure strategy defined. Rolling back!',
err
);
await execUnit.down(context, driver, file);
throw err;
}
await State.endMigration(context._pdriver, file, context.internals);
log.verbose(`[fix] current schema`, util.inspect(context.internals.schema, false, null, true));
// end migration, same as start migration
},
down: async function (context, driver, file) {
// start migration, see up comments
await State.startMigration(context._pdriver, file, context.internals);
await TranslateState(context._driver, file, driver, context.internals, context._pdriver);
await State.endMigration(context._pdriver, file, context.internals);
return Promise.promisify(context.deleteMigrationRecord.bind(context))(file);
// end migration, see up comments
}
};
module.exports = execUnit;