379d43af528f0e16456dd9e8c7a635870620dadf
[oweals/peertube.git] / server / initializers / migrator.ts
1 import { waterfall, eachSeries } from 'async'
2 import * as fs from 'fs'
3 import * as path from 'path'
4 import * as Sequelize from 'sequelize'
5
6 import { database as db } from './database'
7 import { LAST_MIGRATION_VERSION } from './constants'
8 import { logger } from '../helpers'
9 import { ApplicationInstance } from '../models'
10
11 function migrate (finalCallback) {
12   waterfall([
13
14     function checkApplicationTableExists (callback) {
15       db.sequelize.getQueryInterface().showAllTables().asCallback(function (err, tables) {
16         if (err) return callback(err)
17
18         // No tables, we don't need to migrate anything
19         // The installer will do that
20         if (tables.length === 0) return finalCallback(null)
21
22         return callback(null)
23       })
24     },
25
26     function loadMigrationVersion (callback) {
27       db.Application.loadMigrationVersion(callback)
28     },
29
30     function createMigrationRowIfNotExists (actualVersion, callback) {
31       if (actualVersion === null) {
32         db.Application.create({
33           migrationVersion: 0
34         }, function (err) {
35           return callback(err, 0)
36         })
37       }
38
39       return callback(null, actualVersion)
40     },
41
42     function abortMigrationIfNotNeeded (actualVersion, callback) {
43       // No need migrations
44       if (actualVersion >= LAST_MIGRATION_VERSION) return finalCallback(null)
45
46       return callback(null, actualVersion)
47     },
48
49     function getMigrations (actualVersion, callback) {
50       // If there are a new migration scripts
51       logger.info('Begin migrations.')
52
53       getMigrationScripts(function (err, migrationScripts) {
54         return callback(err, actualVersion, migrationScripts)
55       })
56     },
57
58     function doMigrations (actualVersion, migrationScripts, callback) {
59       eachSeries(migrationScripts, function (entity, callbackEach) {
60         executeMigration(actualVersion, entity, callbackEach)
61       }, function (err) {
62         if (err) return callback(err)
63
64         logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
65         return callback(null)
66       })
67     }
68   ], finalCallback)
69 }
70
71 // ---------------------------------------------------------------------------
72
73 export {
74   migrate
75 }
76
77 // ---------------------------------------------------------------------------
78
79 function getMigrationScripts (callback) {
80   fs.readdir(path.join(__dirname, 'migrations'), function (err, files) {
81     if (err) return callback(err)
82
83     const filesToMigrate = []
84
85     files.forEach(function (file) {
86       // Filename is something like 'version-blabla.js'
87       const version = file.split('-')[0]
88       filesToMigrate.push({
89         version,
90         script: file
91       })
92     })
93
94     return callback(err, filesToMigrate)
95   })
96 }
97
98 function executeMigration (actualVersion, entity, callback) {
99   const versionScript = parseInt(entity.version, 10)
100
101   // Do not execute old migration scripts
102   if (versionScript <= actualVersion) return callback(null)
103
104   // Load the migration module and run it
105   const migrationScriptName = entity.script
106   logger.info('Executing %s migration script.', migrationScriptName)
107
108   const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
109
110   db.sequelize.transaction().asCallback(function (err, t) {
111     if (err) return callback(err)
112
113     const options = {
114       transaction: t,
115       queryInterface: db.sequelize.getQueryInterface(),
116       sequelize: db.sequelize,
117       Sequelize: Sequelize
118     }
119     migrationScript.up(options, function (err) {
120       if (err) {
121         t.rollback()
122         return callback(err)
123       }
124
125       // Update the new migration version
126       db.Application.updateMigrationVersion(versionScript, t, function (err) {
127         if (err) {
128           t.rollback()
129           return callback(err)
130         }
131
132         t.commit().asCallback(callback)
133       })
134     })
135   })
136 }