@finos/legend-data-cube 0.1.32 → 0.2.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.
- package/lib/components/DataCubeStatusBar.d.ts.map +1 -1
- package/lib/components/DataCubeStatusBar.js +4 -2
- package/lib/components/DataCubeStatusBar.js.map +1 -1
- package/lib/components/view/editor/DataCubeEditor.d.ts.map +1 -1
- package/lib/components/view/editor/DataCubeEditor.js +5 -1
- package/lib/components/view/editor/DataCubeEditor.js.map +1 -1
- package/lib/components/view/grid/DataCubeMultidimensionalGrid.d.ts.map +1 -1
- package/lib/components/view/grid/DataCubeMultidimensionalGrid.js +40 -2
- package/lib/components/view/grid/DataCubeMultidimensionalGrid.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/DataCubeAPI.d.ts +6 -0
- package/lib/stores/DataCubeAPI.d.ts.map +1 -1
- package/lib/stores/DataCubeAPI.js +4 -0
- package/lib/stores/DataCubeAPI.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilder.d.ts +12 -0
- package/lib/stores/core/DataCubeQueryBuilder.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilder.js +141 -4
- package/lib/stores/core/DataCubeQueryBuilder.js.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts +2 -0
- package/lib/stores/core/DataCubeQueryBuilderUtils.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.js +18 -1
- package/lib/stores/core/DataCubeQueryBuilderUtils.js.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.d.ts +5 -0
- package/lib/stores/core/DataCubeQueryEngine.d.ts.map +1 -1
- package/lib/stores/core/DataCubeQueryEngine.js +8 -0
- package/lib/stores/core/DataCubeQueryEngine.js.map +1 -1
- package/lib/stores/core/DataCubeSnapshot.d.ts +2 -0
- package/lib/stores/core/DataCubeSnapshot.d.ts.map +1 -1
- package/lib/stores/core/DataCubeSnapshot.js.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorDimensionsPanelState.d.ts.map +1 -1
- package/lib/stores/view/editor/DataCubeEditorDimensionsPanelState.js +7 -4
- package/lib/stores/view/editor/DataCubeEditorDimensionsPanelState.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts +163 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridClientEngine.js +134 -2
- package/lib/stores/view/grid/DataCubeGridClientEngine.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts +155 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js +170 -2
- package/lib/stores/view/grid/DataCubeGridConfigurationBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridControllerState.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridControllerState.js +5 -3
- package/lib/stores/view/grid/DataCubeGridControllerState.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridDimensionalTree.d.ts +48 -0
- package/lib/stores/view/grid/DataCubeGridDimensionalTree.d.ts.map +1 -0
- package/lib/stores/view/grid/DataCubeGridDimensionalTree.js +168 -0
- package/lib/stores/view/grid/DataCubeGridDimensionalTree.js.map +1 -0
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.d.ts +1 -0
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.js +197 -0
- package/lib/stores/view/grid/DataCubeGridMenuBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts +2 -0
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js +7 -1
- package/lib/stores/view/grid/DataCubeGridQueryBuilder.js.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.d.ts +4 -1
- package/lib/stores/view/grid/DataCubeGridState.d.ts.map +1 -1
- package/lib/stores/view/grid/DataCubeGridState.js +24 -2
- package/lib/stores/view/grid/DataCubeGridState.js.map +1 -1
- package/package.json +2 -2
- package/src/components/DataCubeStatusBar.tsx +9 -2
- package/src/components/view/editor/DataCubeEditor.tsx +8 -1
- package/src/components/view/grid/DataCubeMultidimensionalGrid.tsx +63 -1
- package/src/stores/DataCubeAPI.ts +10 -0
- package/src/stores/core/DataCubeQueryBuilder.ts +256 -2
- package/src/stores/core/DataCubeQueryBuilderUtils.ts +22 -0
- package/src/stores/core/DataCubeQueryEngine.ts +9 -0
- package/src/stores/core/DataCubeSnapshot.ts +2 -0
- package/src/stores/view/editor/DataCubeEditorDimensionsPanelState.ts +8 -7
- package/src/stores/view/grid/DataCubeGridClientEngine.ts +252 -5
- package/src/stores/view/grid/DataCubeGridConfigurationBuilder.tsx +244 -3
- package/src/stores/view/grid/DataCubeGridControllerState.ts +10 -2
- package/src/stores/view/grid/DataCubeGridDimensionalTree.ts +268 -0
- package/src/stores/view/grid/DataCubeGridMenuBuilder.tsx +240 -0
- package/src/stores/view/grid/DataCubeGridQueryBuilder.ts +22 -1
- package/src/stores/view/grid/DataCubeGridState.ts +52 -2
- package/tsconfig.json +1 -0
|
@@ -23,13 +23,21 @@
|
|
|
23
23
|
|
|
24
24
|
import {
|
|
25
25
|
PRIMITIVE_TYPE,
|
|
26
|
+
V1_AppliedProperty,
|
|
27
|
+
V1_CString,
|
|
26
28
|
V1_Lambda,
|
|
29
|
+
V1_Variable,
|
|
27
30
|
type V1_AppliedFunction,
|
|
28
31
|
} from '@finos/legend-graph';
|
|
29
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
type DataCubeSnapshot,
|
|
34
|
+
type DataCubeSnapshotExtendedColumn,
|
|
35
|
+
type DataCubeSnapshotGroupBy,
|
|
36
|
+
} from './DataCubeSnapshot.js';
|
|
30
37
|
import { at, guaranteeType } from '@finos/legend-shared';
|
|
31
38
|
import {
|
|
32
39
|
DataCubeFunction,
|
|
40
|
+
DataCubeQueryFilterGroupOperator,
|
|
33
41
|
DataCubeQuerySortDirection,
|
|
34
42
|
type DataCubeQueryFunctionMap,
|
|
35
43
|
} from './DataCubeQueryEngine.js';
|
|
@@ -49,10 +57,15 @@ import {
|
|
|
49
57
|
_var,
|
|
50
58
|
_functionCompositionProcessor,
|
|
51
59
|
_extendRootAggregation,
|
|
60
|
+
_flattenFilterSnapshot,
|
|
52
61
|
} from './DataCubeQueryBuilderUtils.js';
|
|
53
62
|
import type { DataCubeSource } from './model/DataCubeSource.js';
|
|
54
|
-
import { _findCol } from './model/DataCubeColumn.js';
|
|
63
|
+
import { _findCol, _toCol } from './model/DataCubeColumn.js';
|
|
55
64
|
import type { DataCubeEngine } from './DataCubeEngine.js';
|
|
65
|
+
import {
|
|
66
|
+
DIMENSIONAL_L0_COLUMN,
|
|
67
|
+
type DataCubeDimensionalNode,
|
|
68
|
+
} from '../view/grid/DataCubeGridDimensionalTree.js';
|
|
56
69
|
|
|
57
70
|
export function buildExecutableQuery(
|
|
58
71
|
snapshot: DataCubeSnapshot,
|
|
@@ -312,3 +325,244 @@ export function buildExecutableQuery(
|
|
|
312
325
|
}
|
|
313
326
|
return at(sequence, sequence.length - 1);
|
|
314
327
|
}
|
|
328
|
+
|
|
329
|
+
export function buildDimensionalExecutableQuery(
|
|
330
|
+
snapshot: DataCubeSnapshot,
|
|
331
|
+
source: DataCubeSource,
|
|
332
|
+
engine: DataCubeEngine,
|
|
333
|
+
nodes: DataCubeDimensionalNode[],
|
|
334
|
+
options?: {
|
|
335
|
+
postProcessor?: (
|
|
336
|
+
snapshot: DataCubeSnapshot,
|
|
337
|
+
sequence: V1_AppliedFunction[],
|
|
338
|
+
funcMap: DataCubeQueryFunctionMap,
|
|
339
|
+
configuration: DataCubeConfiguration,
|
|
340
|
+
engine: DataCubeEngine,
|
|
341
|
+
) => void;
|
|
342
|
+
rootAggregation?:
|
|
343
|
+
| {
|
|
344
|
+
columnName: string;
|
|
345
|
+
}
|
|
346
|
+
| undefined;
|
|
347
|
+
pagination?:
|
|
348
|
+
| {
|
|
349
|
+
start: number;
|
|
350
|
+
end: number;
|
|
351
|
+
}
|
|
352
|
+
| undefined;
|
|
353
|
+
skipExecutionContext?: boolean;
|
|
354
|
+
},
|
|
355
|
+
) {
|
|
356
|
+
const data = snapshot.data;
|
|
357
|
+
const configuration = DataCubeConfiguration.serialization.fromJson(
|
|
358
|
+
data.configuration,
|
|
359
|
+
);
|
|
360
|
+
const sequence: V1_AppliedFunction[] = [];
|
|
361
|
+
const funcMap: DataCubeQueryFunctionMap = {};
|
|
362
|
+
const _process = _functionCompositionProcessor(sequence, funcMap);
|
|
363
|
+
|
|
364
|
+
// ------------------------------ DIMENSIONS -------------------------------------
|
|
365
|
+
|
|
366
|
+
if (data.tree && nodes.length > 0) {
|
|
367
|
+
const dimensionColNames = configuration.dimensions.dimensions.flatMap(
|
|
368
|
+
(col) => col.columns,
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
// removing columns which have been added to represent diimensions
|
|
372
|
+
configuration.columns = configuration.columns.map((col) => {
|
|
373
|
+
if (dimensionColNames.includes(col.name)) {
|
|
374
|
+
col.isSelected = false;
|
|
375
|
+
}
|
|
376
|
+
return col;
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Adding dimensions to the extended column
|
|
380
|
+
nodes.forEach((node) => {
|
|
381
|
+
const lambda = new V1_Lambda();
|
|
382
|
+
const parameter = new V1_Variable();
|
|
383
|
+
parameter.name = 'temp';
|
|
384
|
+
if (node.column === DIMENSIONAL_L0_COLUMN) {
|
|
385
|
+
const defaultValue = new V1_CString();
|
|
386
|
+
defaultValue.value = node.column;
|
|
387
|
+
lambda.body = [defaultValue];
|
|
388
|
+
} else {
|
|
389
|
+
const defaultValue = new V1_AppliedProperty();
|
|
390
|
+
defaultValue.parameters = [parameter];
|
|
391
|
+
defaultValue.property = node.column;
|
|
392
|
+
lambda.body = [defaultValue];
|
|
393
|
+
}
|
|
394
|
+
lambda.parameters = [parameter];
|
|
395
|
+
data.leafExtendedColumns.unshift({
|
|
396
|
+
name: node.dimension,
|
|
397
|
+
type: PRIMITIVE_TYPE.STRING,
|
|
398
|
+
mapFn: engine.serializeValueSpecification(lambda),
|
|
399
|
+
} satisfies DataCubeSnapshotExtendedColumn);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Adding dimensions to selected list
|
|
403
|
+
data.selectColumns = data.selectColumns.filter(
|
|
404
|
+
(col) => !dimensionColNames.includes(col.name),
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
const dimensionCols = nodes.map((col) =>
|
|
408
|
+
_toCol({ name: col.dimension, type: PRIMITIVE_TYPE.STRING }),
|
|
409
|
+
);
|
|
410
|
+
data.selectColumns.unshift(...dimensionCols);
|
|
411
|
+
|
|
412
|
+
// Adding filter based on group by nodes
|
|
413
|
+
const groupByNodes = nodes.flatMap((x) => x.groupByNodes);
|
|
414
|
+
if (groupByNodes.length > 0) {
|
|
415
|
+
const filter = [
|
|
416
|
+
_flattenFilterSnapshot(nodes.flatMap((x) => x.groupByNodes)),
|
|
417
|
+
];
|
|
418
|
+
if (data.filter) {
|
|
419
|
+
filter.push(data.filter);
|
|
420
|
+
data.filter = {
|
|
421
|
+
groupOperator: DataCubeQueryFilterGroupOperator.AND,
|
|
422
|
+
conditions: filter,
|
|
423
|
+
};
|
|
424
|
+
} else {
|
|
425
|
+
data.filter = filter.at(0);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Adding dimensions to groupby
|
|
430
|
+
if (data.groupBy) {
|
|
431
|
+
data.groupBy.columns.unshift(...dimensionCols);
|
|
432
|
+
} else {
|
|
433
|
+
data.groupBy = {
|
|
434
|
+
columns: dimensionCols,
|
|
435
|
+
} satisfies DataCubeSnapshotGroupBy;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// --------------------------------- LEAF-LEVEL EXTEND ---------------------------------
|
|
440
|
+
|
|
441
|
+
if (data.leafExtendedColumns.length) {
|
|
442
|
+
_process(
|
|
443
|
+
'leafExtend',
|
|
444
|
+
data.leafExtendedColumns.map((col) =>
|
|
445
|
+
_function(DataCubeFunction.EXTEND, [
|
|
446
|
+
_cols([
|
|
447
|
+
_colSpec(
|
|
448
|
+
col.name,
|
|
449
|
+
guaranteeType(
|
|
450
|
+
engine.deserializeValueSpecification(col.mapFn),
|
|
451
|
+
V1_Lambda,
|
|
452
|
+
),
|
|
453
|
+
col.reduceFn
|
|
454
|
+
? guaranteeType(
|
|
455
|
+
engine.deserializeValueSpecification(col.reduceFn),
|
|
456
|
+
V1_Lambda,
|
|
457
|
+
)
|
|
458
|
+
: undefined,
|
|
459
|
+
),
|
|
460
|
+
]),
|
|
461
|
+
]),
|
|
462
|
+
),
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// --------------------------------- FILTER ---------------------------------
|
|
467
|
+
|
|
468
|
+
if (data.filter) {
|
|
469
|
+
_process(
|
|
470
|
+
'filter',
|
|
471
|
+
_function(DataCubeFunction.FILTER, [
|
|
472
|
+
_lambda([_var()], [_filter(data.filter, engine.filterOperations)]),
|
|
473
|
+
]),
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// --------------------------------- SELECT ---------------------------------
|
|
478
|
+
|
|
479
|
+
if (data.selectColumns.length) {
|
|
480
|
+
_process(
|
|
481
|
+
'select',
|
|
482
|
+
_function(DataCubeFunction.SELECT, [
|
|
483
|
+
_cols(data.selectColumns.map((col) => _colSpec(col.name))),
|
|
484
|
+
]),
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// --------------------------------- PIVOT ---------------------------------
|
|
489
|
+
|
|
490
|
+
// TODO: rethink pivots for dimensional grid mode
|
|
491
|
+
|
|
492
|
+
// --------------------------------- GROUP BY ---------------------------------
|
|
493
|
+
|
|
494
|
+
if (data.groupBy) {
|
|
495
|
+
const groupBy = data.groupBy;
|
|
496
|
+
if (configuration.showRootAggregation && options?.rootAggregation) {
|
|
497
|
+
sequence.push(_extendRootAggregation(options.rootAggregation.columnName));
|
|
498
|
+
}
|
|
499
|
+
_process(
|
|
500
|
+
'groupBy',
|
|
501
|
+
_function(DataCubeFunction.GROUP_BY, [
|
|
502
|
+
_cols(groupBy.columns.map((col) => _colSpec(col.name))),
|
|
503
|
+
_cols(
|
|
504
|
+
_groupByAggCols(
|
|
505
|
+
groupBy.columns,
|
|
506
|
+
snapshot,
|
|
507
|
+
configuration,
|
|
508
|
+
engine.aggregateOperations,
|
|
509
|
+
),
|
|
510
|
+
),
|
|
511
|
+
]),
|
|
512
|
+
);
|
|
513
|
+
_process(
|
|
514
|
+
'groupBySort',
|
|
515
|
+
_function(DataCubeFunction.SORT, [
|
|
516
|
+
_collection(
|
|
517
|
+
groupBy.columns.map((col) =>
|
|
518
|
+
_function(
|
|
519
|
+
configuration.treeColumnSortDirection ===
|
|
520
|
+
DataCubeQuerySortDirection.ASCENDING
|
|
521
|
+
? DataCubeFunction.ASCENDING
|
|
522
|
+
: DataCubeFunction.DESCENDING,
|
|
523
|
+
[_col(col.name)],
|
|
524
|
+
),
|
|
525
|
+
),
|
|
526
|
+
),
|
|
527
|
+
]),
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// --------------------------------- GROUP-LEVEL EXTEND ---------------------------------
|
|
532
|
+
|
|
533
|
+
// TODO: implement group level extends for dimensional grid mode
|
|
534
|
+
|
|
535
|
+
// --------------------------------- SORT ---------------------------------
|
|
536
|
+
|
|
537
|
+
// TODO: implement sort for dimensional grid mode
|
|
538
|
+
|
|
539
|
+
// --------------------------------- LIMIT ---------------------------------
|
|
540
|
+
|
|
541
|
+
// TODO: rethink limits for dimensional grid mode
|
|
542
|
+
|
|
543
|
+
// --------------------------------- SLICE ---------------------------------
|
|
544
|
+
|
|
545
|
+
// TODO: rethink slice for dimensional grid mode
|
|
546
|
+
// slice can lead to incorrect view of data for dimensionality
|
|
547
|
+
|
|
548
|
+
// --------------------------------- FINALIZE ---------------------------------
|
|
549
|
+
|
|
550
|
+
if (!options?.skipExecutionContext) {
|
|
551
|
+
const executionContext = engine.buildExecutionContext(source);
|
|
552
|
+
if (executionContext) {
|
|
553
|
+
sequence.push(executionContext);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
options?.postProcessor?.(snapshot, sequence, funcMap, configuration, engine);
|
|
558
|
+
|
|
559
|
+
if (sequence.length === 0) {
|
|
560
|
+
return source.query;
|
|
561
|
+
}
|
|
562
|
+
for (let i = 0; i < sequence.length; i++) {
|
|
563
|
+
at(sequence, i).parameters.unshift(
|
|
564
|
+
i === 0 ? source.query : at(sequence, i - 1),
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
return at(sequence, sequence.length - 1);
|
|
568
|
+
}
|
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
isPivotResultColumnName,
|
|
82
82
|
getPivotResultColumnBaseColumnName,
|
|
83
83
|
DEFAULT_ROOT_AGGREGATION_COLUMN_VALUE,
|
|
84
|
+
DataCubeQueryFilterOperator,
|
|
84
85
|
} from './DataCubeQueryEngine.js';
|
|
85
86
|
import type { DataCubeQueryFilterOperation } from './filter/DataCubeQueryFilterOperation.js';
|
|
86
87
|
import type { DataCubeQueryAggregateOperation } from './aggregation/DataCubeQueryAggregateOperation.js';
|
|
@@ -88,6 +89,7 @@ import {
|
|
|
88
89
|
DataCubeColumnConfiguration,
|
|
89
90
|
type DataCubeConfiguration,
|
|
90
91
|
} from './model/DataCubeConfiguration.js';
|
|
92
|
+
import type { DataCubeDimensionalGroupByNode } from '../view/grid/DataCubeGridDimensionalTree.js';
|
|
91
93
|
|
|
92
94
|
// --------------------------------- UTILITIES ---------------------------------
|
|
93
95
|
|
|
@@ -645,3 +647,23 @@ export function _filter(
|
|
|
645
647
|
return filterCondition.not ? _not(condition) : condition;
|
|
646
648
|
}
|
|
647
649
|
}
|
|
650
|
+
|
|
651
|
+
export function _flattenFilterSnapshot(
|
|
652
|
+
groupByNodes: DataCubeDimensionalGroupByNode[],
|
|
653
|
+
): DataCubeSnapshotFilter {
|
|
654
|
+
const filterConditions = groupByNodes.map((node) => {
|
|
655
|
+
return {
|
|
656
|
+
name: node.column,
|
|
657
|
+
type: 'String', // Assuming all filters are strings — update if needed
|
|
658
|
+
operator: DataCubeQueryFilterOperator.EQUAL,
|
|
659
|
+
value: {
|
|
660
|
+
type: 'String',
|
|
661
|
+
value: node.filter,
|
|
662
|
+
} satisfies DataCubeOperationValue,
|
|
663
|
+
} satisfies DataCubeSnapshotFilterCondition;
|
|
664
|
+
});
|
|
665
|
+
return {
|
|
666
|
+
groupOperator: DataCubeQueryFilterGroupOperator.AND,
|
|
667
|
+
conditions: filterConditions,
|
|
668
|
+
} satisfies DataCubeSnapshotFilter;
|
|
669
|
+
}
|
|
@@ -273,6 +273,11 @@ export enum DataCubeGridMode {
|
|
|
273
273
|
MULTIDIMENSIONAL = 'Multidimensional',
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
export enum DataCubeClientModelOption {
|
|
277
|
+
ROW_DATA = 'rowData',
|
|
278
|
+
COLUMN_DEFS = 'columnDefs',
|
|
279
|
+
}
|
|
280
|
+
|
|
276
281
|
export enum DataCubeTitleBarMenuItems {
|
|
277
282
|
VIEW_SOURCE = 'View Source',
|
|
278
283
|
RESET_TO_LATEST_SAVE = 'Reset to Latest Save',
|
|
@@ -409,6 +414,10 @@ export function ofDataType(
|
|
|
409
414
|
return dataTypes.includes(getDataType(type));
|
|
410
415
|
}
|
|
411
416
|
|
|
417
|
+
export function isDimensionalGridMode(gridMode: DataCubeGridMode) {
|
|
418
|
+
return gridMode === DataCubeGridMode.MULTIDIMENSIONAL;
|
|
419
|
+
}
|
|
420
|
+
|
|
412
421
|
export function isPrimitiveType(type: string) {
|
|
413
422
|
return (
|
|
414
423
|
[
|
|
@@ -29,6 +29,7 @@ import type {
|
|
|
29
29
|
DataCubeQuerySortDirection,
|
|
30
30
|
} from './DataCubeQueryEngine.js';
|
|
31
31
|
import type { DataCubeColumn } from './model/DataCubeColumn.js';
|
|
32
|
+
import type { DataCubeDimensionalTree } from '../view/grid/DataCubeGridDimensionalTree.js';
|
|
32
33
|
|
|
33
34
|
export type DataCubeSnapshotFilterCondition = DataCubeColumn & {
|
|
34
35
|
value: DataCubeOperationValue;
|
|
@@ -85,6 +86,7 @@ export type DataCubeSnapshotData = {
|
|
|
85
86
|
groupExtendedColumns: DataCubeSnapshotExtendedColumn[];
|
|
86
87
|
sortColumns: DataCubeSnapshotSortColumn[];
|
|
87
88
|
limit: number | undefined;
|
|
89
|
+
tree?: DataCubeDimensionalTree | undefined;
|
|
88
90
|
};
|
|
89
91
|
|
|
90
92
|
export class DataCubeSnapshot {
|
|
@@ -226,13 +226,14 @@ export class DataCubeEditorDimensionsPanelState
|
|
|
226
226
|
name: dimension.name,
|
|
227
227
|
columns: dimension.columns.map((column) => column.name),
|
|
228
228
|
}));
|
|
229
|
+
newSnapshot.data.configuration = {
|
|
230
|
+
...newSnapshot.data.configuration,
|
|
231
|
+
dimensions: DataCubeDimensionsConfiguration.serialization.toJson(
|
|
232
|
+
dimensionsConfiguration,
|
|
233
|
+
),
|
|
234
|
+
};
|
|
235
|
+
} else {
|
|
236
|
+
newSnapshot = baseSnapshot;
|
|
229
237
|
}
|
|
230
|
-
|
|
231
|
-
newSnapshot.data.configuration = {
|
|
232
|
-
...newSnapshot.data.configuration,
|
|
233
|
-
dimensions: DataCubeDimensionsConfiguration.serialization.toJson(
|
|
234
|
-
dimensionsConfiguration,
|
|
235
|
-
),
|
|
236
|
-
};
|
|
237
238
|
}
|
|
238
239
|
}
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
IllegalStateError,
|
|
26
26
|
assertErrorThrown,
|
|
27
27
|
guaranteeNonNullable,
|
|
28
|
+
guaranteeType,
|
|
28
29
|
hashObject,
|
|
29
30
|
isBoolean,
|
|
30
31
|
isNonNullable,
|
|
@@ -35,11 +36,13 @@ import {
|
|
|
35
36
|
PRIMITIVE_TYPE,
|
|
36
37
|
PureClientVersion,
|
|
37
38
|
type TabularDataSet,
|
|
39
|
+
type TDSRow,
|
|
38
40
|
} from '@finos/legend-graph';
|
|
39
41
|
import { makeObservable, observable, runInAction } from 'mobx';
|
|
40
|
-
import
|
|
42
|
+
import {
|
|
41
43
|
DataCubeConfiguration,
|
|
42
|
-
DataCubeConfigurationColorKey,
|
|
44
|
+
type DataCubeConfigurationColorKey,
|
|
45
|
+
type DataCubeDimensionConfiguration,
|
|
43
46
|
} from '../../core/model/DataCubeConfiguration.js';
|
|
44
47
|
import { type DataCubeSnapshot } from '../../core/DataCubeSnapshot.js';
|
|
45
48
|
import { _findCol, _sortByColName } from '../../core/model/DataCubeColumn.js';
|
|
@@ -47,7 +50,10 @@ import { isPivotResultColumnName } from '../../core/DataCubeQueryEngine.js';
|
|
|
47
50
|
import { buildSnapshotFromGridState } from './DataCubeGridSnapshotBuilder.js';
|
|
48
51
|
import { AlertType } from '../../services/DataCubeAlertService.js';
|
|
49
52
|
import type { DataCubeViewState } from '../DataCubeViewState.js';
|
|
50
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
buildDimensionalGridDataFetchExecutableQuery,
|
|
55
|
+
buildGridDataFetchExecutableQuery,
|
|
56
|
+
} from './DataCubeGridQueryBuilder.js';
|
|
51
57
|
import { DataCubeSettingKey } from '../../../__lib__/DataCubeSetting.js';
|
|
52
58
|
import { DEFAULT_ALERT_WINDOW_CONFIG } from '../../services/DataCubeLayoutService.js';
|
|
53
59
|
import {
|
|
@@ -57,8 +63,22 @@ import {
|
|
|
57
63
|
import { _lambda } from '../../core/DataCubeQueryBuilderUtils.js';
|
|
58
64
|
import { sum } from 'mathjs';
|
|
59
65
|
import { DataCubeEvent } from '../../../__lib__/DataCubeEvent.js';
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
import { generateColumnDefsForDimensions } from './DataCubeGridConfigurationBuilder.js';
|
|
67
|
+
import {
|
|
68
|
+
DataCubeDimensionalMetadata,
|
|
69
|
+
generateDimensionalPaths,
|
|
70
|
+
type DataCubeDimensionalNode,
|
|
71
|
+
type DataCubeDimensionalGroupByNode,
|
|
72
|
+
DIMENSIONAL_L0_COLUMN,
|
|
73
|
+
} from './DataCubeGridDimensionalTree.js';
|
|
74
|
+
|
|
75
|
+
type DataCubeGridClientCellValue =
|
|
76
|
+
| string
|
|
77
|
+
| number
|
|
78
|
+
| boolean
|
|
79
|
+
| Map<string, DataCubeDimensionalMetadata>
|
|
80
|
+
| null
|
|
81
|
+
| undefined;
|
|
62
82
|
type DataCubeGridClientRowData = {
|
|
63
83
|
[key: string]: DataCubeGridClientCellValue;
|
|
64
84
|
};
|
|
@@ -259,6 +279,136 @@ function buildRowData(
|
|
|
259
279
|
});
|
|
260
280
|
}
|
|
261
281
|
|
|
282
|
+
function buildDimensionalRowData(
|
|
283
|
+
result: TabularDataSet,
|
|
284
|
+
snapshot: DataCubeSnapshot,
|
|
285
|
+
dimensionalNodes: DataCubeDimensionalNode[],
|
|
286
|
+
rowData: DataCubeGridClientRowData[],
|
|
287
|
+
dimensions: DataCubeDimensionConfiguration[],
|
|
288
|
+
): DataCubeGridClientRowData[] {
|
|
289
|
+
const newRows = result.rows.map((rawRow) =>
|
|
290
|
+
_createClientRow(rawRow, result.columns, dimensionalNodes, dimensions),
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
const updated = [...rowData];
|
|
294
|
+
for (const newRow of newRows) {
|
|
295
|
+
const insertIndex = _findInsertIndex(newRow, updated, dimensionalNodes);
|
|
296
|
+
updated.splice(insertIndex, 0, newRow);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return updated;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function _createClientRow(
|
|
303
|
+
rawRow: TDSRow,
|
|
304
|
+
columns: string[],
|
|
305
|
+
nodes: DataCubeDimensionalNode[],
|
|
306
|
+
configs: DataCubeDimensionConfiguration[],
|
|
307
|
+
): DataCubeGridClientRowData {
|
|
308
|
+
const row: DataCubeGridClientRowData = {};
|
|
309
|
+
rawRow.values.forEach((value, i) => {
|
|
310
|
+
row[guaranteeNonNullable(columns[i])] = isBoolean(value)
|
|
311
|
+
? String(value)
|
|
312
|
+
: isNonNullable(value)
|
|
313
|
+
? value
|
|
314
|
+
: INTERNAL__GRID_CLIENT_MISSING_VALUE;
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const metadata = new Map<string, DataCubeDimensionalMetadata>();
|
|
318
|
+
for (const node of nodes) {
|
|
319
|
+
const config = guaranteeNonNullable(
|
|
320
|
+
configs.find((d) => d.name === node.dimension),
|
|
321
|
+
);
|
|
322
|
+
metadata.set(
|
|
323
|
+
node.dimension,
|
|
324
|
+
new DataCubeDimensionalMetadata(
|
|
325
|
+
node.column,
|
|
326
|
+
config.columns.indexOf(node.column),
|
|
327
|
+
node.groupByNodes,
|
|
328
|
+
),
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
row.metadata = metadata;
|
|
332
|
+
return row;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function _findInsertIndex(
|
|
336
|
+
newRow: DataCubeGridClientRowData,
|
|
337
|
+
existing: DataCubeGridClientRowData[],
|
|
338
|
+
dimensionalNodes: DataCubeDimensionalNode[],
|
|
339
|
+
): number {
|
|
340
|
+
const metadata = guaranteeType(
|
|
341
|
+
newRow.metadata,
|
|
342
|
+
Map<string, DataCubeDimensionalMetadata>,
|
|
343
|
+
);
|
|
344
|
+
const groupByNodes = [...metadata.values()].flatMap((m) => m.groupByNodes);
|
|
345
|
+
const dimensions = dimensionalNodes.map((d) => d.dimension);
|
|
346
|
+
const latest = _latestGroupByFilters(groupByNodes);
|
|
347
|
+
|
|
348
|
+
for (let i = existing.length - 1; i >= 0; i--) {
|
|
349
|
+
const existingRow = guaranteeNonNullable(existing[i]);
|
|
350
|
+
if (
|
|
351
|
+
_isParentRow(existingRow, groupByNodes.length, newRow, latest, dimensions)
|
|
352
|
+
) {
|
|
353
|
+
return i + 1;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return existing.length;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function _isParentRow(
|
|
361
|
+
existing: DataCubeGridClientRowData,
|
|
362
|
+
groupByCount: number,
|
|
363
|
+
newRow: DataCubeGridClientRowData,
|
|
364
|
+
filters: DataCubeDimensionalGroupByNode[],
|
|
365
|
+
dimensions: string[],
|
|
366
|
+
): boolean {
|
|
367
|
+
if (groupByCount === 0) {
|
|
368
|
+
let allCount = 0;
|
|
369
|
+
const match = dimensions.every((d) => {
|
|
370
|
+
const e = existing[d],
|
|
371
|
+
n = newRow[d];
|
|
372
|
+
if (e === null || n === null) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
if (String(e) === DIMENSIONAL_L0_COLUMN) {
|
|
376
|
+
allCount++;
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
return String(e) === String(n);
|
|
380
|
+
});
|
|
381
|
+
return match && allCount >= 1 && allCount < dimensions.length;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return dimensions.every((d) => {
|
|
385
|
+
const filter = filters.find((f) => f.dimension === d);
|
|
386
|
+
const e = existing[d],
|
|
387
|
+
n = newRow[d];
|
|
388
|
+
if (e === null || n === null) {
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
if (filter) {
|
|
392
|
+
return (
|
|
393
|
+
String(e) === String(filter.filter) ||
|
|
394
|
+
String(e) === String(n) ||
|
|
395
|
+
String(e) === DIMENSIONAL_L0_COLUMN
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
return String(e) === String(n);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function _latestGroupByFilters(
|
|
403
|
+
nodes: DataCubeDimensionalGroupByNode[],
|
|
404
|
+
): DataCubeDimensionalGroupByNode[] {
|
|
405
|
+
const map = new Map<string, DataCubeDimensionalGroupByNode>();
|
|
406
|
+
for (const node of nodes) {
|
|
407
|
+
map.set(node.dimension, node);
|
|
408
|
+
}
|
|
409
|
+
return [...map.values()];
|
|
410
|
+
}
|
|
411
|
+
|
|
262
412
|
async function getCastColumns(
|
|
263
413
|
currentSnapshot: DataCubeSnapshot,
|
|
264
414
|
view: DataCubeViewState,
|
|
@@ -302,6 +452,103 @@ async function getCastColumns(
|
|
|
302
452
|
});
|
|
303
453
|
}
|
|
304
454
|
|
|
455
|
+
export async function fetchDimensionalQueryRows(
|
|
456
|
+
snapshot: DataCubeSnapshot,
|
|
457
|
+
view: DataCubeViewState,
|
|
458
|
+
) {
|
|
459
|
+
const task = view.taskService.newTask('Fetching data...');
|
|
460
|
+
|
|
461
|
+
let rowData: DataCubeGridClientRowData[] = [];
|
|
462
|
+
|
|
463
|
+
const configuration = DataCubeConfiguration.serialization.fromJson(
|
|
464
|
+
snapshot.data.configuration,
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
// upgrade here by not shooting extra sqls
|
|
468
|
+
const paths = generateDimensionalPaths(
|
|
469
|
+
guaranteeNonNullable(snapshot.data.tree),
|
|
470
|
+
);
|
|
471
|
+
|
|
472
|
+
for (const path of paths) {
|
|
473
|
+
const executableQuery = buildDimensionalGridDataFetchExecutableQuery(
|
|
474
|
+
snapshot,
|
|
475
|
+
view.source,
|
|
476
|
+
view.engine,
|
|
477
|
+
path,
|
|
478
|
+
);
|
|
479
|
+
let result: DataCubeExecutionResult;
|
|
480
|
+
|
|
481
|
+
try {
|
|
482
|
+
result = await view.engine.executeQuery(
|
|
483
|
+
_lambda([], [executableQuery]),
|
|
484
|
+
view.source,
|
|
485
|
+
{
|
|
486
|
+
debug: view.settingService.getBooleanValue(
|
|
487
|
+
DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
|
|
488
|
+
),
|
|
489
|
+
clientVersion: view.settingService.getBooleanValue(
|
|
490
|
+
DataCubeSettingKey.DEBUGGER__USE_DEV_CLIENT_PROTOCOL_VERSION,
|
|
491
|
+
)
|
|
492
|
+
? PureClientVersion.VX_X_X
|
|
493
|
+
: undefined,
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
rowData = buildDimensionalRowData(
|
|
498
|
+
result.result.result,
|
|
499
|
+
snapshot,
|
|
500
|
+
path,
|
|
501
|
+
rowData,
|
|
502
|
+
configuration.dimensions.dimensions,
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
view.taskService.endTask(task);
|
|
506
|
+
} catch (error) {
|
|
507
|
+
assertErrorThrown(error);
|
|
508
|
+
if (error instanceof DataCubeExecutionError) {
|
|
509
|
+
view.alertService.alertExecutionError(error, {
|
|
510
|
+
message: `Data Fetch Failure: Can't execute query.`,
|
|
511
|
+
text: `Error: ${error.message}`,
|
|
512
|
+
});
|
|
513
|
+
} else {
|
|
514
|
+
view.alertService.alertError(error, {
|
|
515
|
+
message: `Data Fetch Failure: ${error.message}`,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
view.taskService.endTask(task);
|
|
519
|
+
return {
|
|
520
|
+
rowData: [],
|
|
521
|
+
columnDefs: [],
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (
|
|
526
|
+
view.settingService.getBooleanValue(
|
|
527
|
+
DataCubeSettingKey.DEBUGGER__ENABLE_DEBUG_MODE,
|
|
528
|
+
)
|
|
529
|
+
) {
|
|
530
|
+
view.engine.debugProcess(
|
|
531
|
+
`Execution`,
|
|
532
|
+
['Query', result.executedQuery],
|
|
533
|
+
[
|
|
534
|
+
'Stats',
|
|
535
|
+
`${rowData.length} rows, ${result.result.result.columns.length} columns`,
|
|
536
|
+
],
|
|
537
|
+
[
|
|
538
|
+
'SQL',
|
|
539
|
+
result.executedSQL ?? `-- Error: failed to extract executed SQL`,
|
|
540
|
+
],
|
|
541
|
+
['SQL Execution Time', result.executionTime],
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
rowData: rowData,
|
|
548
|
+
columnDefs: generateColumnDefsForDimensions(snapshot, configuration),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
305
552
|
export type DataCubeGridClientDataFetchRequest = {
|
|
306
553
|
startRow: number | undefined;
|
|
307
554
|
endRow: number | undefined;
|