@sisense/sdk-pivot-query-client 2.17.0

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 (189) hide show
  1. package/LICENSE.md +35 -0
  2. package/README.md +2 -0
  3. package/dist/__test-helpers__/testUtils.d.ts +30 -0
  4. package/dist/__test-helpers__/testUtils.js +89 -0
  5. package/dist/builders/index.d.ts +2 -0
  6. package/dist/builders/index.js +2 -0
  7. package/dist/builders/pivot-data-builder.d.ts +34 -0
  8. package/dist/builders/pivot-data-builder.js +182 -0
  9. package/dist/builders/socket-builder.d.ts +18 -0
  10. package/dist/builders/socket-builder.js +72 -0
  11. package/dist/cjs/__test-helpers__/testUtils.d.ts +30 -0
  12. package/dist/cjs/__test-helpers__/testUtils.js +104 -0
  13. package/dist/cjs/builders/index.d.ts +2 -0
  14. package/dist/cjs/builders/index.js +7 -0
  15. package/dist/cjs/builders/pivot-data-builder.d.ts +34 -0
  16. package/dist/cjs/builders/pivot-data-builder.js +186 -0
  17. package/dist/cjs/builders/socket-builder.d.ts +18 -0
  18. package/dist/cjs/builders/socket-builder.js +79 -0
  19. package/dist/cjs/data-handling/DataService.d.ts +672 -0
  20. package/dist/cjs/data-handling/DataService.js +1364 -0
  21. package/dist/cjs/data-handling/DivergenceComparator.d.ts +7 -0
  22. package/dist/cjs/data-handling/DivergenceComparator.js +20 -0
  23. package/dist/cjs/data-handling/constants.d.ts +44 -0
  24. package/dist/cjs/data-handling/constants.js +43 -0
  25. package/dist/cjs/data-handling/index.d.ts +3 -0
  26. package/dist/cjs/data-handling/index.js +23 -0
  27. package/dist/cjs/data-handling/types.d.ts +104 -0
  28. package/dist/cjs/data-handling/types.js +2 -0
  29. package/dist/cjs/data-handling/utils/createPivotTreeNode.d.ts +13 -0
  30. package/dist/cjs/data-handling/utils/createPivotTreeNode.js +21 -0
  31. package/dist/cjs/data-handling/utils/index.d.ts +4 -0
  32. package/dist/cjs/data-handling/utils/index.js +14 -0
  33. package/dist/cjs/data-handling/utils/jaqlProcessor.d.ts +122 -0
  34. package/dist/cjs/data-handling/utils/jaqlProcessor.js +661 -0
  35. package/dist/cjs/data-handling/utils/pivotTransforms.d.ts +74 -0
  36. package/dist/cjs/data-handling/utils/pivotTransforms.js +373 -0
  37. package/dist/cjs/data-handling/utils/plugins/PluginService.d.ts +135 -0
  38. package/dist/cjs/data-handling/utils/plugins/PluginService.js +383 -0
  39. package/dist/cjs/data-handling/utils/plugins/getters.d.ts +23 -0
  40. package/dist/cjs/data-handling/utils/plugins/getters.js +70 -0
  41. package/dist/cjs/data-handling/utils/plugins/types.d.ts +75 -0
  42. package/dist/cjs/data-handling/utils/plugins/types.js +2 -0
  43. package/dist/cjs/data-handling/utils/plugins/validator.d.ts +13 -0
  44. package/dist/cjs/data-handling/utils/plugins/validator.js +169 -0
  45. package/dist/cjs/data-load/AbstractDataLoadService.d.ts +256 -0
  46. package/dist/cjs/data-load/AbstractDataLoadService.js +473 -0
  47. package/dist/cjs/data-load/DataLoadService.d.ts +63 -0
  48. package/dist/cjs/data-load/DataLoadService.js +152 -0
  49. package/dist/cjs/data-load/SisenseDataLoadService.d.ts +44 -0
  50. package/dist/cjs/data-load/SisenseDataLoadService.js +87 -0
  51. package/dist/cjs/data-load/TestDataLoadService.d.ts +27 -0
  52. package/dist/cjs/data-load/TestDataLoadService.js +76 -0
  53. package/dist/cjs/data-load/constants.d.ts +13 -0
  54. package/dist/cjs/data-load/constants.js +28 -0
  55. package/dist/cjs/data-load/index.d.ts +6 -0
  56. package/dist/cjs/data-load/index.js +14 -0
  57. package/dist/cjs/data-load/sockets/SisenseSocket.d.ts +81 -0
  58. package/dist/cjs/data-load/sockets/SisenseSocket.js +162 -0
  59. package/dist/cjs/data-load/sockets/TestSocket.d.ts +61 -0
  60. package/dist/cjs/data-load/sockets/TestSocket.js +90 -0
  61. package/dist/cjs/data-load/sockets/helpers.d.ts +4 -0
  62. package/dist/cjs/data-load/sockets/helpers.js +27 -0
  63. package/dist/cjs/data-load/sockets/index.d.ts +2 -0
  64. package/dist/cjs/data-load/sockets/index.js +8 -0
  65. package/dist/cjs/data-load/types.d.ts +90 -0
  66. package/dist/cjs/data-load/types.js +2 -0
  67. package/dist/cjs/errors/LoadingCanceledError.d.ts +7 -0
  68. package/dist/cjs/errors/LoadingCanceledError.js +24 -0
  69. package/dist/cjs/errors/index.d.ts +1 -0
  70. package/dist/cjs/errors/index.js +6 -0
  71. package/dist/cjs/index.d.ts +17 -0
  72. package/dist/cjs/index.js +32 -0
  73. package/dist/cjs/package.json +12 -0
  74. package/dist/cjs/pivot-query-client.d.ts +13 -0
  75. package/dist/cjs/pivot-query-client.js +26 -0
  76. package/dist/cjs/tree-structure/AbstractTreeService.d.ts +308 -0
  77. package/dist/cjs/tree-structure/AbstractTreeService.js +716 -0
  78. package/dist/cjs/tree-structure/HeaderTreeService.d.ts +180 -0
  79. package/dist/cjs/tree-structure/HeaderTreeService.js +280 -0
  80. package/dist/cjs/tree-structure/TreeCellMap.d.ts +104 -0
  81. package/dist/cjs/tree-structure/TreeCellMap.js +145 -0
  82. package/dist/cjs/tree-structure/TreeService.d.ts +8 -0
  83. package/dist/cjs/tree-structure/TreeService.js +12 -0
  84. package/dist/cjs/tree-structure/constants.d.ts +6 -0
  85. package/dist/cjs/tree-structure/constants.js +10 -0
  86. package/dist/cjs/tree-structure/index.d.ts +5 -0
  87. package/dist/cjs/tree-structure/index.js +10 -0
  88. package/dist/cjs/tree-structure/types.d.ts +93 -0
  89. package/dist/cjs/tree-structure/types.js +2 -0
  90. package/dist/cjs/tree-structure/utils/index.d.ts +1 -0
  91. package/dist/cjs/tree-structure/utils/index.js +9 -0
  92. package/dist/cjs/tree-structure/utils/treeNode.d.ts +147 -0
  93. package/dist/cjs/tree-structure/utils/treeNode.js +534 -0
  94. package/dist/cjs/utils/array.d.ts +13 -0
  95. package/dist/cjs/utils/array.js +25 -0
  96. package/dist/cjs/utils/cloneObject.d.ts +30 -0
  97. package/dist/cjs/utils/cloneObject.js +225 -0
  98. package/dist/cjs/utils/index.d.ts +3 -0
  99. package/dist/cjs/utils/index.js +9 -0
  100. package/dist/cjs/utils/throttle.d.ts +12 -0
  101. package/dist/cjs/utils/throttle.js +39 -0
  102. package/dist/cjs/utils/types.d.ts +12 -0
  103. package/dist/cjs/utils/types.js +2 -0
  104. package/dist/data-handling/DataService.d.ts +672 -0
  105. package/dist/data-handling/DataService.js +1357 -0
  106. package/dist/data-handling/DivergenceComparator.d.ts +7 -0
  107. package/dist/data-handling/DivergenceComparator.js +16 -0
  108. package/dist/data-handling/constants.d.ts +44 -0
  109. package/dist/data-handling/constants.js +40 -0
  110. package/dist/data-handling/index.d.ts +3 -0
  111. package/dist/data-handling/index.js +4 -0
  112. package/dist/data-handling/types.d.ts +104 -0
  113. package/dist/data-handling/types.js +1 -0
  114. package/dist/data-handling/utils/createPivotTreeNode.d.ts +13 -0
  115. package/dist/data-handling/utils/createPivotTreeNode.js +17 -0
  116. package/dist/data-handling/utils/index.d.ts +4 -0
  117. package/dist/data-handling/utils/index.js +4 -0
  118. package/dist/data-handling/utils/jaqlProcessor.d.ts +122 -0
  119. package/dist/data-handling/utils/jaqlProcessor.js +621 -0
  120. package/dist/data-handling/utils/pivotTransforms.d.ts +74 -0
  121. package/dist/data-handling/utils/pivotTransforms.js +335 -0
  122. package/dist/data-handling/utils/plugins/PluginService.d.ts +135 -0
  123. package/dist/data-handling/utils/plugins/PluginService.js +379 -0
  124. package/dist/data-handling/utils/plugins/getters.d.ts +23 -0
  125. package/dist/data-handling/utils/plugins/getters.js +65 -0
  126. package/dist/data-handling/utils/plugins/types.d.ts +75 -0
  127. package/dist/data-handling/utils/plugins/types.js +1 -0
  128. package/dist/data-handling/utils/plugins/validator.d.ts +13 -0
  129. package/dist/data-handling/utils/plugins/validator.js +165 -0
  130. package/dist/data-load/AbstractDataLoadService.d.ts +256 -0
  131. package/dist/data-load/AbstractDataLoadService.js +466 -0
  132. package/dist/data-load/DataLoadService.d.ts +63 -0
  133. package/dist/data-load/DataLoadService.js +148 -0
  134. package/dist/data-load/SisenseDataLoadService.d.ts +44 -0
  135. package/dist/data-load/SisenseDataLoadService.js +83 -0
  136. package/dist/data-load/TestDataLoadService.d.ts +27 -0
  137. package/dist/data-load/TestDataLoadService.js +69 -0
  138. package/dist/data-load/constants.d.ts +13 -0
  139. package/dist/data-load/constants.js +25 -0
  140. package/dist/data-load/index.d.ts +6 -0
  141. package/dist/data-load/index.js +6 -0
  142. package/dist/data-load/sockets/SisenseSocket.d.ts +81 -0
  143. package/dist/data-load/sockets/SisenseSocket.js +155 -0
  144. package/dist/data-load/sockets/TestSocket.d.ts +61 -0
  145. package/dist/data-load/sockets/TestSocket.js +83 -0
  146. package/dist/data-load/sockets/helpers.d.ts +4 -0
  147. package/dist/data-load/sockets/helpers.js +23 -0
  148. package/dist/data-load/sockets/index.d.ts +2 -0
  149. package/dist/data-load/sockets/index.js +3 -0
  150. package/dist/data-load/types.d.ts +90 -0
  151. package/dist/data-load/types.js +1 -0
  152. package/dist/errors/LoadingCanceledError.d.ts +7 -0
  153. package/dist/errors/LoadingCanceledError.js +20 -0
  154. package/dist/errors/index.d.ts +1 -0
  155. package/dist/errors/index.js +2 -0
  156. package/dist/index.d.ts +17 -0
  157. package/dist/index.js +9 -0
  158. package/dist/pivot-query-client.d.ts +13 -0
  159. package/dist/pivot-query-client.js +22 -0
  160. package/dist/tree-structure/AbstractTreeService.d.ts +308 -0
  161. package/dist/tree-structure/AbstractTreeService.js +712 -0
  162. package/dist/tree-structure/HeaderTreeService.d.ts +180 -0
  163. package/dist/tree-structure/HeaderTreeService.js +276 -0
  164. package/dist/tree-structure/TreeCellMap.d.ts +104 -0
  165. package/dist/tree-structure/TreeCellMap.js +141 -0
  166. package/dist/tree-structure/TreeService.d.ts +8 -0
  167. package/dist/tree-structure/TreeService.js +8 -0
  168. package/dist/tree-structure/constants.d.ts +6 -0
  169. package/dist/tree-structure/constants.js +7 -0
  170. package/dist/tree-structure/index.d.ts +5 -0
  171. package/dist/tree-structure/index.js +4 -0
  172. package/dist/tree-structure/types.d.ts +93 -0
  173. package/dist/tree-structure/types.js +1 -0
  174. package/dist/tree-structure/utils/index.d.ts +1 -0
  175. package/dist/tree-structure/utils/index.js +1 -0
  176. package/dist/tree-structure/utils/treeNode.d.ts +147 -0
  177. package/dist/tree-structure/utils/treeNode.js +515 -0
  178. package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -0
  179. package/dist/utils/array.d.ts +13 -0
  180. package/dist/utils/array.js +21 -0
  181. package/dist/utils/cloneObject.d.ts +30 -0
  182. package/dist/utils/cloneObject.js +221 -0
  183. package/dist/utils/index.d.ts +3 -0
  184. package/dist/utils/index.js +3 -0
  185. package/dist/utils/throttle.d.ts +12 -0
  186. package/dist/utils/throttle.js +35 -0
  187. package/dist/utils/types.d.ts +12 -0
  188. package/dist/utils/types.js +1 -0
  189. package/package.json +61 -0
@@ -0,0 +1,466 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import EventEmitter from 'events';
3
+ import { PanelType } from '../data-handling/constants.js';
4
+ import { cloneObject } from '../utils/index.js';
5
+ import { MESSAGES_ORDER, MessageType } from './constants.js';
6
+ const formattingProps = {
7
+ INCLUDE: [
8
+ 'metadata.$.jaql',
9
+ 'metadata.$.field',
10
+ 'metadata.$.panel',
11
+ 'metadata.$.hierarchies',
12
+ 'metadata.$.format',
13
+ 'metadata.$.disabled',
14
+ 'metadata.$.distinctTotals',
15
+ ],
16
+ EXCLUDE: [
17
+ 'metadata.$.jaql.title',
18
+ 'metadata.$.format.mask',
19
+ 'metadata.$.format.width',
20
+ 'queryGuid',
21
+ 'widget',
22
+ 'dashboard',
23
+ 'grandTotals.title',
24
+ ],
25
+ };
26
+ /**
27
+ * Initiate single socket connection and creates new PivotDataSource for each JAQL request
28
+ */
29
+ export class AbstractDataLoadService {
30
+ constructor(events) {
31
+ /**
32
+ * @private
33
+ *
34
+ * jaql request object
35
+ */
36
+ this.jaql = undefined;
37
+ /**
38
+ * @private
39
+ *
40
+ * cache object
41
+ */
42
+ this.data = undefined;
43
+ /**
44
+ * @private
45
+ *
46
+ * state for "load" method
47
+ */
48
+ this.isLoadInProgress = false;
49
+ /**
50
+ @private */
51
+ this.loadPromiseResolve = undefined;
52
+ /**
53
+ *
54
+ * @private
55
+ */
56
+ this.loadPromiseReject = undefined;
57
+ /**
58
+ * @private
59
+ *
60
+ * info about amount of data which already loaded from cache
61
+ */
62
+ this.loadFromCacheState = undefined;
63
+ /**
64
+ @private */
65
+ this.loadFromCacheInitialTimer = undefined;
66
+ /**
67
+ @private */
68
+ this.loadFromCacheTimer = undefined;
69
+ /**
70
+ * @private
71
+ *
72
+ * defines initial pivot data structure
73
+ */
74
+ this.isSingleBranchTree = false;
75
+ /**
76
+ * @private
77
+ *
78
+ * items count loaded on client side
79
+ */
80
+ this.loadedItemsCount = 0;
81
+ /**
82
+ * @private
83
+ *
84
+ * total items count on back-end side
85
+ */
86
+ this.totalItemsCount = 0;
87
+ /**
88
+ * @private
89
+ *
90
+ * defines if amount of data was limited on back-end or not
91
+ */
92
+ this.isLimited = false;
93
+ /**
94
+ * @private
95
+ *
96
+ * detects if finish event was received
97
+ */
98
+ this.isFinishEventReceived = false;
99
+ this.events = events || new EventEmitter();
100
+ }
101
+ /**
102
+ * Destroys data load service
103
+ *
104
+ * @returns {void}
105
+ */
106
+ destroy() {
107
+ this.data = undefined;
108
+ this.events.removeAllListeners();
109
+ }
110
+ /**
111
+ * Return copy of load service
112
+ *
113
+ * @returns {DataLoadService} - cloned instance
114
+ */
115
+ clone() {
116
+ throw new Error(`"AbstractDataLoadService.clone" should be overridden in subclass`);
117
+ }
118
+ /**
119
+ * Start data loading according to JAQL request
120
+ *
121
+ * @param {JaqlRequest} jaql - JAQL request
122
+ * @returns {Promise<any>} - whole data loading promise
123
+ */
124
+ load(jaql) {
125
+ if (!jaql) {
126
+ throw new Error(`AbstractDataLoadService "jaql" is not defined for "load" method`);
127
+ }
128
+ const shouldLoadFromCache = !!this.data;
129
+ const prevJaql = this.jaql;
130
+ this.jaql = jaql;
131
+ if (shouldLoadFromCache && prevJaql) {
132
+ // do not overwrite jaql queryGuid if data will be loaded from cache
133
+ // needed for sending cancel-query request with proper jaql queryGuid
134
+ this.jaql.queryGuid = prevJaql.queryGuid;
135
+ }
136
+ this.isLoadInProgress = true;
137
+ const loadPromise = new Promise((resolve, reject) => {
138
+ this.loadPromiseResolve = resolve;
139
+ this.loadPromiseReject = reject;
140
+ });
141
+ if (this.loadFromCacheInitialTimer) {
142
+ clearTimeout(this.loadFromCacheInitialTimer);
143
+ }
144
+ try {
145
+ if (shouldLoadFromCache) {
146
+ this.loadFromCache();
147
+ }
148
+ else {
149
+ this.loadFromServer();
150
+ }
151
+ }
152
+ catch (err) {
153
+ this.notifyAboutDataError(err);
154
+ }
155
+ return loadPromise;
156
+ }
157
+ /**
158
+ * Clear data cache
159
+ *
160
+ * @returns {void}
161
+ */
162
+ clear() {
163
+ this.data = undefined;
164
+ }
165
+ /**
166
+ * Returns current jaql request object
167
+ *
168
+ * @returns {JaqlRequest} - jaql request object
169
+ */
170
+ getJaql() {
171
+ return this.jaql;
172
+ }
173
+ /**
174
+ * Defines data structure
175
+ *
176
+ * @returns {boolean} - true - single branch tree
177
+ */
178
+ isSingleRowTree() {
179
+ return this.isSingleBranchTree;
180
+ }
181
+ /**
182
+ * Returns total amount items count handled on back-end side
183
+ *
184
+ * @returns {number} - items count
185
+ */
186
+ getTotalItemsCount() {
187
+ return this.totalItemsCount;
188
+ }
189
+ /**
190
+ * Defines if new jaql has only formatting changes or it requires new data loading from server
191
+ *
192
+ * @param {JaqlRequest} jaql - jaql request object
193
+ * @returns {boolean} - true - only formatting changes, can use cached data
194
+ */
195
+ isFormattingChanges(jaql) {
196
+ const currentFormatInfo = cloneObject(this.jaql, {
197
+ include: formattingProps.INCLUDE,
198
+ exclude: formattingProps.EXCLUDE,
199
+ excludeEmpty: true,
200
+ });
201
+ const newFormatInfo = cloneObject(jaql, {
202
+ include: formattingProps.INCLUDE,
203
+ exclude: formattingProps.EXCLUDE,
204
+ excludeEmpty: true,
205
+ });
206
+ [...((currentFormatInfo === null || currentFormatInfo === void 0 ? void 0 : currentFormatInfo.metadata) || []), ...((newFormatInfo === null || newFormatInfo === void 0 ? void 0 : newFormatInfo.metadata) || [])].forEach((panelItem) => {
207
+ if (panelItem && panelItem.panel === PanelType.SCOPE) {
208
+ delete panelItem.field;
209
+ }
210
+ });
211
+ return JSON.stringify(currentFormatInfo) === JSON.stringify(newFormatInfo);
212
+ }
213
+ /**
214
+ * Defines if service have some data
215
+ *
216
+ * @returns {boolean} - true - has some data
217
+ */
218
+ hasData() {
219
+ return !!(this.data && this.data[MessageType.DATA]);
220
+ }
221
+ /**
222
+ * Defines if service have some error
223
+ *
224
+ * @returns {boolean} - true - has some error
225
+ */
226
+ hasError() {
227
+ if (this.data) {
228
+ return !!this.data[MessageType.ERROR];
229
+ }
230
+ return false;
231
+ }
232
+ /**
233
+ * Start data loading from the server
234
+ *
235
+ * @returns {void}
236
+ * @private
237
+ */
238
+ loadFromServer() {
239
+ throw new Error(`"AbstractDataLoadService.loadFromServer" should be overridden in subclass`);
240
+ }
241
+ /**
242
+ * Method for canceling the processing of query already sent
243
+ *
244
+ * @returns {Promise<void>} - waiting promise
245
+ */
246
+ cancelQuery() {
247
+ const error = new Error(`"AbstractDataLoadService.cancelQuery" should be overridden in subclass.`);
248
+ return Promise.reject(error);
249
+ }
250
+ /**
251
+ * Method for detection if cancel query is still needed
252
+ *
253
+ * @returns {boolean} - is cancel query needed
254
+ */
255
+ isCancelQueryNeeded() {
256
+ return !this.isFinishEventReceived;
257
+ }
258
+ /**
259
+ * Start data loading from the cache
260
+ *
261
+ * @returns {Promise<void>} - waiting promise
262
+ * @private
263
+ */
264
+ loadFromCache() {
265
+ return Promise.resolve()
266
+ .then(() => {
267
+ if (this.loadFromCacheInitialTimer) {
268
+ clearTimeout(this.loadFromCacheInitialTimer);
269
+ }
270
+ return new Promise((resolve) => {
271
+ this.loadFromCacheInitialTimer = setTimeout(resolve);
272
+ // eslint-disable-next-line max-lines
273
+ });
274
+ })
275
+ .then(() => new Promise((resolve) => {
276
+ if (this.loadFromCacheTimer) {
277
+ clearImmediate(this.loadFromCacheTimer);
278
+ }
279
+ this.loadFromCacheState = undefined;
280
+ this.loadMessageFromCache(() => {
281
+ this.loadFromCacheState = undefined;
282
+ if (this.loadFromCacheTimer) {
283
+ clearImmediate(this.loadFromCacheTimer);
284
+ }
285
+ resolve();
286
+ });
287
+ }));
288
+ }
289
+ /**
290
+ * Starts loading data from cache queue
291
+ *
292
+ * @param {Function} onFinish - on finish callback
293
+ * @returns {void}
294
+ * @private
295
+ */
296
+ loadMessageFromCache(onFinish) {
297
+ // Note: removed `setImmediate` as not supported
298
+ this.loadFromCacheState = this.loadFromCacheState || {};
299
+ const state = this.loadFromCacheState;
300
+ let typeToSend = '';
301
+ let indexToSend = 0;
302
+ MESSAGES_ORDER.forEach((type) => {
303
+ if (typeToSend) {
304
+ return;
305
+ }
306
+ state[type] = state[type] || 0;
307
+ const loadedCount = state[type];
308
+ if (loadedCount < ((this.data || {})[type] || []).length) {
309
+ typeToSend = type;
310
+ indexToSend = state[type];
311
+ }
312
+ });
313
+ if (typeToSend) {
314
+ const payload = ((this.data || {})[typeToSend] || [])[indexToSend];
315
+ this.notifyAboutDataChunk(typeToSend || '', payload, true);
316
+ state[typeToSend] = indexToSend + 1;
317
+ this.loadMessageFromCache(onFinish);
318
+ }
319
+ else if (onFinish) {
320
+ onFinish();
321
+ }
322
+ }
323
+ /**
324
+ * Cache appropriate message
325
+ *
326
+ * @param {string} type - message type
327
+ * @param {any} data - message payload
328
+ * @returns {void}
329
+ * @private
330
+ */
331
+ cacheData(type, data) {
332
+ this.data = this.data || {};
333
+ const cache = this.data;
334
+ if (!cache) {
335
+ return;
336
+ }
337
+ cache[type] = cache[type] || [];
338
+ cache[type].push(data || true);
339
+ }
340
+ /*
341
+ *
342
+ * @private
343
+ */
344
+ /**
345
+ * Notify outside about data chunk with saving to inner cache, applying chunk formatting with
346
+ * saving initial messages queue
347
+ *
348
+ * @param {string} type - data chunk type
349
+ * @param {any} chunk - data chunk data
350
+ * @param {boolean} isFromCache - mark data which already was cached
351
+ * @returns {void}
352
+ * @private
353
+ */
354
+ // eslint-disable-next-line sonarjs/cognitive-complexity
355
+ notifyAboutDataChunk(type, chunk, isFromCache = false) {
356
+ // console.log('notifyAboutDataChunk', type, chunk, isFromCache);
357
+ const data = chunk && chunk.data && type === MessageType.DATA ? chunk.data : chunk;
358
+ if (!isFromCache) {
359
+ this.cacheData(type, chunk);
360
+ }
361
+ if (!isFromCache && this.loadFromCacheState) {
362
+ // if load original data but new loading from cache started
363
+ return;
364
+ }
365
+ if (type === MessageType.METADATA) {
366
+ this.isSingleBranchTree = !!(data && data.isSingleBranchTree);
367
+ }
368
+ if (type === MessageType.ERROR) {
369
+ this.notifyAboutDataError(data);
370
+ }
371
+ if (type === MessageType.DATA_FINISH) {
372
+ this.loadedItemsCount = data ? data.rowsCount : 0;
373
+ this.notifyAboutDataLoaded(this.data);
374
+ }
375
+ if (type === MessageType.TOTAL_ROWS) {
376
+ this.totalItemsCount = data ? data.rowsCount : 0;
377
+ if (this.totalItemsCount !== this.loadedItemsCount) {
378
+ this.isLimited = true;
379
+ }
380
+ }
381
+ if (type === MessageType.FINISH) {
382
+ this.isFinishEventReceived = true;
383
+ }
384
+ const clonedData = cloneObject(data);
385
+ this.events.emit(type, clonedData);
386
+ }
387
+ /**
388
+ * Resolve "load" method with appropriate data information
389
+ *
390
+ * @param {any} data - data to resolve with
391
+ * @returns {void}
392
+ * @private
393
+ */
394
+ notifyAboutDataLoaded(data) {
395
+ if (!this.isLoadInProgress) {
396
+ return;
397
+ }
398
+ this.isLoadInProgress = false;
399
+ if (typeof this.loadPromiseResolve === 'function') {
400
+ this.loadPromiseResolve(data);
401
+ }
402
+ this.loadPromiseReject = undefined;
403
+ this.loadPromiseResolve = undefined;
404
+ }
405
+ /**
406
+ * Reject "load" method with appropriate data information
407
+ *
408
+ * @param {any} data - data to reject with
409
+ * @returns {void}
410
+ * @private
411
+ */
412
+ notifyAboutDataError(data) {
413
+ if (!this.isLoadInProgress) {
414
+ return;
415
+ }
416
+ this.isLoadInProgress = false;
417
+ if (typeof this.loadPromiseReject === 'function') {
418
+ this.loadPromiseReject(data);
419
+ }
420
+ this.loadPromiseReject = undefined;
421
+ this.loadPromiseResolve = undefined;
422
+ }
423
+ /**
424
+ * Subscribe to event notification
425
+ *
426
+ * @param {string} eventName - event name to subscribe
427
+ * @param {Function} callback - event handler
428
+ * @returns {void}
429
+ */
430
+ on(eventName, callback) {
431
+ this.events.on(eventName, callback);
432
+ }
433
+ /**
434
+ * Unsubscribe from event notification
435
+ *
436
+ * @param {string} eventName - event name to unsubscribe
437
+ * @param {Function} callback - event handler
438
+ * @returns {void}
439
+ */
440
+ off(eventName, callback) {
441
+ this.events.removeListener(eventName, callback);
442
+ }
443
+ /**
444
+ * Unsubscribe from all event notifications
445
+ *
446
+ * @param {string} eventName - event name to unsubscribe
447
+ * @returns {void}
448
+ */
449
+ offAll(eventName) {
450
+ this.events.removeAllListeners(eventName);
451
+ }
452
+ listenerCount(eventName) {
453
+ return this.events.listenerCount(eventName);
454
+ }
455
+ /**
456
+ * Trigger event notification
457
+ *
458
+ * @param {string} eventName - event name to subscribe
459
+ * @param {Array<any>} rest - arguments will be passed to event handler
460
+ * @returns {void}
461
+ */
462
+ emit(eventName, ...rest) {
463
+ this.events.emit(eventName, ...rest);
464
+ }
465
+ }
466
+ export default AbstractDataLoadService;
@@ -0,0 +1,63 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import EventEmitter from 'events';
3
+ import { AbstractDataLoadService } from './AbstractDataLoadService.js';
4
+ import { DataLoadServiceI, SocketI } from './types.js';
5
+ export declare class DataLoadService extends AbstractDataLoadService implements DataLoadServiceI {
6
+ /**
7
+ * @private
8
+ *
9
+ * Active WebSocket connection instance
10
+ */
11
+ socket: SocketI;
12
+ /**
13
+ * @private
14
+ *
15
+ * WebSocket initialization delay promise
16
+ */
17
+ initPromise?: Promise<void>;
18
+ /**
19
+ *
20
+ * @private
21
+ *
22
+ * WebSocket initialization ready flag
23
+ */
24
+ isInitInProgress: boolean;
25
+ /**
26
+ *
27
+ * @private
28
+ *
29
+ * onMessage remove listeners callback
30
+ */
31
+ onMessageCancel?: Function;
32
+ constructor(socket?: SocketI, events?: EventEmitter);
33
+ destroy(): void;
34
+ /**
35
+ * Return copy of load service
36
+ *
37
+ * @returns {DataLoadService} - cloned instance
38
+ */
39
+ clone(): DataLoadServiceI;
40
+ /**
41
+ * Start data loading from the server
42
+ *
43
+ * @returns {void}
44
+ * @private
45
+ */
46
+ loadFromServer(): void;
47
+ /**
48
+ * Method for canceling the processing of query already sent
49
+ *
50
+ * @returns {Promise<void>} - waiting promise
51
+ */
52
+ cancelQuery(): Promise<void>;
53
+ /**
54
+ * Wait for socket connection
55
+ *
56
+ * @returns {Promise<void>} - wait promise
57
+ * @private
58
+ */
59
+ waitForSocketReady(): Promise<void>;
60
+ onSocketError: (error: Error) => void;
61
+ onSocketDisconnect: () => void;
62
+ }
63
+ export default DataLoadService;
@@ -0,0 +1,148 @@
1
+ import { cloneObject } from '../utils/index.js';
2
+ import { AbstractDataLoadService } from './AbstractDataLoadService.js';
3
+ import { MessageType } from './constants.js';
4
+ export class DataLoadService extends AbstractDataLoadService {
5
+ constructor(socket, events) {
6
+ super(events);
7
+ /**
8
+ * @private
9
+ *
10
+ * WebSocket initialization delay promise
11
+ */
12
+ this.initPromise = undefined;
13
+ /**
14
+ *
15
+ * @private
16
+ *
17
+ * WebSocket initialization ready flag
18
+ */
19
+ this.isInitInProgress = false;
20
+ /**
21
+ *
22
+ * @private
23
+ *
24
+ * onMessage remove listeners callback
25
+ */
26
+ this.onMessageCancel = undefined;
27
+ this.onSocketError = (error) => {
28
+ this.emit('error', {
29
+ error: true,
30
+ type: 500,
31
+ details: `Socket error: ${error.message}`,
32
+ });
33
+ };
34
+ this.onSocketDisconnect = () => {
35
+ this.emit('error', {
36
+ error: true,
37
+ type: 500,
38
+ details: 'Socket disconnected',
39
+ });
40
+ };
41
+ if (!socket) {
42
+ throw new Error(`DataLoadService "socket" not defined.`);
43
+ }
44
+ this.socket = socket;
45
+ this.socket.on('error', this.onSocketError);
46
+ this.socket.on('disconnect', this.onSocketDisconnect);
47
+ this.on(MessageType.ERROR, (data) => {
48
+ const errorMsg = JSON.stringify(data, null, 4);
49
+ if (process.env.NODE_ENV !== 'production') {
50
+ // eslint-disable-next-line no-console
51
+ console.warn(`DataLoadService error message: \n${errorMsg}`);
52
+ }
53
+ });
54
+ }
55
+ destroy() {
56
+ super.destroy();
57
+ if (this.onMessageCancel) {
58
+ this.onMessageCancel();
59
+ this.onMessageCancel = undefined;
60
+ }
61
+ // removed because of duplication of cancel-query request
62
+ // this.cancelQuery();
63
+ this.socket.off('error', this.onSocketError);
64
+ this.socket.off('disconnect', this.onSocketDisconnect);
65
+ }
66
+ /**
67
+ * Return copy of load service
68
+ *
69
+ * @returns {DataLoadService} - cloned instance
70
+ */
71
+ clone() {
72
+ const data = cloneObject(this.data);
73
+ // restore empty headers object
74
+ if (!data[MessageType.HEADERS]) {
75
+ data[MessageType.HEADERS] = [{}];
76
+ }
77
+ const instance = new DataLoadService(this.socket);
78
+ instance.data = data;
79
+ instance.jaql = this.jaql;
80
+ instance.isFinishEventReceived = this.isFinishEventReceived;
81
+ instance.isSingleBranchTree = this.isSingleBranchTree;
82
+ instance.loadedItemsCount = this.loadedItemsCount;
83
+ instance.totalItemsCount = this.totalItemsCount;
84
+ instance.isLimited = this.isLimited;
85
+ return instance;
86
+ }
87
+ /**
88
+ * Start data loading from the server
89
+ *
90
+ * @returns {void}
91
+ * @private
92
+ */
93
+ loadFromServer() {
94
+ // eslint-disable-next-line promise/catch-or-return
95
+ this.waitForSocketReady().then(() => {
96
+ if (this.onMessageCancel) {
97
+ this.onMessageCancel();
98
+ }
99
+ this.onMessageCancel = this.socket.onMessage(undefined, undefined, (type, data) => {
100
+ this.notifyAboutDataChunk(type, data);
101
+ });
102
+ this.socket.send('pivot', this.jaql);
103
+ });
104
+ }
105
+ /**
106
+ * Method for canceling the processing of query already sent
107
+ *
108
+ * @returns {Promise<void>} - waiting promise
109
+ */
110
+ cancelQuery() {
111
+ if (!this.isCancelQueryNeeded()) {
112
+ return Promise.resolve();
113
+ }
114
+ return this.waitForSocketReady().then(() => {
115
+ this.socket.send('pivot/cancel-query', {
116
+ // eslint-disable-next-line promise/always-return
117
+ queryGuid: this.jaql && this.jaql.queryGuid,
118
+ });
119
+ });
120
+ }
121
+ /**
122
+ * Wait for socket connection
123
+ *
124
+ * @returns {Promise<void>} - wait promise
125
+ * @private
126
+ */
127
+ waitForSocketReady() {
128
+ if (this.socket.isReady()) {
129
+ return Promise.resolve();
130
+ }
131
+ if (this.isInitInProgress && this.initPromise) {
132
+ return this.initPromise;
133
+ }
134
+ this.isInitInProgress = true;
135
+ this.initPromise = new Promise((resolve, reject) => {
136
+ this.socket.on('open', () => {
137
+ if (this.socket && this.socket.isReady()) {
138
+ resolve();
139
+ }
140
+ else {
141
+ reject(new Error('Can not open WebSocket connection'));
142
+ }
143
+ });
144
+ });
145
+ return this.initPromise;
146
+ }
147
+ }
148
+ export default DataLoadService;