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