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
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const util = require('util');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Diagnostic fields drivers set on their errors (pg, cockroachdb, mysql2,
|
|
7
|
+
* sqlite3), printed when present. Everything else, like the server source
|
|
8
|
+
* location of pg errors, is only printed verbose.
|
|
9
|
+
*/
|
|
10
|
+
const FIELDS = [
|
|
11
|
+
'code',
|
|
12
|
+
'errno',
|
|
13
|
+
'sqlState',
|
|
14
|
+
'sqlMessage',
|
|
15
|
+
'detail',
|
|
16
|
+
'hint',
|
|
17
|
+
'where',
|
|
18
|
+
'schema',
|
|
19
|
+
'table',
|
|
20
|
+
'column',
|
|
21
|
+
'dataType',
|
|
22
|
+
'constraint'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const indent = (text, prefix) =>
|
|
26
|
+
String(text)
|
|
27
|
+
.split('\n')
|
|
28
|
+
.map(line => prefix + line)
|
|
29
|
+
.join('\n');
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The SQL with a marker below the position reported by the database.
|
|
33
|
+
* Without parameters only, drivers rewrite their placeholders before
|
|
34
|
+
* sending, so the position would be off otherwise.
|
|
35
|
+
*/
|
|
36
|
+
const formatSql = err => {
|
|
37
|
+
// the position refers to the statement as sent, so nothing is trimmed
|
|
38
|
+
// before locating it, leading blank lines are only dropped for display
|
|
39
|
+
const sql = String(err.sql).replace(/\s+$/, '');
|
|
40
|
+
const lines = sql.split('\n');
|
|
41
|
+
let first = 0;
|
|
42
|
+
while (first < lines.length - 1 && lines[first].trim() === '') first++;
|
|
43
|
+
|
|
44
|
+
const position = Number(err.position);
|
|
45
|
+
let marker = null;
|
|
46
|
+
|
|
47
|
+
if (Number.isInteger(position) && position >= 1 && position <= sql.length + 1) {
|
|
48
|
+
if (err.sqlParams) {
|
|
49
|
+
marker = { text: `position: ${position}` };
|
|
50
|
+
} else {
|
|
51
|
+
const before = sql.slice(0, position - 1);
|
|
52
|
+
const row = before.split('\n').length - 1;
|
|
53
|
+
const column = before.length - (before.lastIndexOf('\n') + 1);
|
|
54
|
+
// keep tabs, so the marker lines up with the statement
|
|
55
|
+
marker = {
|
|
56
|
+
row,
|
|
57
|
+
text: ' ' + lines[row].slice(0, column).replace(/[^\t]/g, ' ') + '^'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const out = [];
|
|
63
|
+
lines.slice(first).forEach((line, i) => {
|
|
64
|
+
out.push((i === 0 ? 'SQL: ' : ' ') + line);
|
|
65
|
+
if (marker && marker.row === first + i) out.push(marker.text);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (marker && marker.row === undefined) out.push(marker.text);
|
|
69
|
+
|
|
70
|
+
return out;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Format an error of a failed migration for the log: what failed, the SQL
|
|
75
|
+
* and the diagnostic fields of the driver, and always the stack.
|
|
76
|
+
*/
|
|
77
|
+
module.exports = function formatError (err, { verbose = false } = {}) {
|
|
78
|
+
if (!err || typeof err !== 'object') {
|
|
79
|
+
return String(err);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const message = err.message || String(err);
|
|
83
|
+
const lines = [
|
|
84
|
+
err.migration
|
|
85
|
+
? `Migration "${err.migration}" failed` +
|
|
86
|
+
(err.instruction ? ` ${err.instruction}` : '') +
|
|
87
|
+
`: ${message}`
|
|
88
|
+
: message
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
if (err.sql) {
|
|
92
|
+
lines.push(indent(formatSql(err).join('\n'), ' '));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
FIELDS.forEach(field => {
|
|
96
|
+
const value = err[field];
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
value !== undefined &&
|
|
100
|
+
value !== null &&
|
|
101
|
+
value !== '' &&
|
|
102
|
+
!(field === 'sqlMessage' && value === message)
|
|
103
|
+
) {
|
|
104
|
+
lines.push(` ${field}: ${value}`);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (err.position !== undefined && !err.sql) {
|
|
109
|
+
lines.push(` position: ${err.position}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
lines.push(indent(err.stack || `${err.name}: ${message}`, ' '));
|
|
113
|
+
|
|
114
|
+
if (verbose) {
|
|
115
|
+
lines.push(indent(util.inspect(err, { depth: 4 }), ' '));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return lines.join('\n');
|
|
119
|
+
};
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* To note: If you rollback a migration, linked to a seeder, db-migrate will
|
|
35
35
|
* also rollback the seed. This is also a reason why you can't rollback a
|
|
36
36
|
* specific migration, you would going to break that much, you probably loose
|
|
37
|
-
* a bunch of
|
|
37
|
+
* a bunch of valuable time.
|
|
38
38
|
*/
|
|
39
39
|
|
|
40
40
|
var Promise = require('bluebird');
|
package/lib/learn.js
CHANGED
|
@@ -2,25 +2,34 @@ const Promise = require('bluebird');
|
|
|
2
2
|
const Shadow = require('./driver/shadow');
|
|
3
3
|
|
|
4
4
|
class STD {
|
|
5
|
-
constructor ({ schema, modSchema: mod }, driver) {
|
|
5
|
+
constructor ({ schema, modSchema: mod, unlearn }, driver) {
|
|
6
6
|
this.checkColumn = function (t, c) {
|
|
7
7
|
if (!this.schema[t]) {
|
|
8
8
|
throw new Error(`There is no ${t} table in schema!`);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
if (!this.schema[t][c]) {
|
|
11
|
+
if (!this.schema[t][c] && !this.schema[t].columns?.[c]) {
|
|
12
12
|
throw new Error(`There is no ${c} column in schema!`);
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
+
this.unlearn = unlearn;
|
|
15
16
|
this.validations = {};
|
|
16
17
|
this.driver = driver;
|
|
17
18
|
this.indizies = schema.i;
|
|
18
19
|
this.schema = schema.c;
|
|
19
20
|
this.foreign = schema.f;
|
|
21
|
+
if (!schema.e) {
|
|
22
|
+
schema.e = {};
|
|
23
|
+
}
|
|
24
|
+
this.extra = schema.e;
|
|
25
|
+
if (unlearn) {
|
|
26
|
+
this.modC = [];
|
|
27
|
+
} else {
|
|
28
|
+
this.modC = mod.s;
|
|
29
|
+
}
|
|
20
30
|
this.modS = mod.c;
|
|
21
31
|
this.modI = mod.i;
|
|
22
32
|
this.modF = mod.f;
|
|
23
|
-
this.modC = mod.s;
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
dropTable (t) {
|
|
@@ -87,6 +96,16 @@ class STD {
|
|
|
87
96
|
delete this.schema[t];
|
|
88
97
|
}
|
|
89
98
|
|
|
99
|
+
if (this.foreign[t]) {
|
|
100
|
+
this.modF[n] = this.foreign[n];
|
|
101
|
+
delete this.foreign[t];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (this.indizies[t]) {
|
|
105
|
+
this.modI[n] = this.indizies[t];
|
|
106
|
+
delete this.indizies[t];
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
this.modC.push({ t: 0, a: 'renameTable', c: [n, t] });
|
|
91
110
|
|
|
92
111
|
return Promise.resolve();
|
|
@@ -107,8 +126,10 @@ class STD {
|
|
|
107
126
|
removeColumn (t, c, o = {}) {
|
|
108
127
|
const alter = {};
|
|
109
128
|
this.checkColumn(t, c);
|
|
129
|
+
const hasColumns = this.schema[t].columns !== undefined;
|
|
130
|
+
const columns = hasColumns ? this.schema[t].columns : this.schema[t];
|
|
110
131
|
|
|
111
|
-
if (
|
|
132
|
+
if (columns[c].notNull === true && !this.unlearn) {
|
|
112
133
|
if (this.validations.columnStrategies !== true) {
|
|
113
134
|
if (
|
|
114
135
|
this.driver._meta &&
|
|
@@ -154,12 +175,13 @@ class STD {
|
|
|
154
175
|
}
|
|
155
176
|
}
|
|
156
177
|
|
|
157
|
-
|
|
178
|
+
// keep the columns removed before from the same table
|
|
179
|
+
if (!this.modS[t]) this.modS[t] = {};
|
|
158
180
|
|
|
159
|
-
if (
|
|
181
|
+
if (columns[c].notNull === true && !this.unlearn) {
|
|
160
182
|
switch (o.columnStrategy) {
|
|
161
183
|
case 'delay':
|
|
162
|
-
this.modS[t][c] =
|
|
184
|
+
this.modS[t][c] = columns[c];
|
|
163
185
|
|
|
164
186
|
o.passthrough = o.passthrough || {};
|
|
165
187
|
o.passthrough.column =
|
|
@@ -174,19 +196,23 @@ class STD {
|
|
|
174
196
|
|
|
175
197
|
break;
|
|
176
198
|
case 'defaultValue':
|
|
177
|
-
this.modS[t][c] =
|
|
199
|
+
this.modS[t][c] = columns[c];
|
|
178
200
|
this.modS[t][c].defaultValue = o.passthrough.defaultValue;
|
|
179
201
|
|
|
180
202
|
this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
|
|
181
203
|
break;
|
|
182
204
|
}
|
|
183
|
-
} else {
|
|
184
|
-
this.modS[t][c] =
|
|
205
|
+
} else if (!this.unlearn) {
|
|
206
|
+
this.modS[t][c] = columns[c];
|
|
185
207
|
|
|
186
208
|
this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
|
|
187
209
|
}
|
|
188
210
|
|
|
189
|
-
|
|
211
|
+
if (hasColumns) {
|
|
212
|
+
delete this.schema[t].columns[c];
|
|
213
|
+
} else {
|
|
214
|
+
delete this.schema[t][c];
|
|
215
|
+
}
|
|
190
216
|
|
|
191
217
|
return Promise.resolve(alter);
|
|
192
218
|
}
|
|
@@ -207,7 +233,10 @@ class STD {
|
|
|
207
233
|
throw new Error(`There is no ${t} table in schema!`);
|
|
208
234
|
}
|
|
209
235
|
this.schema[t] = this.schema[t] || {};
|
|
210
|
-
this.schema[t]
|
|
236
|
+
const hasColumns = this.schema[t].columns !== undefined;
|
|
237
|
+
const columns = hasColumns ? this.schema[t].columns : this.schema[t];
|
|
238
|
+
|
|
239
|
+
columns[c] = s;
|
|
211
240
|
|
|
212
241
|
this.modC.push({ t: 0, a: 'removeColumn', c: [t, c] });
|
|
213
242
|
|
|
@@ -219,8 +248,11 @@ class STD {
|
|
|
219
248
|
|
|
220
249
|
if (!this.modS[t]) this.modS[t] = {};
|
|
221
250
|
|
|
222
|
-
|
|
223
|
-
this.schema[t]
|
|
251
|
+
const hasColumns = this.schema[t].columns !== undefined;
|
|
252
|
+
const columns = hasColumns ? this.schema[t].columns : this.schema[t];
|
|
253
|
+
|
|
254
|
+
this.modS[t][c] = columns[c];
|
|
255
|
+
columns[c] = Object.assign(columns[c], s);
|
|
224
256
|
|
|
225
257
|
this.modC.push({ t: 1, a: 'changeColumn', c: [t, c] });
|
|
226
258
|
|
|
@@ -229,7 +261,7 @@ class STD {
|
|
|
229
261
|
|
|
230
262
|
addIndex (t, i, c, u) {
|
|
231
263
|
if (Array.isArray(c)) {
|
|
232
|
-
c.forEach(x => this.checkColumn(t, x));
|
|
264
|
+
c.forEach(x => this.checkColumn(t, typeof x === 'object' ? x.name : x));
|
|
233
265
|
} else {
|
|
234
266
|
this.checkColumn(t, c);
|
|
235
267
|
}
|
|
@@ -269,7 +301,7 @@ class STD {
|
|
|
269
301
|
|
|
270
302
|
alter.i[t] = {};
|
|
271
303
|
alter.i[t][i] = this.indizies[t][i];
|
|
272
|
-
this.modI[t] = {};
|
|
304
|
+
if (!this.modI[t]) this.modI[t] = {};
|
|
273
305
|
this.modI[t][i] = this.indizies[t][i];
|
|
274
306
|
delete this.indizies[t][i];
|
|
275
307
|
|
|
@@ -314,10 +346,12 @@ class STD {
|
|
|
314
346
|
|
|
315
347
|
alter.f[t] = {};
|
|
316
348
|
alter.f[t][k] = this.foreign[t][k];
|
|
317
|
-
this.modF[t] = {};
|
|
349
|
+
if (!this.modF[t]) this.modF[t] = {};
|
|
318
350
|
this.modF[t][k] = this.foreign[t][k];
|
|
319
351
|
delete this.foreign[t][k];
|
|
320
352
|
|
|
353
|
+
this.modC.push({ t: 1, a: 'addForeignKey', c: [t, k] });
|
|
354
|
+
|
|
321
355
|
return Promise.resolve(alter);
|
|
322
356
|
}
|
|
323
357
|
|
|
@@ -340,6 +374,9 @@ const noLearnError = prop => {
|
|
|
340
374
|
};
|
|
341
375
|
|
|
342
376
|
module.exports = {
|
|
377
|
+
// learns the schema and records the reverse operations
|
|
378
|
+
learns: true,
|
|
379
|
+
|
|
343
380
|
getInterface: (context, file, driver, internals) => {
|
|
344
381
|
if (context.learnable) {
|
|
345
382
|
const _std = new STD(internals, context);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const Shadow = require('../../driver/shadow');
|
|
2
|
+
const State = require('../../state');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Records a step as done, after it was executed on the database.
|
|
6
|
+
*/
|
|
7
|
+
module.exports = {
|
|
8
|
+
getInterface: (context, file, driver, internals, pdriver) => {
|
|
9
|
+
const done = () =>
|
|
10
|
+
function () {
|
|
11
|
+
// in memory first, a failing write must not hide the executed step
|
|
12
|
+
internals.migrationDone = internals.migrationOp;
|
|
13
|
+
return State.done(pdriver, internals.migrationOp, internals);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
return Shadow.overshadow(driver, {}, done);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -17,41 +17,45 @@ const DEFAULT = {
|
|
|
17
17
|
removeForeignKey: 'addForeignKey'
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Persists the state around learning a step. Before learning (step) it
|
|
22
|
+
* records the step as started, afterwards it tags the recorded reverse
|
|
23
|
+
* operations with their step and records the step as learned.
|
|
24
|
+
*/
|
|
20
25
|
class StateTravel {
|
|
21
|
-
constructor (internals, file, driver) {
|
|
26
|
+
constructor (internals, file, driver, pdriver, step = true) {
|
|
22
27
|
this.file = file;
|
|
23
28
|
this.internals = internals;
|
|
24
29
|
this.driver = driver;
|
|
25
|
-
this.
|
|
26
|
-
|
|
30
|
+
this.pdriver = pdriver;
|
|
31
|
+
this._default = async function _default () {
|
|
32
|
+
const op = this.internals.migrationOp;
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
if (step) {
|
|
35
|
+
await State.step(this.pdriver, op, this.internals);
|
|
36
|
+
} else {
|
|
37
|
+
this.internals.modSchema.s.forEach(entry => {
|
|
38
|
+
if (entry.n === undefined) entry.n = op;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async default () {
|
|
42
|
-
await this.step();
|
|
43
|
-
const res = await this.update();
|
|
42
|
+
await State.update(
|
|
43
|
+
this.pdriver,
|
|
44
|
+
this.file,
|
|
45
|
+
this.internals.modSchema,
|
|
46
|
+
this.internals
|
|
47
|
+
);
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
if (!step) {
|
|
50
|
+
await State.learned(this.pdriver, op, this.internals);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
Object.keys(DEFAULT).forEach(m => {
|
|
50
57
|
StateTravel.prototype[m] = async function (...args) {
|
|
51
|
-
|
|
52
|
-
const res = await this.update();
|
|
53
|
-
|
|
54
|
-
return res;
|
|
58
|
+
return this._default();
|
|
55
59
|
};
|
|
56
60
|
});
|
|
57
61
|
|
|
@@ -61,24 +65,25 @@ const noTravelError = prop => {
|
|
|
61
65
|
};
|
|
62
66
|
};
|
|
63
67
|
|
|
64
|
-
module.exports = {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
module.exports = function (step = true) {
|
|
69
|
+
return {
|
|
70
|
+
getInterface: (context, file, driver, internals, pdriver) => {
|
|
71
|
+
if (context.learnable) {
|
|
72
|
+
const st = new StateTravel(internals, file, context, pdriver, step);
|
|
73
|
+
return Shadow.overshadow(
|
|
74
|
+
driver,
|
|
75
|
+
Object.assign(st, context.statechanger),
|
|
76
|
+
noTravelError
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
return Shadow.overshadow(
|
|
69
81
|
driver,
|
|
70
|
-
|
|
82
|
+
new StateTravel(internals, file, context, pdriver, step),
|
|
71
83
|
noTravelError
|
|
72
84
|
);
|
|
73
85
|
}
|
|
74
86
|
|
|
75
|
-
return Shadow.overshadow(
|
|
76
|
-
driver,
|
|
77
|
-
new StateTravel(internals, file, context),
|
|
78
|
-
noTravelError
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
87
|
/* hasModification: true,
|
|
83
88
|
|
|
84
89
|
modify: (context, driver, internals) => {
|
|
@@ -96,4 +101,5 @@ module.exports = {
|
|
|
96
101
|
|
|
97
102
|
return { driver: _driver };
|
|
98
103
|
} */
|
|
104
|
+
};
|
|
99
105
|
};
|
|
@@ -2,6 +2,8 @@ const Promise = require('bluebird');
|
|
|
2
2
|
const State = require('../../state');
|
|
3
3
|
const Chain = require('../../chain');
|
|
4
4
|
const Migrate = require('./migrate');
|
|
5
|
+
const Learn = require('../../learn');
|
|
6
|
+
const log = require('db-migrate-shared').log;
|
|
5
7
|
|
|
6
8
|
const methods = {
|
|
7
9
|
createTable: async (driver, [t], internals) => {
|
|
@@ -42,6 +44,31 @@ const methods = {
|
|
|
42
44
|
|
|
43
45
|
changeColumn: async (driver, [t, c], internals) => {
|
|
44
46
|
return driver.changeColumn(t, c, internals.modSchema.c[t][c]);
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
addForeignKey: async (driver, [t, k], internals) => {
|
|
50
|
+
const foreign = internals.modSchema.f[t][k];
|
|
51
|
+
return driver.addForeignKey(t, foreign.rt, k, foreign.m, foreign.r);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
addIndex: async (driver, [t, i], internals) => {
|
|
55
|
+
if (!internals.modSchema.i[t][i]) {
|
|
56
|
+
log.warn(
|
|
57
|
+
`There was an attempt to create the index "${i}" in the table "${t}".`
|
|
58
|
+
);
|
|
59
|
+
log.warn(
|
|
60
|
+
`This index did not exist at the time of deleting it. ` +
|
|
61
|
+
`This can happen if an index was created by hand and then deleted ` +
|
|
62
|
+
`by db-migrate. Make sure to recreate it by hand to avoid any problems.`
|
|
63
|
+
);
|
|
64
|
+
return Promise.resolve();
|
|
65
|
+
}
|
|
66
|
+
return driver.addIndex(
|
|
67
|
+
t,
|
|
68
|
+
i,
|
|
69
|
+
internals.modSchema.i[t][i].c,
|
|
70
|
+
internals.modSchema.i[t][i].u ? true : undefined
|
|
71
|
+
);
|
|
45
72
|
}
|
|
46
73
|
};
|
|
47
74
|
|
|
@@ -50,6 +77,7 @@ async function processEntry (
|
|
|
50
77
|
file,
|
|
51
78
|
driver,
|
|
52
79
|
internals,
|
|
80
|
+
pdriver,
|
|
53
81
|
{ t: type, a: action, c: args }
|
|
54
82
|
) {
|
|
55
83
|
let skip = false;
|
|
@@ -57,7 +85,7 @@ async function processEntry (
|
|
|
57
85
|
if (
|
|
58
86
|
internals.rollback === true &&
|
|
59
87
|
internals.rollbackContinue !== true &&
|
|
60
|
-
driver.udriver._meta
|
|
88
|
+
driver.udriver._meta?.signalColumns?.indexOf(action) !== -1
|
|
61
89
|
) {
|
|
62
90
|
internals.rollbackContinue = true;
|
|
63
91
|
skip = driver.udriver._counter.previousSignal() === null;
|
|
@@ -78,19 +106,23 @@ async function processEntry (
|
|
|
78
106
|
}
|
|
79
107
|
}
|
|
80
108
|
|
|
81
|
-
internals.modSchema.s.
|
|
82
|
-
await State.update(
|
|
109
|
+
internals.modSchema.s.pop();
|
|
110
|
+
await State.update(pdriver, file, internals.modSchema, internals);
|
|
83
111
|
}
|
|
84
112
|
|
|
85
|
-
module.exports = async (context, file, driver, internals) => {
|
|
113
|
+
module.exports = async (context, file, driver, internals, pdriver) => {
|
|
86
114
|
const mod = internals.modSchema;
|
|
87
115
|
|
|
88
|
-
const chain = new Chain(context, file, driver, internals);
|
|
89
|
-
|
|
116
|
+
const chain = new Chain(context, file, driver, internals, pdriver);
|
|
117
|
+
internals.unlearn = true;
|
|
118
|
+
|
|
119
|
+
chain.addChain(Learn);
|
|
90
120
|
chain.addChain(Migrate);
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
// the stored records keep their order, so an interrupted rollback can
|
|
122
|
+
// be continued
|
|
123
|
+
await Promise.resolve(mod.s.slice().reverse()).each(args =>
|
|
124
|
+
processEntry(context, file, chain, internals, pdriver, args)
|
|
93
125
|
);
|
|
94
126
|
|
|
95
|
-
await State.deleteState(
|
|
127
|
+
await State.deleteState(pdriver, file, internals);
|
|
96
128
|
};
|