|
|
@@ -0,0 +1,84 @@
|
|
|
+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
|
|
|
+}
|