dbgate-api-premium 6.4.1 → 6.4.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dbgate-api-premium",
3
3
  "main": "src/index.js",
4
- "version": "6.4.1",
4
+ "version": "6.4.2",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -30,10 +30,10 @@
30
30
  "compare-versions": "^3.6.0",
31
31
  "cors": "^2.8.5",
32
32
  "cross-env": "^6.0.3",
33
- "dbgate-datalib": "^6.4.1",
34
- "dbgate-query-splitter": "^4.11.4",
35
- "dbgate-sqltree": "^6.4.1",
36
- "dbgate-tools": "^6.4.1",
33
+ "dbgate-datalib": "^6.4.2",
34
+ "dbgate-query-splitter": "^4.11.5",
35
+ "dbgate-sqltree": "^6.4.2",
36
+ "dbgate-tools": "^6.4.2",
37
37
  "debug": "^4.3.4",
38
38
  "diff": "^5.0.0",
39
39
  "diff2html": "^3.4.13",
@@ -85,7 +85,7 @@
85
85
  "devDependencies": {
86
86
  "@types/fs-extra": "^9.0.11",
87
87
  "@types/lodash": "^4.14.149",
88
- "dbgate-types": "^6.4.1",
88
+ "dbgate-types": "^6.4.2",
89
89
  "env-cmd": "^10.1.0",
90
90
  "jsdoc-to-markdown": "^9.0.5",
91
91
  "node-loader": "^1.0.2",
@@ -304,6 +304,12 @@ module.exports = {
304
304
  return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
305
305
  },
306
306
 
307
+ scanKeys_meta: true,
308
+ async scanKeys({ conid, database, root, pattern, cursor, count }, req) {
309
+ testConnectionPermission(conid, req);
310
+ return this.loadDataCore('scanKeys', { conid, database, root, pattern, cursor, count });
311
+ },
312
+
307
313
  exportKeys_meta: true,
308
314
  async exportKeys({ conid, database, options }, req) {
309
315
  testConnectionPermission(conid, req);
@@ -141,7 +141,7 @@ module.exports = {
141
141
  },
142
142
 
143
143
  executeQuery_meta: true,
144
- async executeQuery({ sesid, sql, autoCommit }) {
144
+ async executeQuery({ sesid, sql, autoCommit, limitRows }) {
145
145
  const session = this.opened.find(x => x.sesid == sesid);
146
146
  if (!session) {
147
147
  throw new Error('Invalid session');
@@ -149,7 +149,7 @@ module.exports = {
149
149
 
150
150
  logger.info({ sesid, sql }, 'Processing query');
151
151
  this.dispatchMessage(sesid, 'Query execution started');
152
- session.subprocess.send({ msgtype: 'executeQuery', sql, autoCommit });
152
+ session.subprocess.send({ msgtype: 'executeQuery', sql, autoCommit, limitRows });
153
153
 
154
154
  return { state: 'ok' };
155
155
  },
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '6.4.1',
4
- buildTime: '2025-05-03T17:11:03.241Z'
3
+ version: '6.4.2',
4
+ buildTime: '2025-05-14T12:55:08.993Z'
5
5
  };
@@ -12,6 +12,7 @@ const {
12
12
  ScriptWriterEval,
13
13
  SqlGenerator,
14
14
  playJsonScriptWriter,
15
+ serializeJsTypesForJsonStringify,
15
16
  } = require('dbgate-tools');
16
17
  const requireEngineDriver = require('../utility/requireEngineDriver');
17
18
  const { connectUtility } = require('../utility/connectUtility');
@@ -232,7 +233,7 @@ async function handleQueryData({ msgid, sql, range }, skipReadonlyCheck = false)
232
233
  try {
233
234
  if (!skipReadonlyCheck) ensureExecuteCustomScript(driver);
234
235
  const res = await driver.query(dbhan, sql, { range });
235
- process.send({ msgtype: 'response', msgid, ...res });
236
+ process.send({ msgtype: 'response', msgid, ...serializeJsTypesForJsonStringify(res) });
236
237
  } catch (err) {
237
238
  process.send({
238
239
  msgtype: 'response',
@@ -254,7 +255,7 @@ async function handleDriverDataCore(msgid, callMethod, { logName }) {
254
255
  const driver = requireEngineDriver(storedConnection);
255
256
  try {
256
257
  const result = await callMethod(driver);
257
- process.send({ msgtype: 'response', msgid, result });
258
+ process.send({ msgtype: 'response', msgid, result: serializeJsTypesForJsonStringify(result) });
258
259
  } catch (err) {
259
260
  logger.error(extractErrorLogData(err, { logName }), `Error when handling message ${logName}`);
260
261
  process.send({ msgtype: 'response', msgid, errorMessage: extractErrorMessage(err, 'Error executing DB data') });
@@ -274,6 +275,10 @@ async function handleLoadKeys({ msgid, root, filter, limit }) {
274
275
  return handleDriverDataCore(msgid, driver => driver.loadKeys(dbhan, root, filter, limit), { logName: 'loadKeys' });
275
276
  }
276
277
 
278
+ async function handleScanKeys({ msgid, pattern, cursor, count }) {
279
+ return handleDriverDataCore(msgid, driver => driver.scanKeys(dbhan, pattern, cursor, count), { logName: 'scanKeys' });
280
+ }
281
+
277
282
  async function handleExportKeys({ msgid, options }) {
278
283
  return handleDriverDataCore(msgid, driver => driver.exportKeys(dbhan, options), { logName: 'exportKeys' });
279
284
  }
@@ -452,6 +457,7 @@ const messageHandlers = {
452
457
  updateCollection: handleUpdateCollection,
453
458
  collectionData: handleCollectionData,
454
459
  loadKeys: handleLoadKeys,
460
+ scanKeys: handleScanKeys,
455
461
  loadKeyInfo: handleLoadKeyInfo,
456
462
  callMethod: handleCallMethod,
457
463
  loadKeyTableRange: handleLoadKeyTableRange,
@@ -117,7 +117,7 @@ async function handleExecuteControlCommand({ command }) {
117
117
  }
118
118
  }
119
119
 
120
- async function handleExecuteQuery({ sql, autoCommit }) {
120
+ async function handleExecuteQuery({ sql, autoCommit, limitRows }) {
121
121
  lastActivity = new Date().getTime();
122
122
 
123
123
  await waitConnected();
@@ -146,7 +146,7 @@ async function handleExecuteQuery({ sql, autoCommit }) {
146
146
  ...driver.getQuerySplitterOptions('stream'),
147
147
  returnRichInfo: true,
148
148
  })) {
149
- await handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem);
149
+ await handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem, undefined, limitRows);
150
150
  // const handler = new StreamHandler(resultIndex);
151
151
  // const stream = await driver.stream(systemConnection, sqlItem, handler);
152
152
  // handler.stream = stream;
@@ -14,6 +14,7 @@ const logger = getLogger('execQuery');
14
14
  * @param {string} [options.sql] - SQL query
15
15
  * @param {string} [options.sqlFile] - SQL file
16
16
  * @param {boolean} [options.logScriptItems] - whether to log script items instead of whole script
17
+ * @param {boolean} [options.skipLogging] - whether to skip logging
17
18
  */
18
19
  async function executeQuery({
19
20
  connection = undefined,
@@ -22,8 +23,9 @@ async function executeQuery({
22
23
  sql,
23
24
  sqlFile = undefined,
24
25
  logScriptItems = false,
26
+ skipLogging = false,
25
27
  }) {
26
- if (!logScriptItems) {
28
+ if (!logScriptItems && !skipLogging) {
27
29
  logger.info({ sql: getLimitedQuery(sql) }, `Execute query`);
28
30
  }
29
31
 
@@ -36,7 +38,9 @@ async function executeQuery({
36
38
  }
37
39
 
38
40
  try {
39
- logger.debug(`Running SQL query, length: ${sql.length}`);
41
+ if (!skipLogging) {
42
+ logger.debug(`Running SQL query, length: ${sql.length}`);
43
+ }
40
44
 
41
45
  await driver.script(dbhan, sql, { logScriptItems });
42
46
  } finally {
@@ -4,6 +4,7 @@ const fs = require('fs');
4
4
  const _ = require('lodash');
5
5
 
6
6
  const { jsldir } = require('../utility/directories');
7
+ const { serializeJsTypesReplacer } = require('dbgate-tools');
7
8
 
8
9
  class QueryStreamTableWriter {
9
10
  constructor(sesid = undefined) {
@@ -38,7 +39,7 @@ class QueryStreamTableWriter {
38
39
 
39
40
  row(row) {
40
41
  // console.log('ACCEPT ROW', row);
41
- this.currentStream.write(JSON.stringify(row) + '\n');
42
+ this.currentStream.write(JSON.stringify(row, serializeJsTypesReplacer) + '\n');
42
43
  this.currentRowCount += 1;
43
44
 
44
45
  if (!this.plannedStats) {
@@ -81,20 +82,27 @@ class QueryStreamTableWriter {
81
82
  }
82
83
 
83
84
  close(afterClose) {
84
- if (this.currentStream) {
85
- this.currentStream.end(() => {
86
- this.writeCurrentStats(true, true);
87
- if (afterClose) afterClose();
88
- });
89
- }
85
+ return new Promise(resolve => {
86
+ if (this.currentStream) {
87
+ this.currentStream.end(() => {
88
+ this.writeCurrentStats(true, true);
89
+ if (afterClose) afterClose();
90
+ resolve();
91
+ });
92
+ } else {
93
+ resolve();
94
+ }
95
+ });
90
96
  }
91
97
  }
92
98
 
93
99
  class StreamHandler {
94
- constructor(queryStreamInfoHolder, resolve, startLine, sesid = undefined) {
100
+ constructor(queryStreamInfoHolder, resolve, startLine, sesid = undefined, limitRows = undefined) {
95
101
  this.recordset = this.recordset.bind(this);
96
102
  this.startLine = startLine;
97
103
  this.sesid = sesid;
104
+ this.limitRows = limitRows;
105
+ this.rowsLimitOverflow = false;
98
106
  this.row = this.row.bind(this);
99
107
  // this.error = this.error.bind(this);
100
108
  this.done = this.done.bind(this);
@@ -106,6 +114,7 @@ class StreamHandler {
106
114
  this.plannedStats = false;
107
115
  this.queryStreamInfoHolder = queryStreamInfoHolder;
108
116
  this.resolve = resolve;
117
+ this.rowCounter = 0;
109
118
  // currentHandlers = [...currentHandlers, this];
110
119
  }
111
120
 
@@ -117,6 +126,9 @@ class StreamHandler {
117
126
  }
118
127
 
119
128
  recordset(columns) {
129
+ if (this.rowsLimitOverflow) {
130
+ return;
131
+ }
120
132
  this.closeCurrentWriter();
121
133
  this.currentWriter = new QueryStreamTableWriter(this.sesid);
122
134
  this.currentWriter.initializeFromQuery(
@@ -124,6 +136,7 @@ class StreamHandler {
124
136
  this.queryStreamInfoHolder.resultIndex
125
137
  );
126
138
  this.queryStreamInfoHolder.resultIndex += 1;
139
+ this.rowCounter = 0;
127
140
 
128
141
  // this.writeCurrentStats();
129
142
 
@@ -134,8 +147,36 @@ class StreamHandler {
134
147
  // }, 500);
135
148
  }
136
149
  row(row) {
137
- if (this.currentWriter) this.currentWriter.row(row);
138
- else if (row.message) process.send({ msgtype: 'info', info: { message: row.message }, sesid: this.sesid });
150
+ if (this.rowsLimitOverflow) {
151
+ return;
152
+ }
153
+
154
+ if (this.limitRows && this.rowCounter >= this.limitRows) {
155
+ process.send({
156
+ msgtype: 'info',
157
+ info: { message: `Rows limit overflow, loaded ${this.rowCounter} rows, canceling query`, severity: 'error' },
158
+ sesid: this.sesid,
159
+ });
160
+ this.rowsLimitOverflow = true;
161
+
162
+ this.queryStreamInfoHolder.canceled = true;
163
+ if (this.currentWriter) {
164
+ this.currentWriter.close().then(() => {
165
+ process.exit(0);
166
+ });
167
+ } else {
168
+ process.exit(0);
169
+ }
170
+
171
+ return;
172
+ }
173
+
174
+ if (this.currentWriter) {
175
+ this.currentWriter.row(row);
176
+ this.rowCounter += 1;
177
+ } else if (row.message) {
178
+ process.send({ msgtype: 'info', info: { message: row.message }, sesid: this.sesid });
179
+ }
139
180
  // this.onRow(this.jslid);
140
181
  }
141
182
  // error(error) {
@@ -160,10 +201,10 @@ class StreamHandler {
160
201
  }
161
202
  }
162
203
 
163
- function handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem, sesid = undefined) {
204
+ function handleQueryStream(dbhan, driver, queryStreamInfoHolder, sqlItem, sesid = undefined, limitRows = undefined) {
164
205
  return new Promise((resolve, reject) => {
165
206
  const start = sqlItem.trimStart || sqlItem.start;
166
- const handler = new StreamHandler(queryStreamInfoHolder, resolve, start && start.line, sesid);
207
+ const handler = new StreamHandler(queryStreamInfoHolder, resolve, start && start.line, sesid, limitRows);
167
208
  driver.stream(dbhan, sqlItem.text, handler);
168
209
  });
169
210
  }