badmfck-api-server 2.9.4 → 2.9.5

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.
@@ -21,6 +21,18 @@ export interface IDBQuery {
21
21
  calculateCount?: boolean;
22
22
  parseQueryOnly?: boolean;
23
23
  }
24
+ export interface IDBBulkQuery {
25
+ dbid?: string;
26
+ bulk: {
27
+ query: string;
28
+ fields: {
29
+ [key: string]: IDBQueryField | null | string | number | boolean;
30
+ };
31
+ throwable?: boolean;
32
+ calculateCount?: boolean;
33
+ }[];
34
+ queued?: boolean;
35
+ }
24
36
  export interface IDBError {
25
37
  code: string;
26
38
  errno: number;
@@ -52,6 +64,7 @@ export interface DBAdapterOptions {
52
64
  debug?: boolean;
53
65
  }
54
66
  export declare const REQ_DB: Req<IDBQuery, IDBResult>;
67
+ export declare const REQ_DBX: Req<IDBBulkQuery, IDBResult[]>;
55
68
  export declare class DBService extends BaseService {
56
69
  static allInstances: DBService[];
57
70
  options: IDBSericeOptions;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DBService = exports.REQ_DB = void 0;
3
+ exports.DBService = exports.REQ_DBX = exports.REQ_DB = void 0;
4
4
  const badmfck_signal_1 = require("badmfck-signal");
5
5
  const BaseService_1 = require("./BaseService");
6
6
  const MysqlAdapter_1 = require("./db/MysqlAdapter");
7
- exports.REQ_DB = new badmfck_signal_1.Req(undefined, "DB_SELECT");
7
+ exports.REQ_DB = new badmfck_signal_1.Req(undefined, "REQ_DB");
8
+ exports.REQ_DBX = new badmfck_signal_1.Req(undefined, "REQ_DBX");
8
9
  class DBService extends BaseService_1.BaseService {
9
10
  static allInstances = [];
10
11
  options;
@@ -25,6 +26,29 @@ class DBService extends BaseService_1.BaseService {
25
26
  if (this.options.type === "mysql") {
26
27
  await this.createMysqlDatabase();
27
28
  }
29
+ exports.REQ_DBX.listener = async (req) => {
30
+ if (!req.dbid && DBService.allInstances.length === 1 && DBService.allInstances[0].adapter)
31
+ return DBService.allInstances[0].adapter.bulk(req);
32
+ for (let i of DBService.allInstances) {
33
+ if (i.options.id === req.dbid && i.adapter)
34
+ return i.adapter.bulk(req);
35
+ }
36
+ const error = {
37
+ code: "DB_NOT_FOUND",
38
+ errno: -1,
39
+ fatal: true,
40
+ sql: "",
41
+ name: "DB_NOT_FOUND",
42
+ message: "DB not found: " + req.dbid
43
+ };
44
+ let result = [];
45
+ for (let i of req.bulk) {
46
+ result.push({ error: error });
47
+ if (i.throwable)
48
+ throw error;
49
+ }
50
+ return result;
51
+ };
28
52
  exports.REQ_DB.listener = async (req) => {
29
53
  if (!req.dbid && DBService.allInstances.length === 1 && DBService.allInstances[0].adapter)
30
54
  return DBService.allInstances[0].adapter.query(req);
@@ -151,8 +151,11 @@ class MysqlService extends BaseService_1.BaseService {
151
151
  const query = MysqlService.prepareQuery(i.query, i.fields);
152
152
  promises.push(this.execute(query, i.rollbackQuery ?? null, i.transactionID ?? 0, i.throwable ?? false, i.calculateCount ?? false));
153
153
  }
154
- if (this.debug)
154
+ if (this.debug) {
155
155
  console.log("Execute queries: ", data.length);
156
+ for (let i of data)
157
+ console.log(i);
158
+ }
156
159
  const result = await Promise.all(promises);
157
160
  for (let i of result) {
158
161
  if (i.error && i.error.code === "CONN_ERR") {
@@ -1,7 +1,8 @@
1
- import { IDBQuery, IDBResult } from "../DBService";
1
+ import { IDBBulkQuery, IDBQuery, IDBResult } from "../DBService";
2
2
  export interface IDBAdapter {
3
3
  init(): Promise<void>;
4
4
  finish(): Promise<void>;
5
5
  prepareQuery(request: IDBQuery): string;
6
6
  query(request: IDBQuery): Promise<IDBResult>;
7
+ bulk(request: IDBBulkQuery): Promise<IDBResult[]>;
7
8
  }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { DBAdapterOptions, IDBError, IDBQuery, IDBQueryField, IDBResult } from "../DBService";
2
+ import { DBAdapterOptions, IDBBulkQuery, IDBError, IDBQuery, IDBQueryField, IDBResult } from "../DBService";
3
3
  import { IDBAdapter } from "./IDBAdapter";
4
4
  import mysql from 'mysql2/promise';
5
5
  import fs from 'fs';
@@ -34,7 +34,9 @@ export declare class MysqlAdapter implements IDBAdapter {
34
34
  init(): Promise<void>;
35
35
  setupTimers(): void;
36
36
  recreatePool(): Promise<boolean>;
37
- query(request: IDBQuery): Promise<IDBResult>;
37
+ bulk(request: IDBBulkQuery): Promise<IDBResult[]>;
38
+ getConnection(transactionId?: number): Promise<mysql.PoolConnection | IDBError>;
39
+ query(request: IDBQuery, conn?: mysql.PoolConnection): Promise<IDBResult>;
38
40
  finalizeConnection(conn: mysql.PoolConnection): void;
39
41
  prepareQuery(request: IDBQuery): string;
40
42
  static prepareQueryFieldValue(field: IDBQueryField): string | number | boolean | null | undefined;
@@ -44,5 +46,6 @@ export declare class MysqlAdapter implements IDBAdapter {
44
46
  finish(): Promise<void>;
45
47
  createMysqlQueryError(err: any, throwable?: boolean): IDBError;
46
48
  storeTransactionAsProblem(trx: ITransaction, message: string): Promise<void>;
49
+ isError(obj: any): obj is IDBError;
47
50
  }
48
51
  export {};
@@ -154,104 +154,132 @@ class MysqlAdapter {
154
154
  }
155
155
  return true;
156
156
  }
157
- async query(request) {
158
- const query = this.prepareQuery(request);
159
- if (request.parseQueryOnly) {
160
- return {
161
- data: [{ query }],
162
- error: null,
163
- };
157
+ async bulk(request) {
158
+ const results = [];
159
+ let queries = [];
160
+ let conn = null;
161
+ if (request.queued) {
162
+ conn = await this.getConnection();
163
+ if (this.isError(conn)) {
164
+ for (let i of request.bulk)
165
+ results.push({ data: null, error: conn });
166
+ return results;
167
+ }
164
168
  }
169
+ for (let i of request.bulk) {
170
+ if (request.queued && conn) {
171
+ const response = await this.query({
172
+ query: i.query,
173
+ fields: i.fields,
174
+ throwable: i.throwable,
175
+ }, conn);
176
+ results.push(response);
177
+ continue;
178
+ }
179
+ queries.push(this.query({
180
+ query: i.query,
181
+ fields: i.fields,
182
+ throwable: i.throwable,
183
+ }));
184
+ }
185
+ if (conn) {
186
+ this.finalizeConnection(conn);
187
+ conn = null;
188
+ }
189
+ if (queries && queries.length > 0) {
190
+ const responses = await Promise.all(queries);
191
+ for (let i of responses)
192
+ results.push(i);
193
+ }
194
+ return results;
195
+ }
196
+ async getConnection(transactionId) {
165
197
  if (!this.pool) {
166
198
  (0, LogService_1.logError)("${MysqlAdapter.js}", "No pool created, can't execute query");
167
- const error = {
199
+ return {
168
200
  code: "NO_POOL",
169
201
  errno: 100000,
170
202
  fatal: true,
171
- sql: query,
203
+ sql: "",
172
204
  name: "NO_POOL",
173
205
  message: "Mysql pool not created",
174
206
  };
175
- if (request.throwable)
176
- throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
177
- return {
178
- data: null,
179
- error: error,
180
- };
181
207
  }
182
208
  try {
183
209
  let conn = null;
184
- if (request.transactionID && request.transactionID > 0) {
185
- conn = this.transactions.find(i => i.id === request.transactionID)?.conn ?? null;
210
+ if (transactionId && transactionId > 0) {
211
+ conn = this.transactions.find(i => i.id === transactionId)?.conn ?? null;
186
212
  if (this.options.debug)
187
213
  console.log("Execute query on transaction: ", conn?.threadId);
188
214
  }
189
215
  else
190
216
  conn = await this.pool.getConnection();
217
+ if (this.options.debug) {
218
+ console.log("Pool status: ", this.poolConnections, this.acquiredPoolConnections);
219
+ }
191
220
  if (this.options.debug)
192
221
  console.log("Execute query", conn?.threadId);
193
- if (!conn) {
194
- (0, LogService_1.logCrit)("${MysqlAdapter.js}", `No connection created!`);
195
- const error = {
196
- code: "NO_CONN",
197
- errno: 100001,
198
- fatal: true,
199
- sql: query,
200
- name: "NO_CONN",
201
- message: "Mysql pool cant get connection",
202
- };
203
- if (request.throwable)
204
- throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
205
- return {
206
- data: null,
207
- error: error,
208
- };
209
- }
210
- try {
211
- if (this.options.debug)
212
- (0, LogService_1.logInfo)("Execute query:", query);
213
- const result = await conn.query(query);
214
- this.lastSuccessQueryTime = +new Date();
215
- if (!request.transactionID)
216
- this.finalizeConnection(conn);
217
- return {
218
- data: result[0],
219
- error: null
220
- };
221
- }
222
- catch (e) {
223
- if (!request.transactionID)
224
- this.finalizeConnection(conn);
225
- else if (request.transactionID && request.throwable) {
226
- this.rollbackTransaction(this.transactions.find(i => i.id === request.transactionID));
227
- this.finalizeConnection(conn);
228
- }
229
- const error = this.createMysqlQueryError(e);
230
- if (`${e}`.indexOf('ECONNREFUSED') !== -1)
231
- this.recreatePool();
232
- if (request.throwable)
233
- throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
222
+ if (conn)
223
+ return conn;
224
+ }
225
+ catch (e) {
226
+ if (`${e}`.indexOf('ECONNREFUSED') !== -1)
227
+ this.recreatePool();
228
+ }
229
+ (0, LogService_1.logCrit)("${MysqlAdapter.js}", `No connection created!`);
230
+ return {
231
+ code: "NO_CONN",
232
+ errno: 100001,
233
+ fatal: true,
234
+ sql: "",
235
+ name: "NO_CONN",
236
+ message: "Mysql pool cant get connection",
237
+ };
238
+ }
239
+ async query(request, conn) {
240
+ const query = this.prepareQuery(request);
241
+ if (request.parseQueryOnly) {
242
+ return {
243
+ data: [{ query }],
244
+ error: null,
245
+ };
246
+ }
247
+ let doCloseConnection = false;
248
+ if (!conn) {
249
+ doCloseConnection = true;
250
+ conn = await this.getConnection(request.transactionID ?? -1);
251
+ if (this.isError(conn)) {
234
252
  return {
235
253
  data: null,
236
- error: this.createMysqlQueryError(e),
254
+ error: conn,
237
255
  };
238
256
  }
239
257
  }
240
- catch (e) {
241
- (0, LogService_1.logCrit)("MysqlAdapter", `Error when executing query: ${query}`, e);
242
- const error = {
243
- code: "EXEC_ERROR",
244
- errno: 100002,
245
- fatal: true,
246
- sql: query,
247
- name: "EXECUTION_ERROR",
248
- message: e + "",
258
+ try {
259
+ const result = await conn.query(query);
260
+ this.lastSuccessQueryTime = +new Date();
261
+ if (!request.transactionID && doCloseConnection)
262
+ this.finalizeConnection(conn);
263
+ return {
264
+ data: result[0],
265
+ error: null
249
266
  };
267
+ }
268
+ catch (e) {
269
+ if (!request.transactionID && doCloseConnection)
270
+ this.finalizeConnection(conn);
271
+ else if (request.transactionID && request.throwable) {
272
+ this.rollbackTransaction(this.transactions.find(i => i.id === request.transactionID));
273
+ this.finalizeConnection(conn);
274
+ }
275
+ const error = this.createMysqlQueryError(e);
276
+ if (`${e}`.indexOf('ECONNREFUSED') !== -1)
277
+ this.recreatePool();
250
278
  if (request.throwable)
251
279
  throw { ...DefaultErrors_1.default.DB_ERROR, details: error.message, stack: error };
252
280
  return {
253
281
  data: null,
254
- error: error,
282
+ error: this.createMysqlQueryError(e),
255
283
  };
256
284
  }
257
285
  }
@@ -464,6 +492,9 @@ class MysqlAdapter {
464
492
  if (this.options.transactionFailReport)
465
493
  this.options.transactionFailReport(trx, message);
466
494
  }
495
+ isError(obj) {
496
+ return obj && "code" in obj && "errno" in obj && "name" in obj && "message" in obj;
497
+ }
467
498
  }
468
499
  exports.MysqlAdapter = MysqlAdapter;
469
500
  const secret_key = "AKLWkajw%^&dgwqhw#98453i23bfk23rn2knknglrgjeit";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badmfck-api-server",
3
- "version": "2.9.4",
3
+ "version": "2.9.5",
4
4
  "description": "Simple API http server based on express",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",