db-migrate 1.0.0-beta.9 → 1.0.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/LICENSE +26 -0
- package/README.md +13 -5
- package/api.js +27 -2
- package/connect.js +29 -11
- package/lib/chain.js +57 -2
- package/lib/commands/check.js +3 -3
- package/lib/commands/create-migration.js +23 -3
- package/lib/commands/down.js +1 -1
- package/lib/commands/fix.js +53 -0
- package/lib/commands/generated.js +1 -0
- package/lib/commands/helper/register-events.js +3 -2
- package/lib/commands/run.js +23 -8
- package/lib/commands/seed.js +11 -45
- package/lib/commands/set-default-argv.js +17 -1
- package/lib/commands/sync.js +3 -3
- package/lib/commands/undo-seed.js +11 -51
- package/lib/commands/up.js +3 -3
- package/lib/driver/index.js +110 -41
- package/lib/executors/versioned/v2.js +190 -12
- package/lib/file.js +36 -1
- package/lib/format-error.js +119 -0
- package/lib/interface/seederInterface.js +1 -1
- package/lib/learn.js +54 -17
- package/lib/methods/v2/statedone.js +18 -0
- package/lib/methods/v2/statetravel.js +41 -35
- package/lib/methods/v2/translatestate.js +41 -9
- package/lib/state.js +459 -76
- package/lib/walker.js +195 -89
- package/package.json +18 -22
- package/CHANGELOG.md +0 -487
- package/get.js +0 -67
- package/pnpm-lock.yaml +0 -2574
- package/te.js +0 -70
package/lib/walker.js
CHANGED
|
@@ -6,36 +6,38 @@ const log = require('db-migrate-shared').log;
|
|
|
6
6
|
const Promise = require('bluebird');
|
|
7
7
|
const File = require('./file.js');
|
|
8
8
|
|
|
9
|
-
// Not sure what will happen to this yet
|
|
10
|
-
function SeedLink (driver, internals) {
|
|
11
|
-
this.seeder = require('./seeder.js')(
|
|
12
|
-
driver,
|
|
13
|
-
internals.argv['vcseeder-dir'],
|
|
14
|
-
true,
|
|
15
|
-
internals
|
|
16
|
-
);
|
|
17
|
-
this.internals = internals;
|
|
18
|
-
this.links = [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
9
|
const INTERFACES = {
|
|
22
10
|
migration: require('./interface/migratorInterface.js'),
|
|
23
11
|
seed: require('./interface/seederInterface.js'),
|
|
24
12
|
'static-seed': require('./interface/seederInterface.js')
|
|
25
13
|
};
|
|
26
14
|
|
|
27
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Name the migration an error belongs to, for the error output.
|
|
17
|
+
*/
|
|
18
|
+
const failedIn = file => err => {
|
|
19
|
+
if (err && typeof err === 'object' && err.migration === undefined) {
|
|
20
|
+
err.migration = file.name;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
throw err;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const Walker = function (driver, directory, mode, intern, prefix, opts = {}) {
|
|
28
27
|
this.driver = dbmUtil.reduceToInterface(driver, INTERFACES[prefix]);
|
|
29
28
|
this._driver = driver;
|
|
29
|
+
this._pdriver = opts.db2;
|
|
30
30
|
Promise.promisifyAll(this._driver);
|
|
31
|
+
Promise.promisifyAll(this._pdriver);
|
|
31
32
|
this.directory = directory;
|
|
32
33
|
this.internals = intern;
|
|
33
34
|
/**
|
|
34
35
|
* i: index
|
|
35
36
|
* c: schema
|
|
36
37
|
* f: foreignKey
|
|
38
|
+
* e: extra items for the schema (like ENUM types)
|
|
37
39
|
*/
|
|
38
|
-
this.internals.schema = { i: {}, c: {}, f: {} };
|
|
40
|
+
this.internals.schema = { i: {}, c: {}, f: {}, e: {} };
|
|
39
41
|
/**
|
|
40
42
|
* s: commands
|
|
41
43
|
* i: index
|
|
@@ -51,19 +53,17 @@ const Walker = function (driver, directory, mode, intern, prefix) {
|
|
|
51
53
|
this.title = `[${prefix}] `;
|
|
52
54
|
|
|
53
55
|
// keep it until we decide how we do the cross linking
|
|
54
|
-
if (intern.linked === false) {
|
|
55
|
-
this.seedLink = new SeedLink(driver, intern);
|
|
56
|
-
intern.linked = true;
|
|
57
|
-
}
|
|
58
56
|
};
|
|
59
57
|
|
|
60
58
|
Walker.prototype = {
|
|
61
|
-
createTables: async function () {
|
|
62
|
-
await State.init(this.
|
|
63
|
-
return
|
|
59
|
+
createTables: async function (options) {
|
|
60
|
+
await State.init(this._pdriver, this.internals, options);
|
|
61
|
+
return State.createConcurrently(() =>
|
|
62
|
+
this._driver._createList(this.internals.migrationTable)
|
|
63
|
+
);
|
|
64
64
|
},
|
|
65
65
|
|
|
66
|
-
createMigrationsTable: function () {
|
|
66
|
+
createMigrationsTable: function (options = {}) {
|
|
67
67
|
if (
|
|
68
68
|
typeof this._driver._createList !== 'function' ||
|
|
69
69
|
typeof this._driver._getList !== 'function' ||
|
|
@@ -84,7 +84,53 @@ Walker.prototype = {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
return this.createTables();
|
|
87
|
+
return this.createTables(options);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Determine what to run first, only lock when there is actually something
|
|
92
|
+
* to run. If another process holds the lock, wait for its release and
|
|
93
|
+
* determine again, the other process might have done the work already.
|
|
94
|
+
* Once we hold the lock, state and pending migrations are read again.
|
|
95
|
+
*/
|
|
96
|
+
_withLock: async function (determine, run) {
|
|
97
|
+
if (this.prefix !== 'migration' || this.internals.dryRun) {
|
|
98
|
+
return run(await determine());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!State.supportsLock(this._pdriver)) {
|
|
102
|
+
log.warn(
|
|
103
|
+
this.title +
|
|
104
|
+
'Your database driver does not support migration locking, ' +
|
|
105
|
+
'concurrent processes are not prevented from migrating at the ' +
|
|
106
|
+
'same time. Update your driver to a version supporting it.'
|
|
107
|
+
);
|
|
108
|
+
return run(await determine());
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let stale = null;
|
|
112
|
+
let toRun = await determine();
|
|
113
|
+
|
|
114
|
+
while (toRun.length > 0) {
|
|
115
|
+
if (await State.acquire(this._pdriver, this.internals, stale)) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
log.info(this.title + 'Waiting for the migration lock of another process');
|
|
120
|
+
stale = await State.waitForRelease(this._pdriver, this.internals);
|
|
121
|
+
toRun = await determine();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (toRun.length === 0) {
|
|
125
|
+
return run(toRun);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
await State.reloadSchema(this._pdriver, this.internals);
|
|
130
|
+
return await run(await determine());
|
|
131
|
+
} finally {
|
|
132
|
+
await State.release(this._pdriver, this.internals);
|
|
133
|
+
}
|
|
88
134
|
},
|
|
89
135
|
|
|
90
136
|
writeMigrationRecord: function (migration, callback) {
|
|
@@ -146,96 +192,156 @@ Walker.prototype = {
|
|
|
146
192
|
up: function (options, callback) {
|
|
147
193
|
const partialName = options.destination;
|
|
148
194
|
const count = options.count;
|
|
149
|
-
const
|
|
150
|
-
|
|
195
|
+
const determine = () =>
|
|
196
|
+
Promise.all([
|
|
197
|
+
File.loadFromFileystem(this.directory, this.prefix, this.internals),
|
|
198
|
+
File.loadFromDatabase(
|
|
199
|
+
this.directory,
|
|
200
|
+
this.prefix,
|
|
201
|
+
this._driver,
|
|
202
|
+
this.internals
|
|
203
|
+
)
|
|
204
|
+
]).spread((allFiles, completedFiles) =>
|
|
205
|
+
dbmUtil.filterUp(allFiles, completedFiles, partialName, count)
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
if (this.internals.check) {
|
|
209
|
+
return determine()
|
|
210
|
+
.then(toRun => this._checkResult(toRun))
|
|
211
|
+
.nodeify(callback);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return Promise.resolve(
|
|
215
|
+
this._withLock(determine, toRun => {
|
|
216
|
+
if (toRun.length === 0) {
|
|
217
|
+
log.info(this.title + 'Nothing to run');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return Promise.each(toRun, file => {
|
|
221
|
+
log.verbose(this.title + 'preparing to run up:', file.name);
|
|
222
|
+
const _meta = file.get()._meta || {};
|
|
223
|
+
const version = _meta.version || 1;
|
|
224
|
+
this.internals.modSchema = { i: {}, c: {}, f: {}, s: [] };
|
|
225
|
+
return Promise.resolve(
|
|
226
|
+
require(`./executors/versioned/v${version}`).up(
|
|
227
|
+
this,
|
|
228
|
+
this.driver,
|
|
229
|
+
file
|
|
230
|
+
)
|
|
231
|
+
).catch(failedIn(file));
|
|
232
|
+
});
|
|
233
|
+
})
|
|
234
|
+
).nodeify(callback);
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
down: function (options, callback) {
|
|
238
|
+
const partialName = options.destination;
|
|
239
|
+
const count = options.count;
|
|
240
|
+
const determine = () =>
|
|
151
241
|
File.loadFromDatabase(
|
|
152
242
|
this.directory,
|
|
153
243
|
this.prefix,
|
|
154
244
|
this._driver,
|
|
155
245
|
this.internals
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
const toRun = dbmUtil.filterUp(
|
|
159
|
-
allFiles,
|
|
160
|
-
completedFiles,
|
|
161
|
-
partialName,
|
|
162
|
-
count
|
|
246
|
+
).then(completedFiles =>
|
|
247
|
+
dbmUtil.filterDown(completedFiles, partialName, count)
|
|
163
248
|
);
|
|
164
249
|
|
|
165
|
-
if (toRun.length === 0) {
|
|
166
|
-
log.info(this.title + 'Nothing to run');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (this.internals.check) {
|
|
170
|
-
const toRunNames = toRun.map(migration => migration.name);
|
|
171
|
-
log.info(this.title + 'run:', toRunNames);
|
|
172
|
-
return toRunNames;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return toRun;
|
|
176
|
-
});
|
|
177
|
-
|
|
178
250
|
if (this.internals.check) {
|
|
179
|
-
return
|
|
251
|
+
return determine()
|
|
252
|
+
.then(toRun => this._checkResult(toRun))
|
|
253
|
+
.nodeify(callback);
|
|
180
254
|
}
|
|
181
255
|
|
|
182
|
-
return
|
|
183
|
-
.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return
|
|
189
|
-
this,
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
256
|
+
return Promise.resolve(
|
|
257
|
+
this._withLock(determine, toRun => {
|
|
258
|
+
if (toRun.length === 0) {
|
|
259
|
+
log.info(this.title + 'Nothing to run');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return Promise.each(toRun, file => {
|
|
263
|
+
log.verbose(this.title + 'preparing to run down:', file.name);
|
|
264
|
+
const _meta = file.get()._meta || {};
|
|
265
|
+
const version = _meta.version || 1;
|
|
266
|
+
this.internals.modSchema = { i: {}, c: {}, f: {}, s: [] };
|
|
267
|
+
return Promise.resolve(
|
|
268
|
+
require(`./executors/versioned/v${version}`).down(
|
|
269
|
+
this,
|
|
270
|
+
this.driver,
|
|
271
|
+
file
|
|
272
|
+
)
|
|
273
|
+
).catch(failedIn(file));
|
|
274
|
+
});
|
|
193
275
|
})
|
|
194
|
-
|
|
276
|
+
).nodeify(callback);
|
|
195
277
|
},
|
|
196
278
|
|
|
197
|
-
|
|
279
|
+
fix: function (options, callback) {
|
|
198
280
|
const partialName = options.destination;
|
|
199
281
|
const count = options.count;
|
|
282
|
+
const sortFn = function (a, b) {
|
|
283
|
+
a = a.name.slice(0, a.name.indexOf('-'));
|
|
284
|
+
b = b.name.slice(0, b.name.indexOf('-'));
|
|
200
285
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
this.prefix,
|
|
204
|
-
this._driver,
|
|
205
|
-
this.internals
|
|
206
|
-
).then(completedFiles => {
|
|
207
|
-
const toRun = dbmUtil.filterDown(completedFiles, partialName, count);
|
|
208
|
-
|
|
209
|
-
if (toRun.length === 0) {
|
|
210
|
-
log.info(this.title + 'Nothing to run');
|
|
286
|
+
if (!isNaN(a)) {
|
|
287
|
+
return a - b;
|
|
211
288
|
}
|
|
212
289
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
log.info(this.title + 'run:', toRunNames);
|
|
216
|
-
return toRunNames;
|
|
217
|
-
}
|
|
290
|
+
return a.localeCompare(b);
|
|
291
|
+
};
|
|
218
292
|
|
|
219
|
-
|
|
220
|
-
|
|
293
|
+
const determine = () =>
|
|
294
|
+
File.loadFromDatabase(
|
|
295
|
+
this.directory,
|
|
296
|
+
this.prefix,
|
|
297
|
+
this._driver,
|
|
298
|
+
this.internals
|
|
299
|
+
).then(completedFiles =>
|
|
300
|
+
dbmUtil.filterDown(completedFiles, partialName, count).sort(sortFn)
|
|
301
|
+
);
|
|
221
302
|
|
|
222
303
|
if (this.internals.check) {
|
|
223
|
-
return
|
|
304
|
+
return determine()
|
|
305
|
+
.then(toRun => this._checkResult(toRun))
|
|
306
|
+
.nodeify(callback);
|
|
224
307
|
}
|
|
225
308
|
|
|
226
|
-
return
|
|
227
|
-
.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return
|
|
233
|
-
this,
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
309
|
+
return Promise.resolve(
|
|
310
|
+
this._withLock(determine, toRun => {
|
|
311
|
+
if (toRun.length === 0) {
|
|
312
|
+
log.info(this.title + 'Nothing to run');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return Promise.each(toRun, file => {
|
|
316
|
+
log.verbose(this.title + 'preparing to run fix:', file.name);
|
|
317
|
+
const _meta = file.get()._meta || {};
|
|
318
|
+
const version = _meta.version || 1;
|
|
319
|
+
if (version < 2) {
|
|
320
|
+
log.warn(`${this.title} skipping "${file.name}" as v1 migrations do not maintain a schema`);
|
|
321
|
+
return Promise.resolve();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
this.internals.modSchema = { i: {}, c: {}, f: {}, s: [] };
|
|
325
|
+
return Promise.resolve(
|
|
326
|
+
require(`./executors/versioned/v${version}`).fix(
|
|
327
|
+
this,
|
|
328
|
+
this.driver,
|
|
329
|
+
file
|
|
330
|
+
)
|
|
331
|
+
).catch(failedIn(file));
|
|
332
|
+
});
|
|
237
333
|
})
|
|
238
|
-
|
|
334
|
+
).nodeify(callback);
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
_checkResult: function (toRun) {
|
|
338
|
+
if (toRun.length === 0) {
|
|
339
|
+
log.info(this.title + 'Nothing to run');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const toRunNames = toRun.map(migration => migration.name);
|
|
343
|
+
log.info(this.title + 'run:', toRunNames);
|
|
344
|
+
return toRunNames;
|
|
239
345
|
},
|
|
240
346
|
|
|
241
347
|
check: function (options, callback) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "db-migrate",
|
|
3
3
|
"description": "Database migration framework for node.js",
|
|
4
|
-
"author": "Tobias
|
|
4
|
+
"author": "Tobias Gurtzick",
|
|
5
5
|
"bin": "./bin/db-migrate",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"database",
|
|
@@ -27,14 +27,11 @@
|
|
|
27
27
|
"seeds",
|
|
28
28
|
"seeder",
|
|
29
29
|
"migrator",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
30
|
+
"programmatic",
|
|
31
|
+
"programmable",
|
|
32
32
|
"api"
|
|
33
33
|
],
|
|
34
|
-
"version": "1.0.0
|
|
35
|
-
"engines": {
|
|
36
|
-
"node": ">=8.0.0"
|
|
37
|
-
},
|
|
34
|
+
"version": "1.0.0",
|
|
38
35
|
"bugs": {
|
|
39
36
|
"url": "https://github.com/db-migrate/node-db-migrate/issues"
|
|
40
37
|
},
|
|
@@ -44,32 +41,31 @@
|
|
|
44
41
|
"url": "https://github.com/db-migrate/node-db-migrate.git"
|
|
45
42
|
},
|
|
46
43
|
"dependencies": {
|
|
47
|
-
"bluebird": "^3.
|
|
44
|
+
"bluebird": "^3.7.2",
|
|
48
45
|
"db-migrate-shared": "^1.2.0",
|
|
49
46
|
"deep-extend": "^0.6.0",
|
|
50
|
-
"dotenv": "^
|
|
47
|
+
"dotenv": "^16.3.1",
|
|
51
48
|
"final-fs": "^1.6.0",
|
|
52
49
|
"inflection": "^1.10.0",
|
|
53
|
-
"mkdirp": "~0.5.0",
|
|
54
50
|
"parse-database-url": "~0.3.0",
|
|
55
51
|
"rc": "^1.2.8",
|
|
56
|
-
"resolve": "^1.
|
|
57
|
-
"
|
|
58
|
-
"tunnel-ssh": "^4.0.0",
|
|
59
|
-
"yargs": "^15.3.1"
|
|
52
|
+
"resolve": "^1.19.0",
|
|
53
|
+
"yargs": "^17.5.1"
|
|
60
54
|
},
|
|
61
55
|
"devDependencies": {
|
|
62
|
-
"@
|
|
63
|
-
"@hapi/
|
|
56
|
+
"@babel/eslint-parser": "^7.21.8",
|
|
57
|
+
"@hapi/code": "9.x",
|
|
58
|
+
"@hapi/eslint-plugin": "^6.0.0",
|
|
59
|
+
"@hapi/lab": "25.x",
|
|
64
60
|
"db-migrate-base": "^2.1.1",
|
|
65
|
-
"db-migrate-mysql": "^2.
|
|
66
|
-
"db-migrate-sqlite3": "^0.
|
|
67
|
-
"eslint": "^
|
|
61
|
+
"db-migrate-mysql": "^2.2.0",
|
|
62
|
+
"db-migrate-sqlite3": "^0.5.0",
|
|
63
|
+
"eslint": "^7.32.0",
|
|
68
64
|
"eslint-config-standard": "^14.1.1",
|
|
69
|
-
"eslint-plugin-import": "^2.
|
|
65
|
+
"eslint-plugin-import": "^2.26.0",
|
|
70
66
|
"eslint-plugin-node": "^11.1.0",
|
|
71
|
-
"eslint-plugin-promise": "^4.
|
|
72
|
-
"eslint-plugin-standard": "^4.0
|
|
67
|
+
"eslint-plugin-promise": "^4.3.1",
|
|
68
|
+
"eslint-plugin-standard": "^4.1.0",
|
|
73
69
|
"proxyquire": "^1.4.0",
|
|
74
70
|
"rimraf": "^3.0.2",
|
|
75
71
|
"sinon": "^9.0.2"
|