@naturalcycles/mysql-lib 3.16.2 → 4.0.0

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/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './mysql.db';
2
- export * from './mysqlKeyValueDB';
3
- export { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util';
1
+ export * from './mysql.db.js';
2
+ export * from './mysqlKeyValueDB.js';
3
+ export { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util.js';
package/dist/index.js CHANGED
@@ -1,8 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jsonSchemaToMySQLDDL = void 0;
4
- const tslib_1 = require("tslib");
5
- tslib_1.__exportStar(require("./mysql.db"), exports);
6
- tslib_1.__exportStar(require("./mysqlKeyValueDB"), exports);
7
- var mysql_schema_util_1 = require("./schema/mysql.schema.util");
8
- Object.defineProperty(exports, "jsonSchemaToMySQLDDL", { enumerable: true, get: function () { return mysql_schema_util_1.jsonSchemaToMySQLDDL; } });
1
+ export * from './mysql.db.js';
2
+ export * from './mysqlKeyValueDB.js';
3
+ export { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util.js';
@@ -1,7 +1,8 @@
1
- import { BaseCommonDB, CommonDB, CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBSupport, CommonDBType, DBQuery, RunQueryResult } from '@naturalcycles/db-lib';
2
- import { CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
3
- import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
- import { Connection, Pool, PoolConfig, PoolConnection, QueryOptions } from 'mysql';
1
+ import type { CommonDB, CommonDBCreateOptions, CommonDBOptions, CommonDBSaveOptions, CommonDBSupport, RunQueryResult } from '@naturalcycles/db-lib';
2
+ import { BaseCommonDB, CommonDBType, DBQuery } from '@naturalcycles/db-lib';
3
+ import type { CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
4
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
5
+ import type { Connection, Pool, PoolConfig, PoolConnection, QueryOptions } from 'mysql';
5
6
  export interface MysqlDBOptions extends CommonDBOptions {
6
7
  }
7
8
  export interface MysqlDBSaveOptions<ROW extends ObjectWithId> extends CommonDBSaveOptions<ROW> {
package/dist/mysql.db.js CHANGED
@@ -1,15 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MysqlDB = void 0;
4
- const tslib_1 = require("tslib");
5
- const node_stream_1 = require("node:stream");
6
- const node_util_1 = require("node:util");
7
- const db_lib_1 = require("@naturalcycles/db-lib");
8
- const js_lib_1 = require("@naturalcycles/js-lib");
9
- const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
10
- const mysql = tslib_1.__importStar(require("mysql"));
11
- const query_util_1 = require("./query.util");
12
- const mysql_schema_util_1 = require("./schema/mysql.schema.util");
1
+ import { __decorate } from "tslib";
2
+ import { Readable, Transform } from 'node:stream';
3
+ import { promisify } from 'node:util';
4
+ import { BaseCommonDB, commonDBFullSupport, CommonDBType, DBQuery } from '@naturalcycles/db-lib';
5
+ import { _assert, _filterUndefinedValues, _mapKeys, _mapValues, _Memo, _omit, commonLoggerPrefix, } from '@naturalcycles/js-lib';
6
+ import { white } from '@naturalcycles/nodejs-lib';
7
+ import * as mysql from 'mysql';
8
+ import { dbQueryToSQLDelete, dbQueryToSQLSelect, dbQueryToSQLUpdate, insertSQL, } from './query.util.js';
9
+ import { jsonSchemaToMySQLDDL, mapNameFromMySQL, mysqlTableStatsToJsonSchemaField, } from './schema/mysql.schema.util.js';
13
10
  const BOOLEAN_TYPES = new Set(['TINY', 'TINYINT', 'INT']);
14
11
  const BOOLEAN_BIT_TYPES = new Set(['BIT']);
15
12
  const typeCast = (field, next) => {
@@ -31,16 +28,16 @@ const typeCast = (field, next) => {
31
28
  }
32
29
  return next();
33
30
  };
34
- class MysqlDB extends db_lib_1.BaseCommonDB {
31
+ export class MysqlDB extends BaseCommonDB {
32
+ dbType = CommonDBType.relational;
33
+ support = {
34
+ ...commonDBFullSupport,
35
+ updateSaveMethod: false, // todo: can be implemented
36
+ transactions: false, // todo: can be implemented
37
+ increment: false, // todo: can be implemented
38
+ };
35
39
  constructor(cfg = {}) {
36
40
  super();
37
- this.dbType = db_lib_1.CommonDBType.relational;
38
- this.support = {
39
- ...db_lib_1.commonDBFullSupport,
40
- updateSaveMethod: false, // todo: can be implemented
41
- transactions: false, // todo: can be implemented
42
- increment: false, // todo: can be implemented
43
- };
44
41
  this.cfg = {
45
42
  typeCast,
46
43
  // charset: 'utf8mb4', // for emoji support
@@ -49,9 +46,10 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
49
46
  // password: MYSQL_PW,
50
47
  // database: MYSQL_DB,
51
48
  ...cfg,
52
- logger: (0, js_lib_1.commonLoggerPrefix)(cfg.logger || console, '[mysql]'),
49
+ logger: commonLoggerPrefix(cfg.logger || console, '[mysql]'),
53
50
  };
54
51
  }
52
+ cfg;
55
53
  async ping() {
56
54
  const con = await this.getConnection();
57
55
  con.release();
@@ -59,7 +57,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
59
57
  pool() {
60
58
  const pool = mysql.createPool(this.cfg);
61
59
  const { host, database, logger } = this.cfg;
62
- logger.log(`connected to ${(0, nodejs_lib_1.white)(host + '/' + database)}`);
60
+ logger.log(`connected to ${white(host + '/' + database)}`);
63
61
  if (this.cfg.debugConnections) {
64
62
  pool.on('acquire', con => {
65
63
  logger.log(`acquire(${con.threadId})`);
@@ -81,7 +79,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
81
79
  }
82
80
  async close() {
83
81
  const pool = this.pool();
84
- await (0, node_util_1.promisify)(pool.end.bind(pool))();
82
+ await promisify(pool.end.bind(pool))();
85
83
  this.cfg.logger.log('closed');
86
84
  }
87
85
  /**
@@ -89,7 +87,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
89
87
  */
90
88
  async getConnection() {
91
89
  const pool = this.pool();
92
- return await (0, node_util_1.promisify)(pool.getConnection.bind(pool))();
90
+ return await promisify(pool.getConnection.bind(pool))();
93
91
  }
94
92
  /**
95
93
  * Manually create a single (not pool) connection.
@@ -97,7 +95,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
97
95
  */
98
96
  async createSingleConnection() {
99
97
  const con = mysql.createConnection(this.cfg);
100
- await (0, node_util_1.promisify)(con.connect.bind(con))();
98
+ await promisify(con.connect.bind(con))();
101
99
  const { threadId } = con;
102
100
  if (this.cfg.debugConnections) {
103
101
  this.cfg.logger.log(`createSingleConnection(${threadId})`);
@@ -115,19 +113,19 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
115
113
  async getByIds(table, ids, opt = {}) {
116
114
  if (!ids.length)
117
115
  return [];
118
- const q = new db_lib_1.DBQuery(table).filterEq('id', ids);
116
+ const q = new DBQuery(table).filterEq('id', ids);
119
117
  const { rows } = await this.runQuery(q, opt);
120
- return rows.map(r => (0, js_lib_1._mapKeys)(r, k => (0, mysql_schema_util_1.mapNameFromMySQL)(k)));
118
+ return rows.map(r => _mapKeys(r, k => mapNameFromMySQL(k)));
121
119
  }
122
120
  // QUERY
123
121
  async runQuery(q, _opt = {}) {
124
- const sql = (0, query_util_1.dbQueryToSQLSelect)(q);
122
+ const sql = dbQueryToSQLSelect(q);
125
123
  if (!sql) {
126
124
  return {
127
125
  rows: [],
128
126
  };
129
127
  }
130
- 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)));
128
+ const rows = (await this.runSQL({ sql })).map(row => _mapKeys(_filterUndefinedValues(row, true), k => mapNameFromMySQL(k)));
131
129
  // edge case where 0 fields are selected
132
130
  if (q._selectedFieldNames?.length === 0) {
133
131
  return {
@@ -167,24 +165,35 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
167
165
  return rows[0]._count;
168
166
  }
169
167
  streamQuery(q, _opt = {}) {
170
- const sql = (0, query_util_1.dbQueryToSQLSelect)(q);
168
+ const sql = dbQueryToSQLSelect(q);
171
169
  if (!sql) {
172
- return node_stream_1.Readable.from([]);
170
+ return Readable.from([]);
173
171
  }
174
172
  if (this.cfg.logSQL)
175
173
  this.cfg.logger.log(`stream: ${sql}`);
176
- // return this.streamSQL(sql, opt)
177
- return this.pool().query(sql).stream().map(row => (0, js_lib_1._filterUndefinedValues)(row, true));
174
+ // todo: this is nice, but `mysql` package uses `readable-stream@2` which is not compatible with `node:stream` iterable helpers
175
+ // return (this.pool().query(sql).stream() as ReadableTyped<ROW>).map(row =>
176
+ // _filterUndefinedValues(row, true),
177
+ // )
178
+ return this.pool()
179
+ .query(sql)
180
+ .stream()
181
+ .pipe(new Transform({
182
+ objectMode: true,
183
+ transform(row, _encoding, cb) {
184
+ cb(null, _filterUndefinedValues(row, true));
185
+ },
186
+ }));
178
187
  }
179
188
  // SAVE
180
189
  async saveBatch(table, rowsInput, opt = {}) {
181
190
  if (!rowsInput.length)
182
191
  return;
183
192
  // Stringify object values
184
- const rows = rowsInput.map(row => (0, js_lib_1._mapValues)(row, (_k, v) => {
193
+ const rows = rowsInput.map(row => _mapValues(row, (_k, v) => {
185
194
  if (v && typeof v === 'object' && !Buffer.isBuffer(v)) {
186
195
  // This is to avoid implicit Date stringification and mismatch: it gets saved as Date, but loaded as String
187
- (0, js_lib_1._assert)(!(v instanceof Date), 'mysql-lib does not support Date values, please stringify them before passing');
196
+ _assert(!(v instanceof Date), 'mysql-lib does not support Date values, please stringify them before passing');
188
197
  return JSON.stringify(v);
189
198
  }
190
199
  return v;
@@ -196,12 +205,12 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
196
205
  i++;
197
206
  if (row.id) {
198
207
  // Update already existing
199
- const query = new db_lib_1.DBQuery(table).filterEq('id', row.id);
200
- await this.patchByQuery(query, (0, js_lib_1._omit)(row, ['id']));
208
+ const query = new DBQuery(table).filterEq('id', row.id);
209
+ await this.patchByQuery(query, _omit(row, ['id']));
201
210
  }
202
211
  else {
203
212
  // Create new
204
- const sql = (0, query_util_1.insertSQL)(table, [row], 'INSERT', this.cfg.logger)[0];
213
+ const sql = insertSQL(table, [row], 'INSERT', this.cfg.logger)[0];
205
214
  const { insertId } = await this.runSQL({ sql });
206
215
  // Mutate the input row with insertIt
207
216
  rowsInput[i].id = insertId; // this is because we no longer support number ids in CommonDB
@@ -213,15 +222,15 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
213
222
  // TODO: This fails if a combination of entities with id and without id are parsed
214
223
  for (const row of rows) {
215
224
  // Update already existing
216
- (0, js_lib_1._assert)(row.id, 'id is required for updating');
217
- const query = new db_lib_1.DBQuery(table).filterEq('id', row.id);
218
- await this.patchByQuery(query, (0, js_lib_1._omit)(row, ['id']));
225
+ _assert(row.id, 'id is required for updating');
226
+ const query = new DBQuery(table).filterEq('id', row.id);
227
+ await this.patchByQuery(query, _omit(row, ['id']));
219
228
  }
220
229
  return;
221
230
  }
222
231
  const verb = opt.saveMethod === 'insert' ? 'INSERT' : 'REPLACE';
223
232
  // inserts are split into multiple sentenses to respect the max_packet_size (1Mb usually)
224
- const sqls = (0, query_util_1.insertSQL)(table, rows, verb, this.cfg.logger);
233
+ const sqls = insertSQL(table, rows, verb, this.cfg.logger);
225
234
  for (const sql of sqls) {
226
235
  await this.runSQL({ sql });
227
236
  }
@@ -233,14 +242,14 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
233
242
  async deleteByIds(table, ids, _opt) {
234
243
  if (!ids.length)
235
244
  return 0;
236
- const sql = (0, query_util_1.dbQueryToSQLDelete)(new db_lib_1.DBQuery(table).filterEq('id', ids));
245
+ const sql = dbQueryToSQLDelete(new DBQuery(table).filterEq('id', ids));
237
246
  if (!sql)
238
247
  return 0;
239
248
  const { affectedRows } = await this.runSQL({ sql });
240
249
  return affectedRows;
241
250
  }
242
251
  async deleteByQuery(q, _opt) {
243
- const sql = (0, query_util_1.dbQueryToSQLDelete)(q);
252
+ const sql = dbQueryToSQLDelete(q);
244
253
  if (!sql)
245
254
  return 0;
246
255
  const { affectedRows } = await this.runSQL({ sql });
@@ -258,7 +267,7 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
258
267
  async createTable(table, schema, opt = {}) {
259
268
  if (opt.dropIfExists)
260
269
  await this.dropTable(table);
261
- const sql = (0, mysql_schema_util_1.jsonSchemaToMySQLDDL)(table, schema);
270
+ const sql = jsonSchemaToMySQLDDL(table, schema);
262
271
  await this.runSQL({ sql });
263
272
  }
264
273
  async getTables() {
@@ -270,17 +279,16 @@ class MysqlDB extends db_lib_1.BaseCommonDB {
270
279
  const stats = await this.runSQL({
271
280
  sql: `describe ${mysql.escapeId(table)}`,
272
281
  });
273
- return (0, mysql_schema_util_1.mysqlTableStatsToJsonSchemaField)(table, stats, this.cfg.logger);
282
+ return mysqlTableStatsToJsonSchemaField(table, stats, this.cfg.logger);
274
283
  }
275
284
  async patchByQuery(q, patch) {
276
- const sql = (0, query_util_1.dbQueryToSQLUpdate)(q, patch);
285
+ const sql = dbQueryToSQLUpdate(q, patch);
277
286
  if (!sql)
278
287
  return 0;
279
288
  const { affectedRows } = await this.runSQL({ sql });
280
289
  return affectedRows;
281
290
  }
282
291
  }
283
- exports.MysqlDB = MysqlDB;
284
- tslib_1.__decorate([
285
- (0, js_lib_1._Memo)()
292
+ __decorate([
293
+ _Memo()
286
294
  ], MysqlDB.prototype, "pool", null);
@@ -1,7 +1,8 @@
1
- import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
- import { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB';
3
- import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
- import { MysqlDB, MysqlDBCfg } from './mysql.db';
1
+ import type { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
+ import type { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB.js';
3
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
+ import type { MysqlDBCfg } from './mysql.db.js';
5
+ import { MysqlDB } from './mysql.db.js';
5
6
  export declare class MySQLKeyValueDB implements CommonKeyValueDB {
6
7
  cfg: MysqlDBCfg;
7
8
  constructor(cfg: MysqlDBCfg);
@@ -1,18 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MySQLKeyValueDB = void 0;
4
- const db_lib_1 = require("@naturalcycles/db-lib");
5
- const js_lib_1 = require("@naturalcycles/js-lib");
6
- const mysql_db_1 = require("./mysql.db");
7
- class MySQLKeyValueDB {
1
+ import { Transform } from 'node:stream';
2
+ import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib';
3
+ import { AppError, pMap } from '@naturalcycles/js-lib';
4
+ import { MysqlDB } from './mysql.db.js';
5
+ export class MySQLKeyValueDB {
6
+ cfg;
8
7
  constructor(cfg) {
9
8
  this.cfg = cfg;
10
- this.support = {
11
- ...db_lib_1.commonKeyValueDBFullSupport,
12
- increment: false,
13
- };
14
- this.db = new mysql_db_1.MysqlDB(this.cfg);
9
+ this.db = new MysqlDB(this.cfg);
15
10
  }
11
+ db;
12
+ support = {
13
+ ...commonKeyValueDBFullSupport,
14
+ increment: false,
15
+ };
16
16
  async ping() {
17
17
  await this.db.ping();
18
18
  }
@@ -55,7 +55,7 @@ class MySQLKeyValueDB {
55
55
  values: [id, buf],
56
56
  };
57
57
  });
58
- await (0, js_lib_1.pMap)(statements, async (statement) => {
58
+ await pMap(statements, async (statement) => {
59
59
  if (this.cfg.debug)
60
60
  this.db.cfg.logger.log(statement.sql);
61
61
  await this.db.runSQL(statement);
@@ -67,7 +67,18 @@ class MySQLKeyValueDB {
67
67
  sql += ` LIMIT ${limit}`;
68
68
  if (this.cfg.logSQL)
69
69
  this.db.cfg.logger.log(`stream: ${sql}`);
70
- return this.db.pool().query(sql).stream().map(row => row.id);
70
+ // todo: this is nice, but `mysql` package uses `readable-stream@2` which is not compatible with `node:stream` iterable helpers
71
+ // return (this.db.pool().query(sql).stream() as ReadableTyped<ObjectWithId>).map(row => row.id)
72
+ return this.db
73
+ .pool()
74
+ .query(sql)
75
+ .stream()
76
+ .pipe(new Transform({
77
+ objectMode: true,
78
+ transform(row, _encoding, cb) {
79
+ cb(null, row.id);
80
+ },
81
+ }));
71
82
  }
72
83
  streamValues(table, limit) {
73
84
  let sql = `SELECT v FROM ${table}`;
@@ -102,7 +113,6 @@ class MySQLKeyValueDB {
102
113
  return rows[0].cnt;
103
114
  }
104
115
  async incrementBatch(_table, _entries) {
105
- throw new js_lib_1.AppError('MySQLKeyValueDB.incrementBatch() is not implemented');
116
+ throw new AppError('MySQLKeyValueDB.incrementBatch() is not implemented');
106
117
  }
107
118
  }
108
- exports.MySQLKeyValueDB = MySQLKeyValueDB;
@@ -1,6 +1,6 @@
1
- import { DBQuery } from '@naturalcycles/db-lib';
2
- import { CommonLogger } from '@naturalcycles/js-lib';
3
- import { QueryOptions } from 'mysql';
1
+ import type { DBQuery } from '@naturalcycles/db-lib';
2
+ import type { CommonLogger } from '@naturalcycles/js-lib';
3
+ import type { QueryOptions } from 'mysql';
4
4
  /**
5
5
  * Returns `null` if it detects that 0 rows will be returned,
6
6
  * e.g when `IN ()` (empty array) is used.
@@ -1,23 +1,14 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dbQueryToSQLSelect = dbQueryToSQLSelect;
4
- exports.dbQueryToSQLDelete = dbQueryToSQLDelete;
5
- exports.insertSQL = insertSQL;
6
- exports.insertSQLSingle = insertSQLSingle;
7
- exports.insertSQLSetSingle = insertSQLSetSingle;
8
- exports.dbQueryToSQLUpdate = dbQueryToSQLUpdate;
9
- const tslib_1 = require("tslib");
10
- const js_lib_1 = require("@naturalcycles/js-lib");
11
- const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
12
- const mysql = tslib_1.__importStar(require("mysql"));
13
- const mysql_schema_util_1 = require("./schema/mysql.schema.util");
1
+ import { _hb } from '@naturalcycles/js-lib';
2
+ import { white, yellow } from '@naturalcycles/nodejs-lib';
3
+ import * as mysql from 'mysql';
4
+ import { mapNameToMySQL } from './schema/mysql.schema.util.js';
14
5
  const MAX_PACKET_SIZE = 1024 * 1024; // 1Mb
15
6
  const MAX_ROW_SIZE = 800 * 1024; // 1Mb - margin
16
7
  /**
17
8
  * Returns `null` if it detects that 0 rows will be returned,
18
9
  * e.g when `IN ()` (empty array) is used.
19
10
  */
20
- function dbQueryToSQLSelect(q) {
11
+ export function dbQueryToSQLSelect(q) {
21
12
  const tokens = selectTokens(q);
22
13
  // filters
23
14
  const whereTokens = getWhereTokens(q);
@@ -33,7 +24,7 @@ function dbQueryToSQLSelect(q) {
33
24
  /**
34
25
  * Returns null in "0 rows" case.
35
26
  */
36
- function dbQueryToSQLDelete(q) {
27
+ export function dbQueryToSQLDelete(q) {
37
28
  const tokens = [`DELETE FROM`, mysql.escapeId(q.table)];
38
29
  // filters
39
30
  const whereTokens = getWhereTokens(q);
@@ -47,7 +38,7 @@ function dbQueryToSQLDelete(q) {
47
38
  /**
48
39
  * Returns array of sql statements to respect the max sql size.
49
40
  */
50
- function insertSQL(table, rows, verb = 'INSERT', logger = console) {
41
+ export function insertSQL(table, rows, verb = 'INSERT', logger = console) {
51
42
  // INSERT INTO table_name (column1, column2, column3, ...)
52
43
  // VALUES (value1, value2, value3, ...);
53
44
  // eslint-disable-next-line unicorn/no-array-reduce
@@ -60,7 +51,7 @@ function insertSQL(table, rows, verb = 'INSERT', logger = console) {
60
51
  verb,
61
52
  `INTO`,
62
53
  mysql.escapeId(table),
63
- `(` + [...fields].map(f => mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f))).join(',') + `)`,
54
+ `(` + [...fields].map(f => mysql.escapeId(mapNameToMySQL(f))).join(',') + `)`,
64
55
  `VALUES\n`,
65
56
  ].join(' ');
66
57
  const valueRows = rows.map(rec => {
@@ -88,11 +79,11 @@ function insertSQL(table, rows, verb = 'INSERT', logger = console) {
88
79
  if (sql) {
89
80
  sqls.push(sql); // last one
90
81
  }
91
- logger.log(`${(0, nodejs_lib_1.white)(table)} large sql query (${(0, nodejs_lib_1.yellow)((0, js_lib_1._hb)(full.length))}) was split into ${(0, nodejs_lib_1.yellow)(sqls.length)} chunks`);
82
+ logger.log(`${white(table)} large sql query (${yellow(_hb(full.length))}) was split into ${yellow(sqls.length)} chunks`);
92
83
  return sqls;
93
84
  // todo: handle "upsert" later
94
85
  }
95
- function insertSQLSingle(table, record) {
86
+ export function insertSQLSingle(table, record) {
96
87
  // INSERT INTO table_name (column1, column2, column3, ...)
97
88
  // VALUES (value1, value2, value3, ...);
98
89
  const tokens = [
@@ -100,7 +91,7 @@ function insertSQLSingle(table, record) {
100
91
  mysql.escapeId(table),
101
92
  `(` +
102
93
  Object.keys(record)
103
- .map(f => mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f)))
94
+ .map(f => mysql.escapeId(mapNameToMySQL(f)))
104
95
  .join(',') +
105
96
  `)`,
106
97
  `\nVALUES`,
@@ -112,13 +103,13 @@ function insertSQLSingle(table, record) {
112
103
  ];
113
104
  return tokens.join(' ');
114
105
  }
115
- function insertSQLSetSingle(table, record) {
106
+ export function insertSQLSetSingle(table, record) {
116
107
  return {
117
108
  sql: `INSERT INTO ${mysql.escapeId(table)} SET ?`,
118
109
  values: [record],
119
110
  };
120
111
  }
121
- function dbQueryToSQLUpdate(q, patch) {
112
+ export function dbQueryToSQLUpdate(q, patch) {
122
113
  // var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
123
114
  const whereTokens = getWhereTokens(q);
124
115
  if (!whereTokens)
@@ -128,7 +119,7 @@ function dbQueryToSQLUpdate(q, patch) {
128
119
  mysql.escapeId(q.table),
129
120
  `SET`,
130
121
  Object.keys(patch)
131
- .map(f => mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f)) + ' = ?')
122
+ .map(f => mysql.escapeId(mapNameToMySQL(f)) + ' = ?')
132
123
  .join(', '),
133
124
  ...whereTokens,
134
125
  ];
@@ -143,7 +134,7 @@ function selectTokens(q) {
143
134
  return [
144
135
  `SELECT`,
145
136
  q._distinct && 'DISTINCT',
146
- fields.map(f => (0, mysql_schema_util_1.mapNameToMySQL)(f)).join(', '),
137
+ fields.map(f => mapNameToMySQL(f)).join(', '),
147
138
  `FROM`,
148
139
  mysql.escapeId(q.table),
149
140
  ].filter(Boolean);
@@ -186,7 +177,7 @@ function getWhereTokens(q) {
186
177
  if (f.val === null || f.val === undefined) {
187
178
  // special treatment
188
179
  return [
189
- mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f.name)),
180
+ mysql.escapeId(mapNameToMySQL(f.name)),
190
181
  f.op === '==' ? 'IS NULL' : 'IS NOT NULL',
191
182
  ].join(' ');
192
183
  }
@@ -194,10 +185,10 @@ function getWhereTokens(q) {
194
185
  // special case for arrays
195
186
  if (!f.val.length)
196
187
  returnNull = true;
197
- return `${mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f.name))} IN (${mysql.escape(f.val)})`;
188
+ return `${mysql.escapeId(mapNameToMySQL(f.name))} IN (${mysql.escape(f.val)})`;
198
189
  }
199
190
  return [
200
- mysql.escapeId((0, mysql_schema_util_1.mapNameToMySQL)(f.name)),
191
+ mysql.escapeId(mapNameToMySQL(f.name)),
201
192
  OP_MAP[f.op] || f.op,
202
193
  mysql.escape(f.val),
203
194
  ].join(' ');
@@ -1,4 +1,4 @@
1
- import { AnyObject, CommonLogger, JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib';
1
+ import type { AnyObject, CommonLogger, JsonSchemaObject, JsonSchemaRootObject } from '@naturalcycles/js-lib';
2
2
  export interface MySQLTableStats {
3
3
  Field: string;
4
4
  Type: string;
@@ -1,15 +1,8 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.jsonSchemaToMySQLDDL = jsonSchemaToMySQLDDL;
4
- exports.mysqlTableStatsToJsonSchemaField = mysqlTableStatsToJsonSchemaField;
5
- exports.mapNameToMySQL = mapNameToMySQL;
6
- exports.mapNameFromMySQL = mapNameFromMySQL;
7
- const tslib_1 = require("tslib");
8
- const mysql = tslib_1.__importStar(require("mysql"));
1
+ import * as mysql from 'mysql';
9
2
  /**
10
3
  * It currently skips nullability and declares everything as "DEFAULT NULL".
11
4
  */
12
- function jsonSchemaToMySQLDDL(table, schema, opt = {}) {
5
+ export function jsonSchemaToMySQLDDL(table, schema, opt = {}) {
13
6
  const { engine = 'InnoDB' } = opt;
14
7
  const lines = [`CREATE TABLE ${mysql.escapeId(table)} (`];
15
8
  const innerLines = Object.entries(schema.properties).map(([k, s]) => {
@@ -59,7 +52,7 @@ function jsonSchemaToMySQLDDL(table, schema, opt = {}) {
59
52
  lines.push(`) ENGINE=${engine}`);
60
53
  return lines.join('\n');
61
54
  }
62
- function mysqlTableStatsToJsonSchemaField(table, stats, logger) {
55
+ export function mysqlTableStatsToJsonSchemaField(table, stats, logger) {
63
56
  const s = {
64
57
  $id: `${table}.schema.json`,
65
58
  type: 'object',
@@ -101,9 +94,9 @@ function mysqlTableStatsToJsonSchemaField(table, stats, logger) {
101
94
  *
102
95
  * @param name
103
96
  */
104
- function mapNameToMySQL(name) {
97
+ export function mapNameToMySQL(name) {
105
98
  return name.replaceAll('.', '_dot_');
106
99
  }
107
- function mapNameFromMySQL(name) {
100
+ export function mapNameFromMySQL(name) {
108
101
  return name.replaceAll('_dot_', '.');
109
102
  }
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/mysql-lib",
3
+ "type": "module",
3
4
  "scripts": {
4
5
  "prepare": "husky",
5
6
  "build": "dev-lib build",
@@ -9,17 +10,19 @@
9
10
  "lbt": "dev-lib lbt"
10
11
  },
11
12
  "dependencies": {
12
- "@naturalcycles/db-lib": "^9.1.0",
13
- "@naturalcycles/js-lib": "^14.47.0",
14
- "@naturalcycles/nodejs-lib": "^13.1.0",
15
- "@types/mysql": "^2.15.19",
16
- "mysql": "^2.17.1"
13
+ "@naturalcycles/db-lib": "^10",
14
+ "@naturalcycles/js-lib": "^14",
15
+ "@naturalcycles/nodejs-lib": "^13",
16
+ "@types/mysql": "^2",
17
+ "mysql": "^2"
17
18
  },
18
19
  "devDependencies": {
19
- "@naturalcycles/dev-lib": "^15.18.0",
20
- "@types/node": "^22.7.4",
21
- "dotenv": "^16.0.0",
22
- "jest": "^29.0.0"
20
+ "@naturalcycles/dev-lib": "^17",
21
+ "@types/node": "^22",
22
+ "@vitest/coverage-v8": "^3",
23
+ "dotenv": "^16",
24
+ "tsx": "^4",
25
+ "vitest": "^3"
23
26
  },
24
27
  "files": [
25
28
  "dist",
@@ -39,9 +42,9 @@
39
42
  "url": "https://github.com/NaturalCycles/mysql-lib"
40
43
  },
41
44
  "engines": {
42
- "node": ">=20.13.0"
45
+ "node": ">=22.12.0"
43
46
  },
44
- "version": "3.16.2",
47
+ "version": "4.0.0",
45
48
  "description": "MySQL client implementing CommonDB interface",
46
49
  "keywords": [
47
50
  "mysql",
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './mysql.db'
2
- export * from './mysqlKeyValueDB'
3
- export { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util'
1
+ export * from './mysql.db.js'
2
+ export * from './mysqlKeyValueDB.js'
3
+ export { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util.js'
package/src/mysql.db.ts CHANGED
@@ -1,17 +1,20 @@
1
- import { Readable } from 'node:stream'
1
+ import { Readable, Transform } from 'node:stream'
2
2
  import { promisify } from 'node:util'
3
- import {
4
- BaseCommonDB,
3
+ import type {
5
4
  CommonDB,
6
5
  CommonDBCreateOptions,
7
- commonDBFullSupport,
8
6
  CommonDBOptions,
9
7
  CommonDBSaveOptions,
10
8
  CommonDBSupport,
11
- CommonDBType,
12
- DBQuery,
13
9
  RunQueryResult,
14
10
  } from '@naturalcycles/db-lib'
11
+ import { BaseCommonDB, commonDBFullSupport, CommonDBType, DBQuery } from '@naturalcycles/db-lib'
12
+ import type {
13
+ CommonLogger,
14
+ JsonSchemaObject,
15
+ JsonSchemaRootObject,
16
+ ObjectWithId,
17
+ } from '@naturalcycles/js-lib'
15
18
  import {
16
19
  _assert,
17
20
  _filterUndefinedValues,
@@ -19,14 +22,11 @@ import {
19
22
  _mapValues,
20
23
  _Memo,
21
24
  _omit,
22
- CommonLogger,
23
25
  commonLoggerPrefix,
24
- JsonSchemaObject,
25
- JsonSchemaRootObject,
26
- ObjectWithId,
27
26
  } from '@naturalcycles/js-lib'
28
- import { ReadableTyped, white } from '@naturalcycles/nodejs-lib'
29
- import {
27
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
28
+ import { white } from '@naturalcycles/nodejs-lib'
29
+ import type {
30
30
  Connection,
31
31
  OkPacket,
32
32
  Pool,
@@ -36,13 +36,18 @@ import {
36
36
  TypeCast,
37
37
  } from 'mysql'
38
38
  import * as mysql from 'mysql'
39
- import { dbQueryToSQLDelete, dbQueryToSQLSelect, dbQueryToSQLUpdate, insertSQL } from './query.util'
39
+ import {
40
+ dbQueryToSQLDelete,
41
+ dbQueryToSQLSelect,
42
+ dbQueryToSQLUpdate,
43
+ insertSQL,
44
+ } from './query.util.js'
45
+ import type { MySQLTableStats } from './schema/mysql.schema.util.js'
40
46
  import {
41
47
  jsonSchemaToMySQLDDL,
42
48
  mapNameFromMySQL,
43
- MySQLTableStats,
44
49
  mysqlTableStatsToJsonSchemaField,
45
- } from './schema/mysql.schema.util'
50
+ } from './schema/mysql.schema.util.js'
46
51
 
47
52
  export interface MysqlDBOptions extends CommonDBOptions {}
48
53
  export interface MysqlDBSaveOptions<ROW extends ObjectWithId> extends CommonDBSaveOptions<ROW> {}
@@ -277,10 +282,21 @@ export class MysqlDB extends BaseCommonDB implements CommonDB {
277
282
 
278
283
  if (this.cfg.logSQL) this.cfg.logger.log(`stream: ${sql}`)
279
284
 
280
- // return this.streamSQL(sql, opt)
281
- return (this.pool().query(sql).stream() as ReadableTyped<ROW>).map(row =>
282
- _filterUndefinedValues(row, true),
283
- )
285
+ // todo: this is nice, but `mysql` package uses `readable-stream@2` which is not compatible with `node:stream` iterable helpers
286
+ // return (this.pool().query(sql).stream() as ReadableTyped<ROW>).map(row =>
287
+ // _filterUndefinedValues(row, true),
288
+ // )
289
+ return this.pool()
290
+ .query(sql)
291
+ .stream()
292
+ .pipe(
293
+ new Transform({
294
+ objectMode: true,
295
+ transform(row: ROW, _encoding, cb) {
296
+ cb(null, _filterUndefinedValues(row, true))
297
+ },
298
+ }),
299
+ )
284
300
  }
285
301
 
286
302
  // SAVE
@@ -1,14 +1,17 @@
1
- import {
1
+ import { Transform } from 'node:stream'
2
+ import type {
2
3
  CommonDBCreateOptions,
3
4
  CommonKeyValueDB,
4
- commonKeyValueDBFullSupport,
5
5
  KeyValueDBTuple,
6
6
  } from '@naturalcycles/db-lib'
7
- import { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB'
8
- import { AppError, ObjectWithId, pMap } from '@naturalcycles/js-lib'
9
- import { ReadableTyped } from '@naturalcycles/nodejs-lib'
10
- import { QueryOptions } from 'mysql'
11
- import { MysqlDB, MysqlDBCfg } from './mysql.db'
7
+ import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib'
8
+ import type { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB.js'
9
+ import type { ObjectWithId } from '@naturalcycles/js-lib'
10
+ import { AppError, pMap } from '@naturalcycles/js-lib'
11
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
12
+ import type { QueryOptions } from 'mysql'
13
+ import type { MysqlDBCfg } from './mysql.db.js'
14
+ import { MysqlDB } from './mysql.db.js'
12
15
 
13
16
  interface KeyValueObject {
14
17
  id: string
@@ -88,7 +91,20 @@ export class MySQLKeyValueDB implements CommonKeyValueDB {
88
91
  if (limit) sql += ` LIMIT ${limit}`
89
92
  if (this.cfg.logSQL) this.db.cfg.logger.log(`stream: ${sql}`)
90
93
 
91
- return (this.db.pool().query(sql).stream() as ReadableTyped<ObjectWithId>).map(row => row.id)
94
+ // todo: this is nice, but `mysql` package uses `readable-stream@2` which is not compatible with `node:stream` iterable helpers
95
+ // return (this.db.pool().query(sql).stream() as ReadableTyped<ObjectWithId>).map(row => row.id)
96
+ return this.db
97
+ .pool()
98
+ .query(sql)
99
+ .stream()
100
+ .pipe(
101
+ new Transform({
102
+ objectMode: true,
103
+ transform(row: ObjectWithId, _encoding, cb) {
104
+ cb(null, row.id)
105
+ },
106
+ }),
107
+ )
92
108
  }
93
109
 
94
110
  streamValues(table: string, limit?: number): ReadableTyped<Buffer> {
package/src/query.util.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
2
- import { _hb, AnyObjectWithId, CommonLogger } from '@naturalcycles/js-lib'
1
+ import type { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
2
+ import type { AnyObjectWithId, CommonLogger } from '@naturalcycles/js-lib'
3
+ import { _hb } from '@naturalcycles/js-lib'
3
4
  import { white, yellow } from '@naturalcycles/nodejs-lib'
4
- import { QueryOptions } from 'mysql'
5
+ import type { QueryOptions } from 'mysql'
5
6
  import * as mysql from 'mysql'
6
- import { mapNameToMySQL } from './schema/mysql.schema.util'
7
+ import { mapNameToMySQL } from './schema/mysql.schema.util.js'
7
8
 
8
9
  const MAX_PACKET_SIZE = 1024 * 1024 // 1Mb
9
10
  const MAX_ROW_SIZE = 800 * 1024 // 1Mb - margin
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  AnyObject,
3
3
  CommonLogger,
4
4
  JsonSchemaBoolean,