d381551b583bec39aa1b8b9b0908b7122b48c921
[oweals/peertube.git] / server / initializers / migrator.ts
1 import * as path from 'path'
2 import * as Promise from 'bluebird'
3
4 import { database as db } from './database'
5 import { LAST_MIGRATION_VERSION } from './constants'
6 import { logger, readdirPromise } from '../helpers'
7
8 function migrate () {
9   const p = db.sequelize.getQueryInterface().showAllTables()
10     .then(tables => {
11       // No tables, we don't need to migrate anything
12       // The installer will do that
13       if (tables.length === 0) throw null
14     })
15     .then(() => {
16       return db.Application.loadMigrationVersion()
17     })
18     .then(actualVersion => {
19       if (actualVersion === null) {
20         return db.Application.create({ migrationVersion: 0 }).then(() => 0)
21       }
22
23       return actualVersion
24     })
25     .then(actualVersion => {
26       // No need migrations, abort
27       if (actualVersion >= LAST_MIGRATION_VERSION) throw null
28
29       return actualVersion
30     })
31     .then(actualVersion => {
32       // If there are a new migration scripts
33       logger.info('Begin migrations.')
34
35       return getMigrationScripts().then(migrationScripts => ({ actualVersion, migrationScripts }))
36     })
37     .then(({ actualVersion, migrationScripts }) => {
38       return Promise.mapSeries(migrationScripts, entity => {
39         return executeMigration(actualVersion, entity)
40       })
41     })
42     .then(() => {
43       logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
44     })
45     .catch(err => {
46       if (err === null) return undefined
47
48       throw err
49     })
50
51   return p
52 }
53
54 // ---------------------------------------------------------------------------
55
56 export {
57   migrate
58 }
59
60 // ---------------------------------------------------------------------------
61
62 function getMigrationScripts () {
63   return readdirPromise(path.join(__dirname, 'migrations')).then(files => {
64     const filesToMigrate: {
65       version: string,
66       script: string
67     }[] = []
68
69     files.forEach(function (file) {
70       // Filename is something like 'version-blabla.js'
71       const version = file.split('-')[0]
72       filesToMigrate.push({
73         version,
74         script: file
75       })
76     })
77
78     return filesToMigrate
79   })
80 }
81
82 function executeMigration (actualVersion: number, entity: { version: string, script: string }) {
83   const versionScript = parseInt(entity.version, 10)
84
85   // Do not execute old migration scripts
86   if (versionScript <= actualVersion) return undefined
87
88   // Load the migration module and run it
89   const migrationScriptName = entity.script
90   logger.info('Executing %s migration script.', migrationScriptName)
91
92   const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
93
94   return db.sequelize.transaction(t => {
95     const options = {
96       transaction: t,
97       queryInterface: db.sequelize.getQueryInterface(),
98       sequelize: db.sequelize
99     }
100
101     migrationScript.up(options)
102       .then(() => {
103         // Update the new migration version
104         db.Application.updateMigrationVersion(versionScript, t)
105       })
106   })
107 }