@verdnatura/myt 1.5.7 → 1.5.9

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/README.md CHANGED
@@ -45,6 +45,8 @@ Database versioning commands:
45
45
  * **pull**: Incorporate database routine changes into workspace.
46
46
  * **push**: Apply changes into database.
47
47
  * **version**: Creates a new version.
48
+ * **create**: Creates a new routine file.
49
+ * **clean**: Cleans old versions.
48
50
 
49
51
  Local server management commands:
50
52
 
@@ -195,6 +197,14 @@ name mixing a color with a plant name.
195
197
  $ myt version [<name>]
196
198
  ```
197
199
 
200
+ ### create
201
+
202
+ Creates a new routine file with a default template.
203
+
204
+ ```text
205
+ $ myt create [-t <type>] <schema>.<name>
206
+ ```
207
+
198
208
  ### clean
199
209
 
200
210
  Cleans all already applied versions older than *maxOldVersions*.
@@ -1,6 +1,7 @@
1
1
  versionSchema: myt
2
2
  versionDigits: 5
3
3
  maxOldVersions: 30
4
+ sumViews: true
4
5
  schemas:
5
6
  - myt
6
7
  fixtures:
@@ -1,12 +1,12 @@
1
1
  DROP EVENT IF EXISTS <%- schema %>.<%- name %>;
2
2
  DELIMITER $$
3
3
  CREATE DEFINER=<%- definer %> EVENT <%- schema %>.<%- name %><%
4
- if (type == 'RECURRING') { %>
4
+ if (locals.type == 'RECURRING') { %>
5
5
  ON SCHEDULE EVERY <%- intervalValue %> <%- intervalField %><%
6
- if (starts) { %>
6
+ if (locals.starts) { %>
7
7
  STARTS <%- starts %><%
8
8
  }
9
- if (ends) { %>
9
+ if (locals.ends) { %>
10
10
  ENDS <%- ends %><%
11
11
  }
12
12
  } else { %>
@@ -14,7 +14,7 @@ if (type == 'RECURRING') { %>
14
14
  } %>
15
15
  ON COMPLETION <%- onCompletion %>
16
16
  <%- status %><%
17
- if (comment) { %>
17
+ if (locals.comment) { %>
18
18
  COMMENT <%- comment %><%
19
19
  } %>
20
20
  DO <%- body %>$$
@@ -8,6 +8,12 @@ module.exports = {
8
8
  'executeAt',
9
9
  'comment'
10
10
  ],
11
+ defaults: {
12
+ type: 'RECURRING',
13
+ intervalValue: 1,
14
+ intervalField: 'DAY',
15
+ onCompletion: 'PRESERVE'
16
+ },
11
17
  formatter(params) {
12
18
  let status;
13
19
  switch(params.status){
@@ -1,19 +1,19 @@
1
1
  DROP FUNCTION IF EXISTS <%- schema %>.<%- name %>;
2
2
  DELIMITER $$
3
- CREATE DEFINER=<%- definer %> FUNCTION <%- schema %>.<%- name %>(<%- paramList %>)
3
+ CREATE DEFINER=<%- definer %> FUNCTION <%- schema %>.<%- name %>(<%- locals.paramList %>)
4
4
  RETURNS <%- returns %><%
5
- if (isDeterministic == 'NO') { %>
5
+ if (locals.isDeterministic == 'NO') { %>
6
6
  NOT DETERMINISTIC<%
7
7
  } else { %>
8
8
  DETERMINISTIC<%
9
9
  }
10
- if (dataAccess) { %>
10
+ if (locals.dataAccess) { %>
11
11
  <%- dataAccess %><%
12
12
  }
13
- if (securityType == 'INVOKER') { %>
13
+ if (locals.securityType == 'INVOKER') { %>
14
14
  SQL SECURITY <%- securityType %><%
15
15
  }
16
- if (comment) { %>
16
+ if (locals.comment) { %>
17
17
  COMMENT <%- comment %><%
18
18
  } %>
19
19
  <%- body %>$$
@@ -5,6 +5,10 @@ module.exports = {
5
5
  escapeCols: [
6
6
  'comment'
7
7
  ],
8
+ defaults: {
9
+ returns: 'INT',
10
+ isDeterministic: 'NO'
11
+ },
8
12
  formatter(params) {
9
13
  let dataAccess;
10
14
  switch(params.dataAccess) {
@@ -1,13 +1,13 @@
1
1
  DROP PROCEDURE IF EXISTS <%- schema %>.<%- name %>;
2
2
  DELIMITER $$
3
- CREATE DEFINER=<%- definer %> PROCEDURE <%- schema %>.<%- name %>(<%- paramList %>)<%
4
- if (dataAccess) { %>
3
+ CREATE DEFINER=<%- definer %> PROCEDURE <%- schema %>.<%- name %>(<%- locals.paramList %>)<%
4
+ if (locals.dataAccess) { %>
5
5
  <%- dataAccess %><%
6
6
  }
7
- if (securityType == 'INVOKER') { %>
7
+ if (locals.securityType == 'INVOKER') { %>
8
8
  SQL SECURITY <%- securityType %><%
9
9
  }
10
- if (comment) { %>
10
+ if (locals.comment) { %>
11
11
  COMMENT <%- comment %><%
12
12
  } %>
13
13
  <%- body %>$$
@@ -1,5 +1,10 @@
1
1
 
2
2
  module.exports = {
3
3
  schemaCol: 'TRIGGER_SCHEMA',
4
- nameCol: 'TRIGGER_NAME'
4
+ nameCol: 'TRIGGER_NAME',
5
+ defaults: {
6
+ actionTiming: 'AFTER',
7
+ actionType: 'INSERT',
8
+ table: 'table'
9
+ }
5
10
  };
@@ -2,6 +2,6 @@ CREATE OR REPLACE DEFINER=<%- definer %>
2
2
  SQL SECURITY <%- securityType %>
3
3
  VIEW <%- schema %>.<%- name %>
4
4
  AS <%- definition %><%
5
- if (checkOption != 'NONE') { %>
5
+ if (locals.checkOption != 'NONE') { %>
6
6
  WITH <%- checkOption %> CHECK OPTION<%
7
7
  } %>
package/exporters/view.js CHANGED
@@ -4,6 +4,10 @@ const sqlFormatter = require('@sqltools/formatter');
4
4
  module.exports = {
5
5
  schemaCol: 'TABLE_SCHEMA',
6
6
  nameCol: 'TABLE_NAME',
7
+ defaults: {
8
+ securityType: 'DEFINER',
9
+ checkOption: 'NONE'
10
+ },
7
11
  formatter(params) {
8
12
  params.definition = sqlFormatter.format(params.definition, {
9
13
  indent: '\t',
package/lib/dumper.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const docker = require('./docker');
2
2
  const fs = require('fs-extra');
3
3
  const path = require('path');
4
+ const SqlString = require('sqlstring');
4
5
 
5
6
  module.exports = class Dumper {
6
7
  constructor(opts) {
@@ -28,9 +29,8 @@ module.exports = class Dumper {
28
29
  }
29
30
 
30
31
  async use(schema) {
31
- const escapedSchema = '`'+ schema.replace('`', '``') +'`';
32
32
  await this.dumpStream.write(
33
- `USE ${escapedSchema};\n`,
33
+ `USE ${SqlString.escapeId(schema, true)};\n`,
34
34
  'utf8'
35
35
  );
36
36
  }
@@ -1,4 +1,3 @@
1
-
2
1
  const shajs = require('sha.js');
3
2
  const fs = require('fs-extra');
4
3
  const Exporter = require('./exporter');
@@ -36,7 +35,7 @@ module.exports = class ExporterEngine {
36
35
  ];
37
36
 
38
37
  for (const type of types) {
39
- const exporter = new Exporter(this, type, this.conn);
38
+ const exporter = new Exporter(type);
40
39
  await exporter.init();
41
40
 
42
41
  this.exporters.push(exporter);
@@ -46,7 +45,7 @@ module.exports = class ExporterEngine {
46
45
 
47
46
  async fetchRoutine(type, schema, name) {
48
47
  const exporter = this.exporterMap[type];
49
- const [row] = await exporter.query(schema, name);
48
+ const [row] = await exporter.query(this.conn, schema, name);
50
49
  return row && exporter.format(row);
51
50
  }
52
51
 
package/lib/exporter.js CHANGED
@@ -1,13 +1,10 @@
1
-
2
1
  const ejs = require('ejs');
3
2
  const fs = require('fs-extra');
3
+ const SqlString = require('sqlstring');
4
4
 
5
5
  module.exports = class Exporter {
6
- constructor(engine, objectType, conn) {
7
- this.engine = engine;
6
+ constructor(objectType) {
8
7
  this.objectType = objectType;
9
- this.dstDir = `${objectType}s`;
10
- this.conn = conn;
11
8
  }
12
9
 
13
10
  async init() {
@@ -19,60 +16,7 @@ module.exports = class Exporter {
19
16
  this.attrs = require(`${templateDir}.js`);
20
17
  }
21
18
 
22
- async export(exportDir, schema, update, saveSum) {
23
- const res = await this.query(schema);
24
- if (!res.length) return;
25
-
26
- const routineDir = `${exportDir}/${schema}/${this.dstDir}`;
27
- if (!await fs.pathExists(routineDir))
28
- await fs.mkdir(routineDir);
29
-
30
- const routineSet = new Set();
31
- for (const params of res)
32
- routineSet.add(params.name);
33
-
34
- const routines = await fs.readdir(routineDir);
35
- for (const routineFile of routines) {
36
- const match = routineFile.match(/^(.*)\.sql$/);
37
- if (!match) continue;
38
- const routine = match[1];
39
- if (!routineSet.has(routine))
40
- await fs.remove(`${routineDir}/${routine}.sql`);
41
- }
42
-
43
- const engine = this.engine;
44
-
45
- for (const params of res) {
46
- const routineName = params.name;
47
- const sql = this.format(params);
48
- const routineFile = `${routineDir}/${routineName}.sql`;
49
-
50
- const oldSum = engine.getShaSum(routineName);
51
- if (oldSum || saveSum) {
52
- const shaSum = engine.shaSum(sql);
53
- if (oldSum !== shaSum) {
54
- engine.setShaSum(
55
- this.objectType, schema, routineName, shaSum);
56
- update = true;
57
- }
58
- } else if (params.modified && engine.lastPull) {
59
- if (params.modified > engine.lastPull)
60
- update = true;
61
- } else if (await fs.pathExists(routineFile)) {
62
- const currentSql = await fs.readFile(routineFile, 'utf8');
63
- if (sql != currentSql)
64
- update = true;
65
- } else
66
- update = true;
67
-
68
- if (update)
69
- await fs.writeFile(routineFile, sql);
70
- }
71
- }
72
-
73
- async query(schema, name) {
74
- const {conn} = this;
75
-
19
+ async query(conn, schema, name) {
76
20
  const ops = [];
77
21
  function addOp(col, value) {
78
22
  ops.push(conn.format('?? = ?', [col, value]));
@@ -93,22 +37,24 @@ module.exports = class Exporter {
93
37
  }
94
38
 
95
39
  format(params) {
96
- const {conn, attrs} = this;
40
+ const {attrs} = this;
41
+ params = Object.assign({}, attrs.defaults, params);
97
42
 
98
43
  if (attrs.formatter)
99
- attrs.formatter(params, conn);
44
+ attrs.formatter(params);
100
45
 
101
46
  if (attrs.escapeCols)
102
47
  for (const escapeCol of attrs.escapeCols) {
103
48
  if (params[escapeCol])
104
- params[escapeCol] = conn.escape(params[escapeCol])
49
+ params[escapeCol] = SqlString.escape(params[escapeCol])
105
50
  }
106
51
 
107
52
  const split = params.definer.split('@');
108
- params.schema = conn.escapeId(params.schema, true);
109
- params.name = conn.escapeId(params.name, true);
53
+ params.schema = SqlString.escapeId(params.schema, true);
54
+ params.name = SqlString.escapeId(params.name, true);
110
55
  params.definer =
111
- `${conn.escapeId(split[0], true)}@${conn.escapeId(split[1], true)}`;
56
+ SqlString.escapeId(split[0], true) + '@' +
57
+ SqlString.escapeId(split[1], true);
112
58
 
113
59
  return this.template(params);
114
60
  }
package/myt-create.js ADDED
@@ -0,0 +1,74 @@
1
+ const Myt = require('./myt');
2
+ const Command = require('./lib/command');
3
+ const Exporter = require('./lib/exporter');
4
+ const fs = require('fs-extra');
5
+
6
+ class Create extends Command {
7
+ static usage = {
8
+ description: 'Creates a new DB object',
9
+ params: {
10
+ type: 'The object type',
11
+ name: 'The object name, including schema'
12
+ },
13
+ operand: 'name'
14
+ };
15
+
16
+ static opts = {
17
+ alias: {
18
+ type: 't',
19
+ name: 'n'
20
+ },
21
+ string: [
22
+ 'type',
23
+ 'name'
24
+ ],
25
+ default: {
26
+ type: 'procedure'
27
+ }
28
+ };
29
+
30
+ async run(myt, opts) {
31
+ const match = opts.name.match(/^(\w+)\.(\w+)$/);
32
+ if (!match)
33
+ throw new Error('Invalid object name, should contain schema and routine name');
34
+
35
+ const schema = match[1];
36
+ const name = match[2];
37
+
38
+ const params = {
39
+ schema,
40
+ name,
41
+ definer: 'root@localhost'
42
+ };
43
+
44
+ switch (opts.type) {
45
+ case 'event':
46
+ case 'function':
47
+ case 'procedure':
48
+ case 'trigger':
49
+ params.body = "BEGIN\n-- Your code goes here\nEND";
50
+ break;
51
+ case 'view':
52
+ params.definition = "SELECT TRUE"
53
+ break;
54
+ }
55
+
56
+ const exporter = new Exporter(opts.type);
57
+ await exporter.init();
58
+ const sql = exporter.format(params);
59
+
60
+ const routineDir = `${opts.routinesDir}/${schema}/${opts.type}s`;
61
+ if (!await fs.pathExists(routineDir))
62
+ await fs.mkdir(routineDir);
63
+
64
+ const routineFile = `${routineDir}/${name}.sql`;
65
+ await fs.writeFile(routineFile, sql);
66
+
67
+ console.log('Routine created.');
68
+ }
69
+ }
70
+
71
+ module.exports = Create;
72
+
73
+ if (require.main === module)
74
+ new Myt().run(Create);
package/myt-dump.js CHANGED
@@ -52,16 +52,6 @@ class Dump extends Command {
52
52
  }
53
53
 
54
54
  await dumper.end();
55
-
56
- console.log('Saving version.');
57
- await myt.dbConnect();
58
- const version = await myt.fetchDbVersion();
59
- if (version) {
60
- await fs.writeFile(
61
- `${opts.dumpDir}/.dump.json`,
62
- JSON.stringify(version)
63
- );
64
- }
65
55
  }
66
56
  }
67
57
 
package/myt-init.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const Myt = require('./myt');
2
2
  const Command = require('./lib/command');
3
3
  const fs = require('fs-extra');
4
+ const path = require('path');
4
5
 
5
6
  class Init extends Command {
6
7
  static usage = {
@@ -8,12 +9,23 @@ class Init extends Command {
8
9
  };
9
10
 
10
11
  async run(myt, opts) {
11
- const templateDir = `${__dirname}/template`;
12
+ const packageFile = path.join(opts.mytDir, 'package.json');
13
+ const packageExists = await fs.pathExists(packageFile);
14
+
15
+ const templateDir = path.join(__dirname, 'template');
12
16
  const templates = await fs.readdir(templateDir);
13
17
  for (let template of templates) {
14
- const dst = `${opts.mytDir}/${template}`;
18
+ const dst = path.join(opts.mytDir, template);
15
19
  if (!await fs.pathExists(dst))
16
- await fs.copy(`${templateDir}/${template}`, dst);
20
+ await fs.copy(path.join(templateDir, template), dst);
21
+ }
22
+
23
+ if (!packageExists) {
24
+ const packageJson = require(packageFile);
25
+ packageJson.dependencies[myt.packageJson.name] =
26
+ `^${myt.packageJson.version}`;
27
+ await fs.writeFile(packageFile,
28
+ JSON.stringify(packageJson, null, ' '));
17
29
  }
18
30
  }
19
31
  }
package/myt-pull.js CHANGED
@@ -114,13 +114,67 @@ class Pull extends Command {
114
114
  await fs.mkdir(schemaDir);
115
115
 
116
116
  for (const exporter of engine.exporters)
117
- await exporter.export(routinesDir,
118
- schema, opts.update, opts.sums);
117
+ await this.export(conn, engine, exporter, schema);
119
118
  }
120
119
 
121
120
  await engine.refreshPullDate();
122
121
  await engine.saveInfo();
123
122
  }
123
+
124
+ async export(conn, engine, exporter, schema) {
125
+ const {opts} = this;
126
+
127
+ const res = await exporter.query(conn, schema);
128
+ if (!res.length) return;
129
+
130
+ const type = exporter.objectType;
131
+
132
+ const routineDir = `${opts.routinesDir}/${schema}/${type}s`;
133
+ if (!await fs.pathExists(routineDir))
134
+ await fs.mkdir(routineDir);
135
+
136
+ const routineSet = new Set();
137
+ for (const params of res)
138
+ routineSet.add(params.name);
139
+
140
+ const routines = await fs.readdir(routineDir);
141
+ for (const routineFile of routines) {
142
+ const match = routineFile.match(/^(.*)\.sql$/);
143
+ if (!match) continue;
144
+ const routine = match[1];
145
+ if (!routineSet.has(routine)) {
146
+ await fs.remove(`${routineDir}/${routine}.sql`);
147
+ engine.deleteShaSum(type, schema, routine)
148
+ }
149
+ }
150
+
151
+ for (const params of res) {
152
+ const routineName = params.name;
153
+ const sql = exporter.format(params);
154
+ const routineFile = `${routineDir}/${routineName}.sql`;
155
+ let update = opts.update;
156
+
157
+ const oldSum = engine.getShaSum(type, schema, routineName);
158
+ if (oldSum || opts.sums || (opts.sumViews && type === 'view')) {
159
+ const shaSum = engine.shaSum(sql);
160
+ if (oldSum !== shaSum) {
161
+ engine.setShaSum(type, schema, routineName, shaSum);
162
+ update = true;
163
+ }
164
+ } else if (params.modified && engine.lastPull) {
165
+ if (params.modified > engine.lastPull)
166
+ update = true;
167
+ } else if (await fs.pathExists(routineFile)) {
168
+ const currentSql = await fs.readFile(routineFile, 'utf8');
169
+ if (sql != currentSql)
170
+ update = true;
171
+ } else
172
+ update = true;
173
+
174
+ if (update)
175
+ await fs.writeFile(routineFile, sql);
176
+ }
177
+ }
124
178
  }
125
179
 
126
180
  module.exports = Pull;
package/myt-push.js CHANGED
@@ -5,6 +5,7 @@ const nodegit = require('nodegit');
5
5
  const ExporterEngine = require('./lib/exporter-engine');
6
6
  const connExt = require('./lib/conn');
7
7
  const repoExt = require('./lib/repo');
8
+ const SqlString = require('sqlstring');
8
9
 
9
10
  /**
10
11
  * Pushes changes to remote.
@@ -329,7 +330,7 @@ class Push extends Command {
329
330
  console.log('', actionMsg.bold, typeMsg.bold, change.fullName);
330
331
 
331
332
  if (!isEqual) {
332
- const scapedSchema = pushConn.escapeId(schema, true);
333
+ const scapedSchema = SqlString.escapeId(schema, true);
333
334
 
334
335
  if (exists) {
335
336
  if (change.type.name === 'VIEW')
@@ -348,12 +349,12 @@ class Push extends Command {
348
349
  );
349
350
  }
350
351
 
351
- if (opts.sums || oldSum)
352
+ if (opts.sums || oldSum || (opts.sumViews && type === 'view'))
352
353
  await engine.fetchShaSum(type, schema, name);
353
354
  } else {
354
355
  const escapedName =
355
356
  scapedSchema + '.' +
356
- pushConn.escapeId(name, true);
357
+ SqlString.escapeId(name, true);
357
358
 
358
359
  const query = `DROP ${change.type.name} IF EXISTS ${escapedName}`;
359
360
  await pushConn.query(query);
@@ -401,7 +402,7 @@ class Push extends Command {
401
402
  }
402
403
 
403
404
  async updateVersion(column, value) {
404
- column = this.conn.escapeId(column, true);
405
+ column = SqlString.escapeId(column, true);
405
406
  await this.conn.query(
406
407
  `INSERT INTO version
407
408
  SET code = ?,
package/myt.js CHANGED
@@ -45,6 +45,7 @@ class Myt {
45
45
  'Myt'.green,
46
46
  `v${packageJson.version}`.magenta
47
47
  );
48
+ this.packageJson = packageJson;
48
49
 
49
50
  let baseOpts = this.constructor.opts;
50
51
  baseOpts.default = Object.assign(baseOpts.default || {}, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verdnatura/myt",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "author": "Verdnatura Levante SL",
5
5
  "description": "MySQL version control",
6
6
  "license": "GPL-3.0",
@@ -12,7 +12,7 @@
12
12
  "url": "https://github.com/verdnatura/myt.git"
13
13
  },
14
14
  "dependencies": {
15
- "@sqltools/formatter": "^1.2.3",
15
+ "@sqltools/formatter": "^1.2.5",
16
16
  "colors": "^1.4.0",
17
17
  "ejs": "^3.1.6",
18
18
  "fs-extra": "^8.1.0",
@@ -0,0 +1 @@
1
+ FROM mariadb:10.7
@@ -0,0 +1 @@
1
+ -- Executed after data dump
@@ -0,0 +1 @@
1
+ -- Executed before data dump
@@ -8,6 +8,6 @@
8
8
  "type": "git"
9
9
  },
10
10
  "dependencies": {
11
- "@verdnatura/myt": "^1.5.7"
11
+ "@verdnatura/myt": "^1.0.0"
12
12
  }
13
13
  }
@@ -1 +0,0 @@
1
- -- Place your local structure changes here