const _ = require('lodash') const sequelize = require('./sequelize') const Sequelize = require('sequelize') const migrations = require('./migrations') const chalk = require('chalk') const Version = sequelize.define('_version', { key: { type: Sequelize.STRING, primaryKey: true }, value: Sequelize.DOUBLE }, { tableName: '_version', timestamps: false }) const getVersion = async (namespace, queryInterface) => { const defaultVersion = migrations[namespace].defaultVersion || migrations[namespace].map(x => x.version).reduce((a, b) => Math.max(a, b), 0.0) const tables = await queryInterface.showAllTables() if (!tables.includes('_version')) { return defaultVersion } else { const result = await Version.findOne({where: {key: namespace}}) if (result) { return result.value } else { return defaultVersion } } } const setVersion = async (namespace, version, queryInterface) => { await Version.upsert({key: namespace, value: version}, { where: { key: namespace }}) } const migrate = async (namespace, targetVersion) => { const queryInterface = sequelize.getQueryInterface() const currentVersion = await getVersion(namespace, queryInterface) let migs = _.sortBy(migrations[namespace], 'version') if (!targetVersion) targetVersion = migs.map(x => x.version).reduce((a, b) => Math.max(a, b), 0) console.log(chalk.green(`Migrating ${namespace}`)) console.log(chalk.yellow(`Current version: ${currentVersion}`)) console.log(chalk.yellow(`Target version: ${targetVersion}`)) // Sanity check for (let mig of migs) { if (!mig.version) throw new Error(`All migrations require versions`) if (!mig.up) throw new Error('All migrations require `up`') } // Filter to relevant migrations migs = migs.filter(mig => mig.version > currentVersion && mig.version <= targetVersion) console.log(`Migrations to run: ${migs.map(x => x.version).join(', ')}`) let lastVersion = currentVersion for (let mig of migs) { if (mig.version > lastVersion) { console.log(chalk.blue(`Running migration ${mig.version}: ${mig.name}`)) mig.description && console.log(chalk.blue(mig.description)) let newVersion = await mig.up(queryInterface, Sequelize) if (!Number.isFinite(newVersion)) throw new Error(`All migrations must return the resulting version`) if (newVersion < lastVersion) throw new Error(`Up migration downgraded database: ${mig.version} -> ${newVersion}`) await setVersion(namespace, newVersion, queryInterface) console.log(`Database now at version ${newVersion}`) lastVersion = newVersion } else { console.log(chalk.blue(`Skipping migration ${mig.version}: ${mig.name}`)) } } console.log(chalk.cyan(`Migration complete. Current database version: ${await getVersion(namespace, queryInterface)}`)) } const migrateAll = async () => { const namespaces = _.keys(_.omit(migrations, 'material-framework')) await migrate('material-framework') console.log(_.keys(migrations)) for (let namespace of namespaces) { await migrate(namespace) } } module.exports = { getVersion, migrate, migrateAll, migrations, setVersion }