migrator.ts 3.0 KB

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