db-migrate 1.0.0-beta.16

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +487 -0
  2. package/LICENSE +22 -0
  3. package/README.md +100 -0
  4. package/api.js +463 -0
  5. package/bin/db-migrate +39 -0
  6. package/connect.js +198 -0
  7. package/get.js +67 -0
  8. package/index.js +85 -0
  9. package/lib/chain.js +157 -0
  10. package/lib/class.js +75 -0
  11. package/lib/commands/check.js +52 -0
  12. package/lib/commands/create-migration.js +252 -0
  13. package/lib/commands/db.js +63 -0
  14. package/lib/commands/down.js +45 -0
  15. package/lib/commands/dump.js +22 -0
  16. package/lib/commands/fn/plugin.js +45 -0
  17. package/lib/commands/generated.js +32 -0
  18. package/lib/commands/helper/assert.js +15 -0
  19. package/lib/commands/helper/load-config.js +26 -0
  20. package/lib/commands/helper/migration-hook.js +4 -0
  21. package/lib/commands/helper/register-events.js +19 -0
  22. package/lib/commands/index.js +9 -0
  23. package/lib/commands/on-complete.js +28 -0
  24. package/lib/commands/run.js +122 -0
  25. package/lib/commands/seed.js +48 -0
  26. package/lib/commands/set-default-argv.js +169 -0
  27. package/lib/commands/sync.js +52 -0
  28. package/lib/commands/undo-seed.js +54 -0
  29. package/lib/commands/up.js +52 -0
  30. package/lib/config.js +207 -0
  31. package/lib/driver/index.js +156 -0
  32. package/lib/driver/shadow.js +74 -0
  33. package/lib/executors/versioned/v1.js +48 -0
  34. package/lib/executors/versioned/v2.js +78 -0
  35. package/lib/file.js +190 -0
  36. package/lib/interface/migratorInterface.js +127 -0
  37. package/lib/interface/seederInterface.js +145 -0
  38. package/lib/learn.js +369 -0
  39. package/lib/methods/v2/conventions.js +47 -0
  40. package/lib/methods/v2/migrate.js +5 -0
  41. package/lib/methods/v2/statetravel.js +86 -0
  42. package/lib/methods/v2/translatestate.js +117 -0
  43. package/lib/relation.js +37 -0
  44. package/lib/state.js +154 -0
  45. package/lib/template.js +312 -0
  46. package/lib/templates/v2.js +12 -0
  47. package/lib/temputils.js +62 -0
  48. package/lib/walker.js +266 -0
  49. package/package.json +87 -0
  50. package/pnpm-lock.yaml +2574 -0
  51. package/te.js +70 -0
package/lib/learn.js ADDED
@@ -0,0 +1,369 @@
1
+ const Promise = require('bluebird');
2
+ const Shadow = require('./driver/shadow');
3
+
4
+ class STD {
5
+ constructor ({ schema, modSchema: mod }, driver) {
6
+ this.checkColumn = function (t, c) {
7
+ if (!this.schema[t]) {
8
+ throw new Error(`There is no ${t} table in schema!`);
9
+ }
10
+
11
+ if (!this.schema[t][c]) {
12
+ throw new Error(`There is no ${c} column in schema!`);
13
+ }
14
+ };
15
+ this.validations = {};
16
+ this.driver = driver;
17
+ this.indizies = schema.i;
18
+ this.schema = schema.c;
19
+ this.foreign = schema.f;
20
+ if (!schema.e) {
21
+ schema.e = {};
22
+ }
23
+ this.extra = schema.e;
24
+ this.modS = mod.c;
25
+ this.modI = mod.i;
26
+ this.modF = mod.f;
27
+ this.modC = mod.s;
28
+ }
29
+
30
+ dropTable (t) {
31
+ let alter = {};
32
+ alter = { c: {}, i: {}, f: {} };
33
+
34
+ if (this.schema[t]) {
35
+ alter.c[t] = this.schema[t];
36
+ this.modS[t] = this.schema[t];
37
+ delete this.schema[t];
38
+ }
39
+
40
+ if (this.foreign[t]) {
41
+ alter.f[t] = this.foreign[t];
42
+ this.modF[t] = this.foreign[t];
43
+ delete this.foreign[t];
44
+ }
45
+
46
+ if (this.indizies[t]) {
47
+ alter.i[t] = this.indizies[t];
48
+ this.modI[t] = this.indizies[t];
49
+ delete this.indizies[t];
50
+ }
51
+
52
+ this.modC.push({ t: 1, a: 'createTable', c: [t] });
53
+
54
+ return Promise.resolve(alter);
55
+ }
56
+
57
+ createTable (t, s) {
58
+ this.schema[t] = Object.assign({}, s);
59
+
60
+ Object.keys(s).forEach(k => {
61
+ const key = s[k];
62
+
63
+ if (key.foreignKey) {
64
+ if (!this.foreign[t]) this.foreign[t] = {};
65
+
66
+ this.foreign[t][key.foreignKey.name] = { t, rt: key.foreignKey.table };
67
+ if (key.foreignKey.rules) {
68
+ this.foreign[t][key.foreignKey.name].r = key.foreignKey.rules;
69
+ }
70
+
71
+ let mapping = {};
72
+
73
+ if (typeof key.foreignKey.mapping === 'string') {
74
+ mapping[k] = key.foreignKey.mapping;
75
+ } else {
76
+ mapping = Object.assign({}, key.foreignKey.mapping);
77
+ }
78
+
79
+ this.foreign[t][key.foreignKey.name].m = mapping;
80
+ }
81
+ });
82
+
83
+ this.modC.push({ t: 0, a: 'dropTable', c: [t] });
84
+
85
+ return Promise.resolve();
86
+ }
87
+
88
+ renameTable (t, n) {
89
+ if (this.schema[t]) {
90
+ this.schema[n] = this.schema[t];
91
+ delete this.schema[t];
92
+ }
93
+
94
+ if (this.foreign[t]) {
95
+ this.modF[n] = this.foreign[n];
96
+ delete this.foreign[t];
97
+ }
98
+
99
+ if (this.indizies[t]) {
100
+ this.modI[n] = this.indizies[t];
101
+ delete this.indizies[t];
102
+ }
103
+
104
+ this.modC.push({ t: 0, a: 'renameTable', c: [n, t] });
105
+
106
+ return Promise.resolve();
107
+ }
108
+
109
+ renameCollection (...args) {
110
+ return this.renameTable.apply(this, args);
111
+ }
112
+
113
+ dropCollection (...args) {
114
+ return this.dropTable.apply(this, args);
115
+ }
116
+
117
+ createCollection (...args) {
118
+ return this.createTable.apply(this, args);
119
+ }
120
+
121
+ removeColumn (t, c, o = {}) {
122
+ const alter = {};
123
+ this.checkColumn(t, c);
124
+
125
+ if (this.schema[t][c].notNull === true) {
126
+ if (this.validations.columnStrategies !== true) {
127
+ if (
128
+ this.driver._meta &&
129
+ this.driver._meta.supports &&
130
+ this.driver._meta.supports.optionParam === true
131
+ ) {
132
+ /**
133
+ * This is a validation only, no action will be taken unless throwing
134
+ * errors.
135
+ *
136
+ * The driver needs to respect the options properly.
137
+ */
138
+ switch (o.columnStrategy) {
139
+ case 'defaultValue':
140
+ break;
141
+ case 'delay':
142
+ break;
143
+ default:
144
+ if (!o.columnStrategy) {
145
+ throw new Error(
146
+ 'Can not drop a notNull column without providing a' +
147
+ ' recreation strategy.'
148
+ );
149
+ }
150
+ throw new Error(
151
+ `There is no such column recreation strategy "${o.columnStrategy}!"`
152
+ );
153
+ }
154
+ } else {
155
+ throw new Error(
156
+ 'This driver does not support optionParameters which are' +
157
+ ' required to provide a recreation strategy.'
158
+ );
159
+ }
160
+
161
+ if (!this.driver._meta.supports.columnStrategies) {
162
+ throw new Error(
163
+ 'This driver does not support column recreation strategies.'
164
+ );
165
+ }
166
+
167
+ this.validations.columnStrategies = true;
168
+ }
169
+ }
170
+
171
+ this.modS[t] = {};
172
+
173
+ if (this.schema[t][c].notNull === true) {
174
+ switch (o.columnStrategy) {
175
+ case 'delay':
176
+ this.modS[t][c] = this.schema[t][c];
177
+
178
+ o.passthrough = o.passthrough || {};
179
+ o.passthrough.column =
180
+ o.passthrough.column ||
181
+ `__dbmrn_${c}_${new Date().toISOString()}__`;
182
+
183
+ this.modC.push({
184
+ t: 0,
185
+ a: 'renameColumn',
186
+ c: [t, o.passthrough.column, c]
187
+ });
188
+
189
+ break;
190
+ case 'defaultValue':
191
+ this.modS[t][c] = this.schema[t][c];
192
+ this.modS[t][c].defaultValue = o.passthrough.defaultValue;
193
+
194
+ this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
195
+ break;
196
+ }
197
+ } else {
198
+ this.modS[t][c] = this.schema[t][c];
199
+
200
+ this.modC.push({ t: 1, a: 'addColumn', c: [t, c, o] });
201
+ }
202
+
203
+ delete this.schema[t][c];
204
+
205
+ return Promise.resolve(alter);
206
+ }
207
+
208
+ renameColumn (t, o, n) {
209
+ if (this.schema[t]) {
210
+ this.schema[t][n] = this.schema[t][o];
211
+ delete this.schema[t][o];
212
+ }
213
+
214
+ this.modC.push({ t: 0, a: 'renameColumn', c: [t, n, o] });
215
+
216
+ return Promise.resolve();
217
+ }
218
+
219
+ addColumn (t, c, s) {
220
+ if (!this.schema[t]) {
221
+ throw new Error(`There is no ${t} table in schema!`);
222
+ }
223
+ this.schema[t] = this.schema[t] || {};
224
+ this.schema[t][c] = s;
225
+
226
+ this.modC.push({ t: 0, a: 'removeColumn', c: [t, c] });
227
+
228
+ return Promise.resolve();
229
+ }
230
+
231
+ changeColumn (t, c, s) {
232
+ this.checkColumn(t, c);
233
+
234
+ if (!this.modS[t]) this.modS[t] = {};
235
+
236
+ this.modS[t][c] = this.schema[t][c];
237
+ this.schema[t][c] = Object.assign(this.schema[t][c], s);
238
+
239
+ this.modC.push({ t: 1, a: 'changeColumn', c: [t, c] });
240
+
241
+ return Promise.resolve();
242
+ }
243
+
244
+ addIndex (t, i, c, u) {
245
+ if (Array.isArray(c)) {
246
+ c.forEach(x => this.checkColumn(t, x));
247
+ } else {
248
+ this.checkColumn(t, c);
249
+ }
250
+
251
+ const index = { t, c };
252
+
253
+ if (u === true) {
254
+ index.u = true;
255
+ }
256
+
257
+ if (!this.indizies[t]) this.indizies[t] = {};
258
+ this.indizies[t][i] = index;
259
+
260
+ this.modC.push({ t: 0, a: 'removeIndex', c: [t, i] });
261
+
262
+ return Promise.resolve();
263
+ }
264
+
265
+ removeIndex (t, _i) {
266
+ let alter = {};
267
+ alter = { c: {}, i: {}, f: {} };
268
+
269
+ let i;
270
+ if (!_i) {
271
+ i = t;
272
+ } else {
273
+ i = _i;
274
+ }
275
+
276
+ if (!this.schema[t]) {
277
+ throw new Error(`There is no ${t} table in schema!`);
278
+ }
279
+
280
+ if (!this.indizies[t] || !this.indizies[t][i]) {
281
+ throw new Error(`There is no index ${i} in ${t} table!`);
282
+ }
283
+
284
+ alter.i[t] = {};
285
+ alter.i[t][i] = this.indizies[t][i];
286
+ this.modI[t] = {};
287
+ this.modI[t][i] = this.indizies[t][i];
288
+ delete this.indizies[t][i];
289
+
290
+ this.modC.push({ t: 1, a: 'addIndex', c: [t, i] });
291
+
292
+ return Promise.resolve(alter);
293
+ }
294
+
295
+ addForeignKey (t, rt, k, m, r) {
296
+ if (!this.schema[t]) {
297
+ throw new Error(`There is no ${t} table in schema!`);
298
+ }
299
+
300
+ if (!this.schema[rt]) {
301
+ throw new Error(`There is no ${rt} table in schema!`);
302
+ }
303
+
304
+ if (!this.foreign[t]) this.foreign[t] = {};
305
+
306
+ this.foreign[t][k] = { t, rt, m };
307
+
308
+ if (r) {
309
+ this.foreign[t][k].r = r;
310
+ }
311
+
312
+ this.modC.push({ t: 0, a: 'removeForeignKey', c: [t, k] });
313
+
314
+ return Promise.resolve();
315
+ }
316
+
317
+ removeForeignKey (t, k, o) {
318
+ let alter = {};
319
+ alter = { c: {}, i: {}, f: {} };
320
+
321
+ if (!this.schema[t]) {
322
+ throw new Error(`There is no ${t} table in schema!`);
323
+ }
324
+
325
+ if (!this.foreign[t] || !this.foreign[t][k]) {
326
+ throw new Error(`There is no foreign key ${k} in ${t} table!`);
327
+ }
328
+
329
+ alter.f[t] = {};
330
+ alter.f[t][k] = this.foreign[t][k];
331
+ this.modF[t] = {};
332
+ this.modF[t][k] = this.foreign[t][k];
333
+ delete this.foreign[t][k];
334
+
335
+ return Promise.resolve(alter);
336
+ }
337
+
338
+ //
339
+ // checkDBMS: dummy,
340
+ //
341
+ // createDatabase: dummy,
342
+ //
343
+ // switchDatabase: dummy,
344
+ //
345
+ // dropDatabase: dummy,
346
+ //
347
+ // runSql: dummy,
348
+ }
349
+
350
+ const noLearnError = prop => {
351
+ return function () {
352
+ throw new Error(`Can't learn function ${prop}`);
353
+ };
354
+ };
355
+
356
+ module.exports = {
357
+ getInterface: (context, file, driver, internals) => {
358
+ if (context.learnable) {
359
+ const _std = new STD(internals, context);
360
+ return Shadow.overshadow(
361
+ driver,
362
+ Object.assign(_std, context.learnable),
363
+ noLearnError
364
+ );
365
+ }
366
+
367
+ return Shadow.overshadow(driver, new STD(internals, context), noLearnError);
368
+ }
369
+ };
@@ -0,0 +1,47 @@
1
+ const Shadow = require('../../driver/shadow');
2
+
3
+ class AddConventions {
4
+ constructor (internals, file, driver) {
5
+ this.file = file;
6
+ this.internals = internals;
7
+ this.driver = driver;
8
+ this._counter = 0;
9
+ }
10
+
11
+ createTable (t, d) {
12
+ d.__dbmigrate__flag = {
13
+ type: 'string'
14
+ };
15
+
16
+ return Promise.resolve();
17
+ }
18
+
19
+ createCollection (...args) {
20
+ return this.createTable.apply(this, args);
21
+ }
22
+ }
23
+
24
+ const noAction = prop => {
25
+ return function () {
26
+ return Promise.resolve();
27
+ };
28
+ };
29
+
30
+ module.exports = {
31
+ getInterface: (context, file, driver, internals) => {
32
+ if (context.conventions) {
33
+ const st = new AddConventions(internals, file, context);
34
+ return Shadow.overshadow(
35
+ driver,
36
+ Object.assign(st, context.conventions),
37
+ noAction
38
+ );
39
+ }
40
+
41
+ return Shadow.overshadow(
42
+ driver,
43
+ new AddConventions(internals, file, context),
44
+ noAction
45
+ );
46
+ }
47
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ getInterface (context, file, driver) {
3
+ return driver;
4
+ }
5
+ };
@@ -0,0 +1,86 @@
1
+ const Shadow = require('../../driver/shadow');
2
+ const State = require('../../state');
3
+ const DEFAULT = {
4
+ renameCollection: 'renameCollection',
5
+ dropCollection: 'createCollection',
6
+ createCollection: 'dropCollection',
7
+ createTable: 'dropTable',
8
+ dropTable: 'createTable',
9
+ renameTable: 'renameTable',
10
+ addColumn: 'removeColumn',
11
+ removeColumn: 'addColumn',
12
+ renameColumn: 'renameColumn',
13
+ changeColumn: 'changeColumn',
14
+ addIndex: 'removeIndex',
15
+ removeIndex: 'addIndex',
16
+ addForeignKey: 'removeForeignKey',
17
+ removeForeignKey: 'addForeignKey'
18
+ };
19
+
20
+ class StateTravel {
21
+ constructor (internals, file, driver) {
22
+ this.file = file;
23
+ this.internals = internals;
24
+ this.driver = driver;
25
+ this._counter = 0;
26
+ this._default = async function _default () {
27
+ await State.step(this.driver, ++this._counter, this.internals);
28
+
29
+ return State.update(
30
+ this.driver,
31
+ this.file,
32
+ this.internals.modSchema,
33
+ this.internals
34
+ );
35
+ };
36
+ }
37
+ }
38
+
39
+ Object.keys(DEFAULT).forEach(m => {
40
+ StateTravel.prototype[m] = async function (...args) {
41
+ return this._default();
42
+ };
43
+ });
44
+
45
+ const noTravelError = prop => {
46
+ return function () {
47
+ throw new Error(`Can't state travel function ${prop}`);
48
+ };
49
+ };
50
+
51
+ module.exports = {
52
+ getInterface: (context, file, driver, internals) => {
53
+ if (context.learnable) {
54
+ const st = new StateTravel(internals, file, context);
55
+ return Shadow.overshadow(
56
+ driver,
57
+ Object.assign(st, context.statechanger),
58
+ noTravelError
59
+ );
60
+ }
61
+
62
+ return Shadow.overshadow(
63
+ driver,
64
+ new StateTravel(internals, file, context),
65
+ noTravelError
66
+ );
67
+ }
68
+
69
+ /* hasModification: true,
70
+
71
+ modify: (context, driver, internals) => {
72
+ let _driver = Object.assign({}, driver);
73
+ _driver.host = {};
74
+ // Inject into chained operations, in this case
75
+ // we directly process information from the major
76
+ // creation object, so this serves only as an example currently.
77
+ // ['addForeignKey'].forEach(m => {
78
+ // _driver.host[m] = _driver[m];
79
+ // _driver[m] = function (...args) {
80
+ // return _driver.host[m].apply(_driver, args);
81
+ // };
82
+ // });
83
+
84
+ return { driver: _driver };
85
+ } */
86
+ };
@@ -0,0 +1,117 @@
1
+ const Promise = require('bluebird');
2
+ const State = require('../../state');
3
+ const Chain = require('../../chain');
4
+ const Migrate = require('./migrate');
5
+ const log = require('db-migrate-shared').log;
6
+
7
+ const methods = {
8
+ createTable: async (driver, [t], internals) => {
9
+ const mod = internals.modSchema;
10
+ const schema = mod.c[t];
11
+ await driver.createTable(t, schema);
12
+
13
+ Object.keys(schema).forEach(key => {
14
+ if (schema[key].foreignKey) {
15
+ delete mod.f[t][schema[key].foreignKey.name];
16
+ }
17
+ });
18
+
19
+ if (mod.i[t]) {
20
+ await Promise.resolve(Object.keys(mod.i[t])).each(i => {
21
+ const index = mod.i[t][i];
22
+ return driver.addIndex(t, i, index.c, index.u);
23
+ });
24
+ }
25
+
26
+ if (mod.f[t]) {
27
+ await Promise.resolve(Object.keys(mod.f[t])).each(f => {
28
+ const foreign = mod.f[t][f];
29
+ return driver.addForeignKey(
30
+ t,
31
+ foreign.rt,
32
+ foreign.k,
33
+ foreign.m,
34
+ foreign.r
35
+ );
36
+ });
37
+ }
38
+ },
39
+
40
+ addColumn: async (driver, [t, c], internals) => {
41
+ return driver.addColumn(t, c, internals.modSchema.c[t][c]);
42
+ },
43
+
44
+ changeColumn: async (driver, [t, c], internals) => {
45
+ return driver.changeColumn(t, c, internals.modSchema.c[t][c]);
46
+ },
47
+
48
+ addIndex: async (driver, [t, i], internals) => {
49
+ if (!internals.modSchema.i[t][i]) {
50
+ log.warn(
51
+ `There was an attempt to create the index "${i}" in the table "${t}".`
52
+ );
53
+ log.warn(
54
+ `This index did not exist at the time of deleting it. ` +
55
+ `This can happen if an index was created by hand and then deleted` +
56
+ `by db-migrate. Make sure to recreate it by hand to avoid any problems.`
57
+ );
58
+ return Promise.resolve();
59
+ }
60
+ return driver.addIndex(
61
+ t,
62
+ i,
63
+ internals.modSchema.i[t][i].c,
64
+ internals.modSchema.i[t][i].u ? true : undefined
65
+ );
66
+ }
67
+ };
68
+
69
+ async function processEntry (
70
+ context,
71
+ file,
72
+ driver,
73
+ internals,
74
+ { t: type, a: action, c: args }
75
+ ) {
76
+ let skip = false;
77
+
78
+ if (
79
+ internals.rollback === true &&
80
+ internals.rollbackContinue !== true &&
81
+ driver.udriver._meta.signalColumns.indexOf(action) !== -1
82
+ ) {
83
+ internals.rollbackContinue = true;
84
+ skip = driver.udriver._counter.previousSignal() === null;
85
+ }
86
+
87
+ if (!skip) {
88
+ const f = Object.assign(methods, context.reverse);
89
+ switch (type) {
90
+ case 0:
91
+ await driver[action].apply(driver, args);
92
+ break;
93
+ case 1:
94
+ await f[action](driver, args, internals);
95
+ break;
96
+
97
+ default:
98
+ throw new Error(`Invalid state record, of type ${type}`);
99
+ }
100
+ }
101
+
102
+ internals.modSchema.s.shift();
103
+ await State.update(context, file, internals.modSchema, internals);
104
+ }
105
+
106
+ module.exports = async (context, file, driver, internals) => {
107
+ const mod = internals.modSchema;
108
+
109
+ const chain = new Chain(context, file, driver, internals);
110
+ // chain.addChain(Learn);
111
+ chain.addChain(Migrate);
112
+ await Promise.resolve(mod.s.reverse()).each(args =>
113
+ processEntry(context, file, chain, internals, args)
114
+ );
115
+
116
+ await State.deleteState(context, file, internals);
117
+ };
@@ -0,0 +1,37 @@
1
+ var fs = require('fs');
2
+ var log = require('db-migrate-shared').log;
3
+
4
+ function Relation () {
5
+ this.relations = {};
6
+ }
7
+
8
+ Relation.prototype = {
9
+ addRelation: function (table, column, relatedTable, relatedColumn) {
10
+ this.relations[table] = this.relations[table] || {};
11
+ this.relations[table][column] = relatedColumn;
12
+ },
13
+
14
+ getRelation: function (table, column) {
15
+ return this.relations[table][column];
16
+ },
17
+
18
+ fromJson: function (file) {
19
+ // Relation = require(file);
20
+
21
+ log.info('Read Relations from file ' + file);
22
+ },
23
+
24
+ toJson: function (file) {
25
+ fs.writeFile(file, JSON.stringify(this.relations), function (err) {
26
+ if (err) {
27
+ throw err;
28
+ }
29
+
30
+ log.info('Wrote Relations to file ' + file);
31
+ });
32
+ },
33
+
34
+ clearRelations: function () {
35
+ this.relations = {};
36
+ }
37
+ };