@finos/legend-cube-builder 0.0.5 → 0.0.6
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/docs/adding-an-operation.md +4 -2
- package/docs/demo/README.md +1 -1
- package/docs/hosting.md +40 -9
- package/lib/__lib__/LegendCubeHelpText.d.ts.map +1 -1
- package/lib/__lib__/LegendCubeHelpText.js +3 -1
- package/lib/__lib__/LegendCubeHelpText.js.map +1 -1
- package/lib/__lib__/LegendCubeLabels.d.ts +34 -5
- package/lib/__lib__/LegendCubeLabels.d.ts.map +1 -1
- package/lib/__lib__/LegendCubeLabels.js +45 -8
- package/lib/__lib__/LegendCubeLabels.js.map +1 -1
- package/lib/__lib__/LegendCubeNavigation.d.ts +23 -0
- package/lib/__lib__/LegendCubeNavigation.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeNavigation.js +33 -0
- package/lib/__lib__/LegendCubeNavigation.js.map +1 -0
- package/lib/__lib__/LegendCubeTesting.d.ts +3 -1
- package/lib/__lib__/LegendCubeTesting.d.ts.map +1 -1
- package/lib/__lib__/LegendCubeTesting.js +2 -0
- package/lib/__lib__/LegendCubeTesting.js.map +1 -1
- package/lib/__lib__/LegendCubeTour.d.ts +62 -0
- package/lib/__lib__/LegendCubeTour.d.ts.map +1 -0
- package/lib/__lib__/LegendCubeTour.js +149 -0
- package/lib/__lib__/LegendCubeTour.js.map +1 -0
- package/lib/__test-utils__/CubeExampleTestUtils.d.ts +34 -0
- package/lib/__test-utils__/CubeExampleTestUtils.d.ts.map +1 -0
- package/lib/__test-utils__/CubeExampleTestUtils.js +72 -0
- package/lib/__test-utils__/CubeExampleTestUtils.js.map +1 -0
- package/lib/__test-utils__/CubeVariantTestUtils.d.ts +16 -0
- package/lib/__test-utils__/CubeVariantTestUtils.d.ts.map +1 -0
- package/lib/__test-utils__/CubeVariantTestUtils.js +66 -0
- package/lib/__test-utils__/CubeVariantTestUtils.js.map +1 -0
- package/lib/components/CubeAddItems.d.ts.map +1 -1
- package/lib/components/CubeAddItems.js +2 -1
- package/lib/components/CubeAddItems.js.map +1 -1
- package/lib/components/CubeEditor.d.ts.map +1 -1
- package/lib/components/CubeEditor.js +11 -5
- package/lib/components/CubeEditor.js.map +1 -1
- package/lib/components/CubeFileMenu.d.ts.map +1 -1
- package/lib/components/CubeFileMenu.js +2 -1
- package/lib/components/CubeFileMenu.js.map +1 -1
- package/lib/components/CubeNodeIcon.d.ts.map +1 -1
- package/lib/components/CubeNodeIcon.js +2 -1
- package/lib/components/CubeNodeIcon.js.map +1 -1
- package/lib/components/canvas/CubeCanvas.d.ts.map +1 -1
- package/lib/components/canvas/CubeCanvas.js +3 -2
- package/lib/components/canvas/CubeCanvas.js.map +1 -1
- package/lib/components/canvas/CubeCanvasNode.d.ts.map +1 -1
- package/lib/components/canvas/CubeCanvasNode.js +4 -1
- package/lib/components/canvas/CubeCanvasNode.js.map +1 -1
- package/lib/components/dev-settings/CubeDevSettings.d.ts +2 -2
- package/lib/components/dev-settings/CubeDevSettings.d.ts.map +1 -1
- package/lib/components/dev-settings/CubeDevSettings.js +12 -8
- package/lib/components/dev-settings/CubeDevSettings.js.map +1 -1
- package/lib/components/editors/CubeColumnPicker.d.ts.map +1 -1
- package/lib/components/editors/CubeColumnPicker.js +3 -1
- package/lib/components/editors/CubeColumnPicker.js.map +1 -1
- package/lib/components/editors/CubeExplodeEditor.d.ts +26 -0
- package/lib/components/editors/CubeExplodeEditor.d.ts.map +1 -0
- package/lib/components/editors/CubeExplodeEditor.js +61 -0
- package/lib/components/editors/CubeExplodeEditor.js.map +1 -0
- package/lib/components/editors/CubeExpressionFilterEditor.d.ts.map +1 -1
- package/lib/components/editors/CubeExpressionFilterEditor.js +8 -5
- package/lib/components/editors/CubeExpressionFilterEditor.js.map +1 -1
- package/lib/components/editors/CubeExtendEditor.d.ts +0 -2
- package/lib/components/editors/CubeExtendEditor.d.ts.map +1 -1
- package/lib/components/editors/CubeExtendEditor.js +12 -11
- package/lib/components/editors/CubeExtendEditor.js.map +1 -1
- package/lib/components/editors/CubeJsonFieldsTree.d.ts +46 -0
- package/lib/components/editors/CubeJsonFieldsTree.d.ts.map +1 -0
- package/lib/components/editors/CubeJsonFieldsTree.js +93 -0
- package/lib/components/editors/CubeJsonFieldsTree.js.map +1 -0
- package/lib/components/editors/CubeNodeEditorRegistry.d.ts.map +1 -1
- package/lib/components/editors/CubeNodeEditorRegistry.js +3 -1
- package/lib/components/editors/CubeNodeEditorRegistry.js.map +1 -1
- package/lib/components/grid/CubeGridRegion.d.ts.map +1 -1
- package/lib/components/grid/CubeGridRegion.js +5 -4
- package/lib/components/grid/CubeGridRegion.js.map +1 -1
- package/lib/components/grid/CubeGridValues.d.ts +5 -3
- package/lib/components/grid/CubeGridValues.d.ts.map +1 -1
- package/lib/components/grid/CubeGridValues.js +8 -3
- package/lib/components/grid/CubeGridValues.js.map +1 -1
- package/lib/components/grid/CubeJsonExplorerDialog.d.ts +27 -0
- package/lib/components/grid/CubeJsonExplorerDialog.d.ts.map +1 -0
- package/lib/components/grid/CubeJsonExplorerDialog.js +102 -0
- package/lib/components/grid/CubeJsonExplorerDialog.js.map +1 -0
- package/lib/components/grid/CubeJsonViewerDialog.d.ts +27 -0
- package/lib/components/grid/CubeJsonViewerDialog.d.ts.map +1 -0
- package/lib/components/grid/CubeJsonViewerDialog.js +68 -0
- package/lib/components/grid/CubeJsonViewerDialog.js.map +1 -0
- package/lib/components/grid/CubeResultGrid.d.ts +15 -3
- package/lib/components/grid/CubeResultGrid.d.ts.map +1 -1
- package/lib/components/grid/CubeResultGrid.js +95 -3
- package/lib/components/grid/CubeResultGrid.js.map +1 -1
- package/lib/components/grid/CubeServerSideGrid.d.ts.map +1 -1
- package/lib/components/grid/CubeServerSideGrid.js +4 -2
- package/lib/components/grid/CubeServerSideGrid.js.map +1 -1
- package/lib/components/palette/CubePalette.d.ts.map +1 -1
- package/lib/components/palette/CubePalette.js +4 -1
- package/lib/components/palette/CubePalette.js.map +1 -1
- package/lib/components/source-picker/CubeIngestTab.d.ts +2 -2
- package/lib/components/source-picker/CubeIngestTab.d.ts.map +1 -1
- package/lib/components/source-picker/CubeIngestTab.js +19 -13
- package/lib/components/source-picker/CubeIngestTab.js.map +1 -1
- package/lib/components/tour/CubeTour.d.ts +36 -0
- package/lib/components/tour/CubeTour.d.ts.map +1 -0
- package/lib/components/tour/CubeTour.js +183 -0
- package/lib/components/tour/CubeTour.js.map +1 -0
- package/lib/index.css +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/stores/CubeEditorState.d.ts +17 -1
- package/lib/stores/CubeEditorState.d.ts.map +1 -1
- package/lib/stores/CubeEditorState.js +35 -5
- package/lib/stores/CubeEditorState.js.map +1 -1
- package/lib/stores/CubeExamples.d.ts.map +1 -1
- package/lib/stores/CubeExamples.js +101 -4
- package/lib/stores/CubeExamples.js.map +1 -1
- package/lib/stores/CubeExamplesState.d.ts.map +1 -1
- package/lib/stores/CubeExamplesState.js +4 -1
- package/lib/stores/CubeExamplesState.js.map +1 -1
- package/lib/stores/CubeGridQuickActions.d.ts +7 -0
- package/lib/stores/CubeGridQuickActions.d.ts.map +1 -1
- package/lib/stores/CubeGridQuickActions.js +20 -11
- package/lib/stores/CubeGridQuickActions.js.map +1 -1
- package/lib/stores/CubePureText.d.ts +20 -0
- package/lib/stores/CubePureText.d.ts.map +1 -0
- package/lib/stores/CubePureText.js +24 -0
- package/lib/stores/CubePureText.js.map +1 -0
- package/lib/stores/CubeTourState.d.ts +49 -0
- package/lib/stores/CubeTourState.d.ts.map +1 -0
- package/lib/stores/CubeTourState.js +92 -0
- package/lib/stores/CubeTourState.js.map +1 -0
- package/lib/stores/LegendCubeHost.d.ts +88 -0
- package/lib/stores/LegendCubeHost.d.ts.map +1 -0
- package/lib/stores/LegendCubeHost.js +149 -0
- package/lib/stores/LegendCubeHost.js.map +1 -0
- package/lib/stores/editors/CubeExplodeDraft.d.ts +87 -0
- package/lib/stores/editors/CubeExplodeDraft.d.ts.map +1 -0
- package/lib/stores/editors/CubeExplodeDraft.js +221 -0
- package/lib/stores/editors/CubeExplodeDraft.js.map +1 -0
- package/lib/stores/editors/CubeExpressionFilterDraft.d.ts +3 -0
- package/lib/stores/editors/CubeExpressionFilterDraft.d.ts.map +1 -1
- package/lib/stores/editors/CubeExpressionFilterDraft.js +4 -0
- package/lib/stores/editors/CubeExpressionFilterDraft.js.map +1 -1
- package/lib/stores/editors/CubeExtendDraft.d.ts +9 -0
- package/lib/stores/editors/CubeExtendDraft.d.ts.map +1 -1
- package/lib/stores/editors/CubeExtendDraft.js +26 -0
- package/lib/stores/editors/CubeExtendDraft.js.map +1 -1
- package/lib/stores/editors/CubeNodeDraftRegistry.d.ts.map +1 -1
- package/lib/stores/editors/CubeNodeDraftRegistry.js +6 -1
- package/lib/stores/editors/CubeNodeDraftRegistry.js.map +1 -1
- package/lib/stores/fixtures/CubeSalesDuckDbModel.d.ts +1 -0
- package/lib/stores/fixtures/CubeSalesDuckDbModel.d.ts.map +1 -1
- package/lib/stores/fixtures/CubeSalesDuckDbModel.js +8 -2
- package/lib/stores/fixtures/CubeSalesDuckDbModel.js.map +1 -1
- package/lib/stores/source-picker/CubeIngestTabState.d.ts +48 -14
- package/lib/stores/source-picker/CubeIngestTabState.d.ts.map +1 -1
- package/lib/stores/source-picker/CubeIngestTabState.js +159 -62
- package/lib/stores/source-picker/CubeIngestTabState.js.map +1 -1
- package/lib/stores/variant/CubeJson.d.ts +48 -0
- package/lib/stores/variant/CubeJson.d.ts.map +1 -0
- package/lib/stores/variant/CubeJson.js +207 -0
- package/lib/stores/variant/CubeJson.js.map +1 -0
- package/lib/stores/variant/CubeJsonExplorerState.d.ts +88 -0
- package/lib/stores/variant/CubeJsonExplorerState.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonExplorerState.js +297 -0
- package/lib/stores/variant/CubeJsonExplorerState.js.map +1 -0
- package/lib/stores/variant/CubeJsonFieldsState.d.ts +83 -0
- package/lib/stores/variant/CubeJsonFieldsState.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonFieldsState.js +207 -0
- package/lib/stores/variant/CubeJsonFieldsState.js.map +1 -0
- package/lib/stores/variant/CubeJsonOffers.d.ts +76 -0
- package/lib/stores/variant/CubeJsonOffers.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonOffers.js +250 -0
- package/lib/stores/variant/CubeJsonOffers.js.map +1 -0
- package/lib/stores/variant/CubeJsonParse.d.ts +28 -0
- package/lib/stores/variant/CubeJsonParse.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonParse.js +53 -0
- package/lib/stores/variant/CubeJsonParse.js.map +1 -0
- package/lib/stores/variant/CubeJsonSampling.d.ts +41 -0
- package/lib/stores/variant/CubeJsonSampling.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonSampling.js +59 -0
- package/lib/stores/variant/CubeJsonSampling.js.map +1 -0
- package/lib/stores/variant/CubeJsonShape.d.ts +87 -0
- package/lib/stores/variant/CubeJsonShape.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonShape.js +209 -0
- package/lib/stores/variant/CubeJsonShape.js.map +1 -0
- package/lib/stores/variant/CubeJsonViewerState.d.ts +33 -0
- package/lib/stores/variant/CubeJsonViewerState.d.ts.map +1 -0
- package/lib/stores/variant/CubeJsonViewerState.js +53 -0
- package/lib/stores/variant/CubeJsonViewerState.js.map +1 -0
- package/package.json +2 -2
- package/src/__lib__/LegendCubeHelpText.ts +4 -0
- package/src/__lib__/LegendCubeLabels.ts +60 -8
- package/src/__lib__/LegendCubeNavigation.ts +48 -0
- package/src/__lib__/LegendCubeTesting.ts +2 -0
- package/src/__lib__/LegendCubeTour.ts +173 -0
- package/src/__test-utils__/CubeExampleTestUtils.ts +119 -0
- package/src/__test-utils__/CubeVariantTestUtils.ts +103 -0
- package/src/components/CubeAddItems.tsx +2 -0
- package/src/components/CubeEditor.tsx +15 -0
- package/src/components/CubeFileMenu.tsx +2 -0
- package/src/components/CubeNodeIcon.tsx +2 -0
- package/src/components/canvas/CubeCanvas.tsx +17 -1
- package/src/components/canvas/CubeCanvasNode.tsx +7 -0
- package/src/components/dev-settings/CubeDevSettings.tsx +17 -2
- package/src/components/editors/CubeColumnPicker.tsx +3 -0
- package/src/components/editors/CubeExplodeEditor.tsx +207 -0
- package/src/components/editors/CubeExpressionFilterEditor.tsx +25 -8
- package/src/components/editors/CubeExtendEditor.tsx +32 -19
- package/src/components/editors/CubeJsonFieldsTree.tsx +316 -0
- package/src/components/editors/CubeNodeEditorRegistry.ts +3 -0
- package/src/components/grid/CubeGridRegion.tsx +21 -3
- package/src/components/grid/CubeGridValues.ts +8 -3
- package/src/components/grid/CubeJsonExplorerDialog.tsx +304 -0
- package/src/components/grid/CubeJsonViewerDialog.tsx +190 -0
- package/src/components/grid/CubeResultGrid.tsx +144 -2
- package/src/components/grid/CubeServerSideGrid.tsx +13 -0
- package/src/components/palette/CubePalette.tsx +9 -0
- package/src/components/source-picker/CubeIngestTab.tsx +62 -30
- package/src/components/tour/CubeTour.tsx +317 -0
- package/src/index.ts +7 -0
- package/src/stores/CubeEditorState.ts +36 -5
- package/src/stores/CubeExamples.ts +120 -2
- package/src/stores/CubeExamplesState.ts +9 -1
- package/src/stores/CubeGridQuickActions.ts +23 -12
- package/src/stores/CubePureText.ts +28 -0
- package/src/stores/CubeTourState.ts +116 -0
- package/src/stores/LegendCubeHost.ts +243 -0
- package/src/stores/editors/CubeExplodeDraft.ts +272 -0
- package/src/stores/editors/CubeExpressionFilterDraft.ts +4 -0
- package/src/stores/editors/CubeExtendDraft.ts +29 -0
- package/src/stores/editors/CubeNodeDraftRegistry.ts +7 -0
- package/src/stores/fixtures/CubeSalesDuckDbModel.ts +8 -2
- package/src/stores/source-picker/CubeIngestTabState.ts +253 -102
- package/src/stores/variant/CubeJson.ts +229 -0
- package/src/stores/variant/CubeJsonExplorerState.ts +378 -0
- package/src/stores/variant/CubeJsonFieldsState.ts +252 -0
- package/src/stores/variant/CubeJsonOffers.ts +359 -0
- package/src/stores/variant/CubeJsonParse.ts +75 -0
- package/src/stores/variant/CubeJsonSampling.ts +90 -0
- package/src/stores/variant/CubeJsonShape.ts +279 -0
- package/src/stores/variant/CubeJsonViewerState.ts +59 -0
- package/tsconfig.json +22 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026-present, Goldman Sachs
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
type Explode,
|
|
19
|
+
getVariantDatabaseProblem,
|
|
20
|
+
type Schema,
|
|
21
|
+
} from '@finos/legend-cube';
|
|
22
|
+
import { assertErrorThrown, type GeneratorFn } from '@finos/legend-shared';
|
|
23
|
+
import { action, computed, flow, makeObservable, observable } from 'mobx';
|
|
24
|
+
import { CubeEngineError } from '../../graph-manager/CubeEngine.js';
|
|
25
|
+
import type { CubeEditorState } from '../CubeEditorState.js';
|
|
26
|
+
import { CubeQueryRunAborted } from '../CubeQueryRun.js';
|
|
27
|
+
import {
|
|
28
|
+
type CubeJsonField,
|
|
29
|
+
getCubeJsonElementName,
|
|
30
|
+
getCubeJsonFields,
|
|
31
|
+
getFreeCubeColumnName,
|
|
32
|
+
} from '../variant/CubeJsonOffers.js';
|
|
33
|
+
import { readCubeJsonSample } from '../variant/CubeJsonSampling.js';
|
|
34
|
+
import type { CubeJsonSample } from '../variant/CubeJsonShape.js';
|
|
35
|
+
import { isSameList } from './CubeAggregationRows.js';
|
|
36
|
+
import { CubeNodeDraft } from './CubeNodeDraft.js';
|
|
37
|
+
|
|
38
|
+
/** An array a sample of the column holds, to explode */
|
|
39
|
+
export interface CubeExplodeArray {
|
|
40
|
+
/** The keys from the column to it, empty for the column itself */
|
|
41
|
+
readonly path: readonly string[];
|
|
42
|
+
/** What it held, e.g. `list of object` */
|
|
43
|
+
readonly description: string;
|
|
44
|
+
/** Its share, 0 to 1, of the places it could be */
|
|
45
|
+
readonly presence: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The arrays of a column's fields, in tree order */
|
|
49
|
+
const arraysOf = (field: CubeJsonField): CubeExplodeArray[] => [
|
|
50
|
+
...(field.offers.some((offer) => offer.explode !== undefined)
|
|
51
|
+
? [
|
|
52
|
+
{
|
|
53
|
+
path: field.path,
|
|
54
|
+
description: field.description,
|
|
55
|
+
presence: field.presence,
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
: []),
|
|
59
|
+
...field.children.flatMap(arraysOf),
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The Explode Array editor's draft (PLAN §11.20): the Variant column, the
|
|
64
|
+
* keys to its array and the new column's name. The arrays to pick from come
|
|
65
|
+
* from a sample of the column's documents, read after the node's input as
|
|
66
|
+
* Explore JSON reads them. Until a name is typed, the name follows the
|
|
67
|
+
* column and keys (`<last key>_element`, free in the input); picking another
|
|
68
|
+
* column drops the keys and the sample, which were the other column's.
|
|
69
|
+
*/
|
|
70
|
+
export class CubeExplodeDraft extends CubeNodeDraft<Explode> {
|
|
71
|
+
readonly editorState: CubeEditorState;
|
|
72
|
+
column: string;
|
|
73
|
+
path: readonly string[];
|
|
74
|
+
name: string;
|
|
75
|
+
/** What a sample of the column held, once read */
|
|
76
|
+
sample:
|
|
77
|
+
| { readonly column: string; readonly sample: CubeJsonSample }
|
|
78
|
+
| undefined;
|
|
79
|
+
isSampling = false;
|
|
80
|
+
/** Why the sample couldn't be read */
|
|
81
|
+
sampleError: string | undefined;
|
|
82
|
+
/** The name follows the column and keys until one is typed */
|
|
83
|
+
private namedByDefault: boolean;
|
|
84
|
+
private controller: AbortController | undefined;
|
|
85
|
+
/** Anything was changed; until then, `build()` gives the original back */
|
|
86
|
+
private touched = false;
|
|
87
|
+
|
|
88
|
+
constructor(original: Explode, editorState: CubeEditorState) {
|
|
89
|
+
super(original);
|
|
90
|
+
makeObservable<CubeExplodeDraft, 'touched' | 'namedByDefault'>(this, {
|
|
91
|
+
column: observable,
|
|
92
|
+
path: observable.ref,
|
|
93
|
+
name: observable,
|
|
94
|
+
sample: observable.ref,
|
|
95
|
+
isSampling: observable,
|
|
96
|
+
sampleError: observable,
|
|
97
|
+
namedByDefault: observable,
|
|
98
|
+
touched: observable,
|
|
99
|
+
arrays: computed,
|
|
100
|
+
sampleProblem: computed,
|
|
101
|
+
setColumn: action,
|
|
102
|
+
setKey: action,
|
|
103
|
+
addKey: action,
|
|
104
|
+
removeKey: action,
|
|
105
|
+
pickArray: action,
|
|
106
|
+
setName: action,
|
|
107
|
+
stopSample: action,
|
|
108
|
+
readSample: flow,
|
|
109
|
+
});
|
|
110
|
+
this.editorState = editorState;
|
|
111
|
+
this.column = original.column;
|
|
112
|
+
this.path = original.path;
|
|
113
|
+
this.name = original.name;
|
|
114
|
+
// a new node's, or one still named as Explore JSON names it
|
|
115
|
+
this.namedByDefault =
|
|
116
|
+
original.name === '' ||
|
|
117
|
+
original.name === this.defaultName(original.column, original.path);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** The element's default name for a column and keys: `<last key>_element`, free in the input */
|
|
121
|
+
private defaultName(column: string, path: readonly string[]): string {
|
|
122
|
+
return column
|
|
123
|
+
? getFreeCubeColumnName(
|
|
124
|
+
getCubeJsonElementName(column, path),
|
|
125
|
+
this.input?.schema.names() ?? [],
|
|
126
|
+
)
|
|
127
|
+
: '';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Why Find arrays can't read the column: the database the node's input
|
|
132
|
+
* runs on has no JSON functions; `undefined` when it can, or isn't known
|
|
133
|
+
*/
|
|
134
|
+
get sampleProblem(): string | undefined {
|
|
135
|
+
const { editorState, input } = this;
|
|
136
|
+
const { context, query } = editorState.document;
|
|
137
|
+
return input === undefined || context?.runtime === undefined
|
|
138
|
+
? undefined
|
|
139
|
+
: getVariantDatabaseProblem(
|
|
140
|
+
editorState.getRunDatabaseType(
|
|
141
|
+
query,
|
|
142
|
+
input.id,
|
|
143
|
+
context.model,
|
|
144
|
+
context.runtime,
|
|
145
|
+
),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** The node's input: its id and schema, once known */
|
|
150
|
+
private get input(): { id: string; schema: Schema } | undefined {
|
|
151
|
+
const [id] = this.editorState.document.query.getInputIds(this.original.id);
|
|
152
|
+
const schema =
|
|
153
|
+
id === undefined ? undefined : this.editorState.analysis.schemas.get(id);
|
|
154
|
+
return id === undefined || !schema ? undefined : { id, schema };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** The arrays the sample found, if it was of the picked column */
|
|
158
|
+
get arrays(): CubeExplodeArray[] | undefined {
|
|
159
|
+
const { sample, column } = this;
|
|
160
|
+
return sample && sample.column === column
|
|
161
|
+
? arraysOf(getCubeJsonFields(column, sample.sample))
|
|
162
|
+
: undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private edited(): void {
|
|
166
|
+
this.touched = true;
|
|
167
|
+
if (this.namedByDefault) {
|
|
168
|
+
this.name = this.defaultName(this.column, this.path);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Picks the column; another column's keys and sample are dropped */
|
|
173
|
+
setColumn(column: string): void {
|
|
174
|
+
if (column === this.column) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.stopSample();
|
|
178
|
+
this.column = column;
|
|
179
|
+
this.path = [];
|
|
180
|
+
this.sample = undefined;
|
|
181
|
+
this.sampleError = undefined;
|
|
182
|
+
this.edited();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
setKey(index: number, key: string): void {
|
|
186
|
+
this.path = this.path.map((each, at) => (at === index ? key : each));
|
|
187
|
+
this.edited();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
addKey(): void {
|
|
191
|
+
this.path = [...this.path, ''];
|
|
192
|
+
this.edited();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
removeKey(index: number): void {
|
|
196
|
+
this.path = this.path.filter((_, at) => at !== index);
|
|
197
|
+
this.edited();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Takes the keys of an array the sample found */
|
|
201
|
+
pickArray(path: readonly string[]): void {
|
|
202
|
+
this.path = path;
|
|
203
|
+
this.edited();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Types the name: it no longer follows the column and keys */
|
|
207
|
+
setName(name: string): void {
|
|
208
|
+
this.name = name;
|
|
209
|
+
this.namedByDefault = false;
|
|
210
|
+
this.touched = true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
stopSample(): void {
|
|
214
|
+
this.controller?.abort();
|
|
215
|
+
this.controller = undefined;
|
|
216
|
+
this.isSampling = false;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Reads the picked column's first values after the node's input, as
|
|
221
|
+
* Explore JSON does (listed in Runs, can be stopped), for the arrays they
|
|
222
|
+
* hold; picking another column abandons it
|
|
223
|
+
*/
|
|
224
|
+
*readSample(): GeneratorFn<void> {
|
|
225
|
+
const { editorState, column, input } = this;
|
|
226
|
+
const picked = column ? input?.schema.lookup(column) : undefined;
|
|
227
|
+
if (this.isSampling || !input || !picked || this.sampleProblem) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
this.controller = controller;
|
|
232
|
+
this.isSampling = true;
|
|
233
|
+
this.sampleError = undefined;
|
|
234
|
+
try {
|
|
235
|
+
const sample = (yield readCubeJsonSample(editorState, {
|
|
236
|
+
document: editorState.document,
|
|
237
|
+
afterId: input.id,
|
|
238
|
+
column: picked,
|
|
239
|
+
everyRow: false,
|
|
240
|
+
abortController: controller,
|
|
241
|
+
})) as CubeJsonSample | undefined;
|
|
242
|
+
if (this.controller === controller && sample) {
|
|
243
|
+
this.sample = { column, sample };
|
|
244
|
+
}
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if (
|
|
247
|
+
this.controller !== controller ||
|
|
248
|
+
error instanceof CubeQueryRunAborted
|
|
249
|
+
) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
assertErrorThrown(error);
|
|
253
|
+
this.sampleError =
|
|
254
|
+
error instanceof CubeEngineError ? error.firstLine : error.message;
|
|
255
|
+
} finally {
|
|
256
|
+
if (this.controller === controller) {
|
|
257
|
+
this.controller = undefined;
|
|
258
|
+
this.isSampling = false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
build(): Explode {
|
|
264
|
+
const { original, column, path, name } = this;
|
|
265
|
+
return !this.touched ||
|
|
266
|
+
(column === original.column &&
|
|
267
|
+
isSameList(path, original.path) &&
|
|
268
|
+
name === original.name)
|
|
269
|
+
? original
|
|
270
|
+
: original.with({ column, path, name });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
type NodeId,
|
|
51
51
|
} from '../../graph-manager/CubeEngine.js';
|
|
52
52
|
import type { CubeEditorState } from '../CubeEditorState.js';
|
|
53
|
+
import { CubeJsonFieldsState } from '../variant/CubeJsonFieldsState.js';
|
|
53
54
|
import {
|
|
54
55
|
buildCubeConditionCheckLambdas,
|
|
55
56
|
readCubeConditionCheck,
|
|
@@ -118,6 +119,8 @@ const asEngineError = (error: unknown): CubeEngineError =>
|
|
|
118
119
|
*/
|
|
119
120
|
export class CubeExpressionFilterDraft extends CubeNodeDraft<ExpressionFilter> {
|
|
120
121
|
readonly editorState: CubeEditorState;
|
|
122
|
+
/** A Variant input column's fields, opened from its chip (PLAN §11.20, V.9) */
|
|
123
|
+
readonly jsonFields: CubeJsonFieldsState;
|
|
121
124
|
code: string;
|
|
122
125
|
/** What the engine made of the code the last time it parsed it */
|
|
123
126
|
checked: CubeConditionCheckedCode | undefined;
|
|
@@ -149,6 +152,7 @@ export class CubeExpressionFilterDraft extends CubeNodeDraft<ExpressionFilter> {
|
|
|
149
152
|
follow: action,
|
|
150
153
|
});
|
|
151
154
|
this.editorState = editorState;
|
|
155
|
+
this.jsonFields = new CubeJsonFieldsState(editorState, original.id);
|
|
152
156
|
const { code, lambda } = original;
|
|
153
157
|
this.code = code || NEW_CONDITION_CODE;
|
|
154
158
|
this.checked = lambda ? { code, lambda, located: lambda } : undefined;
|
|
@@ -51,6 +51,8 @@ import {
|
|
|
51
51
|
type NodeId,
|
|
52
52
|
} from '../../graph-manager/CubeEngine.js';
|
|
53
53
|
import type { CubeEditorState } from '../CubeEditorState.js';
|
|
54
|
+
import { CubeJsonFieldsState } from '../variant/CubeJsonFieldsState.js';
|
|
55
|
+
import { getFreeCubeColumnName } from '../variant/CubeJsonOffers.js';
|
|
54
56
|
import {
|
|
55
57
|
buildCubeExtendTypingLambdas,
|
|
56
58
|
getCubeExtendUpstream,
|
|
@@ -110,6 +112,8 @@ const problemOf = (error: CubeEngineError): CubeExtendRowProblem => ({
|
|
|
110
112
|
*/
|
|
111
113
|
export class CubeExtendDraft extends CubeNodeDraft<Extend> {
|
|
112
114
|
readonly editorState: CubeEditorState;
|
|
115
|
+
/** A Variant input column's fields, opened from its chip (PLAN §11.20, V.9) */
|
|
116
|
+
readonly jsonFields: CubeJsonFieldsState;
|
|
113
117
|
rows: readonly CubeExtendRow[];
|
|
114
118
|
/** The typing the last Validate gave, for the rows as they were then */
|
|
115
119
|
typing: ExtendTyping | undefined;
|
|
@@ -131,6 +135,7 @@ export class CubeExtendDraft extends CubeNodeDraft<Extend> {
|
|
|
131
135
|
isValidated: computed,
|
|
132
136
|
applyDisabledReason: computed,
|
|
133
137
|
addRow: action,
|
|
138
|
+
addColumn: action,
|
|
134
139
|
removeRow: action,
|
|
135
140
|
moveRow: action,
|
|
136
141
|
setName: action,
|
|
@@ -139,6 +144,7 @@ export class CubeExtendDraft extends CubeNodeDraft<Extend> {
|
|
|
139
144
|
follow: action,
|
|
140
145
|
});
|
|
141
146
|
this.editorState = editorState;
|
|
147
|
+
this.jsonFields = new CubeJsonFieldsState(editorState, original.id);
|
|
142
148
|
const types = original.typing.kind === 'typed' ? original.typing.types : [];
|
|
143
149
|
this.rows = original.columns.map(({ name, code, lambda }, index) => ({
|
|
144
150
|
key: nextRowKey++,
|
|
@@ -214,6 +220,29 @@ export class CubeExtendDraft extends CubeNodeDraft<Extend> {
|
|
|
214
220
|
this.change([...this.rows, this.newRow()]);
|
|
215
221
|
}
|
|
216
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Adds a row of this code, named as given or the next free name, compared
|
|
225
|
+
* as the input's and the other rows' names fold (a JSON field's "+ column",
|
|
226
|
+
* V.9); it replaces a new row still empty
|
|
227
|
+
*/
|
|
228
|
+
addColumn(name: string, code: string): void {
|
|
229
|
+
const blank = this.rows.find(
|
|
230
|
+
(row) => row.code.trim() === NEW_EXPRESSION_CODE.trim() && !row.checked,
|
|
231
|
+
);
|
|
232
|
+
const others = this.rows.filter((row) => row !== blank);
|
|
233
|
+
this.change([
|
|
234
|
+
...others,
|
|
235
|
+
{
|
|
236
|
+
key: nextRowKey++,
|
|
237
|
+
name: getFreeCubeColumnName(name, [
|
|
238
|
+
...(this.inputSchema?.names() ?? []),
|
|
239
|
+
...others.map((row) => row.name),
|
|
240
|
+
]),
|
|
241
|
+
code,
|
|
242
|
+
},
|
|
243
|
+
]);
|
|
244
|
+
}
|
|
245
|
+
|
|
217
246
|
removeRow(key: number): void {
|
|
218
247
|
this.change(this.rows.filter((row) => row.key !== key));
|
|
219
248
|
}
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
Difference,
|
|
20
20
|
Distinct,
|
|
21
21
|
Drop,
|
|
22
|
+
Explode,
|
|
22
23
|
ExpressionFilter,
|
|
23
24
|
Pivot,
|
|
24
25
|
Extend,
|
|
@@ -38,6 +39,7 @@ import { guaranteeType } from '@finos/legend-shared';
|
|
|
38
39
|
import type { CubeEditorState } from '../CubeEditorState.js';
|
|
39
40
|
import { CubeConcatDraft } from './CubeConcatDraft.js';
|
|
40
41
|
import { CubeDifferenceDraft } from './CubeDifferenceDraft.js';
|
|
42
|
+
import { CubeExplodeDraft } from './CubeExplodeDraft.js';
|
|
41
43
|
import { CubeExpressionFilterDraft } from './CubeExpressionFilterDraft.js';
|
|
42
44
|
import { CubePivotDraft } from './CubePivotDraft.js';
|
|
43
45
|
import { CubeExtendDraft } from './CubeExtendDraft.js';
|
|
@@ -113,6 +115,11 @@ export const CUBE_NODE_DRAFT_FACTORIES: ReadonlyMap<
|
|
|
113
115
|
(node, editorState) =>
|
|
114
116
|
new CubePivotDraft(guaranteeType(node, Pivot), editorState),
|
|
115
117
|
],
|
|
118
|
+
[
|
|
119
|
+
Explode.TYPE,
|
|
120
|
+
(node, editorState) =>
|
|
121
|
+
new CubeExplodeDraft(guaranteeType(node, Explode), editorState),
|
|
122
|
+
],
|
|
116
123
|
]);
|
|
117
124
|
|
|
118
125
|
/**
|
|
@@ -24,8 +24,9 @@ import {
|
|
|
24
24
|
// The Sales sample (the review of the demo, 2026-10-13): a small table on an
|
|
25
25
|
// in-memory DuckDB, which the engine builds from setup SQL on each
|
|
26
26
|
// connection, as the H2 samples are. The H2 samples can't run the engine's
|
|
27
|
-
// pivot(); this one can, so Pivot works on a sample out of the box. Its
|
|
28
|
-
//
|
|
27
|
+
// pivot(); this one can, so Pivot works on a sample out of the box. Its orders
|
|
28
|
+
// hold JSON documents as text, for Parse as JSON (PLAN §11.20). Its cubes are
|
|
29
|
+
// direct-connection cubes: the connection is their model.
|
|
29
30
|
|
|
30
31
|
/** The setup SQL that makes the table, one statement an entry */
|
|
31
32
|
export const CUBE_SALES_SETUP_SQLS: readonly string[] = Object.freeze([
|
|
@@ -33,6 +34,10 @@ export const CUBE_SALES_SETUP_SQLS: readonly string[] = Object.freeze([
|
|
|
33
34
|
'create schema demo',
|
|
34
35
|
'create table demo.sales (id INTEGER PRIMARY KEY, country VARCHAR(10), product VARCHAR(10), year INTEGER, amount INTEGER, price DOUBLE)',
|
|
35
36
|
"insert into demo.sales values (1, 'France', 'Tea', 2022, 120, 2.5), (2, 'France', 'Coffee', 2023, 80, 3.1), (3, 'France', 'Tea', 2024, 150, 2.7), (4, 'Germany', 'Tea', 2022, 90, 2.4), (5, 'Germany', 'Coffee', 2022, 60, 3.0), (6, 'Germany', 'Coffee', 2024, 110, 3.3), (7, 'Japan', 'Tea', 2023, 200, 2.9), (8, 'Japan', 'Tea', 2024, 40, 2.9), (9, 'France', 'Coffee', 2024, 30, 3.2), (10, 'Spain', 'Coffee', 2022, 70, 3.0)",
|
|
37
|
+
// orders as JSON documents in a text column (PLAN §11.20): Parse as JSON
|
|
38
|
+
// reads them as a Variant column, which Explore JSON and Explode Array use
|
|
39
|
+
'create table demo.orders (id INTEGER PRIMARY KEY, document VARCHAR)',
|
|
40
|
+
`insert into demo.orders values (1, '{"customer":{"name":"Ann","tier":"gold","country":"France"},"items":[{"product":"Tea","qty":2,"price":2.5},{"product":"Coffee","qty":1,"price":3.1}],"paid":true,"placed":"2024-01-31","tags":["web","promo"]}'), (2, '{"customer":{"name":"Bob","tier":"silver","country":"Germany"},"items":[{"product":"Coffee","qty":3,"price":3.0}],"paid":false,"placed":"2024-02-02","tags":["store"]}'), (3, '{"customer":{"name":"Chloé","country":"France"},"items":[{"product":"Tea","qty":1,"price":2.7},{"product":"Tea","qty":4,"price":2.7},{"product":"Coffee","qty":1,"price":3.2}],"paid":true,"placed":"2024-02-14","tags":["web"]}'), (4, '{"customer":{"name":"Daichi","tier":"gold","country":"Japan"},"items":[{"product":"Tea","qty":5,"price":2.9}],"paid":true,"placed":"2024-03-01","tags":[]}'), (5, '{"customer":{"name":"Eva","tier":"bronze","country":"Spain"},"items":[],"paid":false,"placed":"2024-03-09","tags":["web","promo"]}'), (6, '{"customer":{"name":"Felix","tier":"silver","country":"Germany"},"items":[{"product":"Tea","qty":2,"price":2.4},{"product":"Coffee","qty":2,"price":3.3}],"paid":true,"placed":"2024-04-20","tags":["store","promo"]}'), (7, null), (8, '{"customer":{"name":"Gabi","tier":"gold","country":"Spain"},"items":[{"product":"Coffee","qty":1,"price":3.0}],"paid":true,"placed":"2024-05-05","tags":["web"]}')`,
|
|
36
41
|
]);
|
|
37
42
|
|
|
38
43
|
/** The model of a Sales cube: an in-memory DuckDB connection with its setup SQL */
|
|
@@ -52,3 +57,4 @@ export const CUBE_SALES_DATABASE = CUBE_DIRECT_DATABASE_PATH;
|
|
|
52
57
|
/** As a direct connection's coordinates store a name: quoted */
|
|
53
58
|
export const CUBE_SALES_SCHEMA = '"demo"';
|
|
54
59
|
export const CUBE_SALES_TABLE = '"sales"';
|
|
60
|
+
export const CUBE_SALES_ORDERS_TABLE = '"orders"';
|