@naturalcycles/mysql-lib 3.10.0 → 3.11.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.d.ts +10 -6
- package/dist/mysql.db.js +18 -6
- package/dist/mysqlKeyValueDB.d.ts +1 -1
- package/dist/mysqlKeyValueDB.js +2 -5
- package/dist/query.util.js +17 -9
- package/package.json +2 -2
- package/src/mysql.db.ts +31 -7
- package/src/mysqlKeyValueDB.ts +2 -9
- package/src/query.util.ts +23 -8
package/dist/mysql.db.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BaseCommonDB, CommonDB, CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, DBQuery, RunQueryResult } from '@naturalcycles/db-lib';
|
|
2
2
|
import { AnyObjectWithId, CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
3
3
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
4
|
-
import { Connection, Pool, PoolConfig, PoolConnection, QueryOptions
|
|
4
|
+
import { Connection, Pool, PoolConfig, PoolConnection, QueryOptions } from 'mysql';
|
|
5
5
|
export interface MysqlDBOptions extends CommonDBOptions {
|
|
6
6
|
}
|
|
7
|
-
export interface MysqlDBSaveOptions<ROW extends ObjectWithId = AnyObjectWithId> extends CommonDBSaveOptions<ROW> {
|
|
7
|
+
export interface MysqlDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyObjectWithId> extends CommonDBSaveOptions<ROW> {
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* @default false / undefined
|
|
@@ -23,7 +23,6 @@ export interface MysqlDBCfg extends PoolConfig {
|
|
|
23
23
|
*/
|
|
24
24
|
logger?: CommonLogger;
|
|
25
25
|
}
|
|
26
|
-
export declare const typeCast: TypeCast;
|
|
27
26
|
export declare class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
28
27
|
constructor(cfg?: MysqlDBCfg);
|
|
29
28
|
cfg: MysqlDBCfg & {
|
|
@@ -41,16 +40,21 @@ export declare class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
41
40
|
* Be careful to manage this connection yourself (open, release, etc).
|
|
42
41
|
*/
|
|
43
42
|
createSingleConnection(): Promise<Connection>;
|
|
44
|
-
getByIds<ROW extends ObjectWithId>(table: string, ids:
|
|
43
|
+
getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: MysqlDBOptions): Promise<ROW[]>;
|
|
45
44
|
runQuery<ROW extends ObjectWithId, OUT = ROW>(q: DBQuery<ROW>, _opt?: MysqlDBOptions): Promise<RunQueryResult<OUT>>;
|
|
46
45
|
runSQL<RESULT>(q: QueryOptions): Promise<RESULT>;
|
|
46
|
+
/**
|
|
47
|
+
* Allows to run semicolon-separated "SQL file".
|
|
48
|
+
* E.g "ddl reset script".
|
|
49
|
+
*/
|
|
50
|
+
runSQLString(s: string): Promise<void>;
|
|
47
51
|
runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
48
52
|
streamQuery<ROW extends ObjectWithId, OUT = ROW>(q: DBQuery<ROW>, _opt?: MysqlDBOptions): ReadableTyped<OUT>;
|
|
49
|
-
saveBatch<ROW extends ObjectWithId
|
|
53
|
+
saveBatch<ROW extends Partial<ObjectWithId>>(table: string, _rows: ROW[], opt?: MysqlDBSaveOptions<ROW>): Promise<void>;
|
|
50
54
|
/**
|
|
51
55
|
* Limitation: always returns [], regardless of which rows are actually deleted
|
|
52
56
|
*/
|
|
53
|
-
deleteByIds(table: string, ids:
|
|
57
|
+
deleteByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: MysqlDBOptions): Promise<number>;
|
|
54
58
|
deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBOptions): Promise<number>;
|
|
55
59
|
/**
|
|
56
60
|
* Use with caution!
|
package/dist/mysql.db.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MysqlDB =
|
|
3
|
+
exports.MysqlDB = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const stream_1 = require("stream");
|
|
6
6
|
const util_1 = require("util");
|
|
@@ -31,12 +31,11 @@ const typeCast = (field, next) => {
|
|
|
31
31
|
}
|
|
32
32
|
return next();
|
|
33
33
|
};
|
|
34
|
-
exports.typeCast = typeCast;
|
|
35
34
|
class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
36
35
|
constructor(cfg = {}) {
|
|
37
36
|
super();
|
|
38
37
|
this.cfg = {
|
|
39
|
-
typeCast
|
|
38
|
+
typeCast,
|
|
40
39
|
// charset: 'utf8mb4', // for emoji support
|
|
41
40
|
// host: 'localhost',
|
|
42
41
|
// user: MYSQL_USER,
|
|
@@ -139,6 +138,19 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
139
138
|
});
|
|
140
139
|
});
|
|
141
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Allows to run semicolon-separated "SQL file".
|
|
143
|
+
* E.g "ddl reset script".
|
|
144
|
+
*/
|
|
145
|
+
async runSQLString(s) {
|
|
146
|
+
const queries = s
|
|
147
|
+
.split(';')
|
|
148
|
+
.map(s => s.trim())
|
|
149
|
+
.filter(Boolean);
|
|
150
|
+
for await (const sql of queries) {
|
|
151
|
+
await this.runSQL({ sql });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
142
154
|
async runQueryCount(q, _opt) {
|
|
143
155
|
const { rows } = await this.runQuery(q.select(['count(*) as _count']));
|
|
144
156
|
return rows[0]._count;
|
|
@@ -159,7 +171,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
159
171
|
}));
|
|
160
172
|
}
|
|
161
173
|
// SAVE
|
|
162
|
-
async saveBatch(table, _rows,
|
|
174
|
+
async saveBatch(table, _rows, opt = {}) {
|
|
163
175
|
if (!_rows.length)
|
|
164
176
|
return;
|
|
165
177
|
// Stringify object values
|
|
@@ -167,7 +179,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
167
179
|
return v && typeof v === 'object' && !Buffer.isBuffer(v) ? JSON.stringify(v) : v;
|
|
168
180
|
}));
|
|
169
181
|
// inserts are split into multiple sentenses to respect the max_packet_size (1Mb usually)
|
|
170
|
-
const sqls = (0, query_util_1.insertSQL)(table, rows, 'REPLACE', this.cfg.logger);
|
|
182
|
+
const sqls = (0, query_util_1.insertSQL)(table, rows, opt.saveMethod === 'insert' ? 'INSERT' : 'REPLACE', this.cfg.logger);
|
|
171
183
|
for await (const sql of sqls) {
|
|
172
184
|
await this.runSQL({ sql });
|
|
173
185
|
}
|
|
@@ -215,7 +227,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
|
|
|
215
227
|
return (0, mysql_schema_util_1.mysqlTableStatsToJsonSchemaField)(table, stats, this.cfg.logger);
|
|
216
228
|
}
|
|
217
229
|
}
|
|
218
|
-
|
|
230
|
+
tslib_1.__decorate([
|
|
219
231
|
(0, js_lib_1._Memo)()
|
|
220
232
|
], MysqlDB.prototype, "pool", null);
|
|
221
233
|
exports.MysqlDB = MysqlDB;
|
|
@@ -3,8 +3,8 @@ import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@natur
|
|
|
3
3
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
4
4
|
import { MysqlDB, MysqlDBCfg } from './mysql.db';
|
|
5
5
|
export declare class MySQLKeyValueDB implements CommonKeyValueDB {
|
|
6
|
-
constructor(cfg?: MysqlDBCfg);
|
|
7
6
|
cfg: MysqlDBCfg;
|
|
7
|
+
constructor(cfg: MysqlDBCfg);
|
|
8
8
|
db: MysqlDB;
|
|
9
9
|
ping(): Promise<void>;
|
|
10
10
|
close(): Promise<void>;
|
package/dist/mysqlKeyValueDB.js
CHANGED
|
@@ -5,11 +5,8 @@ const stream_1 = require("stream");
|
|
|
5
5
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
6
6
|
const mysql_db_1 = require("./mysql.db");
|
|
7
7
|
class MySQLKeyValueDB {
|
|
8
|
-
constructor(cfg
|
|
9
|
-
this.cfg =
|
|
10
|
-
typeCast: mysql_db_1.typeCast,
|
|
11
|
-
...cfg,
|
|
12
|
-
};
|
|
8
|
+
constructor(cfg) {
|
|
9
|
+
this.cfg = cfg;
|
|
13
10
|
this.db = new mysql_db_1.MysqlDB(this.cfg);
|
|
14
11
|
}
|
|
15
12
|
async ping() {
|
package/dist/query.util.js
CHANGED
|
@@ -12,7 +12,7 @@ function dbQueryToSQLSelect(q) {
|
|
|
12
12
|
// filters
|
|
13
13
|
tokens.push(...whereTokens(q));
|
|
14
14
|
// order
|
|
15
|
-
tokens.push(...
|
|
15
|
+
tokens.push(...groupOrderTokens(q));
|
|
16
16
|
// offset/limit
|
|
17
17
|
tokens.push(...offsetLimitTokens(q));
|
|
18
18
|
return tokens.join(' ');
|
|
@@ -124,7 +124,13 @@ function selectTokens(q) {
|
|
|
124
124
|
fields = q._selectedFieldNames.length ? q._selectedFieldNames : ['id'];
|
|
125
125
|
}
|
|
126
126
|
// We don't do `escapeId` cause it'll ruin e.g SELECT `count *` FROM ...
|
|
127
|
-
return [
|
|
127
|
+
return [
|
|
128
|
+
`SELECT`,
|
|
129
|
+
q._distinct && 'DISTINCT',
|
|
130
|
+
fields.map(f => (0, mysql_schema_util_1.mapNameToMySQL)(f)).join(', '),
|
|
131
|
+
`FROM`,
|
|
132
|
+
mysql.escapeId(q.table),
|
|
133
|
+
].filter(Boolean);
|
|
128
134
|
}
|
|
129
135
|
function offsetLimitTokens(q) {
|
|
130
136
|
const tokens = [];
|
|
@@ -137,13 +143,15 @@ function offsetLimitTokens(q) {
|
|
|
137
143
|
}
|
|
138
144
|
return tokens;
|
|
139
145
|
}
|
|
140
|
-
function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
function groupOrderTokens(q) {
|
|
147
|
+
const t = [];
|
|
148
|
+
if (q._groupByFieldNames?.length) {
|
|
149
|
+
t.push(`GROUP BY`, q._groupByFieldNames.map(c => `\`${c}\``).join(', '));
|
|
150
|
+
}
|
|
151
|
+
if (q._orders.length) {
|
|
152
|
+
t.push(`ORDER BY`, q._orders.map(o => `\`${o.name}\` ${o.descending ? 'DESC' : 'ASC'}`).join(', '));
|
|
153
|
+
}
|
|
154
|
+
return t;
|
|
147
155
|
}
|
|
148
156
|
const OP_MAP = {
|
|
149
157
|
'==': '=',
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"@naturalcycles/dev-lib": "^12.7.5",
|
|
15
15
|
"@types/node": "^17.0.5",
|
|
16
|
-
"dotenv": "^
|
|
16
|
+
"dotenv": "^16.0.0",
|
|
17
17
|
"jest": "^27.2.4"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=14.15.0"
|
|
38
38
|
},
|
|
39
|
-
"version": "3.
|
|
39
|
+
"version": "3.11.2",
|
|
40
40
|
"description": "MySQL client implementing CommonDB interface",
|
|
41
41
|
"keywords": [
|
|
42
42
|
"mysql",
|
package/src/mysql.db.ts
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
} from './schema/mysql.schema.util'
|
|
35
35
|
|
|
36
36
|
export interface MysqlDBOptions extends CommonDBOptions {}
|
|
37
|
-
export interface MysqlDBSaveOptions<ROW extends ObjectWithId = AnyObjectWithId>
|
|
37
|
+
export interface MysqlDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyObjectWithId>
|
|
38
38
|
extends CommonDBSaveOptions<ROW> {}
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -60,7 +60,7 @@ export interface MysqlDBCfg extends PoolConfig {
|
|
|
60
60
|
const BOOLEAN_TYPES = new Set(['TINY', 'TINYINT', 'INT'])
|
|
61
61
|
const BOOLEAN_BIT_TYPES = new Set(['BIT'])
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
const typeCast: TypeCast = (field, next) => {
|
|
64
64
|
// cast to boolean
|
|
65
65
|
if (field.length === 1) {
|
|
66
66
|
if (BOOLEAN_BIT_TYPES.has(field.type)) {
|
|
@@ -176,7 +176,7 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
176
176
|
// GET
|
|
177
177
|
override async getByIds<ROW extends ObjectWithId>(
|
|
178
178
|
table: string,
|
|
179
|
-
ids:
|
|
179
|
+
ids: ROW['id'][],
|
|
180
180
|
opt: MysqlDBOptions = {},
|
|
181
181
|
): Promise<ROW[]> {
|
|
182
182
|
if (!ids.length) return []
|
|
@@ -218,6 +218,21 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
218
218
|
})
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Allows to run semicolon-separated "SQL file".
|
|
223
|
+
* E.g "ddl reset script".
|
|
224
|
+
*/
|
|
225
|
+
async runSQLString(s: string): Promise<void> {
|
|
226
|
+
const queries = s
|
|
227
|
+
.split(';')
|
|
228
|
+
.map(s => s.trim())
|
|
229
|
+
.filter(Boolean)
|
|
230
|
+
|
|
231
|
+
for await (const sql of queries) {
|
|
232
|
+
await this.runSQL({ sql })
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
221
236
|
override async runQueryCount<ROW extends ObjectWithId>(
|
|
222
237
|
q: DBQuery<ROW>,
|
|
223
238
|
_opt?: CommonDBOptions,
|
|
@@ -249,10 +264,10 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
249
264
|
}
|
|
250
265
|
|
|
251
266
|
// SAVE
|
|
252
|
-
override async saveBatch<ROW extends ObjectWithId
|
|
267
|
+
override async saveBatch<ROW extends Partial<ObjectWithId>>(
|
|
253
268
|
table: string,
|
|
254
269
|
_rows: ROW[],
|
|
255
|
-
|
|
270
|
+
opt: MysqlDBSaveOptions<ROW> = {},
|
|
256
271
|
): Promise<void> {
|
|
257
272
|
if (!_rows.length) return
|
|
258
273
|
|
|
@@ -264,7 +279,12 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
264
279
|
)
|
|
265
280
|
|
|
266
281
|
// inserts are split into multiple sentenses to respect the max_packet_size (1Mb usually)
|
|
267
|
-
const sqls = insertSQL(
|
|
282
|
+
const sqls = insertSQL(
|
|
283
|
+
table,
|
|
284
|
+
rows,
|
|
285
|
+
opt.saveMethod === 'insert' ? 'INSERT' : 'REPLACE',
|
|
286
|
+
this.cfg.logger,
|
|
287
|
+
)
|
|
268
288
|
|
|
269
289
|
for await (const sql of sqls) {
|
|
270
290
|
await this.runSQL({ sql })
|
|
@@ -275,7 +295,11 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
|
|
|
275
295
|
/**
|
|
276
296
|
* Limitation: always returns [], regardless of which rows are actually deleted
|
|
277
297
|
*/
|
|
278
|
-
override async deleteByIds
|
|
298
|
+
override async deleteByIds<ROW extends ObjectWithId>(
|
|
299
|
+
table: string,
|
|
300
|
+
ids: ROW['id'][],
|
|
301
|
+
_opt?: MysqlDBOptions,
|
|
302
|
+
): Promise<number> {
|
|
279
303
|
if (!ids.length) return 0
|
|
280
304
|
const sql = dbQueryToSQLDelete(new DBQuery(table).filterEq('id', ids))
|
|
281
305
|
const res = await this.runSQL<any>({ sql })
|
package/src/mysqlKeyValueDB.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@natur
|
|
|
3
3
|
import { pMap } from '@naturalcycles/js-lib'
|
|
4
4
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
5
5
|
import { QueryOptions } from 'mysql'
|
|
6
|
-
import { MysqlDB, MysqlDBCfg
|
|
6
|
+
import { MysqlDB, MysqlDBCfg } from './mysql.db'
|
|
7
7
|
|
|
8
8
|
interface KeyValueObject {
|
|
9
9
|
id: string
|
|
@@ -11,17 +11,10 @@ interface KeyValueObject {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export class MySQLKeyValueDB implements CommonKeyValueDB {
|
|
14
|
-
constructor(cfg: MysqlDBCfg
|
|
15
|
-
this.cfg = {
|
|
16
|
-
typeCast,
|
|
17
|
-
...cfg,
|
|
18
|
-
}
|
|
19
|
-
|
|
14
|
+
constructor(public cfg: MysqlDBCfg) {
|
|
20
15
|
this.db = new MysqlDB(this.cfg)
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
cfg: MysqlDBCfg
|
|
24
|
-
|
|
25
18
|
db: MysqlDB
|
|
26
19
|
|
|
27
20
|
async ping(): Promise<void> {
|
package/src/query.util.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function dbQueryToSQLSelect(q: DBQuery<any>): string {
|
|
|
16
16
|
tokens.push(...whereTokens(q))
|
|
17
17
|
|
|
18
18
|
// order
|
|
19
|
-
tokens.push(...
|
|
19
|
+
tokens.push(...groupOrderTokens(q))
|
|
20
20
|
|
|
21
21
|
// offset/limit
|
|
22
22
|
tokens.push(...offsetLimitTokens(q))
|
|
@@ -155,7 +155,13 @@ function selectTokens(q: DBQuery): string[] {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// We don't do `escapeId` cause it'll ruin e.g SELECT `count *` FROM ...
|
|
158
|
-
return [
|
|
158
|
+
return [
|
|
159
|
+
`SELECT`,
|
|
160
|
+
q._distinct && ('DISTINCT' as any),
|
|
161
|
+
fields.map(f => mapNameToMySQL(f)).join(', '),
|
|
162
|
+
`FROM`,
|
|
163
|
+
mysql.escapeId(q.table),
|
|
164
|
+
].filter(Boolean)
|
|
159
165
|
}
|
|
160
166
|
|
|
161
167
|
function offsetLimitTokens(q: DBQuery<any>): string[] {
|
|
@@ -173,12 +179,21 @@ function offsetLimitTokens(q: DBQuery<any>): string[] {
|
|
|
173
179
|
return tokens
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
q.
|
|
181
|
-
|
|
182
|
+
function groupOrderTokens(q: DBQuery): string[] {
|
|
183
|
+
const t: string[] = []
|
|
184
|
+
|
|
185
|
+
if (q._groupByFieldNames?.length) {
|
|
186
|
+
t.push(`GROUP BY`, q._groupByFieldNames.map(c => `\`${c}\``).join(', '))
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (q._orders.length) {
|
|
190
|
+
t.push(
|
|
191
|
+
`ORDER BY`,
|
|
192
|
+
q._orders.map(o => `\`${o.name}\` ${o.descending ? 'DESC' : 'ASC'}`).join(', '),
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return t
|
|
182
197
|
}
|
|
183
198
|
|
|
184
199
|
const OP_MAP: Partial<Record<DBQueryFilterOperator, string>> = {
|