@naturalcycles/mysql-lib 3.9.1 → 3.9.2
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/dist/mysql.db.js +13 -7
- package/dist/query.util.d.ts +1 -1
- package/dist/query.util.js +4 -4
- package/dist/schema/mysql.schema.util.js +1 -1
- package/package.json +2 -2
- package/readme.md +27 -6
- package/src/mysql.db.ts +18 -8
- package/src/query.util.ts +4 -4
- package/src/schema/mysql.schema.util.ts +1 -1
package/dist/mysql.db.js
CHANGED
|
@@ -75,7 +75,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
75
75
|
async close() {
|
|
76
76
|
const pool = this.pool();
|
|
77
77
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
78
|
-
await (0, util_1.promisify)(pool.end.bind(pool));
|
|
78
|
+
await (0, util_1.promisify)(pool.end.bind(pool))();
|
|
79
79
|
this.cfg.logger.log('closed');
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
@@ -116,14 +116,20 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
116
116
|
// QUERY
|
|
117
117
|
async runQuery(q, _opt = {}) {
|
|
118
118
|
const sql = (0, query_util_1.dbQueryToSQLSelect)(q);
|
|
119
|
-
const rows = await this.runSQL({ sql });
|
|
119
|
+
const rows = (await this.runSQL({ sql })).map(row => (0, js_lib_1._mapKeys)((0, js_lib_1._filterUndefinedValues)(row, true), k => (0, mysql_schema_util_1.mapNameFromMySQL)(k)));
|
|
120
|
+
// edge case where 0 fields are selected
|
|
121
|
+
if (q._selectedFieldNames?.length === 0) {
|
|
122
|
+
return {
|
|
123
|
+
rows: rows.map(_ => ({})),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
120
126
|
return {
|
|
121
|
-
rows
|
|
127
|
+
rows,
|
|
122
128
|
};
|
|
123
129
|
}
|
|
124
130
|
async runSQL(q) {
|
|
125
131
|
if (this.cfg.logSQL)
|
|
126
|
-
this.cfg.logger.log(q.sql, q.values);
|
|
132
|
+
this.cfg.logger.log(...[q.sql, q.values].filter(Boolean));
|
|
127
133
|
return await new Promise((resolve, reject) => {
|
|
128
134
|
this.pool().query(q, (err, res) => {
|
|
129
135
|
if (err)
|
|
@@ -147,7 +153,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
147
153
|
.pipe(new stream_1.Transform({
|
|
148
154
|
objectMode: true,
|
|
149
155
|
transform(row, _encoding, cb) {
|
|
150
|
-
cb(null, (0, js_lib_1.
|
|
156
|
+
cb(null, (0, js_lib_1._filterUndefinedValues)(row, true));
|
|
151
157
|
},
|
|
152
158
|
}));
|
|
153
159
|
}
|
|
@@ -156,11 +162,11 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
156
162
|
if (!_rows.length)
|
|
157
163
|
return;
|
|
158
164
|
// Stringify object values
|
|
159
|
-
const rows = _rows.map(row => (0, js_lib_1._mapValues)(row, v => {
|
|
165
|
+
const rows = _rows.map(row => (0, js_lib_1._mapValues)(row, (_k, v) => {
|
|
160
166
|
return v && typeof v === 'object' && !Buffer.isBuffer(v) ? JSON.stringify(v) : v;
|
|
161
167
|
}));
|
|
162
168
|
// inserts are split into multiple sentenses to respect the max_packet_size (1Mb usually)
|
|
163
|
-
const sqls = (0, query_util_1.insertSQL)(table, rows, '
|
|
169
|
+
const sqls = (0, query_util_1.insertSQL)(table, rows, 'REPLACE', this.cfg.logger);
|
|
164
170
|
for await (const sql of sqls) {
|
|
165
171
|
await this.runSQL({ sql });
|
|
166
172
|
}
|
package/dist/query.util.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export declare function dbQueryToSQLDelete(q: DBQuery<any>): string;
|
|
|
6
6
|
/**
|
|
7
7
|
* Returns array of sql statements to respect the max sql size.
|
|
8
8
|
*/
|
|
9
|
-
export declare function insertSQL(table: string,
|
|
9
|
+
export declare function insertSQL(table: string, rows: Record<any, any>[], verb?: 'INSERT' | 'REPLACE', logger?: CommonLogger): string[];
|
|
10
10
|
export declare function insertSQLSingle(table: string, record: Record<any, any>): string;
|
|
11
11
|
export declare function insertSQLSetSingle(table: string, record: Record<any, any>): QueryOptions;
|
|
12
12
|
export declare function dbQueryToSQLUpdate(q: DBQuery<any>, record: Record<any, any>): string;
|
package/dist/query.util.js
CHANGED
|
@@ -30,12 +30,12 @@ exports.dbQueryToSQLDelete = dbQueryToSQLDelete;
|
|
|
30
30
|
/**
|
|
31
31
|
* Returns array of sql statements to respect the max sql size.
|
|
32
32
|
*/
|
|
33
|
-
function insertSQL(table,
|
|
33
|
+
function insertSQL(table, rows, verb = 'INSERT', logger = console) {
|
|
34
34
|
// INSERT INTO table_name (column1, column2, column3, ...)
|
|
35
35
|
// VALUES (value1, value2, value3, ...);
|
|
36
36
|
// eslint-disable-next-line unicorn/no-array-reduce
|
|
37
|
-
const fieldSet =
|
|
38
|
-
Object.keys(
|
|
37
|
+
const fieldSet = rows.reduce((set, row) => {
|
|
38
|
+
Object.keys(row).forEach(field => set.add(field));
|
|
39
39
|
return set;
|
|
40
40
|
}, new Set());
|
|
41
41
|
const fields = [...fieldSet];
|
|
@@ -46,7 +46,7 @@ function insertSQL(table, records, verb = 'INSERT', logger = console) {
|
|
|
46
46
|
`(` + [...fields].map(f => mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f))).join(',') + `)`,
|
|
47
47
|
`VALUES\n`,
|
|
48
48
|
].join(' ');
|
|
49
|
-
const valueRows =
|
|
49
|
+
const valueRows = rows.map(rec => {
|
|
50
50
|
return `(` + fields.map(k => mysql.escape(rec[k])).join(',') + `)`;
|
|
51
51
|
});
|
|
52
52
|
const full = start + valueRows.join(',\n');
|
|
@@ -80,7 +80,7 @@ function mysqlTableStatsToJsonSchemaField(table, stats, logger) {
|
|
|
80
80
|
else if (t.startsWith('tinyint') || t.includes('(1)')) {
|
|
81
81
|
s.properties[name] = { type: 'boolean' };
|
|
82
82
|
}
|
|
83
|
-
else if (t.startsWith('int(')) {
|
|
83
|
+
else if (t === 'int' || t.startsWith('int(')) {
|
|
84
84
|
s.properties[name] = { type: 'integer' };
|
|
85
85
|
}
|
|
86
86
|
else if (t.startsWith('float')) {
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@naturalcycles/dev-lib": "^12.7.5",
|
|
15
|
-
"@types/node": "^
|
|
15
|
+
"@types/node": "^17.0.5",
|
|
16
16
|
"dotenv": "^10.0.0",
|
|
17
17
|
"jest": "^27.2.4"
|
|
18
18
|
},
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=14.15.0"
|
|
38
38
|
},
|
|
39
|
-
"version": "3.9.
|
|
39
|
+
"version": "3.9.2",
|
|
40
40
|
"description": "MySQL client implementing CommonDB interface",
|
|
41
41
|
"keywords": [
|
|
42
42
|
"mysql",
|
package/readme.md
CHANGED
|
@@ -3,12 +3,33 @@
|
|
|
3
3
|
> MySQL client implementing CommonDB interface
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@naturalcycles/mysql-lib)
|
|
6
|
-
[](https://circleci.com/gh/NaturalCycles/mysql-lib)
|
|
7
6
|
[](https://github.com/prettier/prettier)
|
|
8
7
|
|
|
9
|
-
#
|
|
8
|
+
# Quick start
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
todo
|
|
11
|
+
|
|
12
|
+
# Develop
|
|
13
|
+
|
|
14
|
+
Install MySQL server+client on Mac:
|
|
15
|
+
|
|
16
|
+
```shell
|
|
17
|
+
|
|
18
|
+
brew install mysql
|
|
19
|
+
|
|
20
|
+
# start
|
|
21
|
+
|
|
22
|
+
mysql.server start
|
|
23
|
+
|
|
24
|
+
# secure
|
|
25
|
+
|
|
26
|
+
mysql_secure_installation
|
|
27
|
+
|
|
28
|
+
# connect
|
|
29
|
+
|
|
30
|
+
mysql -uroot
|
|
31
|
+
|
|
32
|
+
# Default options are read from the following files in the given order:
|
|
33
|
+
# /etc/my.cnf /etc/mysql/my.cnf /opt/homebrew/etc/my.cnf ~/.my.cnf
|
|
34
|
+
|
|
35
|
+
```
|
package/src/mysql.db.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
RunQueryResult,
|
|
11
11
|
} from '@naturalcycles/db-lib'
|
|
12
12
|
import {
|
|
13
|
-
|
|
13
|
+
_filterUndefinedValues,
|
|
14
14
|
_mapKeys,
|
|
15
15
|
_mapValues,
|
|
16
16
|
_Memo,
|
|
@@ -136,7 +136,7 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
136
136
|
async close(): Promise<void> {
|
|
137
137
|
const pool = this.pool()
|
|
138
138
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
139
|
-
await promisify(pool.end.bind(pool))
|
|
139
|
+
await promisify(pool.end.bind(pool))()
|
|
140
140
|
this.cfg.logger.log('closed')
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -191,14 +191,24 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
191
191
|
_opt: MysqlDBOptions = {},
|
|
192
192
|
): Promise<RunQueryResult<OUT>> {
|
|
193
193
|
const sql = dbQueryToSQLSelect(q)
|
|
194
|
-
const rows = await this.runSQL<ROW[]>({ sql })
|
|
194
|
+
const rows = (await this.runSQL<ROW[]>({ sql })).map(
|
|
195
|
+
row => _mapKeys(_filterUndefinedValues(row, true), k => mapNameFromMySQL(k)) as any,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
// edge case where 0 fields are selected
|
|
199
|
+
if (q._selectedFieldNames?.length === 0) {
|
|
200
|
+
return {
|
|
201
|
+
rows: rows.map(_ => ({} as any)),
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
195
205
|
return {
|
|
196
|
-
rows
|
|
206
|
+
rows,
|
|
197
207
|
}
|
|
198
208
|
}
|
|
199
209
|
|
|
200
210
|
async runSQL<RESULT>(q: QueryOptions): Promise<RESULT> {
|
|
201
|
-
if (this.cfg.logSQL) this.cfg.logger.log(q.sql, q.values)
|
|
211
|
+
if (this.cfg.logSQL) this.cfg.logger.log(...[q.sql, q.values].filter(Boolean))
|
|
202
212
|
|
|
203
213
|
return await new Promise<RESULT>((resolve, reject) => {
|
|
204
214
|
this.pool().query(q, (err, res) => {
|
|
@@ -232,7 +242,7 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
232
242
|
new Transform({
|
|
233
243
|
objectMode: true,
|
|
234
244
|
transform(row, _encoding, cb) {
|
|
235
|
-
cb(null,
|
|
245
|
+
cb(null, _filterUndefinedValues(row, true))
|
|
236
246
|
},
|
|
237
247
|
}),
|
|
238
248
|
)
|
|
@@ -248,13 +258,13 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
248
258
|
|
|
249
259
|
// Stringify object values
|
|
250
260
|
const rows = _rows.map(row =>
|
|
251
|
-
_mapValues(row, v => {
|
|
261
|
+
_mapValues(row, (_k, v) => {
|
|
252
262
|
return v && typeof v === 'object' && !Buffer.isBuffer(v) ? JSON.stringify(v) : v
|
|
253
263
|
}),
|
|
254
264
|
)
|
|
255
265
|
|
|
256
266
|
// inserts are split into multiple sentenses to respect the max_packet_size (1Mb usually)
|
|
257
|
-
const sqls = insertSQL(table, rows, '
|
|
267
|
+
const sqls = insertSQL(table, rows, 'REPLACE', this.cfg.logger)
|
|
258
268
|
|
|
259
269
|
for await (const sql of sqls) {
|
|
260
270
|
await this.runSQL({ sql })
|
package/src/query.util.ts
CHANGED
|
@@ -41,7 +41,7 @@ export function dbQueryToSQLDelete(q: DBQuery<any>): string {
|
|
|
41
41
|
*/
|
|
42
42
|
export function insertSQL(
|
|
43
43
|
table: string,
|
|
44
|
-
|
|
44
|
+
rows: Record<any, any>[],
|
|
45
45
|
verb: 'INSERT' | 'REPLACE' = 'INSERT',
|
|
46
46
|
logger: CommonLogger = console,
|
|
47
47
|
): string[] {
|
|
@@ -49,8 +49,8 @@ export function insertSQL(
|
|
|
49
49
|
// VALUES (value1, value2, value3, ...);
|
|
50
50
|
|
|
51
51
|
// eslint-disable-next-line unicorn/no-array-reduce
|
|
52
|
-
const fieldSet =
|
|
53
|
-
Object.keys(
|
|
52
|
+
const fieldSet = rows.reduce((set: Set<string>, row) => {
|
|
53
|
+
Object.keys(row).forEach(field => set.add(field))
|
|
54
54
|
return set
|
|
55
55
|
}, new Set<string>())
|
|
56
56
|
const fields = [...fieldSet]
|
|
@@ -63,7 +63,7 @@ export function insertSQL(
|
|
|
63
63
|
`VALUES\n`,
|
|
64
64
|
].join(' ')
|
|
65
65
|
|
|
66
|
-
const valueRows =
|
|
66
|
+
const valueRows = rows.map(rec => {
|
|
67
67
|
return `(` + fields.map(k => mysql.escape(rec[k])).join(',') + `)`
|
|
68
68
|
})
|
|
69
69
|
|
|
@@ -106,7 +106,7 @@ export function mysqlTableStatsToJsonSchemaField<T = any>(
|
|
|
106
106
|
s.properties[name] = { instanceof: 'Buffer' }
|
|
107
107
|
} else if (t.startsWith('tinyint') || t.includes('(1)')) {
|
|
108
108
|
s.properties[name] = { type: 'boolean' } as JsonSchemaBoolean
|
|
109
|
-
} else if (t.startsWith('int(')) {
|
|
109
|
+
} else if (t === 'int' || t.startsWith('int(')) {
|
|
110
110
|
s.properties[name] = { type: 'integer' } as JsonSchemaNumber
|
|
111
111
|
} else if (t.startsWith('float')) {
|
|
112
112
|
s.properties[name] = { type: 'number' } as JsonSchemaNumber
|