migrator.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import * as path from 'path'
  2. import { logger } from '../helpers/logger'
  3. import { LAST_MIGRATION_VERSION } from './constants'
  4. import { sequelizeTypescript } from './database'
  5. import { readdir } from 'fs-extra'
  6. async function migrate () {
  7. const tables = await sequelizeTypescript.getQueryInterface().showAllTables()
  8. // No tables, we don't need to migrate anything
  9. // The installer will do that
  10. if (tables.length === 0) return
  11. let actualVersion: number | null = null
  12. const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"')
  13. if (rows && rows[0] && rows[0].migrationVersion) {
  14. actualVersion = rows[0].migrationVersion
  15. }
  16. if (actualVersion === null) {
  17. await sequelizeTypescript.query('INSERT INTO "application" ("migrationVersion") VALUES (0)')
  18. actualVersion = 0
  19. }
  20. // No need migrations, abort
  21. if (actualVersion >= LAST_MIGRATION_VERSION) return
  22. // If there are a new migration scripts
  23. logger.info('Begin migrations.')
  24. const migrationScripts = await getMigrationScripts()
  25. for (const migrationScript of migrationScripts) {
  26. try {
  27. await executeMigration(actualVersion, migrationScript)
  28. } catch (err) {
  29. logger.error('Cannot execute migration %s.', migrationScript.version, { err })
  30. process.exit(-1)
  31. }
  32. }
  33. logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
  34. }
  35. // ---------------------------------------------------------------------------
  36. export {
  37. migrate
  38. }
  39. // ---------------------------------------------------------------------------
  40. async function getMigrationScripts () {
  41. const files = await readdir(path.join(__dirname, 'migrations'))
  42. const filesToMigrate: {
  43. version: string,
  44. script: string
  45. }[] = []
  46. files
  47. .filter(file => file.endsWith('.js.map') === false)
  48. .forEach(file => {
  49. // Filename is something like 'version-blabla.js'
  50. const version = file.split('-')[0]
  51. filesToMigrate.push({
  52. version,
  53. script: file
  54. })
  55. })
  56. return filesToMigrate
  57. }
  58. async function executeMigration (actualVersion: number, entity: { version: string, script: string }) {
  59. const versionScript = parseInt(entity.version, 10)
  60. // Do not execute old migration scripts
  61. if (versionScript <= actualVersion) return undefined
  62. // Load the migration module and run it
  63. const migrationScriptName = entity.script
  64. logger.info('Executing %s migration script.', migrationScriptName)
  65. const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
  66. return sequelizeTypescript.transaction(async t => {
  67. const options = {
  68. transaction: t,
  69. queryInterface: sequelizeTypescript.getQueryInterface(),
  70. sequelize: sequelizeTypescript
  71. }
  72. await migrationScript.up(options)
  73. // Update the new migration version
  74. await sequelizeTypescript.query('UPDATE "application" SET "migrationVersion" = ' + versionScript, { transaction: t })
  75. })
  76. }