db-migrate 1.5.0 → 1.6.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/lib/chain.js +2 -2
- package/lib/commands/run.js +44 -1
- package/lib/commands/set-default-argv.js +17 -1
- package/lib/release.js +23 -14
- package/lib/state.js +9 -1
- package/lib/walker.js +21 -6
- package/package.json +1 -1
package/lib/chain.js
CHANGED
|
@@ -190,7 +190,7 @@ class Chain {
|
|
|
190
190
|
throw unknownTable(t);
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
const entry = Release.entry(internals, t, options);
|
|
193
|
+
const entry = Release.entry(internals, t, options, this.file);
|
|
194
194
|
return this.run('setDeprecated', ['tables', t, null, entry], 'learn');
|
|
195
195
|
};
|
|
196
196
|
|
|
@@ -205,7 +205,7 @@ class Chain {
|
|
|
205
205
|
throw unknownColumn(t, c);
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
const entry = Release.entry(internals, c, options);
|
|
208
|
+
const entry = Release.entry(internals, c, options, this.file);
|
|
209
209
|
if (columns[c].notNull) {
|
|
210
210
|
// the application stops writing it. The whole spec, MySQL changes
|
|
211
211
|
// a column by its full definition
|
package/lib/commands/run.js
CHANGED
|
@@ -97,6 +97,49 @@ function run (internals, config) {
|
|
|
97
97
|
report(load('db')(internals, config));
|
|
98
98
|
}
|
|
99
99
|
break;
|
|
100
|
+
case 'work': {
|
|
101
|
+
// runs the jobs of background migrations, until none is left or, with
|
|
102
|
+
// --watch, until stopped
|
|
103
|
+
const argv = internals.argv;
|
|
104
|
+
const options = {};
|
|
105
|
+
[
|
|
106
|
+
['parallel', 'parallel'],
|
|
107
|
+
['pause', 'pause'],
|
|
108
|
+
['batch', 'batch'],
|
|
109
|
+
['interval', 'interval'],
|
|
110
|
+
['job-timeout', 'timeout']
|
|
111
|
+
].forEach(([arg, option]) => {
|
|
112
|
+
if (argv[arg] !== undefined) {
|
|
113
|
+
options[option] = Number(argv[arg]);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
options.watch = argv.watch === true;
|
|
117
|
+
|
|
118
|
+
const worker = load('work')(internals, config, options);
|
|
119
|
+
const stop = () => {
|
|
120
|
+
log.info('[jobs] stopping after the current batches');
|
|
121
|
+
worker.stop();
|
|
122
|
+
};
|
|
123
|
+
process.once('SIGINT', stop);
|
|
124
|
+
process.once('SIGTERM', stop);
|
|
125
|
+
|
|
126
|
+
report(
|
|
127
|
+
worker.done.then(result => {
|
|
128
|
+
log.info(`[jobs] ${result.done.length} job(s) done`);
|
|
129
|
+
|
|
130
|
+
if (result.failed.length) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`${result.failed.length} background job(s) failed: ` +
|
|
133
|
+
result.failed.map(f => f.name).join(', ')
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
process.exit(0);
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
|
|
100
143
|
case 'seed': {
|
|
101
144
|
// seed [name], seed down [name], seed reset
|
|
102
145
|
const args = internals.argv._.map(String);
|
|
@@ -123,7 +166,7 @@ function run (internals, config) {
|
|
|
123
166
|
);
|
|
124
167
|
} else {
|
|
125
168
|
log.error(
|
|
126
|
-
'Invalid Action: Must be [up|down|check|create|reset|sync|db|seed].'
|
|
169
|
+
'Invalid Action: Must be [up|down|check|create|reset|sync|db|seed|work].'
|
|
127
170
|
);
|
|
128
171
|
yargs.showHelp();
|
|
129
172
|
process.exit(1);
|
|
@@ -27,7 +27,7 @@ module.exports = function (internals, isModule) {
|
|
|
27
27
|
internals.argv = yargs
|
|
28
28
|
.default(defaultConfig)
|
|
29
29
|
.usage(
|
|
30
|
-
'Usage: db-migrate [up|down|check|reset|sync|create|db|seed] ' +
|
|
30
|
+
'Usage: db-migrate [up|down|check|reset|sync|create|db|seed|work] ' +
|
|
31
31
|
'[[dbname/]migrationName|all] [options]'
|
|
32
32
|
)
|
|
33
33
|
.describe(
|
|
@@ -128,6 +128,22 @@ module.exports = function (internals, isModule) {
|
|
|
128
128
|
' held by another process is considered stale and taken over.'
|
|
129
129
|
)
|
|
130
130
|
.number('lock-timeout')
|
|
131
|
+
.describe('parallel', 'work: jobs of background migrations run at once.')
|
|
132
|
+
.number('parallel')
|
|
133
|
+
.describe('pause', 'work: milliseconds to wait between two batches of a job.')
|
|
134
|
+
.number('pause')
|
|
135
|
+
.describe('batch', 'work: rows per batch of a job.')
|
|
136
|
+
.number('batch')
|
|
137
|
+
.describe('watch', 'work: keep looking for new jobs, until stopped.')
|
|
138
|
+
.boolean('watch')
|
|
139
|
+
.describe('interval', 'work: milliseconds between looking for new jobs.')
|
|
140
|
+
.number('interval')
|
|
141
|
+
.describe(
|
|
142
|
+
'job-timeout',
|
|
143
|
+
'work: milliseconds after which the job of a worker which stopped ' +
|
|
144
|
+
'responding is taken over.'
|
|
145
|
+
)
|
|
146
|
+
.number('job-timeout')
|
|
131
147
|
.describe(
|
|
132
148
|
'lock-interval',
|
|
133
149
|
'Milliseconds between checks while waiting for the migration lock.'
|
package/lib/release.js
CHANGED
|
@@ -67,10 +67,11 @@ const releases = files => {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
|
-
* The name a deprecated table or column is renamed to
|
|
70
|
+
* The name a deprecated table or column is renamed to, with the time of the
|
|
71
|
+
* migration deprecating it, so fix learns the same name again.
|
|
71
72
|
*/
|
|
72
|
-
const hiddenName = name => {
|
|
73
|
-
const time =
|
|
73
|
+
const hiddenName = (name, file) => {
|
|
74
|
+
const time = String(file.name).split('-')[0];
|
|
74
75
|
const plain = `__dbm_deprecated_${name}_${time}`;
|
|
75
76
|
|
|
76
77
|
if (plain.length <= 60) {
|
|
@@ -116,8 +117,8 @@ const settings = (internals, entry) => {
|
|
|
116
117
|
return Object.assign({}, DEFAULTS, project, entry.o || {});
|
|
117
118
|
};
|
|
118
119
|
|
|
119
|
-
const entry = (internals, name, options) => {
|
|
120
|
-
const e = { r: internals.releaseLabel || null, to: hiddenName(name) };
|
|
120
|
+
const entry = (internals, name, options, file) => {
|
|
121
|
+
const e = { r: internals.releaseLabel || null, to: hiddenName(name, file) };
|
|
121
122
|
const o = checkOptions(options);
|
|
122
123
|
|
|
123
124
|
if (Object.keys(o).length) {
|
|
@@ -310,24 +311,28 @@ const unrecorded = walker =>
|
|
|
310
311
|
});
|
|
311
312
|
|
|
312
313
|
/**
|
|
313
|
-
* Runs the steps due before the first migration of the release label.
|
|
314
|
+
* Runs the steps due before the first migration of the release label. fix
|
|
315
|
+
* only learns them again, like the migrations it learns.
|
|
314
316
|
*/
|
|
315
|
-
const start = async (walker, label, index, releaseIndex) => {
|
|
317
|
+
const start = async (walker, label, index, releaseIndex, mode = 'up') => {
|
|
316
318
|
const internals = walker.internals;
|
|
317
319
|
const { renames, drops } = due(internals, index, releaseIndex);
|
|
318
|
-
const purged = (await duePurges(walker._pdriver, internals, index, releaseIndex)).filter(
|
|
319
|
-
e => e.drop === 'auto'
|
|
320
|
-
);
|
|
321
320
|
|
|
322
|
-
if (
|
|
323
|
-
|
|
321
|
+
if (mode === 'up') {
|
|
322
|
+
const purged = (
|
|
323
|
+
await duePurges(walker._pdriver, internals, index, releaseIndex)
|
|
324
|
+
).filter(e => e.drop === 'auto');
|
|
325
|
+
|
|
326
|
+
if (purged.length) {
|
|
327
|
+
await purge(walker, label, purged);
|
|
328
|
+
}
|
|
324
329
|
}
|
|
325
330
|
|
|
326
331
|
if (!renames.length && !drops.length) {
|
|
327
332
|
return;
|
|
328
333
|
}
|
|
329
334
|
|
|
330
|
-
log.info(`[release] starting release ${label}`);
|
|
335
|
+
log.info(`[release] ${mode === 'fix' ? 'learning' : 'starting'} release ${label}`);
|
|
331
336
|
renames.forEach(item =>
|
|
332
337
|
log.info(`[release] renaming the deprecated ${describe(item)} to ${item.entry.to}`)
|
|
333
338
|
);
|
|
@@ -352,7 +357,11 @@ const start = async (walker, label, index, releaseIndex) => {
|
|
|
352
357
|
return;
|
|
353
358
|
}
|
|
354
359
|
|
|
355
|
-
await require('./executors/versioned/v2')
|
|
360
|
+
await require('./executors/versioned/v2')[mode](
|
|
361
|
+
unrecorded(walker),
|
|
362
|
+
walker.driver,
|
|
363
|
+
file
|
|
364
|
+
);
|
|
356
365
|
};
|
|
357
366
|
|
|
358
367
|
/**
|
package/lib/state.js
CHANGED
|
@@ -328,6 +328,9 @@ module.exports = {
|
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
// fix learns the schema from scratch, it must not be loaded again
|
|
332
|
+
internals.learnFromScratch = emptyState === true;
|
|
333
|
+
|
|
331
334
|
const schema = emptyState !== true ? _schema : null;
|
|
332
335
|
if (schema) {
|
|
333
336
|
internals.schema = parseSchema(schema.value);
|
|
@@ -351,6 +354,10 @@ module.exports = {
|
|
|
351
354
|
* so the schema loaded during init is outdated.
|
|
352
355
|
*/
|
|
353
356
|
reloadSchema: async function (driver, internals) {
|
|
357
|
+
if (internals.learnFromScratch) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
|
|
354
361
|
const schema = await driver._getKV(internals.migrationState, SSTATE);
|
|
355
362
|
if (schema) {
|
|
356
363
|
internals.schema = parseSchema(schema.value);
|
|
@@ -376,7 +383,8 @@ module.exports = {
|
|
|
376
383
|
) {
|
|
377
384
|
const mig = await driver._getKV(internals.migrationState, file.name);
|
|
378
385
|
|
|
379
|
-
|
|
386
|
+
// fix learns the records again from scratch
|
|
387
|
+
if (mig && mig.value !== '{}' && op !== 'fix') {
|
|
380
388
|
internals.modSchema = JSON.parse(mig.value);
|
|
381
389
|
// records of older runs, they belong to no step of this run
|
|
382
390
|
(internals.modSchema.s || []).forEach(entry => {
|
package/lib/walker.js
CHANGED
|
@@ -363,13 +363,13 @@ Walker.prototype = {
|
|
|
363
363
|
/**
|
|
364
364
|
* Runs the steps due, before the first migration of a new release.
|
|
365
365
|
*/
|
|
366
|
-
_enterRelease: async function (file) {
|
|
366
|
+
_enterRelease: async function (file, mode = 'up') {
|
|
367
367
|
const release = this._release || { map: {}, index: {} };
|
|
368
368
|
const r = release.map[file.name] || { label: null, index: 0 };
|
|
369
369
|
|
|
370
370
|
if (r.index > this._applied) {
|
|
371
371
|
this.internals.releaseIndex = release.index;
|
|
372
|
-
await Release.start(this, r.label, r.index, release.index);
|
|
372
|
+
await Release.start(this, r.label, r.index, release.index, mode);
|
|
373
373
|
this._applied = r.index;
|
|
374
374
|
}
|
|
375
375
|
|
|
@@ -513,9 +513,23 @@ Walker.prototype = {
|
|
|
513
513
|
this.prefix,
|
|
514
514
|
this._driver,
|
|
515
515
|
this.internals
|
|
516
|
-
).then(completedFiles =>
|
|
517
|
-
|
|
518
|
-
|
|
516
|
+
).then(async completedFiles => {
|
|
517
|
+
// the releases, learned again from the start
|
|
518
|
+
const allFiles = await File.loadFromFileystem(
|
|
519
|
+
this.directory,
|
|
520
|
+
this.prefix,
|
|
521
|
+
this.internals
|
|
522
|
+
).catch(err => {
|
|
523
|
+
if (err.code === 'ENOENT') {
|
|
524
|
+
return [];
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
throw err;
|
|
528
|
+
});
|
|
529
|
+
this._releases(allFiles, []);
|
|
530
|
+
|
|
531
|
+
return dbmUtil.filterDown(completedFiles, partialName, count).sort(sortFn);
|
|
532
|
+
});
|
|
519
533
|
|
|
520
534
|
if (this.internals.check) {
|
|
521
535
|
return determine()
|
|
@@ -529,8 +543,9 @@ Walker.prototype = {
|
|
|
529
543
|
log.info(this.title + 'Nothing to run');
|
|
530
544
|
}
|
|
531
545
|
|
|
532
|
-
return Promise.each(toRun, file => {
|
|
546
|
+
return Promise.each(toRun, async file => {
|
|
533
547
|
log.verbose(this.title + 'preparing to run fix:', file.name);
|
|
548
|
+
await this._enterRelease(file, 'fix').catch(failedIn(file));
|
|
534
549
|
const _meta = file.get()._meta || {};
|
|
535
550
|
const version = _meta.version || 1;
|
|
536
551
|
if (version < 2) {
|