@finos/legend-data-cube 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/lib/__lib__/DataCubeSetting.d.ts +1 -0
  2. package/lib/__lib__/DataCubeSetting.d.ts.map +1 -1
  3. package/lib/__lib__/DataCubeSetting.js +1 -0
  4. package/lib/__lib__/DataCubeSetting.js.map +1 -1
  5. package/lib/components/DataCubeStatusBar.d.ts.map +1 -1
  6. package/lib/components/DataCubeStatusBar.js +10 -3
  7. package/lib/components/DataCubeStatusBar.js.map +1 -1
  8. package/lib/components/DataCubeTitleBar.js +1 -1
  9. package/lib/components/DataCubeTitleBar.js.map +1 -1
  10. package/lib/components/core/DataCubeAlert.js +1 -1
  11. package/lib/components/core/DataCubeAlert.js.map +1 -1
  12. package/lib/components/view/grid/DataCubeGrid.d.ts.map +1 -1
  13. package/lib/components/view/grid/DataCubeGrid.js +26 -20
  14. package/lib/components/view/grid/DataCubeGrid.js.map +1 -1
  15. package/lib/index.css +1 -1
  16. package/lib/index.d.ts +2 -3
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +4 -3
  19. package/lib/index.js.map +1 -1
  20. package/lib/package.json +3 -3
  21. package/lib/stores/DataCubeAPI.d.ts +6 -0
  22. package/lib/stores/DataCubeAPI.d.ts.map +1 -1
  23. package/lib/stores/DataCubeAPI.js +3 -0
  24. package/lib/stores/DataCubeAPI.js.map +1 -1
  25. package/lib/stores/DataCubeOptions.d.ts +1 -1
  26. package/lib/stores/core/DataCubeConfigurationBuilder.js +1 -1
  27. package/lib/stores/core/DataCubeConfigurationBuilder.js.map +1 -1
  28. package/lib/stores/core/DataCubeEngine.d.ts +13 -6
  29. package/lib/stores/core/DataCubeEngine.d.ts.map +1 -1
  30. package/lib/stores/core/DataCubeEngine.js +32 -8
  31. package/lib/stores/core/DataCubeEngine.js.map +1 -1
  32. package/lib/stores/core/DataCubeQueryBuilder.d.ts +3 -4
  33. package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
  34. package/lib/stores/core/DataCubeQueryBuilder.js +19 -13
  35. package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
  36. package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +2 -7
  37. package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
  38. package/lib/stores/core/DataCubeQueryBuilderUtils.js +34 -46
  39. package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
  40. package/lib/stores/core/DataCubeQuerySnapshot.d.ts +11 -4
  41. package/lib/stores/core/DataCubeQuerySnapshot.d.ts.map +1 -1
  42. package/lib/stores/core/DataCubeQuerySnapshot.js +10 -0
  43. package/lib/stores/core/DataCubeQuerySnapshot.js.map +1 -1
  44. package/lib/stores/core/DataCubeQuerySnapshotBuilder.d.ts.map +1 -1
  45. package/lib/stores/core/DataCubeQuerySnapshotBuilder.js +1 -2
  46. package/lib/stores/core/DataCubeQuerySnapshotBuilder.js.map +1 -1
  47. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.d.ts.map +1 -1
  48. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js +3 -3
  49. package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js.map +1 -1
  50. package/lib/stores/core/model/CachedDataCubeSource.d.ts +4 -0
  51. package/lib/stores/core/model/CachedDataCubeSource.d.ts.map +1 -1
  52. package/lib/stores/core/model/CachedDataCubeSource.js +4 -0
  53. package/lib/stores/core/model/CachedDataCubeSource.js.map +1 -1
  54. package/lib/stores/services/DataCubeQuerySnapshotService.js +1 -1
  55. package/lib/stores/services/DataCubeQuerySnapshotService.js.map +1 -1
  56. package/lib/stores/services/DataCubeSettingService.d.ts.map +1 -1
  57. package/lib/stores/services/DataCubeSettingService.js +8 -0
  58. package/lib/stores/services/DataCubeSettingService.js.map +1 -1
  59. package/lib/stores/services/DataCubeTaskService.d.ts +4 -4
  60. package/lib/stores/services/DataCubeTaskService.d.ts.map +1 -1
  61. package/lib/stores/services/DataCubeTaskService.js +9 -7
  62. package/lib/stores/services/DataCubeTaskService.js.map +1 -1
  63. package/lib/stores/view/DataCubeViewState.d.ts +3 -1
  64. package/lib/stores/view/DataCubeViewState.d.ts.map +1 -1
  65. package/lib/stores/view/DataCubeViewState.js +54 -19
  66. package/lib/stores/view/DataCubeViewState.js.map +1 -1
  67. package/lib/stores/view/editor/DataCubeEditorState.js +1 -1
  68. package/lib/stores/view/editor/DataCubeEditorState.js.map +1 -1
  69. package/lib/stores/view/extend/DataCubeColumnEditorState.d.ts.map +1 -1
  70. package/lib/stores/view/extend/DataCubeColumnEditorState.js +7 -5
  71. package/lib/stores/view/extend/DataCubeColumnEditorState.js.map +1 -1
  72. package/lib/stores/view/extend/DataCubeExtendManagerState.js +2 -2
  73. package/lib/stores/view/extend/DataCubeExtendManagerState.js.map +1 -1
  74. package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts.map +1 -1
  75. package/lib/stores/view/grid/DataCubeGridClientEngine.js +104 -108
  76. package/lib/stores/view/grid/DataCubeGridClientEngine.js.map +1 -1
  77. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
  78. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js +3 -3
  79. package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
  80. package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts +3 -4
  81. package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
  82. package/lib/stores/view/grid/DataCubeGridQueryBuilder.js +5 -5
  83. package/lib/stores/view/grid/DataCubeGridQueryBuilder.js.map +1 -1
  84. package/lib/stores/view/grid/DataCubeGridState.d.ts.map +1 -1
  85. package/lib/stores/view/grid/DataCubeGridState.js +63 -8
  86. package/lib/stores/view/grid/DataCubeGridState.js.map +1 -1
  87. package/package.json +7 -7
  88. package/src/__lib__/DataCubeSetting.ts +1 -0
  89. package/src/components/DataCubeStatusBar.tsx +18 -3
  90. package/src/components/DataCubeTitleBar.tsx +3 -3
  91. package/src/components/core/DataCubeAlert.tsx +1 -1
  92. package/src/components/view/grid/DataCubeGrid.tsx +23 -7
  93. package/src/index.tsx +8 -3
  94. package/src/stores/DataCubeAPI.ts +9 -0
  95. package/src/stores/DataCubeOptions.ts +1 -1
  96. package/src/stores/core/DataCubeConfigurationBuilder.ts +1 -1
  97. package/src/stores/core/DataCubeEngine.tsx +47 -20
  98. package/src/stores/core/DataCubeQueryBuilder.ts +38 -30
  99. package/src/stores/core/DataCubeQueryBuilderUtils.ts +42 -67
  100. package/src/stores/core/DataCubeQuerySnapshot.ts +15 -4
  101. package/src/stores/core/DataCubeQuerySnapshotBuilder.ts +2 -6
  102. package/src/stores/core/DataCubeQuerySnapshotBuilderUtils.ts +2 -3
  103. package/src/stores/core/model/CachedDataCubeSource.ts +4 -0
  104. package/src/stores/services/DataCubeQuerySnapshotService.ts +2 -2
  105. package/src/stores/services/DataCubeSettingService.tsx +8 -0
  106. package/src/stores/services/DataCubeTaskService.ts +9 -7
  107. package/src/stores/view/DataCubeViewState.ts +58 -27
  108. package/src/stores/view/editor/DataCubeEditorState.tsx +1 -1
  109. package/src/stores/view/extend/DataCubeColumnEditorState.tsx +7 -15
  110. package/src/stores/view/extend/DataCubeExtendManagerState.tsx +2 -2
  111. package/src/stores/view/grid/DataCubeGridClientEngine.ts +149 -168
  112. package/src/stores/view/grid/DataCubeGridConfigurationBuilder.tsx +6 -7
  113. package/src/stores/view/grid/DataCubeGridQueryBuilder.ts +19 -32
  114. package/src/stores/view/grid/DataCubeGridState.ts +89 -8
@@ -24,13 +24,6 @@ import {
24
24
  import { DataCubeQuerySnapshotService } from '../services/DataCubeQuerySnapshotService.js';
25
25
  import { DataCubeInfoState } from './DataCubeInfoState.js';
26
26
  import { validateAndBuildQuerySnapshot } from '../core/DataCubeQuerySnapshotBuilder.js';
27
- import {
28
- action,
29
- computed,
30
- makeObservable,
31
- observable,
32
- runInAction,
33
- } from 'mobx';
34
27
  import { DataCubeFilterEditorState } from './filter/DataCubeFilterEditorState.js';
35
28
  import { DataCubeExtendManagerState } from './extend/DataCubeExtendManagerState.js';
36
29
  import type { DataCubeState } from '../DataCubeState.js';
@@ -43,6 +36,9 @@ import { DataCubeConfiguration } from '../core/model/DataCubeConfiguration.js';
43
36
  import type { DataCubeLayoutService } from '../services/DataCubeLayoutService.js';
44
37
  import type { DataCubeAlertService } from '../services/DataCubeAlertService.js';
45
38
  import type { DataCubeSettingService } from '../services/DataCubeSettingService.js';
39
+ import { CachedDataCubeSource } from '../core/model/CachedDataCubeSource.js';
40
+ import { DataCubeSettingKey } from '../../__lib__/DataCubeSetting.js';
41
+ import { PureClientVersion } from '@finos/legend-graph';
46
42
 
47
43
  export class DataCubeViewState {
48
44
  readonly dataCube: DataCubeState;
@@ -61,18 +57,12 @@ export class DataCubeViewState {
61
57
  readonly extend: DataCubeExtendManagerState;
62
58
 
63
59
  readonly initializeState = ActionState.create();
60
+ readonly processCacheState = ActionState.create();
64
61
 
65
62
  private _source?: DataCubeSource | undefined;
66
63
  private _originalSource?: DataCubeSource | undefined;
67
64
 
68
65
  constructor(dataCube: DataCubeState) {
69
- makeObservable<DataCubeViewState, '_source'>(this, {
70
- _source: observable,
71
- source: computed,
72
-
73
- initialize: action,
74
- });
75
-
76
66
  this.dataCube = dataCube;
77
67
  this.engine = dataCube.engine;
78
68
  this.logService = dataCube.logService;
@@ -93,6 +83,10 @@ export class DataCubeViewState {
93
83
  this.extend = new DataCubeExtendManagerState(this);
94
84
  }
95
85
 
86
+ getOriginalSource() {
87
+ return this._originalSource;
88
+ }
89
+
96
90
  async generateDataCubeQuery() {
97
91
  const snapshot = this.snapshotService.currentSnapshot;
98
92
  const query = new DataCubeQuery();
@@ -112,23 +106,62 @@ export class DataCubeViewState {
112
106
  }
113
107
 
114
108
  async initializeCache() {
115
- this.initializeState.inProgress();
116
- const cachedSource = await this.engine.initializeCache(this.source);
117
- if (cachedSource !== undefined) {
118
- this._originalSource = this._source;
119
- this._source = cachedSource;
109
+ this.processCacheState.inProgress();
110
+ const task = this.taskService.newTask('Initializing cache...');
111
+
112
+ try {
113
+ const cachedSource = await this.engine.initializeCache(this.source, {
114
+ debug: this.settingService.getBooleanValue(
115
+ DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
116
+ ),
117
+ clientVersion: this.settingService.getBooleanValue(
118
+ DataCubeSettingKey.DEBUGGER__USE_DEV_CLIENT_PROTOCOL_VERSION,
119
+ )
120
+ ? PureClientVersion.VX_X_X
121
+ : undefined,
122
+ });
123
+ if (cachedSource) {
124
+ this._source = cachedSource;
125
+ }
126
+ this.processCacheState.pass();
127
+ } catch (error) {
128
+ assertErrorThrown(error);
129
+ this.alertService.alertError(error, {
130
+ message: `Cache Processing Failure: ${error.message}`,
131
+ });
132
+ this._source = this._originalSource;
133
+ this.processCacheState.fail();
134
+ } finally {
135
+ this.taskService.endTask(task);
120
136
  }
121
- this.initializeState.pass();
122
137
  }
123
138
 
124
- async clearCache() {
125
- await this.engine.clearCache();
139
+ async disposeCache() {
140
+ if (!(this._source instanceof CachedDataCubeSource)) {
141
+ return;
142
+ }
143
+ const cachedSource = this._source;
126
144
  this._source = this._originalSource;
145
+
146
+ this.processCacheState.inProgress();
147
+ const task = this.taskService.newTask('Disposing cache...');
148
+
149
+ try {
150
+ await this.engine.disposeCache(cachedSource);
151
+ } catch (error) {
152
+ assertErrorThrown(error);
153
+ this.alertService.alertError(error, {
154
+ message: `Cache Processing Failure: ${error.message}`,
155
+ });
156
+ } finally {
157
+ this.processCacheState.complete();
158
+ this.taskService.endTask(task);
159
+ }
127
160
  }
128
161
 
129
162
  async initialize(query: DataCubeQuery) {
130
163
  this.initializeState.inProgress();
131
- const task = this.taskService.newTask('Initializing');
164
+ const task = this.taskService.newTask('Initializing...');
132
165
 
133
166
  try {
134
167
  await Promise.all(
@@ -144,9 +177,8 @@ export class DataCubeViewState {
144
177
  }),
145
178
  );
146
179
  const source = await this.engine.processQuerySource(query.source);
147
- runInAction(() => {
148
- this._source = source;
149
- });
180
+ this._source = source;
181
+ this._originalSource = source;
150
182
  const partialQuery = await this.engine.parseValueSpecification(
151
183
  query.query,
152
184
  );
@@ -156,7 +188,6 @@ export class DataCubeViewState {
156
188
  query,
157
189
  this.engine,
158
190
  );
159
- this.engine.processInitialSnapshot?.(source, initialSnapshot);
160
191
  this.snapshotService.broadcastSnapshot(initialSnapshot);
161
192
  this.dataCube.options?.onViewInitialized?.({
162
193
  api: this.dataCube.api,
@@ -164,7 +164,7 @@ export class DataCubeEditorState extends DataCubeQuerySnapshotController {
164
164
  // finalize
165
165
  newSnapshot.finalize();
166
166
  if (newSnapshot.hashCode !== baseSnapshot.hashCode) {
167
- const task = this.view.taskService.newTask('Validate query');
167
+ const task = this.view.taskService.newTask('Validating query...');
168
168
  // NOTE: Compile the query to validate. This is a helpful check for a lot of different scenarios
169
169
  // where the consistency of the query might be thrown off by changes from various parts that the
170
170
  // editor does not have full control over (i.e. extended columns, pivot cast columns, etc.)
@@ -47,11 +47,7 @@ import {
47
47
  } from '@finos/legend-graph';
48
48
  import type { DataCubeColumnConfiguration } from '../../core/model/DataCubeConfiguration.js';
49
49
  import type { DataCubeQuerySnapshotExtendedColumn } from '../../core/DataCubeQuerySnapshot.js';
50
- import {
51
- _lambda,
52
- _serializeValueSpecification,
53
- _deserializeValueSpecification,
54
- } from '../../core/DataCubeQueryBuilderUtils.js';
50
+ import { _lambda } from '../../core/DataCubeQueryBuilderUtils.js';
55
51
  import { _findCol } from '../../core/model/DataCubeColumn.js';
56
52
 
57
53
  export abstract class DataCubeColumnBaseEditorState {
@@ -220,13 +216,9 @@ export abstract class DataCubeColumnBaseEditorState {
220
216
  return _lambda(
221
217
  [],
222
218
  [
223
- buildExecutableQuery(
224
- snapshot,
225
- this.view.source,
226
- () => undefined,
227
- this.view.engine.filterOperations,
228
- this.view.engine.aggregateOperations,
229
- ),
219
+ buildExecutableQuery(snapshot, this.view.source, this.view.engine, {
220
+ skipExecutionContext: true,
221
+ }),
230
222
  ],
231
223
  );
232
224
  }
@@ -390,7 +382,7 @@ export class DataCubeNewColumnState extends DataCubeColumnBaseEditorState {
390
382
  {
391
383
  name: this.name,
392
384
  type: returnType,
393
- mapFn: _serializeValueSpecification(query),
385
+ mapFn: this.view.engine.serializeValueSpecification(query),
394
386
  },
395
387
  this.isGroupLevel,
396
388
  this.columnKind,
@@ -440,7 +432,7 @@ export class DataCubeExistingColumnEditorState extends DataCubeColumnBaseEditorS
440
432
 
441
433
  override async getInitialCode(): Promise<string> {
442
434
  return this.view.engine.getValueSpecificationCode(
443
- _deserializeValueSpecification(this.initialData.mapFn),
435
+ this.view.engine.deserializeValueSpecification(this.initialData.mapFn),
444
436
  true,
445
437
  );
446
438
  }
@@ -516,7 +508,7 @@ export class DataCubeExistingColumnEditorState extends DataCubeColumnBaseEditorS
516
508
  {
517
509
  name: this.name,
518
510
  type: returnType,
519
- mapFn: _serializeValueSpecification(query),
511
+ mapFn: this.view.engine.serializeValueSpecification(query),
520
512
  },
521
513
  this.isGroupLevel,
522
514
  this.columnKind,
@@ -208,7 +208,7 @@ export class DataCubeExtendManagerState extends DataCubeQuerySnapshotController
208
208
  _findCol(this.columnConfigurations, columnName),
209
209
  );
210
210
 
211
- const task = this.view.taskService.newTask('Column update check');
211
+ const task = this.view.taskService.newTask('Checking column update...');
212
212
 
213
213
  const currentSnapshot = guaranteeNonNullable(this.getLatestSnapshot());
214
214
  const tempSnapshot = currentSnapshot.clone();
@@ -333,7 +333,7 @@ export class DataCubeExtendManagerState extends DataCubeQuerySnapshotController
333
333
  return;
334
334
  }
335
335
 
336
- const task = this.view.taskService.newTask('Column delete check');
336
+ const task = this.view.taskService.newTask('Checking column deletion...');
337
337
 
338
338
  const currentSnapshot = guaranteeNonNullable(this.getLatestSnapshot());
339
339
  const tempSnapshot = currentSnapshot.clone();
@@ -31,11 +31,7 @@ import {
31
31
  pruneObject,
32
32
  } from '@finos/legend-shared';
33
33
  import { buildExecutableQuery } from '../../core/DataCubeQueryBuilder.js';
34
- import {
35
- PureClientVersion,
36
- type TabularDataSet,
37
- V1_Lambda,
38
- } from '@finos/legend-graph';
34
+ import { PureClientVersion, type TabularDataSet } from '@finos/legend-graph';
39
35
  import { makeObservable, observable, runInAction } from 'mobx';
40
36
  import type {
41
37
  DataCubeConfiguration,
@@ -55,6 +51,8 @@ import {
55
51
  import { _colSpecArrayParam } from '../../core/DataCubeQuerySnapshotBuilderUtils.js';
56
52
  import { DataCubeSettingKey } from '../../../__lib__/DataCubeSetting.js';
57
53
  import { DEFAULT_ALERT_WINDOW_CONFIG } from '../../services/DataCubeLayoutService.js';
54
+ import type { DataCubeExecutionResult } from '../../core/DataCubeEngine.js';
55
+ import { _lambda } from '../../core/DataCubeQueryBuilderUtils.js';
58
56
 
59
57
  type DataCubeGridClientCellValue = string | number | boolean | null | undefined;
60
58
  type DataCubeGridClientRowData = {
@@ -265,43 +263,31 @@ async function getCastColumns(
265
263
  snapshot.data.groupExtendedColumns = [];
266
264
  snapshot.data.sortColumns = [];
267
265
  snapshot.data.limit = 0;
268
- const query = buildExecutableQuery(
269
- snapshot,
266
+ const query = buildExecutableQuery(snapshot, view.source, view.engine, {
267
+ postProcessor: (_snapshot, sequence, funcMap, configuration, engine) => {
268
+ // when both pivot and groupBy present, we need to account for the count column
269
+ // in the cast expression
270
+ if (funcMap.pivot && currentSnapshot.data.groupBy) {
271
+ _colSpecArrayParam(funcMap.pivot, 1).colSpecs.push(_aggCountCol());
272
+ }
273
+ },
274
+ });
275
+
276
+ const result = await view.engine.executeQuery(
277
+ _lambda([], [query]),
270
278
  view.source,
271
- (source) => view.engine.buildExecutionContext(source),
272
- view.engine.filterOperations,
273
- view.engine.aggregateOperations,
274
279
  {
275
- postProcessor: (
276
- _snapshot,
277
- sequence,
278
- funcMap,
279
- configuration,
280
- filterOperations,
281
- aggregateOperations,
282
- ) => {
283
- // when both pivot and groupBy present, we need to account for the count column
284
- // in the cast expression
285
- if (funcMap.pivot && currentSnapshot.data.groupBy) {
286
- _colSpecArrayParam(funcMap.pivot, 1).colSpecs.push(_aggCountCol());
287
- }
288
- },
280
+ debug: view.settingService.getBooleanValue(
281
+ DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
282
+ ),
283
+ clientVersion: view.settingService.getBooleanValue(
284
+ DataCubeSettingKey.DEBUGGER__USE_DEV_CLIENT_PROTOCOL_VERSION,
285
+ )
286
+ ? PureClientVersion.VX_X_X
287
+ : undefined,
289
288
  },
290
289
  );
291
290
 
292
- const lambda = new V1_Lambda();
293
- lambda.body.push(query);
294
- const result = await view.engine.executeQuery(lambda, view.source, {
295
- debug: view.settingService.getBooleanValue(
296
- DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
297
- ),
298
- clientVersion: view.settingService.getBooleanValue(
299
- DataCubeSettingKey.DEBUGGER__USE_DEV_CLIENT_PROTOCOL_VERSION,
300
- )
301
- ? PureClientVersion.VX_X_X
302
- : undefined,
303
- });
304
-
305
291
  return result.result.builder.columns.map((column) => ({
306
292
  name: column.name,
307
293
  type: column.type as string,
@@ -338,7 +324,7 @@ export class DataCubeGridClientServerSideDataSource
338
324
  }
339
325
 
340
326
  async fetchRows(params: IServerSideGetRowsParams<unknown, unknown>) {
341
- const task = this._view.taskService.newTask('Fetching data');
327
+ const task = this._view.taskService.newTask('Fetching data...');
342
328
 
343
329
  // ------------------------------ SNAPSHOT ------------------------------
344
330
 
@@ -408,20 +394,18 @@ export class DataCubeGridClientServerSideDataSource
408
394
 
409
395
  // ------------------------------ DATA ------------------------------
410
396
 
397
+ const executableQuery = buildGridDataFetchExecutableQuery(
398
+ request,
399
+ newSnapshot,
400
+ this._view.source,
401
+ this._view.engine,
402
+ this._grid.isPaginationEnabled,
403
+ );
404
+ let result: DataCubeExecutionResult;
405
+
411
406
  try {
412
- const executableQuery = buildGridDataFetchExecutableQuery(
413
- request,
414
- newSnapshot,
415
- this._view.source,
416
- (source) => this._view.engine.buildExecutionContext(source),
417
- this._view.engine.filterOperations,
418
- this._view.engine.aggregateOperations,
419
- this._grid.isPaginationEnabled,
420
- );
421
- const lambda = new V1_Lambda();
422
- lambda.body.push(executableQuery);
423
- const result = await this._view.engine.executeQuery(
424
- lambda,
407
+ result = await this._view.engine.executeQuery(
408
+ _lambda([], [executableQuery]),
425
409
  this._view.source,
426
410
  {
427
411
  debug: this._view.settingService.getBooleanValue(
@@ -434,137 +418,134 @@ export class DataCubeGridClientServerSideDataSource
434
418
  : undefined,
435
419
  },
436
420
  );
437
- const rowData = buildRowData(result.result.result, newSnapshot);
438
- if (
439
- this._view.settingService.getBooleanValue(
440
- DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
441
- )
442
- ) {
443
- this._view.engine.debugProcess(
444
- `Execution`,
445
- ['Query', result.executedQuery],
446
- ['Config', `pagination=${this._grid.isPaginationEnabled}`],
447
- [
448
- 'Stats',
449
- `${rowData.length} rows, ${result.result.result.columns.length} columns`,
450
- ],
451
- ['SQL', result.executedSQL],
452
- ['SQL Execution Time', result.executionTime],
453
- );
454
- }
421
+ } catch (error) {
422
+ assertErrorThrown(error);
423
+ this._view.alertService.alertError(error, {
424
+ message: `Data Fetch Failure: ${error.message}`,
425
+ });
426
+ this._view.taskService.endTask(task);
427
+ params.fail();
428
+ return;
429
+ }
455
430
 
456
- if (this._grid.isPaginationEnabled) {
457
- params.success({ rowData });
458
- // only update row count when loading the top-level drilldown data
459
- if (isTopLevelRequest) {
460
- runInAction(() => {
461
- this.rowCount = (request.startRow ?? 0) + rowData.length;
462
- });
463
- }
431
+ const rowData = buildRowData(result.result.result, newSnapshot);
432
+ if (
433
+ this._view.settingService.getBooleanValue(
434
+ DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
435
+ )
436
+ ) {
437
+ this._view.engine.debugProcess(
438
+ `Execution`,
439
+ ['Query', result.executedQuery],
440
+ [
441
+ 'Stats',
442
+ `${rowData.length} rows, ${result.result.result.columns.length} columns`,
443
+ ],
444
+ ['SQL', result.executedSQL],
445
+ ['SQL Execution Time', result.executionTime],
446
+ );
447
+ }
448
+
449
+ if (this._grid.isPaginationEnabled) {
450
+ params.success({ rowData });
451
+ // only update row count when loading the top-level drilldown data
452
+ if (isTopLevelRequest) {
453
+ runInAction(() => {
454
+ this.rowCount = (request.startRow ?? 0) + rowData.length;
455
+ });
456
+ }
464
457
 
465
- // toggle no-rows overlay
458
+ // toggle no-rows overlay
459
+ if (isTopLevelRequest && request.startRow === 0 && rowData.length === 0) {
460
+ this._grid.client.showNoRowsOverlay();
461
+ } else {
462
+ this._grid.client.hideOverlay();
463
+ }
464
+ } else {
465
+ // NOTE: When pagination is disabled and the user currently scrolls to somewhere in the grid, as data is fetched
466
+ // and the operation does not force a scroll top (for example, grouping will always force scrolling to the
467
+ // top, while sorting will leave scroll position as is), the grid ends up showing the wrong data because
468
+ // the data being displayed does not take into account the scroll position, but by the start and end row
469
+ // which stay constant as pagination is disabled.
470
+ //
471
+ // In order to handle this, when pagination is disabled, we tune the start and end row by setting the cache block size
472
+ // to a high-enough value (100k-1m). However, ag-grid use cache block size to pre-allocate memory for the rows,
473
+ // which means we must cap/tune this value reasonably to prevent the app from crashing.
474
+ //
475
+ // When there are just too many rows (exceeding the maximum cache block size), we will fallback to a slightly less ideal
476
+ // behavior by forcing a scroll top for every data fetch and also reset the cache block size to the default value to save memory
477
+ if (rowData.length > INTERNAL__GRID_CLIENT_MAX_CACHE_BLOCK_SIZE) {
466
478
  if (
467
- isTopLevelRequest &&
468
- request.startRow === 0 &&
469
- rowData.length === 0
479
+ !this._view.settingService.getBooleanValue(
480
+ DataCubeSettingKey.GRID_CLIENT__SUPPRESS_LARGE_DATASET_WARNING,
481
+ )
470
482
  ) {
471
- this._grid.client.showNoRowsOverlay();
472
- } else {
473
- this._grid.client.hideOverlay();
474
- }
475
- } else {
476
- // NOTE: When pagination is disabled and the user currently scrolls to somewhere in the grid, as data is fetched
477
- // and the operation does not force a scroll top (for example, grouping will always force scrolling to the
478
- // top, while sorting will leave scroll position as is), the grid ends up showing the wrong data because
479
- // the data being displayed does not take into account the scroll position, but by the start and end row
480
- // which stay constant as pagination is disabled.
481
- //
482
- // In order to handle this, when pagination is disabled, we tune the start and end row by setting the cache block size
483
- // to a high-enough value (100k-1m). However, ag-grid use cache block size to pre-allocate memory for the rows,
484
- // which means we must cap/tune this value reasonably to prevent the app from crashing.
485
- //
486
- // When there are just too many rows (exceeding the maximum cache block size), we will fallback to a slightly less ideal
487
- // behavior by forcing a scroll top for every data fetch and also reset the cache block size to the default value to save memory
488
- if (rowData.length > INTERNAL__GRID_CLIENT_MAX_CACHE_BLOCK_SIZE) {
489
- if (
490
- !this._view.settingService.getBooleanValue(
491
- DataCubeSettingKey.GRID_CLIENT__SUPPRESS_LARGE_DATASET_WARNING,
492
- )
493
- ) {
494
- this._view.alertService.alert({
495
- message: `Large dataset (>${INTERNAL__GRID_CLIENT_MAX_CACHE_BLOCK_SIZE} rows) detected!`,
496
- text: `Overall app performance can be impacted by large dataset due to longer query execution time and increased memory usage. At its limit, the engine can crash!\nTo boost performance, consider enabling pagination while working with large dataset.`,
497
- type: AlertType.WARNING,
498
- actions: [
499
- {
500
- label: 'Enable Pagination',
501
- handler: () => {
502
- this._grid.setPaginationEnabled(true);
503
- },
483
+ this._view.alertService.alert({
484
+ message: `Large dataset (>${INTERNAL__GRID_CLIENT_MAX_CACHE_BLOCK_SIZE} rows) detected!`,
485
+ text: `Overall app performance can be impacted by large dataset due to longer query execution time and increased memory usage. At its limit, the engine can crash!\nTo boost performance, consider enabling pagination while working with large dataset.`,
486
+ type: AlertType.WARNING,
487
+ actions: [
488
+ {
489
+ label: 'Enable Pagination',
490
+ handler: () => {
491
+ this._grid.setPaginationEnabled(true);
504
492
  },
505
- {
506
- label: 'Dismiss Warning',
507
- handler: () => {
508
- this._view.settingService.updateValue(
509
- this._view.dataCube.api,
510
- DataCubeSettingKey.GRID_CLIENT__SUPPRESS_LARGE_DATASET_WARNING,
511
- true,
512
- );
513
- },
493
+ },
494
+ {
495
+ label: 'Dismiss Warning',
496
+ handler: () => {
497
+ this._view.settingService.updateValue(
498
+ this._view.dataCube.api,
499
+ DataCubeSettingKey.GRID_CLIENT__SUPPRESS_LARGE_DATASET_WARNING,
500
+ true,
501
+ );
514
502
  },
515
- ],
516
- windowConfig: {
517
- ...DEFAULT_ALERT_WINDOW_CONFIG,
518
- width: 600,
519
- minWidth: 300,
520
- minHeight: 150,
521
503
  },
522
- });
523
- }
524
-
525
- // NOTE: when drilldown occurs, we will scroll top until the drilldown row is reached
526
- params.api.ensureIndexVisible(params.parentNode.rowIndex ?? 0, 'top');
527
- }
528
-
529
- params.success({
530
- rowData,
531
- // Setting row count to disable infinite-scrolling when pagination is disabled
532
- // See https://www.ag-grid.com/react-data-grid/infinite-scrolling/#setting-last-row-index
533
- rowCount: rowData.length,
534
- });
535
-
536
- // only update row count when loading the top-level drilldown data
537
- if (isTopLevelRequest) {
538
- runInAction(() => {
539
- this.rowCount = rowData.length;
504
+ ],
505
+ windowConfig: {
506
+ ...DEFAULT_ALERT_WINDOW_CONFIG,
507
+ width: 600,
508
+ minWidth: 300,
509
+ minHeight: 150,
510
+ },
540
511
  });
541
512
  }
542
513
 
543
- // toggle no-rows overlay
544
- if (isTopLevelRequest && rowData.length === 0) {
545
- this._grid.client.showNoRowsOverlay();
546
- } else {
547
- this._grid.client.hideOverlay();
548
- }
514
+ // NOTE: when drilldown occurs, we will scroll top until the drilldown row is reached
515
+ params.api.ensureIndexVisible(params.parentNode.rowIndex ?? 0, 'top');
549
516
  }
550
517
 
551
- // Resize columns to fit content on all actions (drilldown, changing queries, fetching new page, etc.)
552
- // NOTE: we might want to restrict this to only happen on certain actions
553
- //
554
- // `setTimeout()` is need to ensure this runs after the grid has been updated with the new data
555
- // since ag-grid does not provide an event hook for this action for server-side row model.
556
- setTimeout(() => {
557
- this._grid.client.autoSizeAllColumns();
558
- }, 0);
559
- } catch (error) {
560
- assertErrorThrown(error);
561
- this._view.alertService.alertError(error, {
562
- message: `Data Fetch Failure: ${error.message}`,
518
+ params.success({
519
+ rowData,
520
+ // Setting row count to disable infinite-scrolling when pagination is disabled
521
+ // See https://www.ag-grid.com/react-data-grid/infinite-scrolling/#setting-last-row-index
522
+ rowCount: rowData.length,
563
523
  });
564
- params.fail();
565
- } finally {
566
- this._view.taskService.endTask(task);
524
+
525
+ // only update row count when loading the top-level drilldown data
526
+ if (isTopLevelRequest) {
527
+ runInAction(() => {
528
+ this.rowCount = rowData.length;
529
+ });
530
+ }
531
+
532
+ // toggle no-rows overlay
533
+ if (isTopLevelRequest && rowData.length === 0) {
534
+ this._grid.client.showNoRowsOverlay();
535
+ } else {
536
+ this._grid.client.hideOverlay();
537
+ }
567
538
  }
539
+
540
+ // Resize columns to fit content on all actions (drilldown, changing queries, fetching new page, etc.)
541
+ // NOTE: we might want to restrict this to only happen on certain actions
542
+ //
543
+ // `setTimeout()` is need to ensure this runs after the grid has been updated with the new data
544
+ // since ag-grid does not provide an event hook for this action for server-side row model.
545
+ setTimeout(() => {
546
+ this._grid.client.autoSizeAllColumns();
547
+ }, 0);
548
+ this._view.taskService.endTask(task);
568
549
  }
569
550
 
570
551
  getRows(params: IServerSideGetRowsParams<unknown, unknown>) {
@@ -62,7 +62,6 @@ import {
62
62
  } from './DataCubeGridClientEngine.js';
63
63
  import {
64
64
  at,
65
- last,
66
65
  getQueryParameters,
67
66
  getQueryParameterValue,
68
67
  isNonNullable,
@@ -758,15 +757,15 @@ function generateDefinitionForPivotResultColumns(
758
757
 
759
758
  // sort the leaf level columns based on the order of selected/configuration columns
760
759
  (currentCollection as ColDef[]).sort((a, b) => {
761
- const colAName = last(
762
- a.colId?.split(PIVOT_COLUMN_NAME_VALUE_SEPARATOR) ?? [],
763
- );
760
+ const colAName = (
761
+ a.colId?.split(PIVOT_COLUMN_NAME_VALUE_SEPARATOR) ?? []
762
+ ).at(-1);
764
763
  const colAConf = colAName
765
764
  ? _findCol(configuration.columns, colAName)
766
765
  : undefined;
767
- const colBName = last(
768
- b.colId?.split(PIVOT_COLUMN_NAME_VALUE_SEPARATOR) ?? [],
769
- );
766
+ const colBName = (
767
+ b.colId?.split(PIVOT_COLUMN_NAME_VALUE_SEPARATOR) ?? []
768
+ ).at(-1);
770
769
  const colBConf = colBName
771
770
  ? _findCol(configuration.columns, colBName)
772
771
  : undefined;