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 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 initialisation 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))
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
- - [Comparision](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.
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
- - Initialises your database based on your init scripts
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 bersion you would like to migrate to
226
+ # The version you would like to migrate to
227
227
  --v
228
228
 
229
- # Combo Feature to check whether the database was already initialised
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
- // initialisation & migrations are not missing
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.readTasks(path.join(self.migrationPath, 'init'));
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.readTasks(versionPath) || [];
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.name)
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.name,
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
- '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',
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
- _.each(folders, function (folder) {
1152
- // CASE: versions/1.1-members or versions/2.0-payments
1153
- if (folder !== 'init') {
1154
- try {
1155
- folder = folder.match(/([\d._]+)/)[0];
1156
- } catch (err) {
1157
- logging.warn('Cannot parse folder name.');
1158
- logging.warn('Ignore Folder: ' + folder);
1159
- return;
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
- // CASE:
1164
- // if your current version is 1.0 and you add migration scripts for the next version 1.1
1165
- // we won't execute them until your current version changes to 1.1 or until you force KM to migrate to it
1166
- if (self.currentVersion && !force) {
1167
- if (utils.isGreaterThanVersion({smallerVersion: self.currentVersion, greaterVersion: folder})) {
1168
- futureVersions.push(folder);
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
- operations[folder] = self.connection('migrations').where({
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 Reads all migration files from disk based on a path.
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.readTasks = function readTasks(absolutePath) {
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
- _.each(files, function (file) {
66
+ files = files.filter(function (file) {
69
67
  // CASE: ignore dot files
70
- if (file.match(/^\./)) {
71
- debug('Ignore Dotfile: ' + file);
72
- return;
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(files);
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.2",
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": "^10.13.0 || ^12.10.0 || ^14.14.0"
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.1",
54
- "ghost-ignition": "4.5.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.2",
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": "4.2.0"
78
+ "sqlite3": "5.0.2"
79
79
  }
80
80
  }