@naturalcycles/mysql-lib 3.9.2 → 3.10.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,5 +1,6 @@
1
1
  import { getDBAdapter } from './dbAdapter';
2
2
  import { MysqlDB, MysqlDBCfg, MysqlDBOptions, MysqlDBSaveOptions } from './mysql.db';
3
+ import { MySQLKeyValueDB } from './mysqlKeyValueDB';
3
4
  import { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util';
4
5
  export type { MysqlDBCfg, MysqlDBOptions, MysqlDBSaveOptions };
5
- export { MysqlDB, jsonSchemaToMySQLDDL, getDBAdapter };
6
+ export { MysqlDB, MySQLKeyValueDB, jsonSchemaToMySQLDDL, getDBAdapter };
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDBAdapter = exports.jsonSchemaToMySQLDDL = exports.MysqlDB = void 0;
3
+ exports.getDBAdapter = exports.jsonSchemaToMySQLDDL = exports.MySQLKeyValueDB = exports.MysqlDB = void 0;
4
4
  const dbAdapter_1 = require("./dbAdapter");
5
5
  Object.defineProperty(exports, "getDBAdapter", { enumerable: true, get: function () { return dbAdapter_1.getDBAdapter; } });
6
6
  const mysql_db_1 = require("./mysql.db");
7
7
  Object.defineProperty(exports, "MysqlDB", { enumerable: true, get: function () { return mysql_db_1.MysqlDB; } });
8
+ const mysqlKeyValueDB_1 = require("./mysqlKeyValueDB");
9
+ Object.defineProperty(exports, "MySQLKeyValueDB", { enumerable: true, get: function () { return mysqlKeyValueDB_1.MySQLKeyValueDB; } });
8
10
  const mysql_schema_util_1 = require("./schema/mysql.schema.util");
9
11
  Object.defineProperty(exports, "jsonSchemaToMySQLDDL", { enumerable: true, get: function () { return mysql_schema_util_1.jsonSchemaToMySQLDDL; } });
@@ -1,7 +1,7 @@
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 } from 'mysql';
4
+ import { Connection, Pool, PoolConfig, PoolConnection, QueryOptions, TypeCast } from 'mysql';
5
5
  export interface MysqlDBOptions extends CommonDBOptions {
6
6
  }
7
7
  export interface MysqlDBSaveOptions<ROW extends ObjectWithId = AnyObjectWithId> extends CommonDBSaveOptions<ROW> {
@@ -23,6 +23,7 @@ export interface MysqlDBCfg extends PoolConfig {
23
23
  */
24
24
  logger?: CommonLogger;
25
25
  }
26
+ export declare const typeCast: TypeCast;
26
27
  export declare class MysqlDB extends BaseCommonDB implements CommonDB {
27
28
  constructor(cfg?: MysqlDBCfg);
28
29
  cfg: MysqlDBCfg & {
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 = void 0;
3
+ exports.MysqlDB = exports.typeCast = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const stream_1 = require("stream");
6
6
  const util_1 = require("util");
@@ -31,11 +31,12 @@ const typeCast = (field, next) => {
31
31
  }
32
32
  return next();
33
33
  };
34
+ exports.typeCast = typeCast;
34
35
  class MysqlDB extends db_lib_1.BaseCommonDB {
35
36
  constructor(cfg = {}) {
36
37
  super();
37
38
  this.cfg = {
38
- typeCast,
39
+ typeCast: exports.typeCast,
39
40
  // charset: 'utf8mb4', // for emoji support
40
41
  // host: 'localhost',
41
42
  // user: MYSQL_USER,
@@ -0,0 +1,25 @@
1
+ /// <reference types="node" />
2
+ import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
3
+ import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
+ import { MysqlDB, MysqlDBCfg } from './mysql.db';
5
+ export declare class MySQLKeyValueDB implements CommonKeyValueDB {
6
+ constructor(cfg?: MysqlDBCfg);
7
+ cfg: MysqlDBCfg;
8
+ db: MysqlDB;
9
+ ping(): Promise<void>;
10
+ close(): Promise<void>;
11
+ createTable(table: string, opt?: CommonDBCreateOptions): Promise<void>;
12
+ getByIds(table: string, ids: string[]): Promise<KeyValueDBTuple[]>;
13
+ /**
14
+ * Use with caution!
15
+ */
16
+ dropTable(table: string): Promise<void>;
17
+ deleteByIds(table: string, ids: string[]): Promise<void>;
18
+ saveBatch(table: string, entries: KeyValueDBTuple[]): Promise<void>;
19
+ streamIds(table: string, limit?: number): ReadableTyped<string>;
20
+ streamValues(table: string, limit?: number): ReadableTyped<Buffer>;
21
+ streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
22
+ beginTransaction(): Promise<void>;
23
+ endTransaction(): Promise<void>;
24
+ count(table: string): Promise<number>;
25
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MySQLKeyValueDB = void 0;
4
+ const stream_1 = require("stream");
5
+ const js_lib_1 = require("@naturalcycles/js-lib");
6
+ const mysql_db_1 = require("./mysql.db");
7
+ class MySQLKeyValueDB {
8
+ constructor(cfg = {}) {
9
+ this.cfg = {
10
+ typeCast: mysql_db_1.typeCast,
11
+ ...cfg,
12
+ };
13
+ this.db = new mysql_db_1.MysqlDB(this.cfg);
14
+ }
15
+ async ping() {
16
+ await this.db.ping();
17
+ }
18
+ async close() {
19
+ await this.db.close();
20
+ }
21
+ async createTable(table, opt = {}) {
22
+ if (opt.dropIfExists)
23
+ await this.dropTable(table);
24
+ // On blob sizes: https://tableplus.com/blog/2019/10/tinyblob-blob-mediumblob-longblob.html
25
+ // LONGBLOB supports up to 4gb
26
+ // MEDIUMBLOB up to 16Mb
27
+ const sql = `create table ${table} (id VARCHAR(64) PRIMARY KEY, v LONGBLOB NOT NULL)`;
28
+ this.db.cfg.logger.log(sql);
29
+ await this.db.runSQL({ sql });
30
+ }
31
+ async getByIds(table, ids) {
32
+ if (!ids.length)
33
+ return [];
34
+ const sql = `SELECT id,v FROM ${table} where id in (${ids.map(id => `"${id}"`).join(',')})`;
35
+ const rows = await this.db.runSQL({ sql });
36
+ return rows.map(({ id, v }) => [id, v]);
37
+ }
38
+ /**
39
+ * Use with caution!
40
+ */
41
+ async dropTable(table) {
42
+ await this.db.runSQL({ sql: `DROP TABLE IF EXISTS ${table}` });
43
+ }
44
+ async deleteByIds(table, ids) {
45
+ const sql = `DELETE FROM ${table} WHERE id in (${ids.map(id => `"${id}"`).join(',')})`;
46
+ if (this.cfg.logSQL)
47
+ this.db.cfg.logger.log(sql);
48
+ await this.db.runSQL({ sql });
49
+ }
50
+ async saveBatch(table, entries) {
51
+ const statements = entries.map(([id, buf]) => {
52
+ return {
53
+ sql: `INSERT INTO ${table} (id, v) VALUES (?, ?)`,
54
+ values: [id, buf],
55
+ };
56
+ });
57
+ await (0, js_lib_1.pMap)(statements, async (statement) => {
58
+ if (this.cfg.debug)
59
+ this.db.cfg.logger.log(statement.sql);
60
+ await this.db.runSQL(statement);
61
+ });
62
+ }
63
+ streamIds(table, limit) {
64
+ let sql = `SELECT id FROM ${table}`;
65
+ if (limit)
66
+ sql += ` LIMIT ${limit}`;
67
+ if (this.cfg.logSQL)
68
+ this.db.cfg.logger.log(`stream: ${sql}`);
69
+ return this.db
70
+ .pool()
71
+ .query(sql)
72
+ .stream()
73
+ .pipe(new stream_1.Transform({
74
+ objectMode: true,
75
+ transform(row, _, cb) {
76
+ cb(null, row.id);
77
+ },
78
+ }));
79
+ }
80
+ streamValues(table, limit) {
81
+ let sql = `SELECT v FROM ${table}`;
82
+ if (limit)
83
+ sql += ` LIMIT ${limit}`;
84
+ if (this.cfg.logSQL)
85
+ this.db.cfg.logger.log(`stream: ${sql}`);
86
+ return this.db
87
+ .pool()
88
+ .query(sql)
89
+ .stream()
90
+ .pipe(new stream_1.Transform({
91
+ objectMode: true,
92
+ transform(row, _, cb) {
93
+ cb(null, row.v);
94
+ },
95
+ }));
96
+ }
97
+ streamEntries(table, limit) {
98
+ let sql = `SELECT id,v FROM ${table}`;
99
+ if (limit)
100
+ sql += ` LIMIT ${limit}`;
101
+ if (this.cfg.logSQL)
102
+ this.db.cfg.logger.log(`stream: ${sql}`);
103
+ return this.db
104
+ .pool()
105
+ .query(sql)
106
+ .stream()
107
+ .pipe(new stream_1.Transform({
108
+ objectMode: true,
109
+ transform(row, _, cb) {
110
+ cb(null, [row.id, row.v]);
111
+ },
112
+ }));
113
+ }
114
+ async beginTransaction() {
115
+ await this.db.runSQL({ sql: `BEGIN TRANSACTION` });
116
+ }
117
+ async endTransaction() {
118
+ await this.db.runSQL({ sql: `END TRANSACTION` });
119
+ }
120
+ async count(table) {
121
+ const sql = `SELECT count(*) as cnt FROM ${table}`;
122
+ if (this.cfg.logSQL)
123
+ this.db.cfg.logger.log(sql);
124
+ const rows = await this.db.runSQL({ sql });
125
+ return rows[0].cnt;
126
+ }
127
+ }
128
+ exports.MySQLKeyValueDB = MySQLKeyValueDB;
package/package.json CHANGED
@@ -36,7 +36,7 @@
36
36
  "engines": {
37
37
  "node": ">=14.15.0"
38
38
  },
39
- "version": "3.9.2",
39
+ "version": "3.10.0",
40
40
  "description": "MySQL client implementing CommonDB interface",
41
41
  "keywords": [
42
42
  "mysql",
package/src/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { getDBAdapter } from './dbAdapter'
2
2
  import { MysqlDB, MysqlDBCfg, MysqlDBOptions, MysqlDBSaveOptions } from './mysql.db'
3
+ import { MySQLKeyValueDB } from './mysqlKeyValueDB'
3
4
  import { jsonSchemaToMySQLDDL } from './schema/mysql.schema.util'
4
5
 
5
6
  export type { MysqlDBCfg, MysqlDBOptions, MysqlDBSaveOptions }
6
7
 
7
- export { MysqlDB, jsonSchemaToMySQLDDL, getDBAdapter }
8
+ export { MysqlDB, MySQLKeyValueDB, jsonSchemaToMySQLDDL, getDBAdapter }
package/src/mysql.db.ts CHANGED
@@ -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
- const typeCast: TypeCast = (field, next) => {
63
+ export 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)) {
@@ -0,0 +1,155 @@
1
+ import { Transform } from 'stream'
2
+ import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib'
3
+ import { pMap } from '@naturalcycles/js-lib'
4
+ import { ReadableTyped } from '@naturalcycles/nodejs-lib'
5
+ import { QueryOptions } from 'mysql'
6
+ import { MysqlDB, MysqlDBCfg, typeCast } from './mysql.db'
7
+
8
+ interface KeyValueObject {
9
+ id: string
10
+ v: Buffer
11
+ }
12
+
13
+ export class MySQLKeyValueDB implements CommonKeyValueDB {
14
+ constructor(cfg: MysqlDBCfg = {}) {
15
+ this.cfg = {
16
+ typeCast,
17
+ ...cfg,
18
+ }
19
+
20
+ this.db = new MysqlDB(this.cfg)
21
+ }
22
+
23
+ cfg: MysqlDBCfg
24
+
25
+ db: MysqlDB
26
+
27
+ async ping(): Promise<void> {
28
+ await this.db.ping()
29
+ }
30
+
31
+ async close(): Promise<void> {
32
+ await this.db.close()
33
+ }
34
+
35
+ async createTable(table: string, opt: CommonDBCreateOptions = {}): Promise<void> {
36
+ if (opt.dropIfExists) await this.dropTable(table)
37
+
38
+ // On blob sizes: https://tableplus.com/blog/2019/10/tinyblob-blob-mediumblob-longblob.html
39
+ // LONGBLOB supports up to 4gb
40
+ // MEDIUMBLOB up to 16Mb
41
+ const sql = `create table ${table} (id VARCHAR(64) PRIMARY KEY, v LONGBLOB NOT NULL)`
42
+ this.db.cfg.logger.log(sql)
43
+ await this.db.runSQL({ sql })
44
+ }
45
+
46
+ async getByIds(table: string, ids: string[]): Promise<KeyValueDBTuple[]> {
47
+ if (!ids.length) return []
48
+
49
+ const sql = `SELECT id,v FROM ${table} where id in (${ids.map(id => `"${id}"`).join(',')})`
50
+
51
+ const rows = await this.db.runSQL<KeyValueObject[]>({ sql })
52
+
53
+ return rows.map(({ id, v }) => [id, v])
54
+ }
55
+
56
+ /**
57
+ * Use with caution!
58
+ */
59
+ async dropTable(table: string): Promise<void> {
60
+ await this.db.runSQL({ sql: `DROP TABLE IF EXISTS ${table}` })
61
+ }
62
+
63
+ async deleteByIds(table: string, ids: string[]): Promise<void> {
64
+ const sql = `DELETE FROM ${table} WHERE id in (${ids.map(id => `"${id}"`).join(',')})`
65
+ if (this.cfg.logSQL) this.db.cfg.logger.log(sql)
66
+ await this.db.runSQL({ sql })
67
+ }
68
+
69
+ async saveBatch(table: string, entries: KeyValueDBTuple[]): Promise<void> {
70
+ const statements: QueryOptions[] = entries.map(([id, buf]) => {
71
+ return {
72
+ sql: `INSERT INTO ${table} (id, v) VALUES (?, ?)`,
73
+ values: [id, buf],
74
+ }
75
+ })
76
+
77
+ await pMap(statements, async statement => {
78
+ if (this.cfg.debug) this.db.cfg.logger.log(statement.sql)
79
+ await this.db.runSQL(statement)
80
+ })
81
+ }
82
+
83
+ streamIds(table: string, limit?: number): ReadableTyped<string> {
84
+ let sql = `SELECT id FROM ${table}`
85
+ if (limit) sql += ` LIMIT ${limit}`
86
+ if (this.cfg.logSQL) this.db.cfg.logger.log(`stream: ${sql}`)
87
+
88
+ return this.db
89
+ .pool()
90
+ .query(sql)
91
+ .stream()
92
+ .pipe(
93
+ new Transform({
94
+ objectMode: true,
95
+ transform(row, _, cb) {
96
+ cb(null, row.id)
97
+ },
98
+ }),
99
+ )
100
+ }
101
+
102
+ streamValues(table: string, limit?: number): ReadableTyped<Buffer> {
103
+ let sql = `SELECT v FROM ${table}`
104
+ if (limit) sql += ` LIMIT ${limit}`
105
+ if (this.cfg.logSQL) this.db.cfg.logger.log(`stream: ${sql}`)
106
+
107
+ return this.db
108
+ .pool()
109
+ .query(sql)
110
+ .stream()
111
+ .pipe(
112
+ new Transform({
113
+ objectMode: true,
114
+ transform(row, _, cb) {
115
+ cb(null, row.v)
116
+ },
117
+ }),
118
+ )
119
+ }
120
+
121
+ streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple> {
122
+ let sql = `SELECT id,v FROM ${table}`
123
+ if (limit) sql += ` LIMIT ${limit}`
124
+ if (this.cfg.logSQL) this.db.cfg.logger.log(`stream: ${sql}`)
125
+
126
+ return this.db
127
+ .pool()
128
+ .query(sql)
129
+ .stream()
130
+ .pipe(
131
+ new Transform({
132
+ objectMode: true,
133
+ transform(row, _, cb) {
134
+ cb(null, [row.id, row.v])
135
+ },
136
+ }),
137
+ )
138
+ }
139
+
140
+ async beginTransaction(): Promise<void> {
141
+ await this.db.runSQL({ sql: `BEGIN TRANSACTION` })
142
+ }
143
+
144
+ async endTransaction(): Promise<void> {
145
+ await this.db.runSQL({ sql: `END TRANSACTION` })
146
+ }
147
+
148
+ async count(table: string): Promise<number> {
149
+ const sql = `SELECT count(*) as cnt FROM ${table}`
150
+ if (this.cfg.logSQL) this.db.cfg.logger.log(sql)
151
+
152
+ const rows = await this.db.runSQL<{ cnt: number }[]>({ sql })
153
+ return rows[0]!.cnt
154
+ }
155
+ }