dbgate-api-premium 6.2.0 → 6.2.1

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.2.0",
4
+ "version": "6.2.1",
5
5
  "homepage": "https://dbgate.org/",
6
6
  "repository": {
7
7
  "type": "git",
@@ -29,10 +29,10 @@
29
29
  "compare-versions": "^3.6.0",
30
30
  "cors": "^2.8.5",
31
31
  "cross-env": "^6.0.3",
32
- "dbgate-datalib": "^6.2.0",
32
+ "dbgate-datalib": "^6.2.1",
33
33
  "dbgate-query-splitter": "^4.11.3",
34
- "dbgate-sqltree": "^6.2.0",
35
- "dbgate-tools": "^6.2.0",
34
+ "dbgate-sqltree": "^6.2.1",
35
+ "dbgate-tools": "^6.2.1",
36
36
  "debug": "^4.3.4",
37
37
  "diff": "^5.0.0",
38
38
  "diff2html": "^3.4.13",
@@ -83,7 +83,7 @@
83
83
  "devDependencies": {
84
84
  "@types/fs-extra": "^9.0.11",
85
85
  "@types/lodash": "^4.14.149",
86
- "dbgate-types": "^6.2.0",
86
+ "dbgate-types": "^6.2.1",
87
87
  "env-cmd": "^10.1.0",
88
88
  "jsdoc-to-markdown": "^9.0.5",
89
89
  "node-loader": "^1.0.2",
@@ -56,12 +56,19 @@ module.exports = {
56
56
  handle_done(sesid, props) {
57
57
  socket.emit(`session-done-${sesid}`);
58
58
  if (!props.skipFinishedMessage) {
59
- this.dispatchMessage(sesid, 'Query execution finished');
59
+ if (props.controlCommand) {
60
+ this.dispatchMessage(sesid, `${_.startCase(props.controlCommand)} finished`);
61
+ } else {
62
+ this.dispatchMessage(sesid, 'Query execution finished');
63
+ }
60
64
  }
61
65
  const session = this.opened.find(x => x.sesid == sesid);
62
66
  if (session.loadingReader_jslid) {
63
67
  socket.emit(`session-jslid-done-${session.loadingReader_jslid}`);
64
68
  }
69
+ if (props.autoCommit) {
70
+ this.executeControlCommand({ sesid, command: 'commitTransaction' });
71
+ }
65
72
  if (session.killOnDone) {
66
73
  this.kill({ sesid });
67
74
  }
@@ -131,7 +138,7 @@ module.exports = {
131
138
  },
132
139
 
133
140
  executeQuery_meta: true,
134
- async executeQuery({ sesid, sql }) {
141
+ async executeQuery({ sesid, sql, autoCommit }) {
135
142
  const session = this.opened.find(x => x.sesid == sesid);
136
143
  if (!session) {
137
144
  throw new Error('Invalid session');
@@ -139,7 +146,21 @@ module.exports = {
139
146
 
140
147
  logger.info({ sesid, sql }, 'Processing query');
141
148
  this.dispatchMessage(sesid, 'Query execution started');
142
- session.subprocess.send({ msgtype: 'executeQuery', sql });
149
+ session.subprocess.send({ msgtype: 'executeQuery', sql, autoCommit });
150
+
151
+ return { state: 'ok' };
152
+ },
153
+
154
+ executeControlCommand_meta: true,
155
+ async executeControlCommand({ sesid, command }) {
156
+ const session = this.opened.find(x => x.sesid == sesid);
157
+ if (!session) {
158
+ throw new Error('Invalid session');
159
+ }
160
+
161
+ logger.info({ sesid, command }, 'Processing control command');
162
+ this.dispatchMessage(sesid, `${_.startCase(command)} started`);
163
+ session.subprocess.send({ msgtype: 'executeControlCommand', command });
143
164
 
144
165
  return { state: 'ok' };
145
166
  },
@@ -1,5 +1,5 @@
1
1
 
2
2
  module.exports = {
3
- version: '6.2.0',
4
- buildTime: '2025-02-14T13:58:57.650Z'
3
+ version: '6.2.1',
4
+ buildTime: '2025-02-28T09:57:07.127Z'
5
5
  };
@@ -245,7 +245,47 @@ async function handleStopProfiler({ jslid }) {
245
245
  currentProfiler = null;
246
246
  }
247
247
 
248
- async function handleExecuteQuery({ sql }) {
248
+ async function handleExecuteControlCommand({ command }) {
249
+ lastActivity = new Date().getTime();
250
+
251
+ await waitConnected();
252
+ const driver = requireEngineDriver(storedConnection);
253
+
254
+ if (command == 'commitTransaction' && !allowExecuteCustomScript(driver)) {
255
+ process.send({
256
+ msgtype: 'info',
257
+ info: {
258
+ message: 'Connection without read-only sessions is read only',
259
+ severity: 'error',
260
+ },
261
+ });
262
+ process.send({ msgtype: 'done', skipFinishedMessage: true });
263
+ return;
264
+ //process.send({ msgtype: 'error', error: e.message });
265
+ }
266
+
267
+ executingScripts++;
268
+ try {
269
+ const dmp = driver.createDumper();
270
+ switch (command) {
271
+ case 'commitTransaction':
272
+ await dmp.commitTransaction();
273
+ break;
274
+ case 'rollbackTransaction':
275
+ await dmp.rollbackTransaction();
276
+ break;
277
+ case 'beginTransaction':
278
+ await dmp.beginTransaction();
279
+ break;
280
+ }
281
+ await driver.query(dbhan, dmp.s, { discardResult: true });
282
+ process.send({ msgtype: 'done', controlCommand: command });
283
+ } finally {
284
+ executingScripts--;
285
+ }
286
+ }
287
+
288
+ async function handleExecuteQuery({ sql, autoCommit }) {
249
289
  lastActivity = new Date().getTime();
250
290
 
251
291
  await waitConnected();
@@ -279,7 +319,7 @@ async function handleExecuteQuery({ sql }) {
279
319
  // handler.stream = stream;
280
320
  // resultIndex = handler.resultIndex;
281
321
  }
282
- process.send({ msgtype: 'done' });
322
+ process.send({ msgtype: 'done', autoCommit });
283
323
  } finally {
284
324
  executingScripts--;
285
325
  }
@@ -323,6 +363,7 @@ function handlePing() {
323
363
  const messageHandlers = {
324
364
  connect: handleConnect,
325
365
  executeQuery: handleExecuteQuery,
366
+ executeControlCommand: handleExecuteControlCommand,
326
367
  executeReader: handleExecuteReader,
327
368
  startProfiler: handleStartProfiler,
328
369
  stopProfiler: handleStopProfiler,
@@ -0,0 +1,110 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const executeQuery = require('./executeQuery');
4
+ const { connectUtility } = require('../utility/connectUtility');
5
+ const requireEngineDriver = require('../utility/requireEngineDriver');
6
+ const { getAlterDatabaseScript, DatabaseAnalyser, runCommandOnDriver } = require('dbgate-tools');
7
+ const importDbModel = require('../utility/importDbModel');
8
+ const jsonLinesReader = require('./jsonLinesReader');
9
+ const tableWriter = require('./tableWriter');
10
+ const copyStream = require('./copyStream');
11
+
12
+ /**
13
+ * Deploys database model stored in modelFolder (table as yamls) to database
14
+ * @param {object} options
15
+ * @param {connectionType} options.connection - connection object
16
+ * @param {object} options.systemConnection - system connection (result of driver.connect). If not provided, new connection will be created
17
+ * @param {object} options.driver - driver object. If not provided, it will be loaded from connection
18
+ * @param {string} options.folder - folder with model files (YAML files for tables, SQL files for views, procedures, ...)
19
+ * @param {function[]} options.modelTransforms - array of functions for transforming model
20
+ */
21
+ async function importDbFromFolder({ connection, systemConnection, driver, folder, modelTransforms }) {
22
+ if (!driver) driver = requireEngineDriver(connection);
23
+ const dbhan = systemConnection || (await connectUtility(driver, connection, 'read'));
24
+
25
+ try {
26
+ const model = await importDbModel(folder);
27
+
28
+ let modelAdapted = {
29
+ ...model,
30
+ tables: model.tables.map(table => driver.adaptTableInfo(table)),
31
+ };
32
+ for (const transform of modelTransforms || []) {
33
+ modelAdapted = transform(modelAdapted);
34
+ }
35
+
36
+ const modelNoFk = {
37
+ ...modelAdapted,
38
+ tables: modelAdapted.tables.map(table => ({
39
+ ...table,
40
+ foreignKeys: [],
41
+ })),
42
+ };
43
+
44
+ // const plan = createAlterDatabasePlan(
45
+ // DatabaseAnalyser.createEmptyStructure(),
46
+ // driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk,
47
+ // {},
48
+ // DatabaseAnalyser.createEmptyStructure(),
49
+ // driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk,
50
+ // driver
51
+ // );
52
+ // const dmp1 = driver.createDumper({ useHardSeparator: true });
53
+ // if (driver.dialect.enableAllForeignKeys) {
54
+ // dmp1.enableAllForeignKeys(false);
55
+ // }
56
+ // plan.run(dmp1);
57
+ // if (driver.dialect.enableAllForeignKeys) {
58
+ // dmp1.enableAllForeignKeys(true);
59
+ // }
60
+
61
+ const { sql } = getAlterDatabaseScript(
62
+ DatabaseAnalyser.createEmptyStructure(),
63
+ driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk,
64
+ {},
65
+ DatabaseAnalyser.createEmptyStructure(),
66
+ driver.dialect.enableAllForeignKeys ? modelAdapted : modelNoFk,
67
+ driver
68
+ );
69
+ // console.log('CREATING STRUCTURE:', sql);
70
+ await executeQuery({ connection, systemConnection: dbhan, driver, sql, logScriptItems: true });
71
+
72
+ if (driver.dialect.enableAllForeignKeys) {
73
+ await runCommandOnDriver(dbhan, driver, dmp => dmp.enableAllForeignKeys(false));
74
+ }
75
+
76
+ for (const table of modelAdapted.tables) {
77
+ const fileName = path.join(folder, `${table.pureName}.jsonl`);
78
+ if (await fs.exists(fileName)) {
79
+ const src = await jsonLinesReader({ fileName });
80
+ const dst = await tableWriter({
81
+ systemConnection: dbhan,
82
+ pureName: table.pureName,
83
+ driver,
84
+ targetTableStructure: table,
85
+ });
86
+ await copyStream(src, dst);
87
+ }
88
+ }
89
+
90
+ if (driver.dialect.enableAllForeignKeys) {
91
+ await runCommandOnDriver(dbhan, driver, dmp => dmp.enableAllForeignKeys(true));
92
+ } else if (driver.dialect.createForeignKey) {
93
+ const dmp = driver.createDumper();
94
+ for (const table of modelAdapted.tables) {
95
+ for (const fk of table.foreignKeys) {
96
+ dmp.createForeignKey(fk);
97
+ }
98
+ }
99
+
100
+ // create foreign keys
101
+ await executeQuery({ connection, systemConnection: dbhan, driver, sql: dmp.s, logScriptItems: true });
102
+ }
103
+ } finally {
104
+ if (!systemConnection) {
105
+ await driver.close(dbhan);
106
+ }
107
+ }
108
+ }
109
+
110
+ module.exports = importDbFromFolder;
@@ -35,6 +35,7 @@ const sqlTextReplacementTransform = require('./sqlTextReplacementTransform');
35
35
  const autoIndexForeignKeysTransform = require('./autoIndexForeignKeysTransform');
36
36
  const generateDeploySql = require('./generateDeploySql');
37
37
  const dropAllDbObjects = require('./dropAllDbObjects');
38
+ const importDbFromFolder = require('./importDbFromFolder');
38
39
 
39
40
  const dbgateApi = {
40
41
  queryReader,
@@ -73,6 +74,7 @@ const dbgateApi = {
73
74
  autoIndexForeignKeysTransform,
74
75
  generateDeploySql,
75
76
  dropAllDbObjects,
77
+ importDbFromFolder,
76
78
  };
77
79
 
78
80
  requirePlugin.initializeDbgateApi(dbgateApi);
@@ -15,6 +15,7 @@ const logger = getLogger('tableWriter');
15
15
  * @param {boolean} options.truncate - truncate table before insert
16
16
  * @param {boolean} options.createIfNotExists - create table if not exists
17
17
  * @param {boolean} options.commitAfterInsert - commit transaction after insert
18
+ * @param {any} options.targetTableStructure - target table structure (don't analyse if given)
18
19
  * @returns {Promise<writerType>} - writer object
19
20
  */
20
21
  async function tableWriter({ connection, schemaName, pureName, driver, systemConnection, ...options }) {