@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.
Files changed (85) hide show
  1. package/lib/__lib__/LegendDataCubeNavigation.d.ts +26 -0
  2. package/lib/__lib__/LegendDataCubeNavigation.d.ts.map +1 -0
  3. package/lib/__lib__/LegendDataCubeNavigation.js +29 -0
  4. package/lib/__lib__/LegendDataCubeNavigation.js.map +1 -0
  5. package/lib/components/DataCubeEditor.d.ts.map +1 -1
  6. package/lib/components/DataCubeEditor.js +31 -3
  7. package/lib/components/DataCubeEditor.js.map +1 -1
  8. package/lib/components/LegendDataCubeWebApplication.d.ts.map +1 -1
  9. package/lib/components/LegendDataCubeWebApplication.js +4 -2
  10. package/lib/components/LegendDataCubeWebApplication.js.map +1 -1
  11. package/lib/components/source/DataCubeSourceEditor.js.map +1 -1
  12. package/lib/components/source/ExistingDataCubeQuery.d.ts +19 -0
  13. package/lib/components/source/ExistingDataCubeQuery.d.ts.map +1 -0
  14. package/lib/components/source/ExistingDataCubeQuery.js +36 -0
  15. package/lib/components/source/ExistingDataCubeQuery.js.map +1 -0
  16. package/lib/components/source/SavedQuerySourceEditor.js +1 -1
  17. package/lib/components/source/SavedQuerySourceEditor.js.map +1 -1
  18. package/lib/index.css +1 -1
  19. package/lib/package.json +3 -2
  20. package/lib/stores/LegendDataCubeEditorStore.d.ts +9 -3
  21. package/lib/stores/LegendDataCubeEditorStore.d.ts.map +1 -1
  22. package/lib/stores/LegendDataCubeEditorStore.js +66 -4
  23. package/lib/stores/LegendDataCubeEditorStore.js.map +1 -1
  24. package/lib/stores/engine/LegendExecutionDataCubeEngine.d.ts +10 -4
  25. package/lib/stores/engine/LegendExecutionDataCubeEngine.d.ts.map +1 -1
  26. package/lib/stores/engine/LegendExecutionDataCubeEngine.js +17 -13
  27. package/lib/stores/engine/LegendExecutionDataCubeEngine.js.map +1 -1
  28. package/lib/stores/model/DataCubeGenericSource.d.ts +18 -0
  29. package/lib/stores/model/DataCubeGenericSource.d.ts.map +1 -0
  30. package/lib/stores/model/DataCubeGenericSource.js +18 -0
  31. package/lib/stores/model/DataCubeGenericSource.js.map +1 -0
  32. package/lib/stores/model/DataCubeGenericSourceHelper.d.ts +24 -0
  33. package/lib/stores/model/DataCubeGenericSourceHelper.d.ts.map +1 -0
  34. package/lib/stores/model/DataCubeGenericSourceHelper.js +58 -0
  35. package/lib/stores/model/DataCubeGenericSourceHelper.js.map +1 -0
  36. package/lib/stores/model/DataCubeQueryContent.d.ts +23 -0
  37. package/lib/stores/model/DataCubeQueryContent.d.ts.map +1 -0
  38. package/lib/stores/model/DataCubeQueryContent.js +21 -0
  39. package/lib/stores/model/DataCubeQueryContent.js.map +1 -0
  40. package/lib/stores/model/LegendSavedQuerySource.d.ts +21 -0
  41. package/lib/stores/model/LegendSavedQuerySource.d.ts.map +1 -0
  42. package/lib/stores/model/LegendSavedQuerySource.js +24 -0
  43. package/lib/stores/model/LegendSavedQuerySource.js.map +1 -0
  44. package/lib/stores/source/CubeInputSource.d.ts +0 -6
  45. package/lib/stores/source/CubeInputSource.d.ts.map +1 -1
  46. package/lib/stores/source/CubeInputSource.js +0 -9
  47. package/lib/stores/source/CubeInputSource.js.map +1 -1
  48. package/lib/stores/source/CubeInputSourceLoader.d.ts +3 -3
  49. package/lib/stores/source/CubeInputSourceLoader.d.ts.map +1 -1
  50. package/lib/stores/source/CubeInputSourceLoader.js +1 -2
  51. package/lib/stores/source/CubeInputSourceLoader.js.map +1 -1
  52. package/lib/stores/source/LegendCubeViewer.d.ts +3 -3
  53. package/lib/stores/source/LegendCubeViewer.d.ts.map +1 -1
  54. package/lib/stores/source/LegendCubeViewer.js.map +1 -1
  55. package/lib/stores/source/LegendDataCubeSourceBuilder.d.ts +2 -2
  56. package/lib/stores/source/LegendDataCubeSourceBuilder.d.ts.map +1 -1
  57. package/lib/stores/source/LegendDataCubeSourceBuilder.js.map +1 -1
  58. package/lib/stores/source/SavedQueryInputSourceState.d.ts +2 -2
  59. package/lib/stores/source/SavedQueryInputSourceState.d.ts.map +1 -1
  60. package/lib/stores/source/SavedQueryInputSourceState.js +1 -1
  61. package/lib/stores/source/SavedQueryInputSourceState.js.map +1 -1
  62. package/package.json +10 -9
  63. package/src/__lib__/LegendDataCubeNavigation.ts +35 -0
  64. package/src/components/DataCubeEditor.tsx +100 -3
  65. package/src/components/LegendDataCubeWebApplication.tsx +7 -1
  66. package/src/components/source/DataCubeSourceEditor.tsx +2 -2
  67. package/src/components/source/ExistingDataCubeQuery.tsx +101 -0
  68. package/src/components/source/SavedQuerySourceEditor.tsx +1 -1
  69. package/src/stores/LegendDataCubeEditorStore.ts +122 -5
  70. package/src/stores/engine/LegendExecutionDataCubeEngine.ts +29 -19
  71. package/src/stores/model/DataCubeGenericSource.ts +17 -0
  72. package/src/stores/model/DataCubeGenericSourceHelper.ts +97 -0
  73. package/src/stores/model/DataCubeQueryContent.ts +24 -0
  74. package/src/stores/model/LegendSavedQuerySource.ts +26 -0
  75. package/src/stores/source/CubeInputSource.ts +0 -11
  76. package/src/stores/source/CubeInputSourceLoader.ts +3 -3
  77. package/src/stores/source/LegendCubeViewer.ts +3 -3
  78. package/src/stores/source/LegendDataCubeSourceBuilder.ts +2 -2
  79. package/src/stores/source/SavedQueryInputSourceState.ts +3 -5
  80. package/tsconfig.json +6 -1
  81. package/lib/stores/source/SavedDepotInputSourceState.d.ts +0 -47
  82. package/lib/stores/source/SavedDepotInputSourceState.d.ts.map +0 -1
  83. package/lib/stores/source/SavedDepotInputSourceState.js +0 -77
  84. package/lib/stores/source/SavedDepotInputSourceState.js.map +0 -1
  85. 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 { QuestionIcon } from '@finos/legend-art';
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"></div>
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 path="*" element={<DataCubeEditor />} />
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: CubeInputSource, engine: DataCubeEngine) =>
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 className="">
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 { GraphManagerState } from '@finos/legend-graph';
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
- initializeView(source: CubeInputSource, engine: DataCubeEngine): void {
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 { guaranteeType, isNonNullable, LogService } from '@finos/legend-shared';
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
- override getInitialInput(): Promise<DataCubeInitialInput> {
81
- return this.buildBaseQuery();
84
+ get graph(): PureModel {
85
+ return this.graphState.graph;
82
86
  }
83
87
 
84
- async buildBaseQuery(): Promise<DataCubeInitialInput> {
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
- override async parseValueSpecification(
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
- override getValueSpecificationCode(
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
- override getQueryRelationType(query: V1_Lambda, source: DataCubeSource) {
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
- override async getQueryCodeRelationReturnType(
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
- override async executeQuery(query: V1_Lambda, source: DataCubeSource) {
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
- override buildExecutionContext(
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
+ };