Skip to content

Commit

Permalink
add schema fix beta command
Browse files Browse the repository at this point in the history
Signed-off-by: Tobias Gurtzick <[email protected]>
  • Loading branch information
wzrdtales committed Sep 7, 2023
1 parent ac35eb4 commit 0683784
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
25 changes: 25 additions & 0 deletions api.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,31 @@ dbmigrate.prototype = {
);
},

fix: function (specification, opts, callback) {
var executeFix = load('fix');

if (arguments.length > 0) {
if (typeof specification === 'string') {
this.internals.argv.destination = specification;
} else if (typeof specification === 'number') {
this.internals.argv.count = specification;
} else if (typeof specification === 'function') {
callback = specification;
}

if (typeof opts === 'string') {
this.internals.migrationMode = opts;
this.internals.matching = opts;
} else if (typeof opts === 'function') {
callback = opts;
}
}

return Promise.resolve(executeFix(this.internals, this.config)).nodeify(
callback
);
},

check: function (specification, opts, callback) {
var executeCheck = load('check');

Expand Down
52 changes: 52 additions & 0 deletions lib/commands/fix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
var path = require('path');
var log = require('db-migrate-shared').log;
var migrationHook = require('./helper/migration-hook.js');

async function prepare (internals, config) {
try {
await migrationHook(internals);
var Migrator = require('../walker.js');
var index = require('../../connect');

if (!internals.argv.count) {
internals.argv.count = Number.MAX_VALUE;
}
const migrator = await index.connect(
{
config: config.getCurrent().settings,
internals: internals,
prefix: 'migration'
},
Migrator
);

if (internals.locTitle) {
migrator.directory = path.resolve(
internals.argv['migrations-dir'],
internals.locTitle
);
} else {
migrator.directory = path.resolve(internals.argv['migrations-dir']);
}

internals.migrationsDir = migrator.directory;

await migrator.createMigrationsTable();
log.verbose('migration table created');

return migrator;
} catch (err) {
throw err;
}
}

module.exports = async function (internals, config) {
const migrator = await prepare(internals, config);

try {
const res = await migrator.fix(internals.argv);
return internals.onComplete(migrator, internals, null, res);
} catch (err) {
return internals.onComplete(migrator, internals, err);
}
};
4 changes: 4 additions & 0 deletions lib/commands/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function run (internals, config) {

executeSync(internals, config);
break;
case 'fix':
case 'up':
case 'down':
case 'reset':
Expand All @@ -58,6 +59,9 @@ function run (internals, config) {
if (action === 'up') {
var executeUp = load('up');
executeUp(internals, config);
} else if (action === 'fix') {
var executeFix = load('fix');
executeFix(internals, config);
} else {
var executeDown = load('down');
executeDown(internals, config);
Expand Down
40 changes: 40 additions & 0 deletions lib/executors/versioned/v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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) => {
Expand Down Expand Up @@ -65,6 +66,45 @@ const execUnit = {
// 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);
if (!_file._meta.noDefaultColumn) {
chain.addChain(AddConventions);
}
chain.addChain(Learn);
// chain.addChain(StateTravel);

await State.startMigration(context._driver, 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);
await State.endMigration(context._driver, 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._driver, file, context.internals);
Expand Down
59 changes: 59 additions & 0 deletions lib/walker.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,65 @@ Walker.prototype = {
.nodeify(callback);
},

fix: function (options, callback) {
const partialName = options.destination;
const count = options.count;
const sortFn = function (a, b) {
a = a.name.slice(0, a.name.indexOf('-'));
b = b.name.slice(0, b.name.indexOf('-'));

if (!isNaN(a)) {
return a - b;
}

return a.localeCompare(b);
};

const files = File.loadFromDatabase(
this.directory,
this.prefix,
this._driver,
this.internals
).then(completedFiles => {
const toRun = dbmUtil.filterDown(completedFiles, partialName, count).sort(sortFn);

if (toRun.length === 0) {
log.info(this.title + 'Nothing to run');
}

if (this.internals.check) {
const toRunNames = toRun.map(migration => migration.name);
log.info(this.title + 'run:', toRunNames);
return toRunNames;
}

return toRun;
});

if (this.internals.check) {
return files.nodeify(callback);
}

return files
.each(file => {
log.verbose(this.title + 'preparing to run fix:', file.name);
const _meta = file.get()._meta || {};
const version = _meta.version || 1;
if (version < 2) {
log.warn(`${this.title} skipping "${file.name}" as v1 migrations do not maintain a schema`);
return Promise.resolve();
}

this.internals.modSchema = { i: {}, c: {}, f: {}, s: [] };
return require(`./executors/versioned/v${version}`).fix(
this,
this.driver,
file
);
})
.nodeify(callback);
},

check: function (options, callback) {
return Promise.all([
File.loadFromDatabase(
Expand Down

0 comments on commit 0683784

Please sign in to comment.