@verdnatura/myt 1.5.7 → 1.5.8
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 +10 -0
- package/exporters/event.ejs +4 -4
- package/exporters/event.js +6 -0
- package/exporters/function.ejs +5 -5
- package/exporters/function.js +4 -0
- package/exporters/procedure.ejs +4 -4
- package/exporters/trigger.js +6 -1
- package/exporters/view.ejs +1 -1
- package/exporters/view.js +4 -0
- package/lib/dumper.js +2 -2
- package/lib/exporter-engine.js +2 -3
- package/lib/exporter.js +11 -65
- package/myt-create.js +74 -0
- package/myt-pull.js +53 -2
- package/myt-push.js +4 -3
- package/package.json +2 -2
- package/template/package.json +1 -1
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*.
|
package/exporters/event.ejs
CHANGED
|
@@ -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 %>$$
|
package/exporters/event.js
CHANGED
package/exporters/function.ejs
CHANGED
|
@@ -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 %>$$
|
package/exporters/function.js
CHANGED
package/exporters/procedure.ejs
CHANGED
|
@@ -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 %>$$
|
package/exporters/trigger.js
CHANGED
package/exporters/view.ejs
CHANGED
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 ${
|
|
33
|
+
`USE ${SqlString.escapeId(schema, true)};\n`,
|
|
34
34
|
'utf8'
|
|
35
35
|
);
|
|
36
36
|
}
|
package/lib/exporter-engine.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
|
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 {
|
|
40
|
+
const {attrs} = this;
|
|
41
|
+
params = Object.assign({}, attrs.defaults, params);
|
|
97
42
|
|
|
98
43
|
if (attrs.formatter)
|
|
99
|
-
attrs.formatter(params
|
|
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] =
|
|
49
|
+
params[escapeCol] = SqlString.escape(params[escapeCol])
|
|
105
50
|
}
|
|
106
51
|
|
|
107
52
|
const split = params.definer.split('@');
|
|
108
|
-
params.schema =
|
|
109
|
-
params.name =
|
|
53
|
+
params.schema = SqlString.escapeId(params.schema, true);
|
|
54
|
+
params.name = SqlString.escapeId(params.name, true);
|
|
110
55
|
params.definer =
|
|
111
|
-
|
|
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-pull.js
CHANGED
|
@@ -114,13 +114,64 @@ class Pull extends Command {
|
|
|
114
114
|
await fs.mkdir(schemaDir);
|
|
115
115
|
|
|
116
116
|
for (const exporter of engine.exporters)
|
|
117
|
-
await
|
|
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 routineDir = `${opts.routinesDir}/${schema}/${exporter.objectType}s`;
|
|
131
|
+
if (!await fs.pathExists(routineDir))
|
|
132
|
+
await fs.mkdir(routineDir);
|
|
133
|
+
|
|
134
|
+
const routineSet = new Set();
|
|
135
|
+
for (const params of res)
|
|
136
|
+
routineSet.add(params.name);
|
|
137
|
+
|
|
138
|
+
const routines = await fs.readdir(routineDir);
|
|
139
|
+
for (const routineFile of routines) {
|
|
140
|
+
const match = routineFile.match(/^(.*)\.sql$/);
|
|
141
|
+
if (!match) continue;
|
|
142
|
+
const routine = match[1];
|
|
143
|
+
if (!routineSet.has(routine))
|
|
144
|
+
await fs.remove(`${routineDir}/${routine}.sql`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const params of res) {
|
|
148
|
+
const routineName = params.name;
|
|
149
|
+
const sql = exporter.format(params);
|
|
150
|
+
const routineFile = `${routineDir}/${routineName}.sql`;
|
|
151
|
+
let update = opts.update;
|
|
152
|
+
|
|
153
|
+
const oldSum = engine.getShaSum(routineName);
|
|
154
|
+
if (oldSum || opts.sums) {
|
|
155
|
+
const shaSum = engine.shaSum(sql);
|
|
156
|
+
if (oldSum !== shaSum) {
|
|
157
|
+
engine.setShaSum(
|
|
158
|
+
exporter.objectType, schema, routineName, shaSum);
|
|
159
|
+
update = true;
|
|
160
|
+
}
|
|
161
|
+
} else if (params.modified && engine.lastPull) {
|
|
162
|
+
if (params.modified > engine.lastPull)
|
|
163
|
+
update = true;
|
|
164
|
+
} else if (await fs.pathExists(routineFile)) {
|
|
165
|
+
const currentSql = await fs.readFile(routineFile, 'utf8');
|
|
166
|
+
if (sql != currentSql)
|
|
167
|
+
update = true;
|
|
168
|
+
} else
|
|
169
|
+
update = true;
|
|
170
|
+
|
|
171
|
+
if (update)
|
|
172
|
+
await fs.writeFile(routineFile, sql);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
124
175
|
}
|
|
125
176
|
|
|
126
177
|
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 =
|
|
333
|
+
const scapedSchema = SqlString.escapeId(schema, true);
|
|
333
334
|
|
|
334
335
|
if (exists) {
|
|
335
336
|
if (change.type.name === 'VIEW')
|
|
@@ -353,7 +354,7 @@ class Push extends Command {
|
|
|
353
354
|
} else {
|
|
354
355
|
const escapedName =
|
|
355
356
|
scapedSchema + '.' +
|
|
356
|
-
|
|
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 =
|
|
405
|
+
column = SqlString.escapeId(column, true);
|
|
405
406
|
await this.conn.query(
|
|
406
407
|
`INSERT INTO version
|
|
407
408
|
SET code = ?,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@verdnatura/myt",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.8",
|
|
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.
|
|
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",
|