db-migrate 1.0.0-beta.3 → 1.0.0-beta.31

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 (49) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +1 -5
  3. package/api.js +26 -8
  4. package/connect.js +27 -10
  5. package/lib/chain.js +70 -12
  6. package/lib/commands/check.js +3 -3
  7. package/lib/commands/create-migration.js +28 -3
  8. package/lib/commands/down.js +1 -1
  9. package/lib/commands/dump.js +22 -0
  10. package/lib/commands/fix.js +53 -0
  11. package/lib/commands/generated.js +2 -1
  12. package/lib/commands/helper/register-events.js +2 -0
  13. package/lib/commands/run.js +5 -6
  14. package/lib/commands/set-default-argv.js +7 -2
  15. package/lib/commands/sync.js +3 -3
  16. package/lib/commands/up.js +3 -3
  17. package/lib/driver/index.js +37 -11
  18. package/lib/executors/versioned/v2.js +50 -6
  19. package/lib/learn.js +47 -14
  20. package/lib/methods/v2/statetravel.js +16 -13
  21. package/lib/methods/v2/translatestate.js +53 -16
  22. package/lib/state.js +97 -13
  23. package/lib/template.js +4 -1
  24. package/lib/templates/v2.js +12 -0
  25. package/lib/walker.js +83 -7
  26. package/package.json +20 -17
  27. package/tttt.js +2 -0
  28. package/.eslintignore +0 -1
  29. package/.eslintrc +0 -11
  30. package/.jscsrc +0 -0
  31. package/.jshintignore +0 -2
  32. package/.jshintrc +0 -14
  33. package/.labrc.js +0 -10
  34. package/.prettierrc +0 -3
  35. package/.tern-project +0 -7
  36. package/.travis.yml +0 -47
  37. package/CHANGELOG.md +0 -487
  38. package/CODE_OF_CONDUCT.md +0 -46
  39. package/CONTRIBUTING.md +0 -81
  40. package/commitlint.config.js +0 -1
  41. package/coverage.html +0 -17232
  42. package/generateLoader.js +0 -36
  43. package/lib/commands/transition.js +0 -5
  44. package/lib/transitions/1.js +0 -30
  45. package/lib/transitions/ask.js +0 -22
  46. package/lib/transitions/snippets/setup.sjs +0 -8
  47. package/lib/transitions/transitioner.js +0 -78
  48. package/lib/transitions/try-require.js +0 -113
  49. package/lib/transitions/update-version.js +0 -48
@@ -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(config, intern, function (err, db) {
94
- if (err) {
95
- callback(err);
96
- return;
97
- }
98
- log.verbose('connected');
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
- if (!global.immunity) {
101
- db = Shadow.infect(db, internals, ShadowProto);
102
- }
106
+ if (!global.immunity) {
107
+ db = Shadow.infect(db, internals, ShadowProto);
108
+ }
103
109
 
104
- callback(null, db);
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._driver, file, context.internals);
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._driver, file, context.internals);
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._driver, file, context.internals);
66
- await TranslateState(context._driver, file, driver, context.internals);
67
- await State.endMigration(context._driver, file, context.internals);
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 (this.schema[t][c].notNull === true) {
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 (this.schema[t][c].notNull === true) {
180
+ if (columns[c].notNull === true && !this.unlearn) {
160
181
  switch (o.columnStrategy) {
161
182
  case 'delay':
162
- this.modS[t][c] = this.schema[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] = this.schema[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] = this.schema[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
- delete this.schema[t][c];
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][c] = s;
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][c] = this.schema[t][c];
221
- this.schema[t][c] = Object.assign(this.schema[t][c], s);
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
- await State.step(this.driver, ++this._counter, this.internals);
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
- const f = Object.assign(methods, context.reverse);
57
- switch (type) {
58
- case 0:
59
- await driver[action].apply(driver, args);
60
- break;
61
- case 1:
62
- await f[action](driver, args, internals);
63
- break;
64
-
65
- default:
66
- throw new Error(`Invalid state record, of type ${type}`);
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(context, file, internals.modSchema, internals);
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(context, file, internals);
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
- state.s.date = new Date();
23
- return driver._updateKV(
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
- JSON.stringify(state)
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
- init: async function (driver, internals) {
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 schema = await driver._getKV(internals.migrationState, SSTATE);
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 { value: state } = await driver._getKV(
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
- state.s.date = new Date();
104
- return driver._updateKV(
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(
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ module.exports = () => `'use strict';
4
+
5
+ exports.migrate = async (db, opt) => {
6
+ const type = opt.dbm.dataType;
7
+ return null;
8
+ };
9
+
10
+ exports._meta = {
11
+ version: 2
12
+ };`;