knex-migrator 4.0.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/lib/index.js +66 -64
- package/lib/utils.js +24 -11
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -6,14 +6,14 @@ A database migration tool for [knex.js](https://github.com/tgriesser/knex), whic
|
|
|
6
6
|
|
|
7
7
|
- [x] JS API
|
|
8
8
|
- [x] CLI Tool
|
|
9
|
-
- [x] Differentiation between database
|
|
9
|
+
- [x] Differentiation between database initialization and migration (Support for a database schema, [like we use in Ghost](https://github.com/TryGhost/Ghost/blob/1.16.2/core/server/data/schema/schema.js))
|
|
10
10
|
- [x] Support for database creation
|
|
11
11
|
- [x] Hooks
|
|
12
12
|
- [x] Rollback to latest version
|
|
13
13
|
- [x] Auto-Rollback on error
|
|
14
14
|
- [x] Database health check
|
|
15
15
|
- [x] Supports transactions
|
|
16
|
-
- [x] Full atomic, support for separate DML/DDL scripts (no autocommit)
|
|
16
|
+
- [x] Full atomic, support for separate DML/DDL scripts (no autocommit)
|
|
17
17
|
- [x] Migration lock
|
|
18
18
|
- [x] Full debug & pretty log support
|
|
19
19
|
- [x] Custom migration folder structure
|
|
@@ -36,8 +36,8 @@ Add me to your globals:
|
|
|
36
36
|
|
|
37
37
|
- Replicas are unsupported, because Knex.js [doesn't support them](https://github.com/tgriesser/knex/issues/2253).
|
|
38
38
|
- Sqlite does **not** support read locks by default. Read [here](https://github.com/TryGhost/knex-migrator/issues/87) why.
|
|
39
|
-
- [
|
|
40
|
-
- Don't mix DDL/DML statements in a migration script. In MySQL DDL statements use implicit commits.
|
|
39
|
+
- [Comparison](https://github.com/TryGhost/knex-migrator/issues/119) with other available migration tools.
|
|
40
|
+
- Don't mix DDL/DML statements in a migration script. In MySQL DDL statements use implicit commits.
|
|
41
41
|
- It's highly recommended to write both the `up` and the `down` function to ensure a full rollback.
|
|
42
42
|
- If your process dies while migrations are running, knex-migrator won't be able to release the migration lock.
|
|
43
43
|
To release to lock you can run `knex-migrator rollback`. **But** it's recommended to check your database first to see in which state it is.
|
|
@@ -73,7 +73,7 @@ Please take a look at [this real example](https://github.com/TryGhost/Ghost/blob
|
|
|
73
73
|
|
|
74
74
|
```
|
|
75
75
|
project/
|
|
76
|
-
migrations/
|
|
76
|
+
migrations/
|
|
77
77
|
hooks/
|
|
78
78
|
init/
|
|
79
79
|
index.js
|
|
@@ -88,9 +88,9 @@ project/
|
|
|
88
88
|
versions/
|
|
89
89
|
1.0/
|
|
90
90
|
1-add-events-table.js
|
|
91
|
-
2-normalise-settings.js
|
|
91
|
+
2-normalise-settings.js
|
|
92
92
|
2.0/
|
|
93
|
-
1-add-timestamps-columns.js
|
|
93
|
+
1-add-timestamps-columns.js
|
|
94
94
|
2.1/
|
|
95
95
|
1-remove-empty-strings.js
|
|
96
96
|
2-add-webhooks-table.js
|
|
@@ -199,7 +199,7 @@ Commands:
|
|
|
199
199
|
|
|
200
200
|
#### knex-migrator init
|
|
201
201
|
|
|
202
|
-
-
|
|
202
|
+
- Initializes your database based on your init scripts
|
|
203
203
|
- Creates the database if it was not created yet
|
|
204
204
|
|
|
205
205
|
##### Options
|
|
@@ -223,10 +223,10 @@ Commands:
|
|
|
223
223
|
##### Options
|
|
224
224
|
|
|
225
225
|
```bash
|
|
226
|
-
# The
|
|
226
|
+
# The version you would like to migrate to
|
|
227
227
|
--v
|
|
228
228
|
|
|
229
|
-
# Combo Feature to check whether the database was already
|
|
229
|
+
# Combo Feature to check whether the database was already initialized
|
|
230
230
|
--init
|
|
231
231
|
|
|
232
232
|
# Force the execution no matter which current version you are on
|
|
@@ -312,13 +312,13 @@ knexMigrator.reset
|
|
|
312
312
|
knexMigrator.isDatabaseOK()
|
|
313
313
|
.then(function() {
|
|
314
314
|
// database is OK
|
|
315
|
-
//
|
|
315
|
+
// initialization & migrations are not missing
|
|
316
316
|
})
|
|
317
317
|
.catch(function(err) {
|
|
318
318
|
if (err.code === 'DB_NOT_INITIALISED') {
|
|
319
319
|
return knexMigrator.init();
|
|
320
320
|
}
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
if (err.code === 'DB_NEEDS_MIGRATION') {
|
|
323
323
|
return knexMigrator.migrate();
|
|
324
324
|
}
|
package/lib/index.js
CHANGED
|
@@ -119,7 +119,7 @@ KnexMigrator.prototype.init = function init(options) {
|
|
|
119
119
|
}
|
|
120
120
|
})
|
|
121
121
|
.then(function () {
|
|
122
|
-
const initTasks = utils.
|
|
122
|
+
const initTasks = utils.listFiles(path.join(self.migrationPath, 'init'));
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* CASE 1: You can disable init completion manually
|
|
@@ -159,12 +159,12 @@ KnexMigrator.prototype.init = function init(options) {
|
|
|
159
159
|
// CASE: Run over all migration scripts and add the file name to the database.
|
|
160
160
|
return Promise.each(versionsToMigrateTo, function (versionToMigrateTo) {
|
|
161
161
|
let versionPath = path.join(self.migrationPath, self.subfolder, versionToMigrateTo);
|
|
162
|
-
let filesToMigrateTo = utils.
|
|
162
|
+
let filesToMigrateTo = utils.listFiles(versionPath) || [];
|
|
163
163
|
|
|
164
164
|
return Promise.each(filesToMigrateTo, function (fileToMigrateTo) {
|
|
165
165
|
// CASE: check if migration exists, do not insert twice
|
|
166
166
|
return transacting('migrations')
|
|
167
|
-
.where('name', fileToMigrateTo
|
|
167
|
+
.where('name', fileToMigrateTo)
|
|
168
168
|
.then(function (migrationExists) {
|
|
169
169
|
if (migrationExists.length) {
|
|
170
170
|
return Promise.resolve();
|
|
@@ -172,7 +172,7 @@ KnexMigrator.prototype.init = function init(options) {
|
|
|
172
172
|
|
|
173
173
|
return transacting('migrations')
|
|
174
174
|
.insert({
|
|
175
|
-
name: fileToMigrateTo
|
|
175
|
+
name: fileToMigrateTo,
|
|
176
176
|
version: versionToMigrateTo,
|
|
177
177
|
currentVersion: self.currentVersion
|
|
178
178
|
});
|
|
@@ -1045,8 +1045,8 @@ KnexMigrator.prototype._migrateTo = function _migrateTo(options) {
|
|
|
1045
1045
|
throw new errors.MigrationScriptError({
|
|
1046
1046
|
message: 'Field length of %field% in %table% is too long!'.replace('%field%', field).replace('%table%', table),
|
|
1047
1047
|
context: 'This usually happens if your database encoding is utf8mb4.\n' +
|
|
1048
|
-
|
|
1049
|
-
|
|
1048
|
+
'All unique fields and indexes must be lower than 191 characters.\n' +
|
|
1049
|
+
'Please correct your field length and reset your database with knex-migrator reset.\n',
|
|
1050
1050
|
help: 'Read more here: https://github.com/TryGhost/knex-migrator/issues/51\n',
|
|
1051
1051
|
err: err
|
|
1052
1052
|
});
|
|
@@ -1132,7 +1132,6 @@ KnexMigrator.prototype._integrityCheck = function _integrityCheck(options) {
|
|
|
1132
1132
|
subfolder = this.subfolder,
|
|
1133
1133
|
force = options.force,
|
|
1134
1134
|
folders = [],
|
|
1135
|
-
operations = {},
|
|
1136
1135
|
toReturn = {},
|
|
1137
1136
|
futureVersions = [];
|
|
1138
1137
|
|
|
@@ -1148,29 +1147,69 @@ KnexMigrator.prototype._integrityCheck = function _integrityCheck(options) {
|
|
|
1148
1147
|
// ignore
|
|
1149
1148
|
}
|
|
1150
1149
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1150
|
+
return this
|
|
1151
|
+
.connection('migrations')
|
|
1152
|
+
.select('version')
|
|
1153
|
+
.count('version', {as: 'c'})
|
|
1154
|
+
.groupBy('version')
|
|
1155
|
+
.then((dbMigrations) => {
|
|
1156
|
+
_.each(folders, function (folder) {
|
|
1157
|
+
// CASE: versions/1.1-members or versions/2.0-payments
|
|
1158
|
+
if (folder !== 'init') {
|
|
1159
|
+
try {
|
|
1160
|
+
folder = folder.match(/([\d._]+)/)[0];
|
|
1161
|
+
} catch (err) {
|
|
1162
|
+
logging.warn('Cannot parse folder name.');
|
|
1163
|
+
logging.warn('Ignore Folder: ' + folder);
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
// CASE:
|
|
1169
|
+
// if your current version is 1.0 and you add migration scripts for the next version 1.1
|
|
1170
|
+
// we won't execute them until your current version changes to 1.1 or until you force KM to migrate to it
|
|
1171
|
+
if (self.currentVersion && !force) {
|
|
1172
|
+
if (utils.isGreaterThanVersion({smallerVersion: self.currentVersion, greaterVersion: folder})) {
|
|
1173
|
+
futureVersions.push(folder);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
let actual = 0;
|
|
1178
|
+
let expected;
|
|
1179
|
+
|
|
1180
|
+
const migrationCount = dbMigrations.find(m => m.version === folder);
|
|
1181
|
+
if (migrationCount) {
|
|
1182
|
+
actual = migrationCount.c;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
if (folder !== 'init') {
|
|
1186
|
+
expected = utils.listFiles(path.join(self.migrationPath, subfolder, folder)).length;
|
|
1187
|
+
} else {
|
|
1188
|
+
expected = utils.listFiles(path.join(self.migrationPath, folder)).length;
|
|
1189
|
+
}
|
|
1162
1190
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1191
|
+
debug('Version ' + folder + ' expected: ' + expected);
|
|
1192
|
+
debug('Version ' + folder + ' actual: ' + actual);
|
|
1193
|
+
|
|
1194
|
+
toReturn[folder] = {
|
|
1195
|
+
expected: expected,
|
|
1196
|
+
actual: actual
|
|
1197
|
+
};
|
|
1198
|
+
});
|
|
1199
|
+
|
|
1200
|
+
// CASE: ensure that either you have to run `migrate --force` or they ran already
|
|
1201
|
+
if (futureVersions.length) {
|
|
1202
|
+
_.each(futureVersions, function (futureVersion) {
|
|
1203
|
+
if (toReturn[futureVersion].actual !== toReturn[futureVersion].expected) {
|
|
1204
|
+
logging.warn('knex-migrator is skipping ' + futureVersion);
|
|
1205
|
+
logging.warn('Current version in MigratorConfig.js is smaller then requested version, use --force to proceed!');
|
|
1206
|
+
logging.warn('Please run `knex-migrator migrate --v ' + futureVersion + ' --force` to proceed!');
|
|
1207
|
+
delete toReturn[futureVersion];
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1169
1210
|
}
|
|
1170
|
-
}
|
|
1171
1211
|
|
|
1172
|
-
|
|
1173
|
-
version: folder
|
|
1212
|
+
return toReturn;
|
|
1174
1213
|
}).catch(function onMigrationsLookupError(err) {
|
|
1175
1214
|
// CASE: no database selected (database.connection.database="")
|
|
1176
1215
|
if (err.errno === 1046) {
|
|
@@ -1199,43 +1238,6 @@ KnexMigrator.prototype._integrityCheck = function _integrityCheck(options) {
|
|
|
1199
1238
|
|
|
1200
1239
|
throw err;
|
|
1201
1240
|
});
|
|
1202
|
-
});
|
|
1203
|
-
|
|
1204
|
-
return Promise.props(operations)
|
|
1205
|
-
.then(function (result) {
|
|
1206
|
-
_.each(result, function (value, version) {
|
|
1207
|
-
let actual = value.length,
|
|
1208
|
-
expected = actual;
|
|
1209
|
-
|
|
1210
|
-
if (version !== 'init') {
|
|
1211
|
-
expected = utils.readTasks(path.join(self.migrationPath, subfolder, version)).length;
|
|
1212
|
-
} else {
|
|
1213
|
-
expected = utils.readTasks(path.join(self.migrationPath, version)).length;
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
debug('Version ' + version + ' expected: ' + expected);
|
|
1217
|
-
debug('Version ' + version + ' actual: ' + actual);
|
|
1218
|
-
|
|
1219
|
-
toReturn[version] = {
|
|
1220
|
-
expected: expected,
|
|
1221
|
-
actual: actual
|
|
1222
|
-
};
|
|
1223
|
-
});
|
|
1224
|
-
|
|
1225
|
-
// CASE: ensure that either you have to run `migrate --force` or they ran already
|
|
1226
|
-
if (futureVersions.length) {
|
|
1227
|
-
_.each(futureVersions, function (futureVersion) {
|
|
1228
|
-
if (toReturn[futureVersion].actual !== toReturn[futureVersion].expected) {
|
|
1229
|
-
logging.warn('knex-migrator is skipping ' + futureVersion);
|
|
1230
|
-
logging.warn('Current version in MigratorConfig.js is smaller then requested version, use --force to proceed!');
|
|
1231
|
-
logging.warn('Please run `knex-migrator migrate --v ' + futureVersion + ' --force` to proceed!');
|
|
1232
|
-
delete toReturn[futureVersion];
|
|
1233
|
-
}
|
|
1234
|
-
});
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
return toReturn;
|
|
1238
|
-
});
|
|
1239
1241
|
};
|
|
1240
1242
|
|
|
1241
1243
|
module.exports = KnexMigrator;
|
package/lib/utils.js
CHANGED
|
@@ -46,15 +46,13 @@ module.exports.loadConfig = function loadConfig(options) {
|
|
|
46
46
|
};
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* @description
|
|
50
|
-
* It returns an Array of migration files including it's up/down hooks, config and the name.
|
|
49
|
+
* @description List all migration files from disk based on a path.
|
|
51
50
|
*
|
|
52
51
|
* @param absolutePath
|
|
53
52
|
* @returns {Array}
|
|
54
53
|
*/
|
|
55
|
-
exports.
|
|
56
|
-
let files = []
|
|
57
|
-
tasks = [];
|
|
54
|
+
exports.listFiles = function listFiles(absolutePath) {
|
|
55
|
+
let files = [];
|
|
58
56
|
|
|
59
57
|
try {
|
|
60
58
|
files = fs.readdirSync(absolutePath);
|
|
@@ -65,13 +63,28 @@ exports.readTasks = function readTasks(absolutePath) {
|
|
|
65
63
|
});
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
files = files.filter(function (file) {
|
|
69
67
|
// CASE: ignore dot files
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
return !file.match(/^\./);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
debug(files);
|
|
72
|
+
return files;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @description Reads all migration files from disk based on a path.
|
|
77
|
+
* It returns an Array of migration files including it's up/down hooks, config and the name.
|
|
78
|
+
*
|
|
79
|
+
* @param absolutePath
|
|
80
|
+
* @returns {Array}
|
|
81
|
+
*/
|
|
82
|
+
exports.readTasks = function readTasks(absolutePath) {
|
|
83
|
+
let tasks = [];
|
|
84
|
+
|
|
85
|
+
const files = exports.listFiles(absolutePath);
|
|
74
86
|
|
|
87
|
+
_.each(files, function (file) {
|
|
75
88
|
let executeFn = require(path.join(absolutePath, file));
|
|
76
89
|
|
|
77
90
|
try {
|
|
@@ -92,7 +105,7 @@ exports.readTasks = function readTasks(absolutePath) {
|
|
|
92
105
|
}
|
|
93
106
|
});
|
|
94
107
|
|
|
95
|
-
debug(
|
|
108
|
+
debug(tasks);
|
|
96
109
|
return tasks;
|
|
97
110
|
};
|
|
98
111
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knex-migrator",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Database migrations with knex.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ghost",
|
|
@@ -44,18 +44,18 @@
|
|
|
44
44
|
"knex-migrator-rollback": "./bin/knex-migrator-rollback"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": "^
|
|
47
|
+
"node": "^12.22.1 || ^14.17.0 || ^16.13.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"bluebird": "3.7.2",
|
|
51
51
|
"commander": "5.1.0",
|
|
52
52
|
"compare-ver": "2.0.2",
|
|
53
|
-
"debug": "4.3.
|
|
54
|
-
"ghost-ignition": "4.
|
|
53
|
+
"debug": "4.3.2",
|
|
54
|
+
"ghost-ignition": "4.6.3",
|
|
55
55
|
"knex": "0.21.19",
|
|
56
56
|
"lodash": "4.17.21",
|
|
57
57
|
"moment": "2.24.0",
|
|
58
|
-
"nconf": "0.11.
|
|
58
|
+
"nconf": "0.11.3",
|
|
59
59
|
"resolve": "1.20.0"
|
|
60
60
|
},
|
|
61
61
|
"files": [
|
|
@@ -75,6 +75,6 @@
|
|
|
75
75
|
},
|
|
76
76
|
"optionalDependencies": {
|
|
77
77
|
"mysql": "2.18.1",
|
|
78
|
-
"sqlite3": "
|
|
78
|
+
"sqlite3": "5.0.2"
|
|
79
79
|
}
|
|
80
80
|
}
|