db-migrate 1.0.0-beta.3 → 1.0.0-beta.30
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 +1 -5
- package/api.js +25 -7
- package/connect.js +27 -10
- package/lib/chain.js +70 -12
- package/lib/commands/check.js +3 -3
- package/lib/commands/create-migration.js +28 -3
- package/lib/commands/down.js +1 -1
- package/lib/commands/dump.js +22 -0
- package/lib/commands/fix.js +53 -0
- package/lib/commands/generated.js +2 -1
- package/lib/commands/helper/register-events.js +2 -0
- package/lib/commands/run.js +5 -6
- package/lib/commands/set-default-argv.js +7 -2
- package/lib/commands/sync.js +3 -3
- package/lib/commands/up.js +3 -3
- package/lib/driver/index.js +37 -11
- package/lib/executors/versioned/v2.js +50 -6
- package/lib/learn.js +47 -14
- package/lib/methods/v2/statetravel.js +16 -13
- package/lib/methods/v2/translatestate.js +53 -16
- package/lib/state.js +97 -13
- package/lib/template.js +4 -1
- package/lib/templates/v2.js +12 -0
- package/lib/walker.js +83 -7
- package/package.json +20 -17
- package/tttt.js +2 -0
- package/.eslintignore +0 -1
- package/.eslintrc +0 -11
- package/.jscsrc +0 -0
- package/.jshintignore +0 -2
- package/.jshintrc +0 -14
- package/.labrc.js +0 -10
- package/.prettierrc +0 -3
- package/.tern-project +0 -7
- package/.travis.yml +0 -47
- package/CHANGELOG.md +0 -487
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -81
- package/commitlint.config.js +0 -1
- package/coverage.html +0 -17232
- package/generateLoader.js +0 -36
- package/lib/commands/transition.js +0 -5
- package/lib/transitions/1.js +0 -30
- package/lib/transitions/ask.js +0 -22
- package/lib/transitions/snippets/setup.sjs +0 -8
- package/lib/transitions/transitioner.js +0 -78
- package/lib/transitions/try-require.js +0 -113
- package/lib/transitions/update-version.js +0 -48
package/lib/driver/index.js
CHANGED
|
@@ -18,6 +18,8 @@ var ShadowProto = {
|
|
|
18
18
|
|
|
19
19
|
exports.connect = function (config, intern, callback) {
|
|
20
20
|
var driver, req;
|
|
21
|
+
let plugin = false;
|
|
22
|
+
const { plugins } = intern;
|
|
21
23
|
|
|
22
24
|
var mod = internals.mod;
|
|
23
25
|
internals = intern;
|
|
@@ -90,27 +92,51 @@ exports.connect = function (config, intern, callback) {
|
|
|
90
92
|
log.verbose('connecting');
|
|
91
93
|
|
|
92
94
|
var connect = function (config) {
|
|
93
|
-
driver.connect(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
driver.connect(
|
|
96
|
+
// safe disconnect of our config object into userspace
|
|
97
|
+
JSON.parse(JSON.stringify(config)),
|
|
98
|
+
intern,
|
|
99
|
+
function (err, db) {
|
|
100
|
+
if (err) {
|
|
101
|
+
callback(err);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
log.verbose('connected');
|
|
99
105
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
if (!global.immunity) {
|
|
107
|
+
db = Shadow.infect(db, internals, ShadowProto);
|
|
108
|
+
}
|
|
103
109
|
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
callback(null, db);
|
|
111
|
+
}
|
|
112
|
+
);
|
|
106
113
|
};
|
|
107
114
|
|
|
108
115
|
if (config.tunnel) {
|
|
109
116
|
var tunnel = require('tunnel-ssh');
|
|
110
117
|
var tunnelConfig = JSON.parse(JSON.stringify(config.tunnel));
|
|
118
|
+
const { tunnelType } = tunnelConfig;
|
|
119
|
+
|
|
120
|
+
if (plugins) {
|
|
121
|
+
plugin = plugins.overwrite(
|
|
122
|
+
`connection:tunnel:${
|
|
123
|
+
tunnelType && tunnelType !== 'ssh' ? tunnelType : 'ssh'
|
|
124
|
+
}`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
111
128
|
tunnelConfig.dstHost = config.host;
|
|
112
129
|
tunnelConfig.dstPort = config.port;
|
|
113
130
|
|
|
131
|
+
if (plugin) {
|
|
132
|
+
tunnel =
|
|
133
|
+
plugin[
|
|
134
|
+
`connection:tunnel:${
|
|
135
|
+
tunnelType && tunnelType !== 'ssh' ? tunnelType : 'ssh'
|
|
136
|
+
}`
|
|
137
|
+
](tunnelConfig);
|
|
138
|
+
}
|
|
139
|
+
|
|
114
140
|
if (tunnelConfig.privateKeyPath) {
|
|
115
141
|
tunnelConfig.privateKey = require('fs').readFileSync(
|
|
116
142
|
tunnelConfig.privateKeyPath
|
|
@@ -9,6 +9,7 @@ const StateTravel = require('../../methods/v2/statetravel');
|
|
|
9
9
|
const Migrate = require('../../methods/v2/migrate');
|
|
10
10
|
const TranslateState = require('../../methods/v2/translatestate');
|
|
11
11
|
const AddConventions = require('../../methods/v2/conventions');
|
|
12
|
+
const util = require('util');
|
|
12
13
|
|
|
13
14
|
const execUnit = {
|
|
14
15
|
_extend: (context, type) => {
|
|
@@ -28,7 +29,7 @@ const execUnit = {
|
|
|
28
29
|
|
|
29
30
|
up: async function (context, driver, file) {
|
|
30
31
|
const _file = file.get();
|
|
31
|
-
const chain = new Chain(context._driver, file, driver, context.internals);
|
|
32
|
+
const chain = new Chain(context._driver, file, driver, context.internals, context._pdriver);
|
|
32
33
|
if (!_file._meta.noDefaultColumn) {
|
|
33
34
|
chain.addChain(AddConventions);
|
|
34
35
|
}
|
|
@@ -36,7 +37,7 @@ const execUnit = {
|
|
|
36
37
|
chain.addChain(StateTravel);
|
|
37
38
|
chain.addChain(Migrate);
|
|
38
39
|
|
|
39
|
-
await State.startMigration(context.
|
|
40
|
+
await State.startMigration(context._pdriver, file, context.internals);
|
|
40
41
|
// startMigration - needs secondary instance since we can not afford to
|
|
41
42
|
// loose state and the transaction start will include these for roll back
|
|
42
43
|
// we will disable them probably at all from DDL when the driver does not
|
|
@@ -48,6 +49,11 @@ const execUnit = {
|
|
|
48
49
|
dbm: context.internals.safeOptions.dbmigrate
|
|
49
50
|
});
|
|
50
51
|
} catch (err) {
|
|
52
|
+
context.internals.rollback = true;
|
|
53
|
+
|
|
54
|
+
// transfer last state
|
|
55
|
+
chain.transferInt();
|
|
56
|
+
|
|
51
57
|
log.error(
|
|
52
58
|
'An error occured. No alternative failure strategy defined. Rolling back!',
|
|
53
59
|
err
|
|
@@ -56,15 +62,53 @@ const execUnit = {
|
|
|
56
62
|
throw err;
|
|
57
63
|
}
|
|
58
64
|
await Promise.promisify(context.writeMigrationRecord.bind(context))(file);
|
|
59
|
-
return State.endMigration(context.
|
|
65
|
+
return State.endMigration(context._pdriver, file, context.internals);
|
|
66
|
+
// end migration, same as start migration
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
fix: async function (context, driver, file) {
|
|
70
|
+
const _file = file.get();
|
|
71
|
+
const chain = new Chain(context._driver, file, driver, context.internals, context._pdriver);
|
|
72
|
+
if (!_file._meta.noDefaultColumn) {
|
|
73
|
+
chain.addChain(AddConventions);
|
|
74
|
+
}
|
|
75
|
+
chain.addChain(Learn);
|
|
76
|
+
chain.addChain(StateTravel);
|
|
77
|
+
|
|
78
|
+
await State.startMigration(context._pdriver, file, context.internals);
|
|
79
|
+
// startMigration - needs secondary instance since we can not afford to
|
|
80
|
+
// loose state and the transaction start will include these for roll back
|
|
81
|
+
// we will disable them probably at all from DDL when the driver does not
|
|
82
|
+
// explicitly signal DDL transaction support (like crdb)
|
|
83
|
+
try {
|
|
84
|
+
await _file.migrate(chain, {
|
|
85
|
+
options: context.internals.safeOptions,
|
|
86
|
+
seedLink: context.seedLink,
|
|
87
|
+
dbm: context.internals.safeOptions.dbmigrate
|
|
88
|
+
});
|
|
89
|
+
} catch (err) {
|
|
90
|
+
context.internals.rollback = true;
|
|
91
|
+
|
|
92
|
+
// transfer last state
|
|
93
|
+
chain.transferInt();
|
|
94
|
+
|
|
95
|
+
log.error(
|
|
96
|
+
'An error occured. No alternative failure strategy defined. Rolling back!',
|
|
97
|
+
err
|
|
98
|
+
);
|
|
99
|
+
await execUnit.down(context, driver, file);
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
await State.endMigration(context._pdriver, file, context.internals);
|
|
103
|
+
log.verbose(`[fix] current schema`, util.inspect(context.internals.schema, false, null, true));
|
|
60
104
|
// end migration, same as start migration
|
|
61
105
|
},
|
|
62
106
|
|
|
63
107
|
down: async function (context, driver, file) {
|
|
64
108
|
// start migration, see up comments
|
|
65
|
-
await State.startMigration(context.
|
|
66
|
-
await TranslateState(context._driver, file, driver, context.internals);
|
|
67
|
-
await State.endMigration(context.
|
|
109
|
+
await State.startMigration(context._pdriver, file, context.internals);
|
|
110
|
+
await TranslateState(context._driver, file, driver, context.internals, context._pdriver);
|
|
111
|
+
await State.endMigration(context._pdriver, file, context.internals);
|
|
68
112
|
return Promise.promisify(context.deleteMigrationRecord.bind(context))(file);
|
|
69
113
|
// end migration, see up comments
|
|
70
114
|
}
|
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 &&
|
|
@@ -156,10 +177,10 @@ class STD {
|
|
|
156
177
|
|
|
157
178
|
this.modS[t] = {};
|
|
158
179
|
|
|
159
|
-
if (
|
|
180
|
+
if (columns[c].notNull === true && !this.unlearn) {
|
|
160
181
|
switch (o.columnStrategy) {
|
|
161
182
|
case 'delay':
|
|
162
|
-
this.modS[t][c] =
|
|
183
|
+
this.modS[t][c] = columns[c];
|
|
163
184
|
|
|
164
185
|
o.passthrough = o.passthrough || {};
|
|
165
186
|
o.passthrough.column =
|
|
@@ -174,19 +195,23 @@ class STD {
|
|
|
174
195
|
|
|
175
196
|
break;
|
|
176
197
|
case 'defaultValue':
|
|
177
|
-
this.modS[t][c] =
|
|
198
|
+
this.modS[t][c] = columns[c];
|
|
178
199
|
this.modS[t][c].defaultValue = o.passthrough.defaultValue;
|
|
179
200
|
|
|
180
201
|
this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
|
|
181
202
|
break;
|
|
182
203
|
}
|
|
183
|
-
} else {
|
|
184
|
-
this.modS[t][c] =
|
|
204
|
+
} else if (!this.unlearn) {
|
|
205
|
+
this.modS[t][c] = columns[c];
|
|
185
206
|
|
|
186
207
|
this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
|
|
187
208
|
}
|
|
188
209
|
|
|
189
|
-
|
|
210
|
+
if (hasColumns) {
|
|
211
|
+
delete this.schema[t].columns[c];
|
|
212
|
+
} else {
|
|
213
|
+
delete this.schema[t][c];
|
|
214
|
+
}
|
|
190
215
|
|
|
191
216
|
return Promise.resolve(alter);
|
|
192
217
|
}
|
|
@@ -207,7 +232,10 @@ class STD {
|
|
|
207
232
|
throw new Error(`There is no ${t} table in schema!`);
|
|
208
233
|
}
|
|
209
234
|
this.schema[t] = this.schema[t] || {};
|
|
210
|
-
this.schema[t]
|
|
235
|
+
const hasColumns = this.schema[t].columns !== undefined;
|
|
236
|
+
const columns = hasColumns ? this.schema[t].columns : this.schema[t];
|
|
237
|
+
|
|
238
|
+
columns[c] = s;
|
|
211
239
|
|
|
212
240
|
this.modC.push({ t: 0, a: 'removeColumn', c: [t, c] });
|
|
213
241
|
|
|
@@ -217,8 +245,13 @@ class STD {
|
|
|
217
245
|
changeColumn (t, c, s) {
|
|
218
246
|
this.checkColumn(t, c);
|
|
219
247
|
|
|
220
|
-
this.modS[t]
|
|
221
|
-
|
|
248
|
+
if (!this.modS[t]) this.modS[t] = {};
|
|
249
|
+
|
|
250
|
+
const hasColumns = this.schema[t].columns !== undefined;
|
|
251
|
+
const columns = hasColumns ? this.schema[t].columns : this.schema[t];
|
|
252
|
+
|
|
253
|
+
this.modS[t][c] = columns[c];
|
|
254
|
+
columns[c] = Object.assign(columns[c], s);
|
|
222
255
|
|
|
223
256
|
this.modC.push({ t: 1, a: 'changeColumn', c: [t, c] });
|
|
224
257
|
|
|
@@ -227,7 +260,7 @@ class STD {
|
|
|
227
260
|
|
|
228
261
|
addIndex (t, i, c, u) {
|
|
229
262
|
if (Array.isArray(c)) {
|
|
230
|
-
c.forEach(x => this.checkColumn(t, x));
|
|
263
|
+
c.forEach(x => this.checkColumn(t, typeof x === 'object' ? x.name : x));
|
|
231
264
|
} else {
|
|
232
265
|
this.checkColumn(t, c);
|
|
233
266
|
}
|
|
@@ -18,25 +18,28 @@ const DEFAULT = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
class StateTravel {
|
|
21
|
-
constructor (internals, file, driver) {
|
|
21
|
+
constructor (internals, file, driver, pdriver) {
|
|
22
22
|
this.file = file;
|
|
23
23
|
this.internals = internals;
|
|
24
24
|
this.driver = driver;
|
|
25
|
+
this.pdriver = pdriver;
|
|
25
26
|
this._counter = 0;
|
|
27
|
+
this._default = async function _default () {
|
|
28
|
+
await State.step(this.pdriver, ++this._counter, this.internals);
|
|
29
|
+
|
|
30
|
+
return State.update(
|
|
31
|
+
this.pdriver,
|
|
32
|
+
this.file,
|
|
33
|
+
this.internals.modSchema,
|
|
34
|
+
this.internals
|
|
35
|
+
);
|
|
36
|
+
};
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
|
|
29
40
|
Object.keys(DEFAULT).forEach(m => {
|
|
30
41
|
StateTravel.prototype[m] = async function (...args) {
|
|
31
|
-
|
|
32
|
-
const res = await State.update(
|
|
33
|
-
this.driver,
|
|
34
|
-
this.file,
|
|
35
|
-
this.internals.modSchema,
|
|
36
|
-
this.internals
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
return res;
|
|
42
|
+
return this._default();
|
|
40
43
|
};
|
|
41
44
|
});
|
|
42
45
|
|
|
@@ -47,9 +50,9 @@ const noTravelError = prop => {
|
|
|
47
50
|
};
|
|
48
51
|
|
|
49
52
|
module.exports = {
|
|
50
|
-
getInterface: (context, file, driver, internals) => {
|
|
53
|
+
getInterface: (context, file, driver, internals, pdriver) => {
|
|
51
54
|
if (context.learnable) {
|
|
52
|
-
const st = new StateTravel(internals, file, context);
|
|
55
|
+
const st = new StateTravel(internals, file, context, pdriver);
|
|
53
56
|
return Shadow.overshadow(
|
|
54
57
|
driver,
|
|
55
58
|
Object.assign(st, context.statechanger),
|
|
@@ -59,7 +62,7 @@ module.exports = {
|
|
|
59
62
|
|
|
60
63
|
return Shadow.overshadow(
|
|
61
64
|
driver,
|
|
62
|
-
new StateTravel(internals, file, context),
|
|
65
|
+
new StateTravel(internals, file, context, pdriver),
|
|
63
66
|
noTravelError
|
|
64
67
|
);
|
|
65
68
|
}
|
|
@@ -3,6 +3,7 @@ const State = require('../../state');
|
|
|
3
3
|
const Chain = require('../../chain');
|
|
4
4
|
const Migrate = require('./migrate');
|
|
5
5
|
const Learn = require('../../learn');
|
|
6
|
+
const log = require('db-migrate-shared').log;
|
|
6
7
|
|
|
7
8
|
const methods = {
|
|
8
9
|
createTable: async (driver, [t], internals) => {
|
|
@@ -43,6 +44,26 @@ const methods = {
|
|
|
43
44
|
|
|
44
45
|
changeColumn: async (driver, [t, c], internals) => {
|
|
45
46
|
return driver.changeColumn(t, c, internals.modSchema.c[t][c]);
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
addIndex: async (driver, [t, i], internals) => {
|
|
50
|
+
if (!internals.modSchema.i[t][i]) {
|
|
51
|
+
log.warn(
|
|
52
|
+
`There was an attempt to create the index "${i}" in the table "${t}".`
|
|
53
|
+
);
|
|
54
|
+
log.warn(
|
|
55
|
+
`This index did not exist at the time of deleting it. ` +
|
|
56
|
+
`This can happen if an index was created by hand and then deleted ` +
|
|
57
|
+
`by db-migrate. Make sure to recreate it by hand to avoid any problems.`
|
|
58
|
+
);
|
|
59
|
+
return Promise.resolve();
|
|
60
|
+
}
|
|
61
|
+
return driver.addIndex(
|
|
62
|
+
t,
|
|
63
|
+
i,
|
|
64
|
+
internals.modSchema.i[t][i].c,
|
|
65
|
+
internals.modSchema.i[t][i].u ? true : undefined
|
|
66
|
+
);
|
|
46
67
|
}
|
|
47
68
|
};
|
|
48
69
|
|
|
@@ -51,34 +72,50 @@ async function processEntry (
|
|
|
51
72
|
file,
|
|
52
73
|
driver,
|
|
53
74
|
internals,
|
|
75
|
+
pdriver,
|
|
54
76
|
{ t: type, a: action, c: args }
|
|
55
77
|
) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
let skip = false;
|
|
79
|
+
|
|
80
|
+
if (
|
|
81
|
+
internals.rollback === true &&
|
|
82
|
+
internals.rollbackContinue !== true &&
|
|
83
|
+
driver.udriver._meta?.signalColumns?.indexOf(action) !== -1
|
|
84
|
+
) {
|
|
85
|
+
internals.rollbackContinue = true;
|
|
86
|
+
skip = driver.udriver._counter.previousSignal() === null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!skip) {
|
|
90
|
+
const f = Object.assign(methods, context.reverse);
|
|
91
|
+
switch (type) {
|
|
92
|
+
case 0:
|
|
93
|
+
await driver[action].apply(driver, args);
|
|
94
|
+
break;
|
|
95
|
+
case 1:
|
|
96
|
+
await f[action](driver, args, internals);
|
|
97
|
+
break;
|
|
98
|
+
|
|
99
|
+
default:
|
|
100
|
+
throw new Error(`Invalid state record, of type ${type}`);
|
|
101
|
+
}
|
|
67
102
|
}
|
|
68
103
|
|
|
69
104
|
internals.modSchema.s.shift();
|
|
70
|
-
await State.update(
|
|
105
|
+
await State.update(pdriver, file, internals.modSchema, internals);
|
|
71
106
|
}
|
|
72
107
|
|
|
73
|
-
module.exports = async (context, file, driver, internals) => {
|
|
108
|
+
module.exports = async (context, file, driver, internals, pdriver) => {
|
|
74
109
|
const mod = internals.modSchema;
|
|
75
110
|
|
|
76
|
-
const chain = new Chain(context, file, driver, internals);
|
|
111
|
+
const chain = new Chain(context, file, driver, internals, pdriver);
|
|
112
|
+
internals.unlearn = true;
|
|
113
|
+
|
|
77
114
|
chain.addChain(Learn);
|
|
78
115
|
chain.addChain(Migrate);
|
|
79
116
|
await Promise.resolve(mod.s.reverse()).each(args =>
|
|
80
|
-
processEntry(context, file, chain, internals, args)
|
|
117
|
+
processEntry(context, file, chain, internals, pdriver, args)
|
|
81
118
|
);
|
|
82
119
|
|
|
83
|
-
await State.deleteState(
|
|
120
|
+
await State.deleteState(pdriver, file, internals);
|
|
84
121
|
};
|
package/lib/state.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
const MSTATE = '__dbmigrate_state__';
|
|
2
2
|
const SSTATE = '__dbmigrate_schema__';
|
|
3
|
+
const RUNON = 'run_on';
|
|
4
|
+
|
|
3
5
|
const log = require('db-migrate-shared').log;
|
|
6
|
+
const fs = require('fs').promises;
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
|
+
|
|
10
|
+
const ID = crypto.randomBytes(32).toString('base64');
|
|
11
|
+
let owner = false;
|
|
4
12
|
|
|
5
13
|
module.exports = {
|
|
14
|
+
/**
|
|
15
|
+
* Lock state will add the basic state controller an ID
|
|
16
|
+
* and a process controlled date.
|
|
17
|
+
* It is important that all systems are in sync. We will use the
|
|
18
|
+
* database clock instead if possible.
|
|
19
|
+
*/
|
|
6
20
|
lockState: async function (driver, state, internals) {
|
|
7
21
|
if (!state) {
|
|
22
|
+
owner = true;
|
|
8
23
|
return driver._insertKV(
|
|
9
24
|
internals.migrationState,
|
|
10
25
|
MSTATE,
|
|
@@ -12,29 +27,72 @@ module.exports = {
|
|
|
12
27
|
s: {
|
|
13
28
|
step: 0,
|
|
14
29
|
fin: 0,
|
|
30
|
+
ID,
|
|
15
31
|
date: new Date()
|
|
16
32
|
}
|
|
17
33
|
})
|
|
18
34
|
);
|
|
19
35
|
} else {
|
|
36
|
+
let runOn = state.run_on;
|
|
20
37
|
state = state.value;
|
|
21
38
|
state = JSON.parse(state);
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
|
|
40
|
+
if (!state.s.ID || state.s.ID !== ID) {
|
|
41
|
+
owner = true;
|
|
42
|
+
state.s.ID = ID;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const d = new Date();
|
|
46
|
+
|
|
47
|
+
state.s.date = d;
|
|
48
|
+
await driver._updateKVC(
|
|
24
49
|
internals.migrationState,
|
|
25
50
|
MSTATE,
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
JSON.stringify(state),
|
|
52
|
+
RUNON,
|
|
53
|
+
runOn
|
|
28
54
|
);
|
|
55
|
+
|
|
56
|
+
state = await driver._getKV(internals.migrationState, MSTATE);
|
|
57
|
+
|
|
58
|
+
runOn = state.run_on;
|
|
59
|
+
state = state.value;
|
|
60
|
+
state = JSON.parse(state);
|
|
61
|
+
|
|
62
|
+
if (state.s.ID !== ID) {
|
|
63
|
+
owner = false;
|
|
64
|
+
}
|
|
29
65
|
}
|
|
30
66
|
},
|
|
31
67
|
|
|
32
|
-
|
|
68
|
+
isOwner: function () {
|
|
69
|
+
return owner;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
init: async function (driver, internals, { emptyState, backupState }) {
|
|
33
73
|
await driver._createKV(internals.migrationState);
|
|
34
|
-
const
|
|
74
|
+
const _schema = await driver._getKV(internals.migrationState, SSTATE);
|
|
75
|
+
|
|
76
|
+
if (_schema && backupState) {
|
|
77
|
+
const newName = `${internals.migrationState}_b_${Math.floor((new Date() - 0) / 1000)}`;
|
|
78
|
+
log.info(`[state] Created a backup of ${internals.migrationState} by writing to file ${newName}.dbmigrate`);
|
|
79
|
+
|
|
80
|
+
await fs.writeFile(path.resolve(`${newName}.dbmigrate`), JSON.stringify(_schema), 'utf8');
|
|
81
|
+
|
|
82
|
+
if (emptyState) {
|
|
83
|
+
await driver.renameTable(internals.migrationState,
|
|
84
|
+
newName);
|
|
85
|
+
|
|
86
|
+
log.info(`[state] Created a backup of ${internals.migrationState} by renaming table to ${newName}`);
|
|
87
|
+
await driver._createKV(internals.migrationState);
|
|
88
|
+
await driver._insertKV(internals.migrationState, SSTATE, '{}');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const schema = emptyState !== true ? _schema : null;
|
|
35
93
|
if (schema) {
|
|
36
94
|
internals.schema = JSON.parse(schema.value);
|
|
37
|
-
} else {
|
|
95
|
+
} else if (!emptyState) {
|
|
38
96
|
await driver._insertKV(internals.migrationState, SSTATE, '{}');
|
|
39
97
|
}
|
|
40
98
|
|
|
@@ -50,7 +108,7 @@ module.exports = {
|
|
|
50
108
|
const state = await driver._getKV(internals.migrationState, MSTATE);
|
|
51
109
|
const mig = await driver._getKV(internals.migrationState, file.name);
|
|
52
110
|
|
|
53
|
-
if (mig) {
|
|
111
|
+
if (mig && mig.value !== '{}') {
|
|
54
112
|
internals.modSchema = JSON.parse(mig.value);
|
|
55
113
|
}
|
|
56
114
|
|
|
@@ -77,7 +135,7 @@ module.exports = {
|
|
|
77
135
|
return Promise.resolve();
|
|
78
136
|
}
|
|
79
137
|
|
|
80
|
-
await driver._updateKV(internals.migrationState, SSTATE, internals.schema);
|
|
138
|
+
await driver._updateKV(internals.migrationState, SSTATE, JSON.stringify(internals.schema));
|
|
81
139
|
|
|
82
140
|
return driver._updateKV(
|
|
83
141
|
internals.migrationState,
|
|
@@ -95,17 +153,40 @@ module.exports = {
|
|
|
95
153
|
return Promise.resolve();
|
|
96
154
|
}
|
|
97
155
|
|
|
98
|
-
let
|
|
156
|
+
let state = await driver._getKV(
|
|
99
157
|
internals.migrationState,
|
|
100
158
|
MSTATE
|
|
101
159
|
);
|
|
160
|
+
|
|
161
|
+
let runOn = state.run_on;
|
|
162
|
+
state = state.value;
|
|
102
163
|
state = JSON.parse(state);
|
|
103
|
-
|
|
104
|
-
|
|
164
|
+
|
|
165
|
+
if (!state.s.ID || state.s.ID !== ID) {
|
|
166
|
+
owner = true;
|
|
167
|
+
state.s.ID = ID;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const d = new Date();
|
|
171
|
+
|
|
172
|
+
state.s.date = d;
|
|
173
|
+
await driver._updateKVC(
|
|
105
174
|
internals.migrationState,
|
|
106
175
|
MSTATE,
|
|
107
|
-
JSON.stringify(state)
|
|
176
|
+
JSON.stringify(state),
|
|
177
|
+
RUNON,
|
|
178
|
+
runOn
|
|
108
179
|
);
|
|
180
|
+
|
|
181
|
+
state = await driver._getKV(internals.migrationState, MSTATE);
|
|
182
|
+
|
|
183
|
+
runOn = state.run_on;
|
|
184
|
+
state = state.value;
|
|
185
|
+
state = JSON.parse(state);
|
|
186
|
+
|
|
187
|
+
if (state.s.ID !== ID) {
|
|
188
|
+
owner = false;
|
|
189
|
+
}
|
|
109
190
|
},
|
|
110
191
|
|
|
111
192
|
step: async function (driver, step, internals) {
|
|
@@ -145,6 +226,9 @@ module.exports = {
|
|
|
145
226
|
state.s.date = new Date();
|
|
146
227
|
state.s.fin = 1;
|
|
147
228
|
|
|
229
|
+
// unlock from current process
|
|
230
|
+
state.s.ID = 0;
|
|
231
|
+
|
|
148
232
|
return driver._updateKV(
|
|
149
233
|
internals.migrationState,
|
|
150
234
|
MSTATE,
|
package/lib/template.js
CHANGED
|
@@ -258,7 +258,8 @@ Template.TemplateType = {
|
|
|
258
258
|
SQL_FILE_LOADER: 2,
|
|
259
259
|
DEFAULT_COFFEE: 3,
|
|
260
260
|
COFFEE_SQL_FILE_LOADER: 4,
|
|
261
|
-
SQL_FILE_LOADER_IGNORE_ON_INIT: 5
|
|
261
|
+
SQL_FILE_LOADER_IGNORE_ON_INIT: 5,
|
|
262
|
+
V2_DEFAULT: 6
|
|
262
263
|
};
|
|
263
264
|
|
|
264
265
|
Template.prototype.getTemplate = function () {
|
|
@@ -277,6 +278,8 @@ Template.prototype.getTemplate = function () {
|
|
|
277
278
|
return this.sqlFileLoaderIgnoreOnInitTemplate();
|
|
278
279
|
case Template.TemplateType.DEFAULT_JS:
|
|
279
280
|
return this.defaultJsTemplate();
|
|
281
|
+
case Template.TemplateType.V2_DEFAULT:
|
|
282
|
+
return require('./templates/v2.js')();
|
|
280
283
|
default:
|
|
281
284
|
if (this.plugins) {
|
|
282
285
|
plugin = this.plugins.overwrite(
|