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,222 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const crypto = require('crypto');
4
+ const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir } = require('../utility/directories');
5
+ const getChartExport = require('../utility/getChartExport');
6
+ const { hasPermission } = require('../utility/hasPermission');
7
+ const socket = require('../utility/socket');
8
+ const scheduler = require('./scheduler');
9
+ const getDiagramExport = require('../utility/getDiagramExport');
10
+ const apps = require('./apps');
11
+ const getMapExport = require('../utility/getMapExport');
12
+
13
+ function serialize(format, data) {
14
+ if (format == 'text') return data;
15
+ if (format == 'json') return JSON.stringify(data);
16
+ throw new Error(`Invalid format: ${format}`);
17
+ }
18
+
19
+ function deserialize(format, text) {
20
+ if (format == 'text') return text;
21
+ if (format == 'json') return JSON.parse(text);
22
+ throw new Error(`Invalid format: ${format}`);
23
+ }
24
+
25
+ module.exports = {
26
+ list_meta: true,
27
+ async list({ folder }, req) {
28
+ if (!hasPermission(`files/${folder}/read`, req)) return [];
29
+ const dir = path.join(filesdir(), folder);
30
+ if (!(await fs.exists(dir))) return [];
31
+ const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
32
+ return files;
33
+ },
34
+
35
+ listAll_meta: true,
36
+ async listAll(_params, req) {
37
+ const folders = await fs.readdir(filesdir());
38
+ const res = [];
39
+ for (const folder of folders) {
40
+ if (!hasPermission(`files/${folder}/read`, req)) continue;
41
+ const dir = path.join(filesdir(), folder);
42
+ const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
43
+ res.push(...files);
44
+ }
45
+ return res;
46
+ },
47
+
48
+ delete_meta: true,
49
+ async delete({ folder, file }, req) {
50
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
51
+ await fs.unlink(path.join(filesdir(), folder, file));
52
+ socket.emitChanged(`files-changed`, { folder });
53
+ socket.emitChanged(`all-files-changed`);
54
+ return true;
55
+ },
56
+
57
+ rename_meta: true,
58
+ async rename({ folder, file, newFile }, req) {
59
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
60
+ await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
61
+ socket.emitChanged(`files-changed`, { folder });
62
+ socket.emitChanged(`all-files-changed`);
63
+ return true;
64
+ },
65
+
66
+ refresh_meta: true,
67
+ async refresh({ folders }, req) {
68
+ for (const folder of folders) {
69
+ socket.emitChanged(`files-changed`, { folder });
70
+ socket.emitChanged(`all-files-changed`);
71
+ }
72
+ return true;
73
+ },
74
+
75
+ copy_meta: true,
76
+ async copy({ folder, file, newFile }, req) {
77
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
78
+ await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
79
+ socket.emitChanged(`files-changed`, { folder });
80
+ socket.emitChanged(`all-files-changed`);
81
+ return true;
82
+ },
83
+
84
+ load_meta: true,
85
+ async load({ folder, file, format }, req) {
86
+ if (folder.startsWith('archive:')) {
87
+ const text = await fs.readFile(path.join(resolveArchiveFolder(folder.substring('archive:'.length)), file), {
88
+ encoding: 'utf-8',
89
+ });
90
+ return deserialize(format, text);
91
+ } else if (folder.startsWith('app:')) {
92
+ const text = await fs.readFile(path.join(appdir(), folder.substring('app:'.length), file), {
93
+ encoding: 'utf-8',
94
+ });
95
+ return deserialize(format, text);
96
+ } else {
97
+ if (!hasPermission(`files/${folder}/read`, req)) return null;
98
+ const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
99
+ return deserialize(format, text);
100
+ }
101
+ },
102
+
103
+ loadFrom_meta: true,
104
+ async loadFrom({ filePath, format }, req) {
105
+ const text = await fs.readFile(filePath, { encoding: 'utf-8' });
106
+ return deserialize(format, text);
107
+ },
108
+
109
+ save_meta: true,
110
+ async save({ folder, file, data, format }, req) {
111
+ if (folder.startsWith('archive:')) {
112
+ if (!hasPermission(`archive/write`, req)) return false;
113
+ const dir = resolveArchiveFolder(folder.substring('archive:'.length));
114
+ await fs.writeFile(path.join(dir, file), serialize(format, data));
115
+ socket.emitChanged(`archive-files-changed`, { folder: folder.substring('archive:'.length) });
116
+ return true;
117
+ } else if (folder.startsWith('app:')) {
118
+ if (!hasPermission(`apps/write`, req)) return false;
119
+ const app = folder.substring('app:'.length);
120
+ await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
121
+ socket.emitChanged(`app-files-changed`, { app });
122
+ socket.emitChanged('used-apps-changed');
123
+ apps.emitChangedDbApp(folder);
124
+ return true;
125
+ } else {
126
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
127
+ const dir = path.join(filesdir(), folder);
128
+ if (!(await fs.exists(dir))) {
129
+ await fs.mkdir(dir);
130
+ }
131
+ await fs.writeFile(path.join(dir, file), serialize(format, data));
132
+ socket.emitChanged(`files-changed`, { folder });
133
+ socket.emitChanged(`all-files-changed`);
134
+ if (folder == 'shell') {
135
+ scheduler.reload();
136
+ }
137
+ return true;
138
+ }
139
+ },
140
+
141
+ saveAs_meta: true,
142
+ async saveAs({ filePath, data, format }) {
143
+ await fs.writeFile(filePath, serialize(format, data));
144
+ },
145
+
146
+ favorites_meta: true,
147
+ async favorites(_params, req) {
148
+ if (!hasPermission(`files/favorites/read`, req)) return [];
149
+ const dir = path.join(filesdir(), 'favorites');
150
+ if (!(await fs.exists(dir))) return [];
151
+ const files = await fs.readdir(dir);
152
+ const res = [];
153
+ for (const file of files) {
154
+ const filePath = path.join(dir, file);
155
+ const text = await fs.readFile(filePath, { encoding: 'utf-8' });
156
+ res.push({
157
+ file,
158
+ folder: 'favorites',
159
+ ...JSON.parse(text),
160
+ });
161
+ }
162
+ return res;
163
+ },
164
+
165
+ generateUploadsFile_meta: true,
166
+ async generateUploadsFile({ extension }) {
167
+ const fileName = `${crypto.randomUUID()}.${extension || 'html'}`;
168
+ return {
169
+ fileName,
170
+ filePath: path.join(uploadsdir(), fileName),
171
+ };
172
+ },
173
+
174
+ exportChart_meta: true,
175
+ async exportChart({ filePath, title, config, image }) {
176
+ const fileName = path.parse(filePath).base;
177
+ const imageFile = fileName.replace('.html', '-preview.png');
178
+ const html = getChartExport(title, config, imageFile);
179
+ await fs.writeFile(filePath, html);
180
+ if (image) {
181
+ const index = image.indexOf('base64,');
182
+ if (index > 0) {
183
+ const data = image.substr(index + 'base64,'.length);
184
+ const buf = Buffer.from(data, 'base64');
185
+ await fs.writeFile(filePath.replace('.html', '-preview.png'), buf);
186
+ }
187
+ }
188
+ return true;
189
+ },
190
+
191
+ exportMap_meta: true,
192
+ async exportMap({ filePath, geoJson }) {
193
+ await fs.writeFile(filePath, getMapExport(geoJson));
194
+ return true;
195
+ },
196
+
197
+ exportDiagram_meta: true,
198
+ async exportDiagram({ filePath, html, css, themeType, themeClassName }) {
199
+ await fs.writeFile(filePath, getDiagramExport(html, css, themeType, themeClassName));
200
+ return true;
201
+ },
202
+
203
+ getFileRealPath_meta: true,
204
+ async getFileRealPath({ folder, file }, req) {
205
+ if (folder.startsWith('archive:')) {
206
+ if (!hasPermission(`archive/write`, req)) return false;
207
+ const dir = resolveArchiveFolder(folder.substring('archive:'.length));
208
+ return path.join(dir, file);
209
+ } else if (folder.startsWith('app:')) {
210
+ if (!hasPermission(`apps/write`, req)) return false;
211
+ const app = folder.substring('app:'.length);
212
+ return path.join(appdir(), app, file);
213
+ } else {
214
+ if (!hasPermission(`files/${folder}/write`, req)) return false;
215
+ const dir = path.join(filesdir(), folder);
216
+ if (!(await fs.exists(dir))) {
217
+ await fs.mkdir(dir);
218
+ }
219
+ return path.join(dir, file);
220
+ }
221
+ },
222
+ };
@@ -0,0 +1,296 @@
1
+ const { filterName } = require('dbgate-tools');
2
+ const fs = require('fs');
3
+ const lineReader = require('line-reader');
4
+ const _ = require('lodash');
5
+ const { __ } = require('lodash/fp');
6
+ const DatastoreProxy = require('../utility/DatastoreProxy');
7
+ const getJslFileName = require('../utility/getJslFileName');
8
+ const JsonLinesDatastore = require('../utility/JsonLinesDatastore');
9
+ const requirePluginFunction = require('../utility/requirePluginFunction');
10
+ const socket = require('../utility/socket');
11
+
12
+ function readFirstLine(file) {
13
+ return new Promise((resolve, reject) => {
14
+ lineReader.open(file, (err, reader) => {
15
+ if (err) {
16
+ reject(err);
17
+ return;
18
+ }
19
+ if (reader.hasNextLine()) {
20
+ reader.nextLine((err, line) => {
21
+ if (err) {
22
+ reader.close(() => reject(err)); // Ensure reader is closed on error
23
+ return;
24
+ }
25
+ reader.close(() => resolve(line)); // Ensure reader is closed after reading
26
+ });
27
+ } else {
28
+ reader.close(() => resolve(null)); // Properly close if no lines are present
29
+ }
30
+ });
31
+ });
32
+ }
33
+
34
+ module.exports = {
35
+ datastores: {},
36
+
37
+ // closeReader(jslid) {
38
+ // // console.log('CLOSING READER');
39
+ // if (!this.openedReaders[jslid]) return Promise.resolve();
40
+ // return new Promise((resolve, reject) => {
41
+ // this.openedReaders[jslid].reader.close((err) => {
42
+ // if (err) reject(err);
43
+ // delete this.openedReaders[jslid];
44
+ // resolve();
45
+ // });
46
+ // });
47
+ // },
48
+
49
+ // readLine(readerInfo) {
50
+ // return new Promise((resolve, reject) => {
51
+ // const { reader } = readerInfo;
52
+ // if (!reader.hasNextLine()) {
53
+ // resolve(null);
54
+ // return;
55
+ // }
56
+ // reader.nextLine((err, line) => {
57
+ // if (readerInfo.readedSchemaRow) readerInfo.readedDataRowCount += 1;
58
+ // else readerInfo.readedSchemaRow = true;
59
+ // if (err) reject(err);
60
+ // resolve(line);
61
+ // });
62
+ // });
63
+ // },
64
+
65
+ // openReader(jslid) {
66
+ // // console.log('OPENING READER');
67
+ // // console.log(
68
+ // // 'OPENING READER, LINES=',
69
+ // // fs.readFileSync(path.join(jsldir(), `${jslid}.jsonl`), 'utf-8').split('\n').length
70
+ // // );
71
+ // const file = getJslFileName(jslid);
72
+ // return new Promise((resolve, reject) =>
73
+ // lineReader.open(file, (err, reader) => {
74
+ // if (err) reject(err);
75
+ // const readerInfo = {
76
+ // reader,
77
+ // readedDataRowCount: 0,
78
+ // readedSchemaRow: false,
79
+ // isReading: true,
80
+ // };
81
+ // this.openedReaders[jslid] = readerInfo;
82
+ // resolve(readerInfo);
83
+ // })
84
+ // );
85
+ // },
86
+
87
+ // async ensureReader(jslid, offset) {
88
+ // if (this.openedReaders[jslid] && this.openedReaders[jslid].readedDataRowCount > offset) {
89
+ // await this.closeReader(jslid);
90
+ // }
91
+ // let readerInfo = this.openedReaders[jslid];
92
+ // if (!this.openedReaders[jslid]) {
93
+ // readerInfo = await this.openReader(jslid);
94
+ // }
95
+ // readerInfo.isReading = true;
96
+ // if (!readerInfo.readedSchemaRow) {
97
+ // await this.readLine(readerInfo); // skip structure
98
+ // }
99
+ // while (readerInfo.readedDataRowCount < offset) {
100
+ // await this.readLine(readerInfo);
101
+ // }
102
+ // return readerInfo;
103
+ // },
104
+
105
+ async ensureDatastore(jslid, formatterFunction) {
106
+ let datastore = this.datastores[jslid];
107
+ if (!datastore || datastore.formatterFunction != formatterFunction) {
108
+ if (datastore) {
109
+ datastore._closeReader();
110
+ }
111
+ datastore = new JsonLinesDatastore(getJslFileName(jslid), formatterFunction);
112
+ // datastore = new DatastoreProxy(getJslFileName(jslid));
113
+ this.datastores[jslid] = datastore;
114
+ }
115
+ return datastore;
116
+ },
117
+
118
+ async closeDataStore(jslid) {
119
+ const datastore = this.datastores[jslid];
120
+ if (datastore) {
121
+ await datastore._closeReader();
122
+ delete this.datastores[jslid];
123
+ }
124
+ },
125
+
126
+ getInfo_meta: true,
127
+ async getInfo({ jslid }) {
128
+ const file = getJslFileName(jslid);
129
+ try {
130
+ const firstLine = await readFirstLine(file);
131
+ if (firstLine) {
132
+ const parsed = JSON.parse(firstLine);
133
+ if (parsed.__isStreamHeader) {
134
+ return parsed;
135
+ }
136
+ return {
137
+ __isStreamHeader: true,
138
+ __isDynamicStructure: true,
139
+ };
140
+ }
141
+ return null;
142
+ } catch (err) {
143
+ return null;
144
+ }
145
+ },
146
+
147
+ getRows_meta: true,
148
+ async getRows({ jslid, offset, limit, filters, sort, formatterFunction }) {
149
+ const datastore = await this.ensureDatastore(jslid, formatterFunction);
150
+ return datastore.getRows(offset, limit, _.isEmpty(filters) ? null : filters, _.isEmpty(sort) ? null : sort);
151
+ },
152
+
153
+ exists_meta: true,
154
+ async exists({ jslid }) {
155
+ const fileName = getJslFileName(jslid);
156
+ return fs.existsSync(fileName);
157
+ },
158
+
159
+ getStats_meta: true,
160
+ getStats({ jslid }) {
161
+ const file = `${getJslFileName(jslid)}.stats`;
162
+ if (fs.existsSync(file)) {
163
+ try {
164
+ return JSON.parse(fs.readFileSync(file, 'utf-8'));
165
+ } catch (e) {
166
+ return {};
167
+ }
168
+ }
169
+ return {};
170
+ },
171
+
172
+ loadFieldValues_meta: true,
173
+ async loadFieldValues({ jslid, field, search, formatterFunction }) {
174
+ const datastore = await this.ensureDatastore(jslid, formatterFunction);
175
+ const res = new Set();
176
+ await datastore.enumRows(row => {
177
+ if (!filterName(search, row[field])) return true;
178
+ res.add(row[field]);
179
+ return res.size < 100;
180
+ });
181
+ // @ts-ignore
182
+ return [...res].map(value => ({ value }));
183
+ },
184
+
185
+ async notifyChangedStats(stats) {
186
+ // console.log('SENDING STATS', JSON.stringify(stats));
187
+ const datastore = this.datastores[stats.jslid];
188
+ if (datastore) await datastore.notifyChanged();
189
+ socket.emit(`jsldata-stats-${stats.jslid}`, stats);
190
+
191
+ // const readerInfo = this.openedReaders[stats.jslid];
192
+ // if (readerInfo && readerInfo.isReading) {
193
+ // readerInfo.closeAfterReadAndSendStats = stats;
194
+ // } else {
195
+ // await this.closeReader(stats.jslid);
196
+ // socket.emit(`jsldata-stats-${stats.jslid}`, stats);
197
+ // }
198
+ },
199
+
200
+ saveText_meta: true,
201
+ async saveText({ jslid, text }) {
202
+ await fs.promises.writeFile(getJslFileName(jslid), text);
203
+ return true;
204
+ },
205
+
206
+ saveRows_meta: true,
207
+ async saveRows({ jslid, rows }) {
208
+ const fileStream = fs.createWriteStream(getJslFileName(jslid));
209
+ for (const row of rows) {
210
+ await fileStream.write(JSON.stringify(row) + '\n');
211
+ }
212
+ await fileStream.close();
213
+ return true;
214
+ },
215
+
216
+ extractTimelineChart_meta: true,
217
+ async extractTimelineChart({ jslid, timestampFunction, aggregateFunction, measures }) {
218
+ const timestamp = requirePluginFunction(timestampFunction);
219
+ const aggregate = requirePluginFunction(aggregateFunction);
220
+ const datastore = new JsonLinesDatastore(getJslFileName(jslid));
221
+ let mints = null;
222
+ let maxts = null;
223
+ // pass 1 - counts stats, time range
224
+ await datastore.enumRows(row => {
225
+ const ts = timestamp(row);
226
+ if (!mints || ts < mints) mints = ts;
227
+ if (!maxts || ts > maxts) maxts = ts;
228
+ return true;
229
+ });
230
+ const minTime = new Date(mints).getTime();
231
+ const maxTime = new Date(maxts).getTime();
232
+ const duration = maxTime - minTime;
233
+ const STEPS = 100;
234
+ let stepCount = duration > 100 * 1000 ? STEPS : Math.round((maxTime - minTime) / 1000);
235
+ if (stepCount < 2) {
236
+ stepCount = 2;
237
+ }
238
+ const stepDuration = duration / stepCount;
239
+ const labels = _.range(stepCount).map(i => new Date(minTime + stepDuration / 2 + stepDuration * i));
240
+
241
+ // const datasets = measures.map(m => ({
242
+ // label: m.label,
243
+ // data: Array(stepCount).fill(0),
244
+ // }));
245
+
246
+ const mproc = measures.map(m => ({
247
+ ...m,
248
+ }));
249
+
250
+ const data = Array(stepCount)
251
+ .fill(0)
252
+ .map(() => ({}));
253
+
254
+ // pass 2 - count measures
255
+ await datastore.enumRows(row => {
256
+ const ts = timestamp(row);
257
+ let part = Math.round((new Date(ts).getTime() - minTime) / stepDuration);
258
+ if (part < 0) part = 0;
259
+ if (part >= stepCount) part - stepCount - 1;
260
+ if (data[part]) {
261
+ data[part] = aggregate(data[part], row, stepDuration);
262
+ }
263
+ return true;
264
+ });
265
+
266
+ datastore._closeReader();
267
+
268
+ // const measureByField = _.fromPairs(measures.map((m, i) => [m.field, i]));
269
+
270
+ // for (let mindex = 0; mindex < measures.length; mindex++) {
271
+ // for (let stepIndex = 0; stepIndex < stepCount; stepIndex++) {
272
+ // const measure = measures[mindex];
273
+ // if (measure.perSecond) {
274
+ // datasets[mindex].data[stepIndex] /= stepDuration / 1000;
275
+ // }
276
+ // if (measure.perField) {
277
+ // datasets[mindex].data[stepIndex] /= datasets[measureByField[measure.perField]].data[stepIndex];
278
+ // }
279
+ // }
280
+ // }
281
+
282
+ // for (let i = 0; i < measures.length; i++) {
283
+ // if (measures[i].hidden) {
284
+ // datasets[i] = null;
285
+ // }
286
+ // }
287
+
288
+ return {
289
+ labels,
290
+ datasets: mproc.map(m => ({
291
+ label: m.label,
292
+ data: data.map(d => d[m.field] || 0),
293
+ })),
294
+ };
295
+ },
296
+ };
@@ -0,0 +1,47 @@
1
+ const _ = require('lodash');
2
+ const fp = require('lodash/fp');
3
+ const databaseConnections = require('./databaseConnections');
4
+
5
+ function pickObjectNames(array) {
6
+ return _.sortBy(array, x => `${x.schemaName}.${x.pureName}`).map(fp.pick(['pureName', 'schemaName']));
7
+ }
8
+
9
+ module.exports = {
10
+ // tableData_meta: true,
11
+ // async tableData({ conid, database, schemaName, pureName }) {
12
+ // const opened = await databaseConnections.ensureOpened(conid, database);
13
+ // const res = await databaseConnections.sendRequest(opened, { msgtype: 'tableData', schemaName, pureName });
14
+ // return res;
15
+ // },
16
+
17
+ listObjects_meta: true,
18
+ async listObjects({ conid, database }) {
19
+ const opened = await databaseConnections.ensureOpened(conid, database);
20
+ const types = ['tables', 'collections', 'views', 'procedures', 'functions', 'triggers'];
21
+ return types.reduce(
22
+ (res, type) => ({
23
+ ...res,
24
+ [type]: pickObjectNames(opened.structure[type]),
25
+ }),
26
+ {}
27
+ );
28
+ },
29
+
30
+ tableInfo_meta: true,
31
+ async tableInfo({ conid, database, schemaName, pureName }) {
32
+ const opened = await databaseConnections.ensureOpened(conid, database);
33
+ const table = opened.structure.tables.find(x => x.pureName == pureName && x.schemaName == schemaName);
34
+ const allForeignKeys = _.flatten(opened.structure.tables.map(x => x.foreignKeys));
35
+ return {
36
+ ...table,
37
+ dependencies: allForeignKeys.filter(x => x.refSchemaName == schemaName && x.refTableName == pureName),
38
+ };
39
+ },
40
+
41
+ sqlObjectInfo_meta: true,
42
+ async sqlObjectInfo({ objectTypeField, conid, database, schemaName, pureName }) {
43
+ const opened = await databaseConnections.ensureOpened(conid, database);
44
+ const res = opened.structure[objectTypeField].find(x => x.pureName == pureName && x.schemaName == schemaName);
45
+ return res;
46
+ },
47
+ };