dbgate-api-premium 5.5.7-alpha.45

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.
Files changed (125) hide show
  1. package/.env +19 -0
  2. package/.yarnrc +2 -0
  3. package/README.md +1 -0
  4. package/env/dblogin/.env +14 -0
  5. package/env/portal/.env +70 -0
  6. package/env/singledb/.env +17 -0
  7. package/env/storage/.env +43 -0
  8. package/package.json +89 -0
  9. package/src/auth/authCommon.js +16 -0
  10. package/src/auth/authProvider.js +343 -0
  11. package/src/auth/storageAuthProvider.js +393 -0
  12. package/src/controllers/apps.js +280 -0
  13. package/src/controllers/archive.js +217 -0
  14. package/src/controllers/auth.js +136 -0
  15. package/src/controllers/config.js +271 -0
  16. package/src/controllers/connections.js +486 -0
  17. package/src/controllers/databaseConnections.js +561 -0
  18. package/src/controllers/files.js +222 -0
  19. package/src/controllers/jsldata.js +296 -0
  20. package/src/controllers/metadata.js +47 -0
  21. package/src/controllers/plugins.js +216 -0
  22. package/src/controllers/queryHistory.js +54 -0
  23. package/src/controllers/runners.js +234 -0
  24. package/src/controllers/scheduler.js +46 -0
  25. package/src/controllers/serverConnections.js +271 -0
  26. package/src/controllers/sessions.js +243 -0
  27. package/src/controllers/storage.js +380 -0
  28. package/src/controllers/storageDb.js +215 -0
  29. package/src/controllers/uploads.js +133 -0
  30. package/src/currentVersion.js +5 -0
  31. package/src/gistSecret.js +2 -0
  32. package/src/index.js +139 -0
  33. package/src/main.js +202 -0
  34. package/src/packagedPluginsContent.js +1 -0
  35. package/src/proc/connectProcess.js +38 -0
  36. package/src/proc/databaseConnectionProcess.js +431 -0
  37. package/src/proc/index.js +15 -0
  38. package/src/proc/jslDatastoreProcess.js +60 -0
  39. package/src/proc/serverConnectionProcess.js +188 -0
  40. package/src/proc/sessionProcess.js +390 -0
  41. package/src/proc/sshForwardProcess.js +75 -0
  42. package/src/shell/archiveReader.js +11 -0
  43. package/src/shell/archiveWriter.js +22 -0
  44. package/src/shell/autoIndexForeignKeysTransform.js +19 -0
  45. package/src/shell/collectorWriter.js +33 -0
  46. package/src/shell/consoleObjectWriter.js +16 -0
  47. package/src/shell/copyStream.js +48 -0
  48. package/src/shell/dataDuplicator.js +63 -0
  49. package/src/shell/dataTypeMapperTransform.js +21 -0
  50. package/src/shell/dbModelToJson.js +16 -0
  51. package/src/shell/deployDb.js +56 -0
  52. package/src/shell/download.js +15 -0
  53. package/src/shell/dropAllDbObjects.js +42 -0
  54. package/src/shell/dumpDatabase.js +49 -0
  55. package/src/shell/executeQuery.js +39 -0
  56. package/src/shell/fakeObjectReader.js +35 -0
  57. package/src/shell/finalizer.js +12 -0
  58. package/src/shell/generateDeploySql.js +95 -0
  59. package/src/shell/generateModelSql.js +30 -0
  60. package/src/shell/importDatabase.js +85 -0
  61. package/src/shell/index.js +80 -0
  62. package/src/shell/initializeApiEnvironment.js +9 -0
  63. package/src/shell/jslDataReader.js +9 -0
  64. package/src/shell/jsonLinesReader.js +52 -0
  65. package/src/shell/jsonLinesWriter.js +36 -0
  66. package/src/shell/jsonReader.js +84 -0
  67. package/src/shell/jsonToDbModel.js +9 -0
  68. package/src/shell/jsonWriter.js +97 -0
  69. package/src/shell/loadDatabase.js +27 -0
  70. package/src/shell/loadFile.js +10 -0
  71. package/src/shell/modifyJsonLinesReader.js +148 -0
  72. package/src/shell/queryReader.js +30 -0
  73. package/src/shell/registerPlugins.js +9 -0
  74. package/src/shell/requirePlugin.js +43 -0
  75. package/src/shell/runScript.js +19 -0
  76. package/src/shell/sqlDataWriter.js +52 -0
  77. package/src/shell/sqlTextReplacementTransform.js +32 -0
  78. package/src/shell/tableReader.js +39 -0
  79. package/src/shell/tableWriter.js +18 -0
  80. package/src/storageModel.js +819 -0
  81. package/src/utility/ColumnMapTransformStream.js +21 -0
  82. package/src/utility/DatastoreProxy.js +106 -0
  83. package/src/utility/EnsureStreamHeaderStream.js +31 -0
  84. package/src/utility/JsonLinesDatabase.js +148 -0
  85. package/src/utility/JsonLinesDatastore.js +232 -0
  86. package/src/utility/LineReader.js +88 -0
  87. package/src/utility/SSHConnection.js +251 -0
  88. package/src/utility/authProxy.js +133 -0
  89. package/src/utility/checkLicense.js +186 -0
  90. package/src/utility/childProcessChecker.js +21 -0
  91. package/src/utility/cleanDirectory.js +24 -0
  92. package/src/utility/cloudUpgrade.js +61 -0
  93. package/src/utility/connectUtility.js +111 -0
  94. package/src/utility/crypting.js +105 -0
  95. package/src/utility/diff2htmlPage.js +8 -0
  96. package/src/utility/directories.js +179 -0
  97. package/src/utility/downloadPackage.js +51 -0
  98. package/src/utility/downloader.js +25 -0
  99. package/src/utility/exceptions.js +9 -0
  100. package/src/utility/exportDbModel.js +31 -0
  101. package/src/utility/exportDbModelSql.js +80 -0
  102. package/src/utility/getChartExport.js +55 -0
  103. package/src/utility/getDiagramExport.js +25 -0
  104. package/src/utility/getExpressPath.js +10 -0
  105. package/src/utility/getJslFileName.js +16 -0
  106. package/src/utility/getMapExport.js +77 -0
  107. package/src/utility/hardwareFingerprint.js +89 -0
  108. package/src/utility/hasPermission.js +101 -0
  109. package/src/utility/importDbModel.js +9 -0
  110. package/src/utility/loadFilesRecursive.js +20 -0
  111. package/src/utility/loadModelFolder.js +29 -0
  112. package/src/utility/loadModelTransform.js +36 -0
  113. package/src/utility/pipeForkLogs.js +19 -0
  114. package/src/utility/platformInfo.js +62 -0
  115. package/src/utility/processArgs.js +39 -0
  116. package/src/utility/processComm.js +18 -0
  117. package/src/utility/requireEngineDriver.js +26 -0
  118. package/src/utility/requirePluginFunction.js +16 -0
  119. package/src/utility/socket.js +68 -0
  120. package/src/utility/sshTunnel.js +106 -0
  121. package/src/utility/sshTunnelProxy.js +36 -0
  122. package/src/utility/timingSafeCheckToken.js +9 -0
  123. package/src/utility/useController.js +99 -0
  124. package/tsconfig.json +13 -0
  125. package/webpack.config.js +55 -0
@@ -0,0 +1,561 @@
1
+ const connections = require('./connections');
2
+ const archive = require('./archive');
3
+ const socket = require('../utility/socket');
4
+ const { fork } = require('child_process');
5
+ const {
6
+ DatabaseAnalyser,
7
+ computeDbDiffRows,
8
+ getCreateObjectScript,
9
+ getAlterDatabaseScript,
10
+ generateDbPairingId,
11
+ matchPairedObjects,
12
+ extendDatabaseInfo,
13
+ modelCompareDbDiffOptions,
14
+ getLogger,
15
+ extractErrorLogData,
16
+ filterStructureBySchema,
17
+ } = require('dbgate-tools');
18
+ const { html, parse } = require('diff2html');
19
+ const { handleProcessCommunication } = require('../utility/processComm');
20
+ const config = require('./config');
21
+ const fs = require('fs-extra');
22
+ const exportDbModel = require('../utility/exportDbModel');
23
+ const { archivedir, resolveArchiveFolder, uploadsdir } = require('../utility/directories');
24
+ const path = require('path');
25
+ const importDbModel = require('../utility/importDbModel');
26
+ const requireEngineDriver = require('../utility/requireEngineDriver');
27
+ const generateDeploySql = require('../shell/generateDeploySql');
28
+ const { createTwoFilesPatch } = require('diff');
29
+ const diff2htmlPage = require('../utility/diff2htmlPage');
30
+ const processArgs = require('../utility/processArgs');
31
+ const { testConnectionPermission } = require('../utility/hasPermission');
32
+ const { MissingCredentialsError } = require('../utility/exceptions');
33
+ const pipeForkLogs = require('../utility/pipeForkLogs');
34
+ const crypto = require('crypto');
35
+ const loadModelTransform = require('../utility/loadModelTransform');
36
+ const exportDbModelSql = require('../utility/exportDbModelSql');
37
+
38
+ const logger = getLogger('databaseConnections');
39
+
40
+ module.exports = {
41
+ /** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
42
+ opened: [],
43
+ closed: {},
44
+ requests: {},
45
+
46
+ async _init() {
47
+ connections._closeAll = conid => this.closeAll(conid);
48
+ },
49
+
50
+ handle_structure(conid, database, { structure }) {
51
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
52
+ if (!existing) return;
53
+ existing.structure = structure;
54
+ socket.emitChanged('database-structure-changed', { conid, database });
55
+ },
56
+ handle_structureTime(conid, database, { analysedTime }) {
57
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
58
+ if (!existing) return;
59
+ existing.analysedTime = analysedTime;
60
+ socket.emitChanged(`database-status-changed`, { conid, database });
61
+ },
62
+ handle_version(conid, database, { version }) {
63
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
64
+ if (!existing) return;
65
+ existing.serverVersion = version;
66
+ socket.emitChanged(`database-server-version-changed`, { conid, database });
67
+ },
68
+
69
+ handle_error(conid, database, props) {
70
+ const { error } = props;
71
+ logger.error(`Error in database connection ${conid}, database ${database}: ${error}`);
72
+ },
73
+ handle_response(conid, database, { msgid, ...response }) {
74
+ const [resolve, reject] = this.requests[msgid];
75
+ resolve(response);
76
+ delete this.requests[msgid];
77
+ },
78
+ handle_status(conid, database, { status }) {
79
+ // console.log('HANDLE SET STATUS', status);
80
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
81
+ if (!existing) return;
82
+ if (existing.status && status && existing.status.counter > status.counter) return;
83
+ existing.status = status;
84
+ socket.emitChanged(`database-status-changed`, { conid, database });
85
+ },
86
+
87
+ handle_ping() {},
88
+
89
+ async ensureOpened(conid, database) {
90
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
91
+ if (existing) return existing;
92
+ const connection = await connections.getCore({ conid });
93
+ if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
94
+ throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });
95
+ }
96
+ if (connection.useRedirectDbLogin) {
97
+ throw new MissingCredentialsError({ conid, redirectToDbLogin: true });
98
+ }
99
+ const subprocess = fork(
100
+ global['API_PACKAGE'] || process.argv[1],
101
+ [
102
+ '--is-forked-api',
103
+ '--start-process',
104
+ 'databaseConnectionProcess',
105
+ ...processArgs.getPassArgs(),
106
+ // ...process.argv.slice(3),
107
+ ],
108
+ {
109
+ stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
110
+ }
111
+ );
112
+ pipeForkLogs(subprocess);
113
+ const lastClosed = this.closed[`${conid}/${database}`];
114
+ const newOpened = {
115
+ conid,
116
+ database,
117
+ subprocess,
118
+ structure: lastClosed ? lastClosed.structure : DatabaseAnalyser.createEmptyStructure(),
119
+ serverVersion: lastClosed ? lastClosed.serverVersion : null,
120
+ connection,
121
+ status: { name: 'pending' },
122
+ };
123
+ this.opened.push(newOpened);
124
+ subprocess.on('message', message => {
125
+ // @ts-ignore
126
+ const { msgtype } = message;
127
+ if (handleProcessCommunication(message, subprocess)) return;
128
+ if (newOpened.disconnected) return;
129
+ this[`handle_${msgtype}`](conid, database, message);
130
+ });
131
+ subprocess.on('exit', () => {
132
+ if (newOpened.disconnected) return;
133
+ this.close(conid, database, false);
134
+ });
135
+
136
+ subprocess.send({
137
+ msgtype: 'connect',
138
+ connection: { ...connection, database },
139
+ structure: lastClosed ? lastClosed.structure : null,
140
+ globalSettings: await config.getSettings(),
141
+ });
142
+ return newOpened;
143
+ },
144
+
145
+ /** @param {import('dbgate-types').OpenedDatabaseConnection} conn */
146
+ sendRequest(conn, message) {
147
+ const msgid = crypto.randomUUID();
148
+ const promise = new Promise((resolve, reject) => {
149
+ this.requests[msgid] = [resolve, reject];
150
+ try {
151
+ conn.subprocess.send({ msgid, ...message });
152
+ } catch (err) {
153
+ logger.error(extractErrorLogData(err), 'Error sending request do process');
154
+ this.close(conn.conid, conn.database);
155
+ }
156
+ });
157
+ return promise;
158
+ },
159
+
160
+ queryData_meta: true,
161
+ async queryData({ conid, database, sql }, req) {
162
+ testConnectionPermission(conid, req);
163
+ logger.info({ conid, database, sql }, 'Processing query');
164
+ const opened = await this.ensureOpened(conid, database);
165
+ // if (opened && opened.status && opened.status.name == 'error') {
166
+ // return opened.status;
167
+ // }
168
+ const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
169
+ return res;
170
+ },
171
+
172
+ sqlSelect_meta: true,
173
+ async sqlSelect({ conid, database, select }, req) {
174
+ testConnectionPermission(conid, req);
175
+ const opened = await this.ensureOpened(conid, database);
176
+ const res = await this.sendRequest(opened, { msgtype: 'sqlSelect', select });
177
+ return res;
178
+ },
179
+
180
+ runScript_meta: true,
181
+ async runScript({ conid, database, sql, useTransaction }, req) {
182
+ testConnectionPermission(conid, req);
183
+ logger.info({ conid, database, sql }, 'Processing script');
184
+ const opened = await this.ensureOpened(conid, database);
185
+ const res = await this.sendRequest(opened, { msgtype: 'runScript', sql, useTransaction });
186
+ return res;
187
+ },
188
+
189
+ runOperation_meta: true,
190
+ async runOperation({ conid, database, operation, useTransaction }, req) {
191
+ testConnectionPermission(conid, req);
192
+ logger.info({ conid, database, operation }, 'Processing operation');
193
+ const opened = await this.ensureOpened(conid, database);
194
+ const res = await this.sendRequest(opened, { msgtype: 'runOperation', operation, useTransaction });
195
+ return res;
196
+ },
197
+
198
+ collectionData_meta: true,
199
+ async collectionData({ conid, database, options }, req) {
200
+ testConnectionPermission(conid, req);
201
+ const opened = await this.ensureOpened(conid, database);
202
+ const res = await this.sendRequest(opened, { msgtype: 'collectionData', options });
203
+ return res.result || null;
204
+ },
205
+
206
+ async loadDataCore(msgtype, { conid, database, ...args }, req) {
207
+ testConnectionPermission(conid, req);
208
+ const opened = await this.ensureOpened(conid, database);
209
+ const res = await this.sendRequest(opened, { msgtype, ...args });
210
+ if (res.errorMessage) {
211
+ console.error(res.errorMessage);
212
+
213
+ return {
214
+ errorMessage: res.errorMessage,
215
+ };
216
+ }
217
+ return res.result || null;
218
+ },
219
+
220
+ schemaList_meta: true,
221
+ async schemaList({ conid, database }, req) {
222
+ testConnectionPermission(conid, req);
223
+ return this.loadDataCore('schemaList', { conid, database });
224
+ },
225
+
226
+ dispatchDatabaseChangedEvent_meta: true,
227
+ dispatchDatabaseChangedEvent({ event, conid, database }) {
228
+ socket.emitChanged(event, { conid, database });
229
+ },
230
+
231
+ loadKeys_meta: true,
232
+ async loadKeys({ conid, database, root, filter }, req) {
233
+ testConnectionPermission(conid, req);
234
+ return this.loadDataCore('loadKeys', { conid, database, root, filter });
235
+ },
236
+
237
+ exportKeys_meta: true,
238
+ async exportKeys({ conid, database, options }, req) {
239
+ testConnectionPermission(conid, req);
240
+ return this.loadDataCore('exportKeys', { conid, database, options });
241
+ },
242
+
243
+ loadKeyInfo_meta: true,
244
+ async loadKeyInfo({ conid, database, key }, req) {
245
+ testConnectionPermission(conid, req);
246
+ return this.loadDataCore('loadKeyInfo', { conid, database, key });
247
+ },
248
+
249
+ loadKeyTableRange_meta: true,
250
+ async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
251
+ testConnectionPermission(conid, req);
252
+ return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
253
+ },
254
+
255
+ loadFieldValues_meta: true,
256
+ async loadFieldValues({ conid, database, schemaName, pureName, field, search }, req) {
257
+ testConnectionPermission(conid, req);
258
+ return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search });
259
+ },
260
+
261
+ callMethod_meta: true,
262
+ async callMethod({ conid, database, method, args }, req) {
263
+ testConnectionPermission(conid, req);
264
+ return this.loadDataCore('callMethod', { conid, database, method, args });
265
+
266
+ // const opened = await this.ensureOpened(conid, database);
267
+ // const res = await this.sendRequest(opened, { msgtype: 'callMethod', method, args });
268
+ // if (res.errorMessage) {
269
+ // console.error(res.errorMessage);
270
+ // }
271
+ // return res.result || null;
272
+ },
273
+
274
+ updateCollection_meta: true,
275
+ async updateCollection({ conid, database, changeSet }, req) {
276
+ testConnectionPermission(conid, req);
277
+ const opened = await this.ensureOpened(conid, database);
278
+ const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
279
+ if (res.errorMessage) {
280
+ return {
281
+ errorMessage: res.errorMessage,
282
+ };
283
+ }
284
+ return res.result || null;
285
+ },
286
+
287
+ status_meta: true,
288
+ async status({ conid, database }, req) {
289
+ if (!conid) {
290
+ return {
291
+ name: 'error',
292
+ message: 'No connection',
293
+ };
294
+ }
295
+ testConnectionPermission(conid, req);
296
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
297
+ if (existing) {
298
+ return {
299
+ ...existing.status,
300
+ analysedTime: existing.analysedTime,
301
+ };
302
+ }
303
+ const lastClosed = this.closed[`${conid}/${database}`];
304
+ if (lastClosed) {
305
+ return {
306
+ ...lastClosed.status,
307
+ analysedTime: lastClosed.analysedTime,
308
+ };
309
+ }
310
+ return {
311
+ name: 'error',
312
+ message: 'Not connected',
313
+ };
314
+ },
315
+
316
+ ping_meta: true,
317
+ async ping({ conid, database }, req) {
318
+ testConnectionPermission(conid, req);
319
+ let existing = this.opened.find(x => x.conid == conid && x.database == database);
320
+
321
+ if (existing) {
322
+ try {
323
+ existing.subprocess.send({ msgtype: 'ping' });
324
+ } catch (err) {
325
+ logger.error(extractErrorLogData(err), 'Error pinging DB connection');
326
+ this.close(conid, database);
327
+
328
+ return {
329
+ status: 'error',
330
+ message: 'Ping failed',
331
+ };
332
+ }
333
+ } else {
334
+ // @ts-ignore
335
+ existing = await this.ensureOpened(conid, database);
336
+ }
337
+
338
+ return {
339
+ status: 'ok',
340
+ connectionStatus: existing ? existing.status : null,
341
+ };
342
+ },
343
+
344
+ refresh_meta: true,
345
+ async refresh({ conid, database, keepOpen }, req) {
346
+ testConnectionPermission(conid, req);
347
+ if (!keepOpen) this.close(conid, database);
348
+
349
+ await this.ensureOpened(conid, database);
350
+ return { status: 'ok' };
351
+ },
352
+
353
+ syncModel_meta: true,
354
+ async syncModel({ conid, database, isFullRefresh }, req) {
355
+ if (conid == '__model') {
356
+ socket.emitChanged('database-structure-changed', { conid, database });
357
+ return { status: 'ok' };
358
+ }
359
+
360
+ testConnectionPermission(conid, req);
361
+ const conn = await this.ensureOpened(conid, database);
362
+ conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
363
+ return { status: 'ok' };
364
+ },
365
+
366
+ close(conid, database, kill = true) {
367
+ const existing = this.opened.find(x => x.conid == conid && x.database == database);
368
+ if (existing) {
369
+ existing.disconnected = true;
370
+ if (kill) {
371
+ try {
372
+ existing.subprocess.kill();
373
+ } catch (err) {
374
+ logger.error(extractErrorLogData(err), 'Error killing subprocess');
375
+ }
376
+ }
377
+ this.opened = this.opened.filter(x => x.conid != conid || x.database != database);
378
+ this.closed[`${conid}/${database}`] = {
379
+ status: {
380
+ ...existing.status,
381
+ name: 'error',
382
+ },
383
+ structure: existing.structure,
384
+ };
385
+ socket.emitChanged(`database-status-changed`, { conid, database });
386
+ }
387
+ },
388
+
389
+ closeAll(conid, kill = true) {
390
+ for (const existing of this.opened.filter(x => x.conid == conid)) {
391
+ this.close(conid, existing.database, kill);
392
+ }
393
+ },
394
+
395
+ disconnect_meta: true,
396
+ async disconnect({ conid, database }, req) {
397
+ testConnectionPermission(conid, req);
398
+ await this.close(conid, database, true);
399
+ return { status: 'ok' };
400
+ },
401
+
402
+ structure_meta: true,
403
+ async structure({ conid, database, modelTransFile = null }, req) {
404
+ testConnectionPermission(conid, req);
405
+ if (conid == '__model') {
406
+ const model = await importDbModel(database);
407
+ const trans = await loadModelTransform(modelTransFile);
408
+ return trans ? trans(model) : model;
409
+ }
410
+
411
+ const opened = await this.ensureOpened(conid, database);
412
+ return opened.structure;
413
+ // const existing = this.opened.find((x) => x.conid == conid && x.database == database);
414
+ // if (existing) return existing.status;
415
+ // return {
416
+ // name: 'error',
417
+ // message: 'Not connected',
418
+ // };
419
+ },
420
+
421
+ serverVersion_meta: true,
422
+ async serverVersion({ conid, database }, req) {
423
+ if (!conid) {
424
+ return null;
425
+ }
426
+ testConnectionPermission(conid, req);
427
+ if (!conid) return null;
428
+ const opened = await this.ensureOpened(conid, database);
429
+ return opened.serverVersion || null;
430
+ },
431
+
432
+ sqlPreview_meta: true,
433
+ async sqlPreview({ conid, database, objects, options }, req) {
434
+ testConnectionPermission(conid, req);
435
+ // wait for structure
436
+ await this.structure({ conid, database });
437
+
438
+ const opened = await this.ensureOpened(conid, database);
439
+ const res = await this.sendRequest(opened, { msgtype: 'sqlPreview', objects, options });
440
+ return res;
441
+ },
442
+
443
+ exportModel_meta: true,
444
+ async exportModel({ conid, database, outputFolder, schema }, req) {
445
+ testConnectionPermission(conid, req);
446
+
447
+ const realFolder = outputFolder.startsWith('archive:')
448
+ ? resolveArchiveFolder(outputFolder.substring('archive:'.length))
449
+ : outputFolder;
450
+
451
+ const model = await this.structure({ conid, database });
452
+ const filteredModel = schema ? filterStructureBySchema(model, schema) : model;
453
+ await exportDbModel(extendDatabaseInfo(filteredModel), realFolder);
454
+
455
+ if (outputFolder.startsWith('archive:')) {
456
+ socket.emitChanged(`archive-files-changed`, { folder: outputFolder.substring('archive:'.length) });
457
+ }
458
+ return { status: 'ok' };
459
+ },
460
+
461
+ exportModelSql_meta: true,
462
+ async exportModelSql({ conid, database, outputFolder, outputFile, schema }, req) {
463
+ testConnectionPermission(conid, req);
464
+
465
+ const connection = await connections.getCore({ conid });
466
+ const driver = requireEngineDriver(connection);
467
+
468
+ const model = await this.structure({ conid, database });
469
+ const filteredModel = schema ? filterStructureBySchema(model, schema) : model;
470
+ await exportDbModelSql(extendDatabaseInfo(filteredModel), driver, outputFolder, outputFile);
471
+
472
+ return { status: 'ok' };
473
+ },
474
+
475
+ generateDeploySql_meta: true,
476
+ async generateDeploySql({ conid, database, archiveFolder }, req) {
477
+ testConnectionPermission(conid, req);
478
+ const opened = await this.ensureOpened(conid, database);
479
+ const res = await this.sendRequest(opened, {
480
+ msgtype: 'generateDeploySql',
481
+ modelFolder: resolveArchiveFolder(archiveFolder),
482
+ });
483
+ return res;
484
+
485
+ // const connection = await connections.get({ conid });
486
+ // return generateDeploySql({
487
+ // connection,
488
+ // analysedStructure: await this.structure({ conid, database }),
489
+ // modelFolder: resolveArchiveFolder(archiveFolder),
490
+ // });
491
+
492
+ // const deployedModel = generateDbPairingId(await importDbModel(path.join(archivedir(), archiveFolder)));
493
+ // const currentModel = generateDbPairingId(await this.structure({ conid, database }));
494
+ // const currentModelPaired = matchPairedObjects(deployedModel, currentModel);
495
+ // const connection = await connections.get({ conid });
496
+ // const driver = requireEngineDriver(connection);
497
+ // const { sql } = getAlterDatabaseScript(currentModelPaired, deployedModel, {}, deployedModel, driver);
498
+ // return {
499
+ // deployedModel,
500
+ // currentModel,
501
+ // currentModelPaired,
502
+ // sql,
503
+ // };
504
+ // return sql;
505
+ },
506
+ // runCommand_meta: true,
507
+ // async runCommand({ conid, database, sql }) {
508
+ // console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`);
509
+ // const opened = await this.ensureOpened(conid, database);
510
+ // const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
511
+ // return res;
512
+ // },
513
+
514
+ async getUnifiedDiff({ sourceConid, sourceDatabase, targetConid, targetDatabase }) {
515
+ const dbDiffOptions = sourceConid == '__model' ? modelCompareDbDiffOptions : {};
516
+
517
+ const sourceDb = generateDbPairingId(
518
+ extendDatabaseInfo(await this.structure({ conid: sourceConid, database: sourceDatabase }))
519
+ );
520
+ const targetDb = generateDbPairingId(
521
+ extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
522
+ );
523
+ // const sourceConnection = await connections.getCore({conid:sourceConid})
524
+ const connection = await connections.getCore({ conid: targetConid });
525
+ const driver = requireEngineDriver(connection);
526
+ const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
527
+ const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
528
+
529
+ // console.log('sourceDb', sourceDb);
530
+ // console.log('targetDb', targetDb);
531
+ // console.log('sourceConid, sourceDatabase', sourceConid, sourceDatabase);
532
+
533
+ let res = '';
534
+ for (const row of diffRows) {
535
+ // console.log('PAIR', row.source && row.source.pureName, row.target && row.target.pureName);
536
+ const unifiedDiff = createTwoFilesPatch(
537
+ (row.target && row.target.pureName) || '',
538
+ (row.source && row.source.pureName) || '',
539
+ getCreateObjectScript(row.target, driver),
540
+ getCreateObjectScript(row.source, driver),
541
+ '',
542
+ ''
543
+ );
544
+ res += unifiedDiff;
545
+ }
546
+ return res;
547
+ },
548
+
549
+ generateDbDiffReport_meta: true,
550
+ async generateDbDiffReport({ filePath, sourceConid, sourceDatabase, targetConid, targetDatabase }) {
551
+ const unifiedDiff = await this.getUnifiedDiff({ sourceConid, sourceDatabase, targetConid, targetDatabase });
552
+
553
+ const diffJson = parse(unifiedDiff);
554
+ // $: diffHtml = html(diffJson, { outputFormat: 'side-by-side', drawFileList: false });
555
+ const diffHtml = html(diffJson, { outputFormat: 'side-by-side' });
556
+
557
+ await fs.writeFile(filePath, diff2htmlPage(diffHtml));
558
+
559
+ return true;
560
+ },
561
+ };