diff --git a/bin/runmigration.js b/bin/runmigration.js index cc8c585..095733b 100644 --- a/bin/runmigration.js +++ b/bin/runmigration.js @@ -1,88 +1,115 @@ #!/bin/node -const path = require("path"); -const commandLineArgs = require('command-line-args'); -const fs = require("fs"); -const Async = require("async"); +const path = require('path'); +const commandLineArgs = require('command-line-args'); +const fs = require('fs'); +const Async = require('async'); +const Sequelize = require('sequelize'); +const migrate = require('../lib/migrate'); -const migrate = require("../lib/migrate"); +const migrationsDir = path.join(process.env.PWD, 'migrations'); +const modelsDir = path.join(process.env.PWD, 'models'); const optionDefinitions = [ - { name: 'rev', alias: 'r', type: Number, description: 'Set migration revision (default: 0)', defaultValue: 0 }, - { name: 'pos', alias: 'p', type: Number, description: 'Run first migration at pos (default: 0)', defaultValue: 0 }, - { name: 'one', type: Boolean, description: 'Do not run next migrations', defaultValue: false }, - { name: 'list', alias: 'l', type: Boolean, description: 'Show migration file list (without execution)', defaultValue: false }, - { name: 'migrations-path', type: String, description: 'The path to the migrations folder' }, - { name: 'models-path', type: String, description: 'The path to the models folder' }, - { name: 'help', type: Boolean, description: 'Show this message' } + { + name: 'rev', alias: 'r', type: Number, description: 'Set migration revision (default: 0)', defaultValue: 0, + }, + { + name: 'pos', alias: 'p', type: Number, description: 'Run first migration at pos (default: 0)', defaultValue: 0, + }, + { + name: 'one', type: Boolean, description: 'Do not run next migrations', defaultValue: false, + }, + { + name: 'list', alias: 'l', type: Boolean, description: 'Show migration file list (without execution)', defaultValue: false, + }, + { name: 'help', type: Boolean, description: 'Show this message' }, ]; const options = commandLineArgs(optionDefinitions); -let migrationsDir = path.join(process.env.PWD, options['migrations-path'] || 'migrations'), - modelsDir = path.join(process.env.PWD, options['models-path'] || 'models'); -if (options.help) -{ - console.log("Simple sequelize migration execution tool\n\nUsage:"); - optionDefinitions.forEach((option) => { - let alias = (option.alias) ? ` (-${option.alias})` : '\t'; - console.log(`\t --${option.name}${alias} \t${option.description}`); - }); - process.exit(0); +if (options.help) { + console.log('Simple sequelize migration execution tool\n\nUsage:'); + optionDefinitions.forEach((option) => { + const alias = (option.alias) ? ` (-${option.alias})` : '\t'; + console.log(`\t --${option.name}${alias} \t${option.description}`); + }); + process.exit(0); } -const Sequelize = require("sequelize"); -const sequelize = require(modelsDir).sequelize; +const { sequelize } = require(modelsDir); const queryInterface = sequelize.getQueryInterface(); // execute all migration from -let fromRevision = options.rev; -let fromPos = parseInt(options.pos); -let stop = options.one; - -let migrationFiles = fs.readdirSync(migrationsDir) -// filter JS files - .filter((file) => { - return (file.indexOf('.') !== 0) && (file.slice(-3) === '.js'); - }) -// sort by revision - .sort( (a, b) => { - let revA = parseInt( path.basename(a).split('-',2)[0]), - revB = parseInt( path.basename(b).split('-',2)[0]); - if (revA < revB) return -1; - if (revA > revB) return 1; - return 0; - }) -// remove all migrations before fromRevision - .filter((file) => { - let rev = parseInt( path.basename(file).split('-',2)[0]); - return (rev >= fromRevision); - }); - -console.log("Migrations to execute:"); -migrationFiles.forEach((file) => { - console.log("\t"+file); -}); - -if (options.list) - process.exit(0); +const fromRevision = options.rev; +let fromPos = parseInt(options.pos, 10); +const stop = options.one; - -Async.eachSeries(migrationFiles, - function (file, cb) { - console.log("Execute migration from file: "+file); - migrate.executeMigration(queryInterface, path.join(migrationsDir, file), fromPos, (err) => { - if (stop) - return cb("Stopped"); - - cb(err); +queryInterface.createTable('SequelizeMeta', { + name: { + type: Sequelize.STRING, + allowNull: false, + unique: true, + primaryKey: true, + }, +}).then(() => { + const alreadyExecuted = []; + try { + sequelize.query('SELECT * FROM "SequelizeMeta"', { type: sequelize.QueryTypes.SELECT }) + .then((scripts) => { + (scripts || []).forEach((script) => { + alreadyExecuted[script.name] = true; + }); + const migrationFiles = fs.readdirSync(migrationsDir) + .filter(file => (file.indexOf('.') !== 0) && (file.slice(-3) === '.js')) + .sort((a, b) => { + const revA = parseInt(path.basename(a).split('-', 2)[0], 10); + const revB = parseInt(path.basename(b).split('-', 2)[0], 10); + if (revA < revB) return -1; + if (revA > revB) return 1; + return 0; + }) + .filter((file) => { + const rev = parseInt(path.basename(file).split('-', 2)[0], 10); + return (rev >= fromRevision); + }) + .filter(file => alreadyExecuted[file] !== true); + console.log('Migrations to execute:'); + migrationFiles.forEach((file) => { + console.log(`\t${file}`); }); - // set pos to 0 for next migration - fromPos = 0; - }, - function(err) { - console.log(err); - process.exit(0); - } -); + + if (options.list) { process.exit(0); } + Async.eachSeries( + migrationFiles, (file, cb) => { + console.log(`Execute migration from file: ${file}`); + migrate.executeMigration( + queryInterface, path.join(migrationsDir, file), fromPos, + (err) => { + if (stop) { return cb('Stopped'); } + if (!err) { + return queryInterface.bulkInsert('SequelizeMeta', [{ + name: file, + }]).then(() => cb()).catch(error => cb(error)); + } + return cb(err); + }, + ); + // set pos to 0 for next migration + fromPos = 0; + }, + (err) => { + if (err) { + console.log(err); + } + process.exit(0); + }, + ); + }).catch(error => console.log(error)); + } catch (e) { + console.log(e); + } +}).catch((error) => { + console.log(error); +});