@finos/legend-application-data-cube 0.1.2 → 0.1.4
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__/LegendDataCubeNavigation.d.ts +26 -0
- package/lib/__lib__/LegendDataCubeNavigation.d.ts.map +1 -0
- package/lib/__lib__/LegendDataCubeNavigation.js +29 -0
- package/lib/__lib__/LegendDataCubeNavigation.js.map +1 -0
- package/lib/components/DataCubeEditor.d.ts.map +1 -1
- package/lib/components/DataCubeEditor.js +31 -3
- package/lib/components/DataCubeEditor.js.map +1 -1
- package/lib/components/LegendDataCubeWebApplication.d.ts.map +1 -1
- package/lib/components/LegendDataCubeWebApplication.js +4 -2
- package/lib/components/LegendDataCubeWebApplication.js.map +1 -1
- package/lib/components/source/DataCubeSourceEditor.js.map +1 -1
- package/lib/components/source/ExistingDataCubeQuery.d.ts +19 -0
- package/lib/components/source/ExistingDataCubeQuery.d.ts.map +1 -0
- package/lib/components/source/ExistingDataCubeQuery.js +36 -0
- package/lib/components/source/ExistingDataCubeQuery.js.map +1 -0
- package/lib/components/source/SavedQuerySourceEditor.js +1 -1
- package/lib/components/source/SavedQuerySourceEditor.js.map +1 -1
- package/lib/index.css +1 -1
- package/lib/package.json +3 -2
- package/lib/stores/LegendDataCubeEditorStore.d.ts +9 -3
- package/lib/stores/LegendDataCubeEditorStore.d.ts.map +1 -1
- package/lib/stores/LegendDataCubeEditorStore.js +66 -4
- package/lib/stores/LegendDataCubeEditorStore.js.map +1 -1
- package/lib/stores/engine/LegendExecutionDataCubeEngine.d.ts +10 -4
- package/lib/stores/engine/LegendExecutionDataCubeEngine.d.ts.map +1 -1
- package/lib/stores/engine/LegendExecutionDataCubeEngine.js +17 -13
- package/lib/stores/engine/LegendExecutionDataCubeEngine.js.map +1 -1
- package/lib/stores/model/DataCubeGenericSource.d.ts +18 -0
- package/lib/stores/model/DataCubeGenericSource.d.ts.map +1 -0
- package/lib/stores/model/DataCubeGenericSource.js +18 -0
- package/lib/stores/model/DataCubeGenericSource.js.map +1 -0
- package/lib/stores/model/DataCubeGenericSourceHelper.d.ts +24 -0
- package/lib/stores/model/DataCubeGenericSourceHelper.d.ts.map +1 -0
- package/lib/stores/model/DataCubeGenericSourceHelper.js +58 -0
- package/lib/stores/model/DataCubeGenericSourceHelper.js.map +1 -0
- package/lib/stores/model/DataCubeQueryContent.d.ts +23 -0
- package/lib/stores/model/DataCubeQueryContent.d.ts.map +1 -0
- package/lib/stores/model/DataCubeQueryContent.js +21 -0
- package/lib/stores/model/DataCubeQueryContent.js.map +1 -0
- package/lib/stores/model/LegendSavedQuerySource.d.ts +21 -0
- package/lib/stores/model/LegendSavedQuerySource.d.ts.map +1 -0
- package/lib/stores/model/LegendSavedQuerySource.js +24 -0
- package/lib/stores/model/LegendSavedQuerySource.js.map +1 -0
- package/lib/stores/source/CubeInputSource.d.ts +0 -6
- package/lib/stores/source/CubeInputSource.d.ts.map +1 -1
- package/lib/stores/source/CubeInputSource.js +0 -9
- package/lib/stores/source/CubeInputSource.js.map +1 -1
- package/lib/stores/source/CubeInputSourceLoader.d.ts +3 -3
- package/lib/stores/source/CubeInputSourceLoader.d.ts.map +1 -1
- package/lib/stores/source/CubeInputSourceLoader.js +1 -2
- package/lib/stores/source/CubeInputSourceLoader.js.map +1 -1
- package/lib/stores/source/LegendCubeViewer.d.ts +3 -3
- package/lib/stores/source/LegendCubeViewer.d.ts.map +1 -1
- package/lib/stores/source/LegendCubeViewer.js.map +1 -1
- package/lib/stores/source/LegendDataCubeSourceBuilder.d.ts +2 -2
- package/lib/stores/source/LegendDataCubeSourceBuilder.d.ts.map +1 -1
- package/lib/stores/source/LegendDataCubeSourceBuilder.js.map +1 -1
- package/lib/stores/source/SavedQueryInputSourceState.d.ts +2 -2
- package/lib/stores/source/SavedQueryInputSourceState.d.ts.map +1 -1
- package/lib/stores/source/SavedQueryInputSourceState.js +1 -1
- package/lib/stores/source/SavedQueryInputSourceState.js.map +1 -1
- package/package.json +10 -9
- package/src/__lib__/LegendDataCubeNavigation.ts +35 -0
- package/src/components/DataCubeEditor.tsx +100 -3
- package/src/components/LegendDataCubeWebApplication.tsx +7 -1
- package/src/components/source/DataCubeSourceEditor.tsx +2 -2
- package/src/components/source/ExistingDataCubeQuery.tsx +101 -0
- package/src/components/source/SavedQuerySourceEditor.tsx +1 -1
- package/src/stores/LegendDataCubeEditorStore.ts +122 -5
- package/src/stores/engine/LegendExecutionDataCubeEngine.ts +29 -19
- package/src/stores/model/DataCubeGenericSource.ts +17 -0
- package/src/stores/model/DataCubeGenericSourceHelper.ts +97 -0
- package/src/stores/model/DataCubeQueryContent.ts +24 -0
- package/src/stores/model/LegendSavedQuerySource.ts +26 -0
- package/src/stores/source/CubeInputSource.ts +0 -11
- package/src/stores/source/CubeInputSourceLoader.ts +3 -3
- package/src/stores/source/LegendCubeViewer.ts +3 -3
- package/src/stores/source/LegendDataCubeSourceBuilder.ts +2 -2
- package/src/stores/source/SavedQueryInputSourceState.ts +3 -5
- package/tsconfig.json +6 -1
- package/lib/stores/source/SavedDepotInputSourceState.d.ts +0 -47
- package/lib/stores/source/SavedDepotInputSourceState.d.ts.map +0 -1
- package/lib/stores/source/SavedDepotInputSourceState.js +0 -77
- package/lib/stores/source/SavedDepotInputSourceState.js.map +0 -1
- package/src/stores/source/SavedDepotInputSourceState.ts +0 -103
|
@@ -15,11 +15,94 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { observer } from 'mobx-react-lite';
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
Dialog,
|
|
20
|
+
Modal,
|
|
21
|
+
ModalBody,
|
|
22
|
+
ModalFooter,
|
|
23
|
+
ModalFooterButton,
|
|
24
|
+
ModalHeader,
|
|
25
|
+
PanelListItem,
|
|
26
|
+
PanelLoadingIndicator,
|
|
27
|
+
QuestionIcon,
|
|
28
|
+
clsx,
|
|
29
|
+
} from '@finos/legend-art';
|
|
19
30
|
import { useLegendDataCubeBaseStore } from './LegendDataCubeFrameworkProvider.js';
|
|
20
31
|
import { DataCubeSourceEditor } from './source/DataCubeSourceEditor.js';
|
|
21
|
-
import { useEffect } from 'react';
|
|
32
|
+
import { useEffect, useRef, useState } from 'react';
|
|
22
33
|
import { DataCube } from '@finos/legend-data-cube';
|
|
34
|
+
import type { LegendDataCubeStore } from '../stores/LegendDataCubeEditorStore.js';
|
|
35
|
+
import type { LegendCubeViewer } from '../stores/source/LegendCubeViewer.js';
|
|
36
|
+
import { flowResult } from 'mobx';
|
|
37
|
+
|
|
38
|
+
const CreateQueryDialog = observer(
|
|
39
|
+
(props: { view: LegendCubeViewer; store: LegendDataCubeStore }) => {
|
|
40
|
+
const { store } = props;
|
|
41
|
+
const close = (): void => store.setSaveModal(false);
|
|
42
|
+
const [queryName, setQueryName] = useState('');
|
|
43
|
+
const create = (): void => {
|
|
44
|
+
flowResult(store.saveQuery(queryName)).catch(
|
|
45
|
+
store.applicationStore.alertUnhandledError,
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
const isEmptyName = !queryName;
|
|
49
|
+
// name
|
|
50
|
+
const nameInputRef = useRef<HTMLInputElement>(null);
|
|
51
|
+
const setFocus = (): void => {
|
|
52
|
+
nameInputRef.current?.focus();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const changeName: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
|
56
|
+
setQueryName(event.target.value);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setTimeout(() => setFocus(), 1);
|
|
61
|
+
}, []);
|
|
62
|
+
return (
|
|
63
|
+
<Dialog
|
|
64
|
+
open={store.saveModal}
|
|
65
|
+
onClose={close}
|
|
66
|
+
classes={{
|
|
67
|
+
root: 'editor-modal__root-container',
|
|
68
|
+
container: 'editor-modal__container',
|
|
69
|
+
paper: 'editor-modal__content',
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<Modal darkMode={false} className="query-export">
|
|
73
|
+
<ModalHeader title="Create New Query" />
|
|
74
|
+
<ModalBody>
|
|
75
|
+
<PanelLoadingIndicator
|
|
76
|
+
isLoading={store.saveModalState.isInProgress}
|
|
77
|
+
/>
|
|
78
|
+
<PanelListItem>
|
|
79
|
+
<div className="input--with-validation">
|
|
80
|
+
<input
|
|
81
|
+
ref={nameInputRef}
|
|
82
|
+
className={clsx('input input--dark', {
|
|
83
|
+
'input--caution': false,
|
|
84
|
+
})}
|
|
85
|
+
spellCheck={false}
|
|
86
|
+
value={queryName}
|
|
87
|
+
onChange={changeName}
|
|
88
|
+
title="New Query Name"
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
91
|
+
</PanelListItem>
|
|
92
|
+
</ModalBody>
|
|
93
|
+
<ModalFooter>
|
|
94
|
+
<ModalFooterButton
|
|
95
|
+
text="Create Query"
|
|
96
|
+
title="Create new query"
|
|
97
|
+
disabled={isEmptyName}
|
|
98
|
+
onClick={create}
|
|
99
|
+
/>
|
|
100
|
+
</ModalFooter>
|
|
101
|
+
</Modal>
|
|
102
|
+
</Dialog>
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
);
|
|
23
106
|
|
|
24
107
|
export const DataCubeEditor = observer(() => {
|
|
25
108
|
const dataCubeStore = useLegendDataCubeBaseStore();
|
|
@@ -55,7 +138,15 @@ export const DataCubeEditor = observer(() => {
|
|
|
55
138
|
{dataCubeStore.cubeViewer ? (
|
|
56
139
|
<>
|
|
57
140
|
<div className="h-[calc(100%_-_30px)]">
|
|
58
|
-
<div className="h-12 w-full bg-gray-200"
|
|
141
|
+
<div className="h-12 w-full bg-gray-200">
|
|
142
|
+
<button
|
|
143
|
+
onClick={() => dataCubeStore.setSaveModal(true)}
|
|
144
|
+
type="button"
|
|
145
|
+
className="relative rounded-full bg-sky-900 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
|
|
146
|
+
>
|
|
147
|
+
Save
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
59
150
|
<div className="h-[calc(100%_-_30px)]">
|
|
60
151
|
<DataCube engine={dataCubeStore.cubeViewer.engine} />
|
|
61
152
|
</div>
|
|
@@ -88,6 +179,12 @@ export const DataCubeEditor = observer(() => {
|
|
|
88
179
|
{sourceSelector.open && (
|
|
89
180
|
<DataCubeSourceEditor sourceBuilder={sourceSelector} />
|
|
90
181
|
)}
|
|
182
|
+
{dataCubeStore.cubeViewer && dataCubeStore.saveModal && (
|
|
183
|
+
<CreateQueryDialog
|
|
184
|
+
store={dataCubeStore}
|
|
185
|
+
view={dataCubeStore.cubeViewer}
|
|
186
|
+
/>
|
|
187
|
+
)}
|
|
91
188
|
</>
|
|
92
189
|
);
|
|
93
190
|
});
|
|
@@ -19,12 +19,18 @@ import { Route, Routes } from '@finos/legend-application/browser';
|
|
|
19
19
|
import { LegendDataCubeFrameworkProvider } from './LegendDataCubeFrameworkProvider.js';
|
|
20
20
|
import { observer } from 'mobx-react-lite';
|
|
21
21
|
import { DataCubeEditor } from './DataCubeEditor.js';
|
|
22
|
+
import { ExistingDataCubeQuery } from './source/ExistingDataCubeQuery.js';
|
|
23
|
+
import { LEGEND_DATA_CUBE_ROUTE_PATTERN } from '../__lib__/LegendDataCubeNavigation.js';
|
|
22
24
|
|
|
23
25
|
const LegendDataCubeWebApplicationRouter = observer(() => {
|
|
24
26
|
return (
|
|
25
27
|
<div className="app">
|
|
26
28
|
<Routes>
|
|
27
|
-
<Route
|
|
29
|
+
<Route
|
|
30
|
+
path={LEGEND_DATA_CUBE_ROUTE_PATTERN.VIEW_EXISTING_QUERY}
|
|
31
|
+
element={<ExistingDataCubeQuery />}
|
|
32
|
+
/>
|
|
33
|
+
<Route path="/" element={<DataCubeEditor />} />
|
|
28
34
|
</Routes>
|
|
29
35
|
</div>
|
|
30
36
|
);
|
|
@@ -28,8 +28,8 @@ import { SavedQuerySourceEditor } from './SavedQuerySourceEditor.js';
|
|
|
28
28
|
import { SavedQueryInputSourceState } from '../../stores/source/SavedQueryInputSourceState.js';
|
|
29
29
|
import { useLegendDataCubeBaseStore } from '../LegendDataCubeFrameworkProvider.js';
|
|
30
30
|
import { flowResult } from 'mobx';
|
|
31
|
-
import type { CubeInputSource } from '../../stores/source/CubeInputSource.js';
|
|
32
31
|
import type { DataCubeEngine } from '@finos/legend-data-cube';
|
|
32
|
+
import type { DataCubeGenericSource } from '../../stores/model/DataCubeGenericSource.js';
|
|
33
33
|
|
|
34
34
|
export const DataCubeSourceEditor = observer(
|
|
35
35
|
(props: { sourceBuilder: LegendDataCubeSourceBuilder }) => {
|
|
@@ -111,7 +111,7 @@ export const DataCubeSourceEditor = observer(
|
|
|
111
111
|
onClick={() => {
|
|
112
112
|
flowResult(
|
|
113
113
|
sourceBuilder.inputSource(
|
|
114
|
-
(source:
|
|
114
|
+
(source: DataCubeGenericSource, engine: DataCubeEngine) =>
|
|
115
115
|
store.initializeView(source, engine),
|
|
116
116
|
),
|
|
117
117
|
).catch(store.context.applicationStore.alertUnhandledError);
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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 { observer } from 'mobx-react-lite';
|
|
18
|
+
import { useLegendDataCubeBaseStore } from '../LegendDataCubeFrameworkProvider.js';
|
|
19
|
+
import { useEffect } from 'react';
|
|
20
|
+
import { QuestionIcon } from '@finos/legend-art';
|
|
21
|
+
import { useParams } from '@finos/legend-application/browser';
|
|
22
|
+
import { DataCube } from '@finos/legend-data-cube';
|
|
23
|
+
import { guaranteeNonNullable } from '@finos/legend-shared';
|
|
24
|
+
import {
|
|
25
|
+
LEGEND_DATA_CUBE_ROUTE_PATTERN_TOKEN,
|
|
26
|
+
type ExistingDataCubeViewerPathParams,
|
|
27
|
+
} from '../../__lib__/LegendDataCubeNavigation.js';
|
|
28
|
+
import { flowResult } from 'mobx';
|
|
29
|
+
|
|
30
|
+
export const ExistingDataCubeQuery = observer(() => {
|
|
31
|
+
const dataCubeStore = useLegendDataCubeBaseStore();
|
|
32
|
+
const params = useParams<ExistingDataCubeViewerPathParams>();
|
|
33
|
+
const sourceSelector = dataCubeStore.sourceSelector;
|
|
34
|
+
const queryId = guaranteeNonNullable(
|
|
35
|
+
params[LEGEND_DATA_CUBE_ROUTE_PATTERN_TOKEN.DATA_CUBE_QUERY_ID],
|
|
36
|
+
);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
flowResult(dataCubeStore.initialize(queryId)).catch(
|
|
39
|
+
dataCubeStore.applicationStore.alertUnhandledError,
|
|
40
|
+
);
|
|
41
|
+
}, [dataCubeStore, queryId]);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<>
|
|
45
|
+
<div className="h-full w-full bg-white">
|
|
46
|
+
<div className="bg-sky-900">
|
|
47
|
+
<div className="mx-auto max-w-full px-2 sm:px-6 lg:px-8">
|
|
48
|
+
<div className="relative flex h-12 items-center justify-between">
|
|
49
|
+
<div className="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start">
|
|
50
|
+
<div className="flex flex-shrink-0 items-center">
|
|
51
|
+
<div className="text-gray-300">Legend Data Cube</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div className="md:block">
|
|
55
|
+
<div className="ml-4 flex items-center md:ml-6">
|
|
56
|
+
<button
|
|
57
|
+
type="button"
|
|
58
|
+
className="relative rounded-full bg-sky-900 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
|
|
59
|
+
>
|
|
60
|
+
<QuestionIcon />
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
{dataCubeStore.cubeViewer ? (
|
|
68
|
+
<>
|
|
69
|
+
<div className="h-[calc(100%_-_30px)]">
|
|
70
|
+
<div className="h-[calc(100%_-_30px)]">
|
|
71
|
+
<DataCube engine={dataCubeStore.cubeViewer.engine} />
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</>
|
|
75
|
+
) : (
|
|
76
|
+
<>
|
|
77
|
+
<div
|
|
78
|
+
onClick={() => sourceSelector.openModal()}
|
|
79
|
+
className="bg-white shadow"
|
|
80
|
+
>
|
|
81
|
+
<div className="mx-auto h-40 px-4 py-6 sm:px-6 lg:px-8">
|
|
82
|
+
<div className="group flex w-full flex-col items-center justify-center rounded-md border-2 border-dashed border-slate-300 py-3 text-base font-medium leading-6 text-slate-900 hover:cursor-pointer hover:border-solid hover:border-blue-500 hover:bg-white hover:text-blue-500">
|
|
83
|
+
<svg
|
|
84
|
+
className="mb-1 text-slate-400 group-hover:text-blue-500"
|
|
85
|
+
width="20"
|
|
86
|
+
height="20"
|
|
87
|
+
fill="currentColor"
|
|
88
|
+
aria-hidden="true"
|
|
89
|
+
>
|
|
90
|
+
<path d="M10 5a1 1 0 0 1 1 1v3h3a1 1 0 1 1 0 2h-3v3a1 1 0 1 1-2 0v-3H6a1 1 0 1 1 0-2h3V6a1 1 0 0 1 1-1Z" />
|
|
91
|
+
</svg>
|
|
92
|
+
Add Source
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
</>
|
|
100
|
+
);
|
|
101
|
+
});
|
|
@@ -29,7 +29,7 @@ export const SavedQuerySourceEditor = observer(
|
|
|
29
29
|
{savedQuery ? (
|
|
30
30
|
<div className="p-3">
|
|
31
31
|
<div className="text-l font-bold">Saved Query</div>
|
|
32
|
-
<div
|
|
32
|
+
<div>
|
|
33
33
|
<div className="flex pt-px">
|
|
34
34
|
<div className="font-bold">Name:</div>
|
|
35
35
|
<div>{savedQuery.name}</div>
|
|
@@ -19,19 +19,36 @@ import {
|
|
|
19
19
|
type ApplicationStore,
|
|
20
20
|
} from '@finos/legend-application';
|
|
21
21
|
import type { LegendDataCubePluginManager } from '../application/LegendDataCubePluginManager.js';
|
|
22
|
-
import { DepotServerClient } from '@finos/legend-server-depot';
|
|
22
|
+
import { DepotServerClient, resolveVersion } from '@finos/legend-server-depot';
|
|
23
23
|
import type { LegendDataCubeApplicationConfig } from '../application/LegendDataCubeApplicationConfig.js';
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
GraphManagerState,
|
|
26
|
+
LegendSDLC,
|
|
27
|
+
PersistentDataCubeQuery,
|
|
28
|
+
type QueryInfo,
|
|
29
|
+
type RawLambda,
|
|
30
|
+
} from '@finos/legend-graph';
|
|
25
31
|
import { LegendDataCubeSourceBuilder } from './source/LegendDataCubeSourceBuilder.js';
|
|
26
32
|
import {
|
|
27
33
|
ActionState,
|
|
34
|
+
UnsupportedOperationError,
|
|
28
35
|
assertErrorThrown,
|
|
36
|
+
guaranteeNonNullable,
|
|
37
|
+
uuid,
|
|
29
38
|
type GeneratorFn,
|
|
30
39
|
} from '@finos/legend-shared';
|
|
31
|
-
import { action, flow, makeObservable, observable } from 'mobx';
|
|
40
|
+
import { action, flow, flowResult, makeObservable, observable } from 'mobx';
|
|
32
41
|
import { LegendCubeViewer } from './source/LegendCubeViewer.js';
|
|
33
|
-
import type { CubeInputSource } from './source/CubeInputSource.js';
|
|
34
42
|
import type { DataCubeEngine } from '@finos/legend-data-cube';
|
|
43
|
+
import type { DataCubeGenericSource } from './model/DataCubeGenericSource.js';
|
|
44
|
+
import {
|
|
45
|
+
createQueryBuilderContent,
|
|
46
|
+
deserializeDataCubeQueryConent,
|
|
47
|
+
serializeDataCubeQueryConent,
|
|
48
|
+
} from './model/DataCubeGenericSourceHelper.js';
|
|
49
|
+
import { LegendSavedQuerySource } from './model/LegendSavedQuerySource.js';
|
|
50
|
+
import { LegendExecutionDataCubeEngine } from './engine/LegendExecutionDataCubeEngine.js';
|
|
51
|
+
import { generatedSavedQueryUrl } from '../__lib__/LegendDataCubeNavigation.js';
|
|
35
52
|
|
|
36
53
|
export type LegendDataCubeApplicationStore = ApplicationStore<
|
|
37
54
|
LegendDataCubeApplicationConfig,
|
|
@@ -99,14 +116,24 @@ export class LegendDataCubeStore {
|
|
|
99
116
|
readonly applicationStore: LegendDataCubeApplicationStore;
|
|
100
117
|
readonly context: LegendDataCubeStoreContext;
|
|
101
118
|
readonly pluginManager: LegendDataCubePluginManager;
|
|
119
|
+
|
|
102
120
|
sourceSelector: LegendDataCubeSourceBuilder;
|
|
103
121
|
cubeViewer: LegendCubeViewer | undefined;
|
|
122
|
+
saveModal = false;
|
|
123
|
+
saveModalState = ActionState.create();
|
|
124
|
+
savedQuery: PersistentDataCubeQuery | undefined;
|
|
104
125
|
|
|
105
126
|
constructor(applicationStore: LegendDataCubeApplicationStore) {
|
|
106
127
|
makeObservable(this, {
|
|
107
128
|
cubeViewer: observable,
|
|
108
129
|
sourceSelector: observable,
|
|
130
|
+
saveModal: observable,
|
|
131
|
+
setSaveModal: observable,
|
|
132
|
+
saveModalState: observable,
|
|
133
|
+
savedQuery: observable,
|
|
109
134
|
initializeView: action,
|
|
135
|
+
initialize: flow,
|
|
136
|
+
saveQuery: flow,
|
|
110
137
|
});
|
|
111
138
|
this.applicationStore = applicationStore;
|
|
112
139
|
this.pluginManager = applicationStore.pluginManager;
|
|
@@ -114,7 +141,97 @@ export class LegendDataCubeStore {
|
|
|
114
141
|
this.sourceSelector = new LegendDataCubeSourceBuilder(this.context);
|
|
115
142
|
}
|
|
116
143
|
|
|
117
|
-
|
|
144
|
+
setSaveModal(val: boolean): void {
|
|
145
|
+
this.saveModal = val;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
initializeView(source: DataCubeGenericSource, engine: DataCubeEngine): void {
|
|
118
149
|
this.cubeViewer = new LegendCubeViewer(source, engine);
|
|
119
150
|
}
|
|
151
|
+
|
|
152
|
+
*initialize(id: string): GeneratorFn<void> {
|
|
153
|
+
try {
|
|
154
|
+
yield flowResult(this.context.initialize());
|
|
155
|
+
const query =
|
|
156
|
+
(yield this.context.graphManagerState.graphManager.getDataCubeQuery(
|
|
157
|
+
id,
|
|
158
|
+
)) as unknown as PersistentDataCubeQuery;
|
|
159
|
+
this.savedQuery = query;
|
|
160
|
+
const source = deserializeDataCubeQueryConent(query.content).source;
|
|
161
|
+
if (source instanceof LegendSavedQuerySource) {
|
|
162
|
+
const queryInfo =
|
|
163
|
+
(yield this.context.graphManagerState.graphManager.getQueryInfo(
|
|
164
|
+
source.id,
|
|
165
|
+
)) as unknown as QueryInfo;
|
|
166
|
+
const execConext =
|
|
167
|
+
(yield this.context.graphManagerState.graphManager.resolveQueryInfoExecutionContext(
|
|
168
|
+
queryInfo,
|
|
169
|
+
() =>
|
|
170
|
+
this.context.depotServerClient.getVersionEntities(
|
|
171
|
+
queryInfo.groupId,
|
|
172
|
+
queryInfo.artifactId,
|
|
173
|
+
queryInfo.versionId,
|
|
174
|
+
),
|
|
175
|
+
)) as { mapping: string | undefined; runtime: string };
|
|
176
|
+
const lambda =
|
|
177
|
+
(yield this.context.graphManagerState.graphManager.pureCodeToLambda(
|
|
178
|
+
queryInfo.content,
|
|
179
|
+
)) as unknown as RawLambda;
|
|
180
|
+
this.context.graphManagerState.graph.setOrigin(
|
|
181
|
+
new LegendSDLC(
|
|
182
|
+
queryInfo.groupId,
|
|
183
|
+
queryInfo.artifactId,
|
|
184
|
+
resolveVersion(queryInfo.versionId),
|
|
185
|
+
),
|
|
186
|
+
);
|
|
187
|
+
// TODO: we should be able to call engine and convert lambda to relation if not one.
|
|
188
|
+
const engine = new LegendExecutionDataCubeEngine(
|
|
189
|
+
lambda,
|
|
190
|
+
undefined,
|
|
191
|
+
execConext.mapping,
|
|
192
|
+
execConext.runtime,
|
|
193
|
+
this.context.graphManagerState,
|
|
194
|
+
);
|
|
195
|
+
this.initializeView(source, engine);
|
|
196
|
+
} else {
|
|
197
|
+
throw new UnsupportedOperationError('not supported');
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
assertErrorThrown(error);
|
|
201
|
+
this.applicationStore.notificationService.notifyError(
|
|
202
|
+
`Unable to initialie query with id '${id}'`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
*saveQuery(name: string): GeneratorFn<void> {
|
|
208
|
+
try {
|
|
209
|
+
this.saveModalState.inProgress();
|
|
210
|
+
const view = guaranteeNonNullable(this.cubeViewer);
|
|
211
|
+
const content = serializeDataCubeQueryConent(
|
|
212
|
+
createQueryBuilderContent(view.source),
|
|
213
|
+
);
|
|
214
|
+
const cubeQuery = new PersistentDataCubeQuery();
|
|
215
|
+
cubeQuery.content = content;
|
|
216
|
+
cubeQuery.name = name;
|
|
217
|
+
cubeQuery.id = uuid();
|
|
218
|
+
const querySaved =
|
|
219
|
+
(yield this.context.graphManagerState.graphManager.createQueryDataCube(
|
|
220
|
+
cubeQuery,
|
|
221
|
+
)) as unknown as PersistentDataCubeQuery;
|
|
222
|
+
this.savedQuery = querySaved;
|
|
223
|
+
// TODO: fix reload
|
|
224
|
+
this.applicationStore.navigationService.navigator.goToLocation(
|
|
225
|
+
generatedSavedQueryUrl(querySaved.id),
|
|
226
|
+
);
|
|
227
|
+
this.setSaveModal(false);
|
|
228
|
+
this.saveModalState.complete();
|
|
229
|
+
} catch (error) {
|
|
230
|
+
assertErrorThrown(error);
|
|
231
|
+
this.saveModalState.fail();
|
|
232
|
+
this.applicationStore.notificationService.notifyError(
|
|
233
|
+
`Unable to save query`,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
120
237
|
}
|
|
@@ -37,12 +37,16 @@ import {
|
|
|
37
37
|
DataCubeSource,
|
|
38
38
|
type RelationType,
|
|
39
39
|
DataCubeQuery,
|
|
40
|
-
type DataCubeInitialInput,
|
|
41
40
|
type CompletionItem,
|
|
42
41
|
_function,
|
|
43
42
|
DataCubeFunction,
|
|
44
43
|
} from '@finos/legend-data-cube';
|
|
45
|
-
import {
|
|
44
|
+
import {
|
|
45
|
+
guaranteeType,
|
|
46
|
+
isNonNullable,
|
|
47
|
+
LogService,
|
|
48
|
+
type PlainObject,
|
|
49
|
+
} from '@finos/legend-shared';
|
|
46
50
|
|
|
47
51
|
class QueryBuilderDataCubeSource extends DataCubeSource {
|
|
48
52
|
mapping?: string | undefined;
|
|
@@ -77,11 +81,11 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
77
81
|
return `Query Builder Report`;
|
|
78
82
|
}
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
return this.
|
|
84
|
+
get graph(): PureModel {
|
|
85
|
+
return this.graphState.graph;
|
|
82
86
|
}
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
private getSourceFunctionExpression() {
|
|
85
89
|
let srcFuncExp = V1_deserializeValueSpecification(
|
|
86
90
|
this.graphState.graphManager.serializeRawValueSpecification(
|
|
87
91
|
this.selectInitialQuery,
|
|
@@ -97,6 +101,11 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
97
101
|
) {
|
|
98
102
|
srcFuncExp = srcFuncExp.body[0];
|
|
99
103
|
}
|
|
104
|
+
return srcFuncExp;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async getBaseQuery() {
|
|
108
|
+
const srcFuncExp = this.getSourceFunctionExpression();
|
|
100
109
|
this._parameters = this.selectInitialQuery.parameters;
|
|
101
110
|
const fromFuncExp = new V1_AppliedFunction();
|
|
102
111
|
fromFuncExp.function = _functionName(SUPPORTED_FUNCTIONS.FROM);
|
|
@@ -111,19 +120,20 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
111
120
|
.columns;
|
|
112
121
|
const query = new DataCubeQuery();
|
|
113
122
|
query.query = `~[${columns.map((e) => `'${e.name}'`)}]->select()`;
|
|
123
|
+
|
|
124
|
+
return query;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async processQuerySource(value: PlainObject) {
|
|
128
|
+
const srcFuncExp = this.getSourceFunctionExpression();
|
|
129
|
+
const columns = (await this.getRelationalType(this.selectInitialQuery))
|
|
130
|
+
.columns;
|
|
114
131
|
const source = new QueryBuilderDataCubeSource();
|
|
115
132
|
source.sourceColumns = columns;
|
|
116
133
|
source.mapping = this.mappingPath;
|
|
117
134
|
source.runtime = this.runtimePath;
|
|
118
135
|
source.query = srcFuncExp;
|
|
119
|
-
return
|
|
120
|
-
query,
|
|
121
|
-
source,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
get graph(): PureModel {
|
|
126
|
-
return this.graphState.graph;
|
|
136
|
+
return source;
|
|
127
137
|
}
|
|
128
138
|
|
|
129
139
|
private buildRawLambdaFromValueSpec(query: V1_Lambda): RawLambda {
|
|
@@ -156,7 +166,7 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
156
166
|
return result.completions as CompletionItem[];
|
|
157
167
|
}
|
|
158
168
|
|
|
159
|
-
|
|
169
|
+
async parseValueSpecification(
|
|
160
170
|
code: string,
|
|
161
171
|
returnSourceInformation?: boolean,
|
|
162
172
|
) {
|
|
@@ -169,7 +179,7 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
169
179
|
);
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
|
|
182
|
+
async getValueSpecificationCode(
|
|
173
183
|
value: V1_ValueSpecification,
|
|
174
184
|
pretty?: boolean | undefined,
|
|
175
185
|
) {
|
|
@@ -188,12 +198,12 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
188
198
|
return relationType;
|
|
189
199
|
}
|
|
190
200
|
|
|
191
|
-
|
|
201
|
+
async getQueryRelationType(query: V1_Lambda, source: DataCubeSource) {
|
|
192
202
|
const lambda = this.buildRawLambdaFromValueSpec(query);
|
|
193
203
|
return this.getRelationalType(lambda);
|
|
194
204
|
}
|
|
195
205
|
|
|
196
|
-
|
|
206
|
+
async getQueryCodeRelationReturnType(
|
|
197
207
|
code: string,
|
|
198
208
|
baseQuery: V1_ValueSpecification,
|
|
199
209
|
source: DataCubeSource,
|
|
@@ -208,7 +218,7 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
208
218
|
);
|
|
209
219
|
}
|
|
210
220
|
|
|
211
|
-
|
|
221
|
+
async executeQuery(query: V1_Lambda, source: DataCubeSource) {
|
|
212
222
|
const lambda = this.buildRawLambdaFromValueSpec(query);
|
|
213
223
|
lambda.parameters = this._parameters;
|
|
214
224
|
const [executionWithMetadata, queryString] = await Promise.all([
|
|
@@ -240,7 +250,7 @@ export class LegendExecutionDataCubeEngine extends DataCubeEngine {
|
|
|
240
250
|
};
|
|
241
251
|
}
|
|
242
252
|
|
|
243
|
-
|
|
253
|
+
buildExecutionContext(
|
|
244
254
|
source: DataCubeSource,
|
|
245
255
|
): V1_AppliedFunction | undefined {
|
|
246
256
|
if (source instanceof QueryBuilderDataCubeSource) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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
|
+
export abstract class DataCubeGenericSource {}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020-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
|
+
UnsupportedOperationError,
|
|
19
|
+
optionalCustom,
|
|
20
|
+
usingConstantValueSchema,
|
|
21
|
+
type PlainObject,
|
|
22
|
+
} from '@finos/legend-shared';
|
|
23
|
+
import type { DataCubeGenericSource } from './DataCubeGenericSource.js';
|
|
24
|
+
import { LegendSavedQuerySource } from './LegendSavedQuerySource.js';
|
|
25
|
+
import {
|
|
26
|
+
createModelSchema,
|
|
27
|
+
primitive,
|
|
28
|
+
deserialize,
|
|
29
|
+
serialize,
|
|
30
|
+
optional,
|
|
31
|
+
raw,
|
|
32
|
+
} from 'serializr';
|
|
33
|
+
import { DataCubeQueryConent } from './DataCubeQueryContent.js';
|
|
34
|
+
|
|
35
|
+
enum SavedDataCubeQueryType {
|
|
36
|
+
LEGEND_QUERY = 'LegendQuery',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const legendSavedQuerySourceModelSchema = createModelSchema(
|
|
40
|
+
LegendSavedQuerySource,
|
|
41
|
+
{
|
|
42
|
+
_type: usingConstantValueSchema(SavedDataCubeQueryType.LEGEND_QUERY),
|
|
43
|
+
id: primitive(),
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const deserializeDataCubeGenericSource = (
|
|
48
|
+
content: PlainObject<object>,
|
|
49
|
+
): DataCubeGenericSource => {
|
|
50
|
+
switch (content._type) {
|
|
51
|
+
case SavedDataCubeQueryType.LEGEND_QUERY:
|
|
52
|
+
return deserialize(legendSavedQuerySourceModelSchema, content);
|
|
53
|
+
default:
|
|
54
|
+
}
|
|
55
|
+
throw new UnsupportedOperationError(
|
|
56
|
+
`Can't de serialize saved data cube`,
|
|
57
|
+
content._type,
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const serializeDataCubeGenericSource = (
|
|
62
|
+
genericSource: DataCubeGenericSource,
|
|
63
|
+
): PlainObject<DataCubeGenericSource> => {
|
|
64
|
+
if (genericSource instanceof LegendSavedQuerySource) {
|
|
65
|
+
return serialize(legendSavedQuerySourceModelSchema, genericSource);
|
|
66
|
+
}
|
|
67
|
+
throw new UnsupportedOperationError(`Can't serialize saved data cube`);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const dataCubeQueryConentModelSchema = createModelSchema(DataCubeQueryConent, {
|
|
71
|
+
query: optional(primitive()),
|
|
72
|
+
configuration: optional(raw()),
|
|
73
|
+
source: optionalCustom(
|
|
74
|
+
(val) => serializeDataCubeGenericSource(val),
|
|
75
|
+
(val) => deserializeDataCubeGenericSource(val),
|
|
76
|
+
),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const createQueryBuilderContent = (
|
|
80
|
+
source: DataCubeGenericSource,
|
|
81
|
+
): DataCubeQueryConent => {
|
|
82
|
+
const content = new DataCubeQueryConent();
|
|
83
|
+
content.source = source;
|
|
84
|
+
return content;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const serializeDataCubeQueryConent = (
|
|
88
|
+
content: DataCubeQueryConent,
|
|
89
|
+
): PlainObject<DataCubeQueryConent> => {
|
|
90
|
+
return serialize(dataCubeQueryConentModelSchema, content);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const deserializeDataCubeQueryConent = (
|
|
94
|
+
content: PlainObject<DataCubeQueryConent>,
|
|
95
|
+
): DataCubeQueryConent => {
|
|
96
|
+
return deserialize(dataCubeQueryConentModelSchema, content);
|
|
97
|
+
};
|