function onComplete(err) { if (err) { log.error(migration.name, err); } else { log.info('Processed migration', migration.name); } callback(err); }
return Promise.resolve(toRun).each(function(migration) { log.verbose('preparing to run down migration:', migration.name); return self.driver.startMigration() .then(function() { var setup = migration.setup(); if(typeof(setup) === 'function') setup(self.internals.migrationOptions, self.seedLink); return self.down(migration.down.bind(migration)); }) .then(function() { if( self.seedLink && self.seedLink.links.length ) { log.info('Calling linked seeds'); return self.seedLink.process(); } return; }) .then(function() { return (Promise.promisify(self.deleteMigrationRecord.bind(self)))(migration); }) .then(self.driver.endMigration.bind(self.driver)); })
fs.writeFile(file, JSON.stringify(this.relations), function (err) { if (err) { throw err; } log.info('Wrote Relations to file ' + file); });
migrationHook(internals).then(function () { var Migrator = require('../walker.js'); var index = require('../../connect'); if (!internals.argv.count) { log.info('Defaulting to running 1 down migration.'); internals.argv.count = 1; } index.connect( { config: config.getCurrent().settings, internals: internals, prefix: 'migration' }, Migrator, function (err, migrator) { if (!assert(err)) return; migrator.migrationsDir = path.resolve(internals.argv['migrations-dir']); migrator.driver.createMigrationsTable(function (err) { if (!assert(err)) return; migrator.down( internals.argv, internals.onComplete.bind(this, migrator, internals, callback) ); }); } ); });
migrator.driver.createMigrationsTable(function (err) { if (!assert(err, callback)) return; log.verbose('migration table created'); migrator.check( internals.argv, internals.onComplete.bind(this, migrator, internals, callback) ); });
.then(function() { if( self.seedLink && self.seedLink.links.length ) { log.info('Calling linked seeds'); return self.seedLink.process(); } return; })
function tryRequire (migration) { try { if (handled && !installed) { return installAsync(migration, tryRequire.bind(this, migration)); } return require(migration.internals.cwd + '/' + migration.path); } catch (ex) { if (ex instanceof ReferenceError) { if (removedGlobals[ex.message]) { log.info(ex.message, 'Initiating removal of old globals...'); return removedGlobals[ex.message]( migration.path, tryRequire.bind(this, migration) ); } else { log.error( ex.stack, 'Unknown failure, please check your file', migration ); throw new Error( 'Unhandled ReferenceError while transition. Please ' + 'fix the issues and rerun the transitioner again.' ); } } else if (removedGlobals[ex.message]) { return removedGlobals[ex.message]( migration, tryRequire.bind(this, migration) ); } else { log.error(ex.stack, migration); throw new Error( 'Unhandled Error while transition. Please ' + 'fix the issues and rerun the transitioner again.' ); } } }
function installAsync (migration, retry) { var cmd = ['install', '--save', 'async']; if (installed) { retry(); } else { installed = true; } log.info('Installing async...'); cp.spawnSync('npm', cmd, { cwd: migration.internals.cwd, stdio: 'inherit' }); return retry(); }
function executeUndoSeed (internals, config, callback) { var index = require('./connect'); var Seeder = require('./lib/walker.js'); if (!internals.argv.count) { log.info('Defaulting to running 1 down seed.'); internals.argv.count = 1; } if (internals.argv._.length > 0) { internals.argv.destination = internals.argv._.shift().toString(); } index.connect( { config: config.getCurrent().settings, internals: internals, prefix: 'seed' }, Seeder, function (err, seeder) { assert.ifError(err); var seedDir = internals.mode !== 'static' ? 'vcseeder-dir' : 'staticseeder-dir'; seeder.seedDir = path.resolve(internals.argv[seedDir]); if (internals.mode === 'static') { internals.onComplete(seeder, callback, { stack: "Static seeders can't be undone. Use VC Seeders instead!" }); } else { seeder.createSeedsTable(function (err) { if (_assert(err, callback)) { seeder.down( internals.argv, internals.onComplete.bind(this, seeder, internals, callback) ); } }); } } ); }
Migration.loadFromDatabase(self.migrationsDir, self._driver, self.internals, function(err, completedMigrations) { if (err) { callback(err); return; } var toRun = dbmUtil.filterUp(allMigrations, completedMigrations, partialName, count); if (toRun.length === 0) { log.info('No migrations to run'); callback(null); return; } return Promise.resolve(toRun).each(function(migration) { log.verbose('preparing to run up migration:', migration.name); return self.driver.startMigration() .then(function() { var setup = migration.setup(); if(typeof(setup) === 'function') setup(self.internals.migrationOptions, self.seedLink); return self.up(migration.up.bind(migration)); }) .then(function() { if( self.seedLink && self.seedLink.links.length ) { log.info('Calling linked seeds'); return self.seedLink.process(); } return; }) .then(function() { return (Promise.promisify(self.writeMigrationRecord.bind(self)))(migration); }) .then(self.driver.endMigration.bind(self.driver)); }) .nodeify(callback); });
fromJson: function (file) { // Relation = require(file); log.info('Read Relations from file ' + file); },
module.exports = function (internals, isModule) { var rc = require('rc'); var deepExtend = require('deep-extend'); var defaultConfig = { verbose: false, table: 'migrations', 'seeds-table': 'seeds', 'force-exit': false, 'sql-file': false, 'non-transactional': false, config: internals.configFile || internals.cwd + '/database.json', 'migrations-dir': internals.cwd + '/migrations', 'vcseeder-dir': internals.cwd + '/VCSeeder', 'staticseeder-dir': internals.cwd + '/Seeder', 'ignore-completed-migrations': false }; if (!isModule) { internals.argv = optimist .default(defaultConfig) .usage( 'Usage: db-migrate [up|down|check|reset|sync|create|db|transition] ' + '[[dbname/]migrationName|all] [options]' ) .describe( 'env', 'The environment to run the migrations under (dev, test, prod).' ) .alias('e', 'env') .string('e') .describe( 'migrations-dir', 'The directory containing your migration files.' ) .alias('m', 'migrations-dir') .string('m') .describe('count', 'Max number of migrations to run.') .alias('c', 'count') .string('c') .describe('dry-run', "Prints the SQL but doesn't run it.") .boolean('dry-run') .describe('check', 'Prints the migrations to be run without running them.') .boolean('check') .describe( 'force-exit', 'Forcibly exit the migration process on completion.' ) .boolean('force-exit') .describe('verbose', 'Verbose mode.') .alias('v', 'verbose') .boolean('v') .alias('h', 'help') .alias('h', '?') .boolean('h') .describe('version', 'Print version info.') .alias('i', 'version') .boolean('version') .describe('config', 'Location of the database.json file.') .string('config') .describe( 'sql-file', 'Automatically create two sql files for up and down statements in ' + '/sqls and generate the javascript code that loads them.' ) .boolean('sql-file') .describe('coffee-file', 'Create a coffeescript migration file') .boolean('coffee-file') .describe( 'ignore-on-init', 'Create files that will run only if ignore-on-init in the env is set ' + 'to false (currently works only with SQL)' ) .boolean('ignore-on-init') .describe( 'migration-table', 'Set the name of the migration table, which stores the migration history.' ) .alias('table', 'migration-table') .alias('t', 'table') .string('t') .describe( 'seeds-table', 'Set the name of the seeds table, which stores the seed history.' ) .string('seeds-table') .describe( 'vcseeder-dir', 'Set the path to the Version Controlled Seeder directory.' ) .string('vcseeder-dir') .describe('staticseeder-dir', 'Set the path to the Seeder directory.') .string('staticseeder-dir') .describe('non-transactional', 'Explicitly disable transactions') .boolean('non-transactional') .describe('ignore-completed-migrations', 'Start at the first migration') .boolean('ignore-completed-migrations') .describe('log-level', 'Set the log-level, for example sql|warn') .string('log-level'); } else { const _internalsArgv = Object.assign(defaultConfig, internals.cmdOptions); internals.argv = { get argv () { return _internalsArgv; } }; } var plugins = internals.plugins; var plugin = plugins.hook('init:cli:config:hook'); var _config = internals.argv.argv.config; if (plugin) { plugin.forEach(function (plugin) { // var configs = plugin['init:cli:config:hook'](); // if (!configs) return; // hook not yet used, we look into migrating away from optimist first }); } internals.argv = deepExtend(internals.argv.argv, rc('db-migrate', {})); internals.argv.rcconfig = internals.argv.config; internals.argv.config = internals.argv.configFile || _config; if (internals.argv.version) { console.log(internals.dbm.version); process.exit(0); } if (!isModule && (internals.argv.help || internals.argv._.length === 0)) { optimist.showHelp(); process.exit(1); } if (internals.argv['log-level']) { log.setLogLevel(internals.argv['log-level']); } internals.ignoreCompleted = internals.argv['ignore-completed-migrations']; internals.migrationTable = internals.argv.table; internals.seedTable = internals.argv['seeds-table']; internals.matching = ''; internals.verbose = internals.argv.verbose; global.verbose = internals.verbose; internals.notransactions = internals.argv['non-transactional']; internals.dryRun = internals.argv['dry-run']; global.dryRun = internals.dryRun; internals.check = internals.argv['check']; if (internals.dryRun) { log.info('dry run'); } if (internals.check) { log.info('check'); } };
driver.connect(config, internals, function (err, db) { if (err) { callback(err); return; } if (internals.migrationMode) { var dirPath = path.resolve( internals.argv['migrations-dir'] || 'migrations' ); if (internals.migrationMode !== 'all') { var switched = false; var newConf; try { newConf = require(path.resolve( internals.argv['migrations-dir'] || 'migrations', internals.migrationMode ) + '/config.json'); log.info( 'loaded extra config for migration subfolder: "' + internals.migrationMode + '/config.json"' ); switched = true; } catch (e) {} if (switched) { db.switchDatabase(newConf, function (err) { if (err) { return callback(err); } internals.locTitle = internals.migrationMode; callback( null, new PassedClass( db, internals.argv['migrations-dir'], internals.mode !== 'static', internals, prefix ) ); }); } else { internals.locTitle = internals.migrationMode; callback( null, new PassedClass( db, internals.argv['migrations-dir'], internals.mode !== 'static', internals, prefix ) ); } } else { recursive( dirPath, false, internals.argv['migrations-dir'] || 'migrations' ).then(function (files) { var oldClose = db.close; files = files.filter(function (file) { return file !== 'migrations' && fs.statSync(file).isDirectory(); }); files.push(''); db.close = function (cb) { migrationFiles( files, callback, config, internals, PassedClass, db, oldClose, prefix, cb ); }; db.close(); }); } } else { callback( null, new PassedClass( db, internals.argv['migrations-dir'], internals.mode !== 'static', internals, prefix ) ); } });
function migrationFiles ( files, callback, config, internals, PassedClass, db, close, prefix, cb ) { var file; var switched = false; var newConf; if (files.length === 1) { db.close = close; } file = files.pop(); log.info('Enter scope "' + (file !== '' ? file : '/') + '"'); if (file !== '') { try { fs.statSync(path.resolve(file + '/config.json')); newConf = require(path.resolve(file + '/config.json')); log.info( 'loaded extra config for migration subfolder: "' + file + '/config.json"' ); switched = true; } catch (e) {} } db.switchDatabase(switched ? newConf : config.database, function () { internals.matching = file.substr( file.indexOf(internals.argv['migrations-dir'] || 'migrations') + (internals.argv['migrations-dir'] || 'migrations').length + 1 ); if (internals.matching.length === 0) { internals.matching = ''; } internals.locTitle = internals.matching; callback( null, new PassedClass( db, internals.argv['migrations-dir'], internals.mode !== 'static', internals, prefix ) ); if (typeof cb === 'function') { cb(); } }); }