@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.
- package/lib/__lib__/DataCubeSetting.d.ts +1 -0
- package/lib/__lib__/DataCubeSetting.d.ts.map +1 -1
- package/lib/__lib__/DataCubeSetting.js +1 -0
- package/lib/__lib__/DataCubeSetting.js.map +1 -1
- package/lib/components/DataCubeStatusBar.d.ts.map +1 -1
- package/lib/components/DataCubeStatusBar.js +10 -3
- package/lib/components/DataCubeStatusBar.js.map +1 -1
- package/lib/components/DataCubeTitleBar.js +1 -1
- package/lib/components/DataCubeTitleBar.js.map +1 -1
- package/lib/components/core/DataCubeAlert.js +1 -1
- package/lib/components/core/DataCubeAlert.js.map +1 -1
- package/lib/components/view/grid/DataCubeGrid.d.ts.map +1 -1
- package/lib/components/view/grid/DataCubeGrid.js +26 -20
- package/lib/components/view/grid/DataCubeGrid.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +2 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/index.js.map +1 -1
- package/lib/package.json +3 -3
- package/lib/stores/DataCubeAPI.d.ts +6 -0
- package/lib/stores/DataCubeAPI.d.ts.map +1 -1
- package/lib/stores/DataCubeAPI.js +3 -0
- package/lib/stores/DataCubeAPI.js.map +1 -1
- package/lib/stores/DataCubeOptions.d.ts +1 -1
- package/lib/stores/core/DataCubeConfigurationBuilder.js +1 -1
- package/lib/stores/core/DataCubeConfigurationBuilder.js.map +1 -1
- package/lib/stores/core/DataCubeEngine.d.ts +13 -6
- package/lib/stores/core/DataCubeEngine.d.ts.map +1 -1
- package/lib/stores/core/DataCubeEngine.js +32 -8
- package/lib/stores/core/DataCubeEngine.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilder.d.ts +3 -4
- package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilder.js +19 -13
- package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +2 -7
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.js +34 -46
- package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshot.d.ts +11 -4
- package/lib/stores/core/DataCubeQuerySnapshot.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshot.js +10 -0
- package/lib/stores/core/DataCubeQuerySnapshot.js.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshotBuilder.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshotBuilder.js +1 -2
- package/lib/stores/core/DataCubeQuerySnapshotBuilder.js.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js +3 -3
- package/lib/stores/core/DataCubeQuerySnapshotBuilderUtils.js.map +1 -1
- package/lib/stores/core/model/CachedDataCubeSource.d.ts +4 -0
- package/lib/stores/core/model/CachedDataCubeSource.d.ts.map +1 -1
- package/lib/stores/core/model/CachedDataCubeSource.js +4 -0
- package/lib/stores/core/model/CachedDataCubeSource.js.map +1 -1
- package/lib/stores/services/DataCubeQuerySnapshotService.js +1 -1
- package/lib/stores/services/DataCubeQuerySnapshotService.js.map +1 -1
- package/lib/stores/services/DataCubeSettingService.d.ts.map +1 -1
- package/lib/stores/services/DataCubeSettingService.js +8 -0
- package/lib/stores/services/DataCubeSettingService.js.map +1 -1
- package/lib/stores/services/DataCubeTaskService.d.ts +4 -4
- package/lib/stores/services/DataCubeTaskService.d.ts.map +1 -1
- package/lib/stores/services/DataCubeTaskService.js +9 -7
- package/lib/stores/services/DataCubeTaskService.js.map +1 -1
- package/lib/stores/view/DataCubeViewState.d.ts +3 -1
- package/lib/stores/view/DataCubeViewState.d.ts.map +1 -1
- package/lib/stores/view/DataCubeViewState.js +54 -19
- package/lib/stores/view/DataCubeViewState.js.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorState.js +1 -1
- package/lib/stores/view/editor/DataCubeEditorState.js.map +1 -1
- package/lib/stores/view/extend/DataCubeColumnEditorState.d.ts.map +1 -1
- package/lib/stores/view/extend/DataCubeColumnEditorState.js +7 -5
- package/lib/stores/view/extend/DataCubeColumnEditorState.js.map +1 -1
- package/lib/stores/view/extend/DataCubeExtendManagerState.js +2 -2
- package/lib/stores/view/extend/DataCubeExtendManagerState.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.js +104 -108
- package/lib/stores/view/grid/DataCubeGridClientEngine.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js +3 -3
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts +3 -4
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js +5 -5
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.js +63 -8
- package/lib/stores/view/grid/DataCubeGridState.js.map +1 -1
- package/package.json +7 -7
- package/src/__lib__/DataCubeSetting.ts +1 -0
- package/src/components/DataCubeStatusBar.tsx +18 -3
- package/src/components/DataCubeTitleBar.tsx +3 -3
- package/src/components/core/DataCubeAlert.tsx +1 -1
- package/src/components/view/grid/DataCubeGrid.tsx +23 -7
- package/src/index.tsx +8 -3
- package/src/stores/DataCubeAPI.ts +9 -0
- package/src/stores/DataCubeOptions.ts +1 -1
- package/src/stores/core/DataCubeConfigurationBuilder.ts +1 -1
- package/src/stores/core/DataCubeEngine.tsx +47 -20
- package/src/stores/core/DataCubeQueryBuilder.ts +38 -30
- package/src/stores/core/DataCubeQueryBuilderUtils.ts +42 -67
- package/src/stores/core/DataCubeQuerySnapshot.ts +15 -4
- package/src/stores/core/DataCubeQuerySnapshotBuilder.ts +2 -6
- package/src/stores/core/DataCubeQuerySnapshotBuilderUtils.ts +2 -3
- package/src/stores/core/model/CachedDataCubeSource.ts +4 -0
- package/src/stores/services/DataCubeQuerySnapshotService.ts +2 -2
- package/src/stores/services/DataCubeSettingService.tsx +8 -0
- package/src/stores/services/DataCubeTaskService.ts +9 -7
- package/src/stores/view/DataCubeViewState.ts +58 -27
- package/src/stores/view/editor/DataCubeEditorState.tsx +1 -1
- package/src/stores/view/extend/DataCubeColumnEditorState.tsx +7 -15
- package/src/stores/view/extend/DataCubeExtendManagerState.tsx +2 -2
- package/src/stores/view/grid/DataCubeGridClientEngine.ts +149 -168
- package/src/stores/view/grid/DataCubeGridConfigurationBuilder.tsx +6 -7
- package/src/stores/view/grid/DataCubeGridQueryBuilder.ts +19 -32
- 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.
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.
|
|
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
|
|
125
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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('
|
|
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
|
-
|
|
225
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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('
|
|
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('
|
|
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
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
413
|
-
|
|
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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
)
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
468
|
-
|
|
469
|
-
|
|
479
|
+
!this._view.settingService.getBooleanValue(
|
|
480
|
+
DataCubeSettingKey.GRID_CLIENT__SUPPRESS_LARGE_DATASET_WARNING,
|
|
481
|
+
)
|
|
470
482
|
) {
|
|
471
|
-
this.
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
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
|
-
|
|
526
|
-
|
|
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
|
-
//
|
|
544
|
-
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
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
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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 =
|
|
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 =
|
|
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;
|