Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added --from and --to support for db:migrate #581

Merged
merged 4 commits into from
Nov 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions src/commands/migrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ import { getMigrator, ensureCurrentMetaSchema, addTimestampsToSchema } from '../
import helpers from '../helpers';
import _ from 'lodash';

exports.builder = yargs => _baseOptions(yargs).help().argv;
exports.builder = yargs => _baseOptions(yargs)
.option('to', {
describe: 'Migration name to run migrations until',
type: 'string'
})
.option('from', {
describe: 'Migration name to start migrations from (excluding)',
type: 'string'
})
.help()
.argv;
exports.handler = async function (args) {
const command = args._[0];

Expand All @@ -29,14 +39,30 @@ exports.handler = async function (args) {
function migrate(args) {
return getMigrator('migration', args).then(migrator => {
return ensureCurrentMetaSchema(migrator)
.then(() => migrator.pending())
.then(() => migrator.pending())
.then(migrations => {
const options = {};
if (migrations.length === 0) {
helpers.view.log('No migrations were executed, database schema was already up to date.');
process.exit(0);
}
if (args.to) {
if (migrations.filter(migration => migration.file === args.to).length === 0) {
helpers.view.log('No migrations were executed, database schema was already up to date.');
process.exit(0);
}
options.to = args.to;
}
if (args.from) {
if (migrations.map(migration => migration.file).lastIndexOf(args.from) === -1) {
helpers.view.log('No migrations were executed, database schema was already up to date.');
process.exit(0);
}
options.from = args.from;
}
return options;
})
.then(() => migrator.up());
.then(options => migrator.up(options));
}).catch(e => helpers.view.error(e));
}

Expand Down
163 changes: 161 additions & 2 deletions test/db/migrate.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


const fs = require('fs');
const expect = require('expect.js');
const Support = require(__dirname + '/../support');
const helpers = require(__dirname + '/../support/helpers');
Expand Down Expand Up @@ -246,3 +245,163 @@ describe(Support.getTestDialectTeaser('db:migrate'), () => {
});
});
});

describe(Support.getTestDialectTeaser('db:migrate'), () => {
describe('optional migration parameters', () => {
const prepare = function (runArgs = '', callback) {
const config = { url: helpers.getTestUrl() };
const configContent = 'module.exports = ' + JSON.stringify(config);
let result = '';

return gulp
.src(Support.resolveSupportPath('tmp'))
.pipe(helpers.clearDirectory())
.pipe(helpers.runCli('init'))
.pipe(helpers.removeFile('config/config.json'))
.pipe(helpers.copyMigration('createPerson.js'))
.pipe(helpers.copyMigration('renamePersonToUser.js'))
.pipe(helpers.copyMigration('createTestTableForTrigger.js'))
.pipe(helpers.copyMigration('createPost.js'))
.pipe(helpers.overwriteFile(configContent, 'config/config.js'))
.pipe(helpers.runCli('db:migrate ' + runArgs))
.on('error', e => {
callback(e);
})
.on('data', data => {
result += data.toString();
})
.on('end', () => {
callback(null, result);
});
};

const runCli = function (cliArgs, callback) {
let result = '';
// avoid double callbacks
let done = callback;
return gulp
.src(Support.resolveSupportPath('tmp'))
.pipe(helpers.runCli(cliArgs, { pipeStdout: true, exitCode: 0 }))
.on('error', e => {
done(e);
done = () => {};
})
.on('data', data => {
result += data.toString();
})
.on('end', () => {
done(null, result);
});
};

it('--to', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createTriggers = migrations.filter(migration => migration.indexOf('createTestTableForTrigger') > -1);

prepare('--to ' + createTriggers, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(3);
expect(tables).to.contain('User');
expect(tables).to.contain('trigger_test');
done();
});
});
});

it('--to full migration in two parts', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createTriggers = migrations.filter(migration => migration.indexOf('createTestTableForTrigger') > -1);
const createPost = migrations.filter(migration => migration.indexOf('createPost') > -1);

prepare('--to ' + createTriggers, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(3);
expect(tables).to.contain('User');
expect(tables).to.contain('trigger_test');
runCli('db:migrate --to ' + createPost, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(4);
expect(tables).to.contain('Post');
done();
});
});
});
});
});

it('--to should exit with 0 when there are no migrations', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createTriggers = migrations.filter(migration => migration.indexOf('createTestTableForTrigger') > -1);

prepare('--to ' + createTriggers, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(3);
expect(tables).to.contain('User');
runCli('db:migrate --to ' + createTriggers, (err, result) => {
expect(result).to.contain('No migrations were executed, database schema was already up to date.');
done(err);
});
});
});
});

it('--from', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createPersonMigration = migrations.filter(migration => migration.indexOf('renamePersonToUser') > -1);

prepare('--from ' + createPersonMigration, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(3);
expect(tables).to.contain('Post');
expect(tables).to.contain('trigger_test');
done();
});
});
});

it('--from should exit with 0 when there are no migrations', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createPersonMigration = migrations.filter(migration => migration.indexOf('renamePersonToUser') > -1);
const createPost = migrations.filter(migration => migration.indexOf('createPost') > -1);

prepare('--from ' + createPersonMigration, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(3);
expect(tables).to.contain('Post');
expect(tables).to.contain('trigger_test');
runCli('db:migrate --from ' + createPost, (err, result) => {
expect(result).to.contain('No migrations were executed, database schema was already up to date.');
done(err);
});
});
});
});


it('--to and --from together', function (done) {
const self = this;
const migrationsPath = Support.resolveSupportPath('assets', 'migrations');
const migrations = fs.readdirSync(migrationsPath);
const createPersonMigration = migrations.filter(migration => migration.indexOf('renamePersonToUser') > -1);
const createPost = migrations.filter(migration => migration.indexOf('createTestTableForTrigger') > -1);

prepare('--from ' + createPersonMigration + ' --to ' + createPost, () => {
helpers.readTables(self.sequelize, tables => {
expect(tables).to.have.length(2);
expect(tables).to.contain('trigger_test');
done();
});
});
});
});
});