@finos/legend-application-studio 28.7.0 → 28.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/lib/__lib__/LegendStudioTesting.d.ts +1 -0
  2. package/lib/__lib__/LegendStudioTesting.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioTesting.js +1 -0
  4. package/lib/__lib__/LegendStudioTesting.js.map +1 -1
  5. package/lib/application/LegendStudioApplicationConfig.d.ts +4 -5
  6. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  7. package/lib/application/LegendStudioApplicationConfig.js +5 -6
  8. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  9. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts.map +1 -1
  10. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js +41 -4
  11. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js.map +1 -1
  12. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts +2 -0
  13. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts.map +1 -1
  14. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js +13 -3
  15. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js.map +1 -1
  16. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts +18 -0
  17. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts.map +1 -0
  18. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js +54 -0
  19. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js.map +1 -0
  20. package/lib/components/editor/panel-group/PanelGroup.d.ts.map +1 -1
  21. package/lib/components/editor/panel-group/PanelGroup.js +1 -5
  22. package/lib/components/editor/panel-group/PanelGroup.js.map +1 -1
  23. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  24. package/lib/components/editor/side-bar/Explorer.js +8 -2
  25. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  26. package/lib/components/editor/side-bar/ProjectOverview.d.ts.map +1 -1
  27. package/lib/components/editor/side-bar/ProjectOverview.js +1 -1
  28. package/lib/components/editor/side-bar/ProjectOverview.js.map +1 -1
  29. package/lib/index.css +1 -1
  30. package/lib/package.json +1 -1
  31. package/lib/stores/editor/EditorConfig.d.ts +2 -1
  32. package/lib/stores/editor/EditorConfig.d.ts.map +1 -1
  33. package/lib/stores/editor/EditorConfig.js +1 -0
  34. package/lib/stores/editor/EditorConfig.js.map +1 -1
  35. package/lib/stores/editor/EditorSDLCState.d.ts +1 -2
  36. package/lib/stores/editor/EditorSDLCState.d.ts.map +1 -1
  37. package/lib/stores/editor/EditorSDLCState.js +3 -14
  38. package/lib/stores/editor/EditorSDLCState.js.map +1 -1
  39. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +5 -2
  40. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
  41. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +209 -2
  42. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
  43. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts +1 -2
  44. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts.map +1 -1
  45. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js +2 -2
  46. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js.map +1 -1
  47. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts +37 -0
  48. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts.map +1 -0
  49. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js +127 -0
  50. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js.map +1 -0
  51. package/lib/stores/project-view/ProjectViewerStore.d.ts.map +1 -1
  52. package/lib/stores/project-view/ProjectViewerStore.js +1 -0
  53. package/lib/stores/project-view/ProjectViewerStore.js.map +1 -1
  54. package/package.json +7 -7
  55. package/src/__lib__/LegendStudioTesting.ts +2 -0
  56. package/src/application/LegendStudioApplicationConfig.ts +6 -7
  57. package/src/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.tsx +117 -16
  58. package/src/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.tsx +40 -1
  59. package/src/components/editor/editor-group/database/IsolatedQueryDatabase.tsx +138 -0
  60. package/src/components/editor/panel-group/PanelGroup.tsx +3 -8
  61. package/src/components/editor/side-bar/Explorer.tsx +21 -6
  62. package/src/components/editor/side-bar/ProjectOverview.tsx +0 -19
  63. package/src/stores/editor/EditorConfig.ts +1 -0
  64. package/src/stores/editor/EditorSDLCState.ts +6 -19
  65. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +288 -2
  66. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts +2 -5
  67. package/src/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.ts +234 -0
  68. package/src/stores/project-view/ProjectViewerStore.ts +1 -0
  69. package/tsconfig.json +2 -0
@@ -48,7 +48,6 @@ import {
48
48
  Workspace,
49
49
  WorkspaceAccessType,
50
50
  Patch,
51
- ProjectAccessRole,
52
51
  AuthorizableProjectAction,
53
52
  } from '@finos/legend-server-sdlc';
54
53
  import { LEGEND_STUDIO_APP_EVENT } from '../../__lib__/LegendStudioEvent.js';
@@ -77,7 +76,6 @@ export class EditorSDLCState {
77
76
  projectVersions: Version[] = [];
78
77
  projectPublishedVersions: string[] = [];
79
78
  authorizedActions: AuthorizableProjectAction[] | undefined;
80
- accessRole: ProjectAccessRole | undefined;
81
79
 
82
80
  constructor(editorStore: EditorStore) {
83
81
  makeObservable(this, {
@@ -94,7 +92,6 @@ export class EditorSDLCState {
94
92
  isFetchingProject: observable,
95
93
  projectPublishedVersions: observable,
96
94
  authorizedActions: observable,
97
- accessRole: observable,
98
95
  activeProject: computed,
99
96
  activeWorkspace: computed,
100
97
  activeRevision: computed,
@@ -174,12 +171,9 @@ export class EditorSDLCState {
174
171
  }
175
172
 
176
173
  unAuthorizedActionMessage(_action: AuthorizableProjectAction): string {
177
- if (this.accessRole) {
178
- return `Your role ${
179
- this.accessRole.accessRole
180
- } does not allow you to perform the action '${prettyCONSTName(_action)}'`;
181
- }
182
- return `Your are not entitled to perform the action: ${_action}`;
174
+ return `Your are not entitled to perform the action: ${prettyCONSTName(
175
+ _action,
176
+ )}`;
183
177
  }
184
178
 
185
179
  userCanPerformAction(authorizedAction: AuthorizableProjectAction): boolean {
@@ -568,26 +562,19 @@ export class EditorSDLCState {
568
562
 
569
563
  *fetchAuthorizedActions(): GeneratorFn<void> {
570
564
  try {
571
- const [authorizedActions, accessRoleRaw] = (yield Promise.all([
572
- this.editorStore.sdlcServerClient.getAutorizedActions(
573
- this.activeProject.projectId,
574
- ),
575
- this.editorStore.sdlcServerClient.getAccessRole(
565
+ const authorizedActions =
566
+ (yield this.editorStore.sdlcServerClient.getAutorizedActions(
576
567
  this.activeProject.projectId,
577
- ),
578
- ])) as [AuthorizableProjectAction[], PlainObject<ProjectAccessRole>];
568
+ )) as AuthorizableProjectAction[];
579
569
  this.authorizedActions = authorizedActions;
580
- this.accessRole = ProjectAccessRole.serialization.fromJson(accessRoleRaw);
581
570
  } catch (error) {
582
571
  assertErrorThrown(error);
583
572
  // if there is an error fetching authorized actions we should set undefined
584
573
  this.authorizedActions = undefined;
585
- this.accessRole = undefined;
586
574
  this.editorStore.applicationStore.logService.error(
587
575
  LogEvent.create(LEGEND_STUDIO_APP_EVENT.SDLC_MANAGER_FAILURE),
588
576
  error,
589
577
  );
590
- this.editorStore.applicationStore.notificationService.notifyError(error);
591
578
  }
592
579
  }
593
580
 
@@ -30,6 +30,7 @@ import {
30
30
  guaranteeType,
31
31
  assertNonEmptyString,
32
32
  assertTrue,
33
+ UnsupportedOperationError,
33
34
  } from '@finos/legend-shared';
34
35
  import {
35
36
  observable,
@@ -42,9 +43,18 @@ import {
42
43
  import { LEGEND_STUDIO_APP_EVENT } from '../../../../../__lib__/LegendStudioEvent.js';
43
44
  import type { EditorStore } from '../../../EditorStore.js';
44
45
  import {
46
+ type RawLambda,
47
+ type PureModel,
48
+ type Runtime,
49
+ type ExecutionResult,
50
+ TDSExecutionResult,
51
+ getColumn,
52
+ PrimitiveType,
53
+ PRIMITIVE_TYPE,
54
+ TDSRow,
45
55
  type Schema,
46
- type Table,
47
- type RelationalDatabaseConnection,
56
+ Table,
57
+ RelationalDatabaseConnection,
48
58
  DatabaseBuilderInput,
49
59
  DatabasePattern,
50
60
  TargetDatabase,
@@ -57,9 +67,173 @@ import {
57
67
  isStubbed_PackageableElement,
58
68
  isValidFullPath,
59
69
  PackageableElementExplicitReference,
70
+ getTable,
71
+ Mapping,
72
+ EngineRuntime,
73
+ StoreConnections,
74
+ IdentifiedConnection,
60
75
  } from '@finos/legend-graph';
61
76
  import { GraphEditFormModeState } from '../../../GraphEditFormModeState.js';
62
77
  import { connection_setStore } from '../../../../graph-modifier/DSL_Mapping_GraphModifierHelper.js';
78
+ import { getTDSColumnDerivedProperyFromType } from '@finos/legend-query-builder';
79
+ import { getPrimitiveTypeFromRelationalType } from '../../../utils/MockDataUtils.js';
80
+
81
+ const GENERATED_PACKAGE = 'generated';
82
+ const TDS_LIMIT = 1000;
83
+
84
+ const buildTableToTDSQueryGrammar = (table: Table): string => {
85
+ const tableName = table.name;
86
+ const schemaName = table.schema.name;
87
+ const db = table.schema._OWNER.path;
88
+ return `|${db}->tableReference(
89
+ '${schemaName}',
90
+ '${tableName}'
91
+ )->tableToTDS()->take(${TDS_LIMIT})`;
92
+ };
93
+
94
+ const buildTableToTDSQueryNonNumericWithColumnGrammar = (
95
+ column: Column,
96
+ ): string => {
97
+ const table = guaranteeType(column.owner, Table);
98
+ const tableName = table.name;
99
+ const colName = column.name;
100
+ const schemaName = table.schema.name;
101
+ const db = table.schema._OWNER.path;
102
+ const PREVIEW_COLUMN_NAME = 'Count Value';
103
+ const columnGetter = getTDSColumnDerivedProperyFromType(
104
+ getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING,
105
+ );
106
+ return `|${db}->tableReference(
107
+ '${schemaName}',
108
+ '${tableName}'
109
+ )->tableToTDS()->restrict(
110
+ ['${colName}']
111
+ )->groupBy(
112
+ ['${colName}'],
113
+ '${PREVIEW_COLUMN_NAME}'->agg(
114
+ row|$row.${columnGetter}('${colName}'),
115
+ y|$y->count()
116
+ )
117
+ )->sort(
118
+ [
119
+ desc('${colName}'),
120
+ asc('${PREVIEW_COLUMN_NAME}')
121
+ ]
122
+ )->take(${TDS_LIMIT})`;
123
+ };
124
+
125
+ const buildTableToTDSQueryNumericWithColumnGrammar = (
126
+ column: Column,
127
+ ): string => {
128
+ const table = guaranteeType(column.owner, Table);
129
+ const tableName = table.name;
130
+ const colName = column.name;
131
+ const schemaName = table.schema.name;
132
+ const db = table.schema._OWNER.path;
133
+ const columnGetter = getTDSColumnDerivedProperyFromType(
134
+ getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING,
135
+ );
136
+ return `|${db}->tableReference(
137
+ '${schemaName}',
138
+ '${tableName}'
139
+ )->tableToTDS()->restrict(
140
+ ['${colName}']
141
+ )->groupBy(
142
+ [],
143
+ [
144
+ 'Count'->agg(
145
+ row|$row.${columnGetter}('${colName}'),
146
+ x|$x->count()
147
+ ),
148
+ 'Distinct Count'->agg(
149
+ row|$row.${columnGetter}('${colName}'),
150
+ x|$x->distinct()->count()
151
+ ),
152
+ 'Sum'->agg(
153
+ row|$row.${columnGetter}('${colName}'),
154
+ x|$x->sum()
155
+ ),
156
+ 'Min'->agg(
157
+ row|$row.${columnGetter}('${colName}'),
158
+ x|$x->min()
159
+ ),
160
+ 'Max'->agg(
161
+ row|$row.${columnGetter}('${colName}'),
162
+ x|$x->max()
163
+ ),
164
+ 'Average'->agg(
165
+ row|$row.${columnGetter}('${colName}'),
166
+ x|$x->average()
167
+ ),
168
+ 'Std Dev (Population)'->agg(
169
+ row|$row.${columnGetter}('${colName}'),
170
+ x|$x->stdDevPopulation()
171
+ ),
172
+ 'Std Dev (Sample)'->agg(
173
+ row|$row.${columnGetter}('${colName}'),
174
+ x|$x->stdDevSample()
175
+ )
176
+ ]
177
+ )`;
178
+ };
179
+
180
+ const buildTableToTDSQueryColumnQuery = (column: Column): [string, boolean] => {
181
+ const type =
182
+ getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING;
183
+ const numerics = [
184
+ PRIMITIVE_TYPE.NUMBER,
185
+ PRIMITIVE_TYPE.INTEGER,
186
+ PRIMITIVE_TYPE.DECIMAL,
187
+ PRIMITIVE_TYPE.FLOAT,
188
+ ];
189
+ if (numerics.includes(type.path as PRIMITIVE_TYPE)) {
190
+ return [buildTableToTDSQueryNumericWithColumnGrammar(column), true];
191
+ }
192
+
193
+ return [buildTableToTDSQueryNonNumericWithColumnGrammar(column), false];
194
+ };
195
+
196
+ // 1. mapping
197
+ // 2. connection
198
+ // 3. runtime
199
+
200
+ const buildTDSModel = (
201
+ graph: PureModel,
202
+ connection: RelationalDatabaseConnection,
203
+ db: Database,
204
+ ): {
205
+ mapping: Mapping;
206
+ runtime: Runtime;
207
+ } => {
208
+ // mapping
209
+ const mappingName = 'EmptyMapping';
210
+ const _mapping = new Mapping(mappingName);
211
+ graph.addElement(_mapping, GENERATED_PACKAGE);
212
+ const engineRuntime = new EngineRuntime();
213
+ engineRuntime.mappings = [
214
+ PackageableElementExplicitReference.create(_mapping),
215
+ ];
216
+ const _storeConnection = new StoreConnections(
217
+ PackageableElementExplicitReference.create(db),
218
+ );
219
+ // copy over new connection
220
+ const newconnection = new RelationalDatabaseConnection(
221
+ PackageableElementExplicitReference.create(db),
222
+ connection.type,
223
+ connection.datasourceSpecification,
224
+ connection.authenticationStrategy,
225
+ );
226
+ newconnection.localMode = connection.localMode;
227
+ newconnection.timeZone = connection.timeZone;
228
+ _storeConnection.storeConnections = [
229
+ new IdentifiedConnection('connection1', newconnection),
230
+ ];
231
+ engineRuntime.connections = [_storeConnection];
232
+ return {
233
+ runtime: engineRuntime,
234
+ mapping: _mapping,
235
+ };
236
+ };
63
237
 
64
238
  export abstract class DatabaseSchemaExplorerTreeNodeData
65
239
  implements TreeNodeData
@@ -138,6 +312,8 @@ export class DatabaseSchemaExplorerState {
138
312
  isGeneratingDatabase = false;
139
313
  isUpdatingDatabase = false;
140
314
  treeData?: DatabaseExplorerTreeData | undefined;
315
+ previewer: TDSExecutionResult | undefined;
316
+ previewDataState = ActionState.create();
141
317
 
142
318
  constructor(
143
319
  editorStore: EditorStore,
@@ -148,6 +324,8 @@ export class DatabaseSchemaExplorerState {
148
324
  isUpdatingDatabase: observable,
149
325
  treeData: observable,
150
326
  targetDatabasePath: observable,
327
+ previewer: observable,
328
+ previewDataState: observable,
151
329
  isCreatingNewDatabase: computed,
152
330
  resolveDatabasePackageAndName: computed,
153
331
  setTreeData: action,
@@ -158,6 +336,7 @@ export class DatabaseSchemaExplorerState {
158
336
  fetchTableMetadata: flow,
159
337
  generateDatabase: flow,
160
338
  updateDatabase: flow,
339
+ previewData: flow,
161
340
  });
162
341
 
163
342
  this.connection = connection;
@@ -455,6 +634,113 @@ export class DatabaseSchemaExplorerState {
455
634
  );
456
635
  }
457
636
 
637
+ *previewData(node: DatabaseSchemaExplorerTreeNodeData): GeneratorFn<void> {
638
+ try {
639
+ this.previewer = undefined;
640
+ this.previewDataState.inProgress();
641
+ let column: Column | undefined;
642
+ let table: Table | undefined;
643
+ if (node instanceof DatabaseSchemaExplorerTreeTableNodeData) {
644
+ table = node.table;
645
+ } else if (node instanceof DatabaseSchemaExplorerTreeColumnNodeData) {
646
+ table = guaranteeType(node.column.owner, Table);
647
+ column = node.column;
648
+ } else {
649
+ throw new UnsupportedOperationError(
650
+ 'Preview data only supported for column and table',
651
+ );
652
+ }
653
+ const schemaName = table.schema.name;
654
+ const tableName = table.name;
655
+ const dummyPackage = 'generation';
656
+ const dummyName = 'myDB';
657
+ const dummyDbPath = `${dummyPackage}::${dummyName}`;
658
+ const databaseBuilderInput = new DatabaseBuilderInput(this.connection);
659
+ databaseBuilderInput.targetDatabase = new TargetDatabase(
660
+ dummyPackage,
661
+ dummyName,
662
+ );
663
+ const config = databaseBuilderInput.config;
664
+ config.maxTables = undefined;
665
+ config.enrichTables = true;
666
+ config.enrichColumns = true;
667
+ config.enrichPrimaryKeys = true;
668
+ config.patterns.push(new DatabasePattern(table.schema.name, table.name));
669
+ const entities =
670
+ (yield this.editorStore.graphManagerState.graphManager.buildDatabase(
671
+ databaseBuilderInput,
672
+ )) as Entity[];
673
+ assertTrue(entities.length === 1);
674
+ const dbEntity = guaranteeNonNullable(entities[0]);
675
+ const emptyGraph = this.editorStore.graphManagerState.createNewGraph();
676
+ (yield this.editorStore.graphManagerState.graphManager.buildGraph(
677
+ emptyGraph,
678
+ [dbEntity],
679
+ ActionState.create(),
680
+ )) as Entity[];
681
+ const generatedDb = emptyGraph.getDatabase(dummyDbPath);
682
+ const resolvedTable = getTable(
683
+ getSchema(generatedDb, schemaName),
684
+ tableName,
685
+ );
686
+ let queryGrammar: string;
687
+ let resolveResult = false;
688
+ if (column) {
689
+ const resolvedColumn = getColumn(resolvedTable, column.name);
690
+ const grammarResult = buildTableToTDSQueryColumnQuery(resolvedColumn);
691
+ queryGrammar = grammarResult[0];
692
+ resolveResult = grammarResult[1];
693
+ } else {
694
+ queryGrammar = buildTableToTDSQueryGrammar(resolvedTable);
695
+ }
696
+ const rawLambda =
697
+ (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(
698
+ queryGrammar,
699
+ 'QUERY',
700
+ )) as RawLambda;
701
+ const { mapping, runtime } = buildTDSModel(
702
+ emptyGraph,
703
+ this.connection,
704
+ generatedDb,
705
+ );
706
+ const execPlan =
707
+ (yield this.editorStore.graphManagerState.graphManager.runQuery(
708
+ rawLambda,
709
+ mapping,
710
+ runtime,
711
+ emptyGraph,
712
+ )) as ExecutionResult;
713
+ let tdsResult = guaranteeType(
714
+ execPlan,
715
+ TDSExecutionResult,
716
+ 'Execution from `tabletoTDS` expected to be TDS',
717
+ );
718
+ if (resolveResult) {
719
+ const newResult = new TDSExecutionResult();
720
+ newResult.result.columns = ['Aggregation', 'Value'];
721
+ newResult.result.rows = tdsResult.result.columns.map((col, idx) => {
722
+ const _row = new TDSRow();
723
+ _row.values = [
724
+ col,
725
+ guaranteeNonNullable(
726
+ guaranteeNonNullable(tdsResult.result.rows[0]).values[idx],
727
+ ),
728
+ ];
729
+ return _row;
730
+ });
731
+ tdsResult = newResult;
732
+ }
733
+ this.previewer = tdsResult;
734
+ } catch (error) {
735
+ assertErrorThrown(error);
736
+ this.editorStore.applicationStore.notificationService.notifyError(
737
+ `Unable to preview data: ${error.message}`,
738
+ );
739
+ } finally {
740
+ this.previewDataState.complete();
741
+ }
742
+ }
743
+
458
744
  *generateDatabase(): GeneratorFn<Entity> {
459
745
  try {
460
746
  this.isGeneratingDatabase = true;
@@ -25,11 +25,9 @@ import {
25
25
  import { observable, action, makeObservable, flow, flowResult } from 'mobx';
26
26
  import { LEGEND_STUDIO_APP_EVENT } from '../../../../../__lib__/LegendStudioEvent.js';
27
27
  import type { EditorStore } from '../../../EditorStore.js';
28
- import type { Database } from '@finos/legend-graph';
28
+ import { type Database, DEFAULT_GENERATION_PACKAGE } from '@finos/legend-graph';
29
29
  import { EntityChangeType, type EntityChange } from '@finos/legend-server-sdlc';
30
30
 
31
- export const GENERATED = 'generated';
32
-
33
31
  export class DatabaseModelBuilderState {
34
32
  readonly editorStore: EditorStore;
35
33
  readonly database: Database;
@@ -64,7 +62,7 @@ export class DatabaseModelBuilderState {
64
62
  this.editorStore = editorStore;
65
63
  this.database = database;
66
64
  this.isReadOnly = isReadOnly;
67
- this.targetPackage = database.package?.path ?? GENERATED;
65
+ this.targetPackage = database.package?.path ?? DEFAULT_GENERATION_PACKAGE;
68
66
  }
69
67
 
70
68
  setShowModal(val: boolean): void {
@@ -98,7 +96,6 @@ export class DatabaseModelBuilderState {
98
96
  this.targetPackage,
99
97
  this.editorStore.graphManagerState.graph,
100
98
  )) as Entity[];
101
-
102
99
  this.setEntities(entities);
103
100
  this.setDatabaseGrammarCode(
104
101
  (yield this.editorStore.graphManagerState.graphManager.entitiesToPureCode(
@@ -0,0 +1,234 @@
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
+ DEFAULT_GENERATION_PACKAGE,
19
+ EngineRuntime,
20
+ Database,
21
+ RelationalDatabaseConnection,
22
+ PackageableElementExplicitReference,
23
+ StoreConnections,
24
+ IdentifiedConnection,
25
+ GraphManagerState,
26
+ getMappingCompatibleClasses,
27
+ } from '@finos/legend-graph';
28
+ import type { EditorStore } from '../../../EditorStore.js';
29
+ import {
30
+ ActionState,
31
+ assertErrorThrown,
32
+ guaranteeNonNullable,
33
+ type GeneratorFn,
34
+ assertTrue,
35
+ } from '@finos/legend-shared';
36
+ import { action, flow, flowResult, makeObservable, observable } from 'mobx';
37
+ import type { Entity } from '@finos/legend-storage';
38
+ import {
39
+ QueryBuilderConfig,
40
+ QueryBuilderState,
41
+ } from '@finos/legend-query-builder';
42
+ import {
43
+ DEFAULT_TAB_SIZE,
44
+ type GenericLegendApplicationStore,
45
+ } from '@finos/legend-application';
46
+ import { payloadDebugger } from '../../../panel-group/DevToolPanelState.js';
47
+ import { renderDatabaseQueryBuilderSetupPanelContent } from '../../../../../components/editor/editor-group/database/IsolatedQueryDatabase.js';
48
+
49
+ const replaceConnectionInEngineRuntime = (
50
+ engineRuntime: EngineRuntime,
51
+ connection: RelationalDatabaseConnection,
52
+ databse: Database,
53
+ ): void => {
54
+ const _storeConnection = new StoreConnections(
55
+ PackageableElementExplicitReference.create(databse),
56
+ );
57
+ const newconnection = new RelationalDatabaseConnection(
58
+ PackageableElementExplicitReference.create(databse),
59
+ connection.type,
60
+ connection.datasourceSpecification,
61
+ connection.authenticationStrategy,
62
+ );
63
+ newconnection.localMode = connection.localMode;
64
+ newconnection.timeZone = connection.timeZone;
65
+ _storeConnection.storeConnections = [
66
+ new IdentifiedConnection('connection1', newconnection),
67
+ ];
68
+ engineRuntime.connections = [_storeConnection];
69
+ };
70
+ export class IsolatedDatabaseBuilderState extends QueryBuilderState {
71
+ readonly database: Database;
72
+ globalGraphManagerState: GraphManagerState;
73
+ engineRuntime: EngineRuntime;
74
+ connectionKey: string;
75
+ compatibleConnections: Map<string, RelationalDatabaseConnection>;
76
+
77
+ override TEMPORARY__setupPanelContentRenderer = (): React.ReactNode =>
78
+ renderDatabaseQueryBuilderSetupPanelContent(this);
79
+
80
+ constructor(
81
+ applicationStore: GenericLegendApplicationStore,
82
+ isolatedGraphManagerState: GraphManagerState,
83
+ globalGraphManagerState: GraphManagerState,
84
+ database: Database,
85
+ connectionKey: string,
86
+ runtime: EngineRuntime,
87
+ compatibleConnections: Map<string, RelationalDatabaseConnection>,
88
+ acceptedElementPaths?: string[],
89
+ config?: QueryBuilderConfig | undefined,
90
+ ) {
91
+ super(applicationStore, isolatedGraphManagerState, config);
92
+ makeObservable(this, {
93
+ connectionKey: observable,
94
+ engineRuntime: observable,
95
+ changeConnection: action,
96
+ });
97
+ this.database = database;
98
+ this.globalGraphManagerState = globalGraphManagerState;
99
+ this.engineRuntime = runtime;
100
+ this.compatibleConnections = compatibleConnections;
101
+ this.connectionKey = connectionKey;
102
+ const classes = isolatedGraphManagerState.usableClasses;
103
+ const electedMapping = guaranteeNonNullable(
104
+ isolatedGraphManagerState.graph.mappings.filter((m) =>
105
+ acceptedElementPaths ? acceptedElementPaths.includes(m.path) : true,
106
+ )[0],
107
+ 'Compatible mapping expected',
108
+ );
109
+
110
+ this.class = guaranteeNonNullable(
111
+ getMappingCompatibleClasses(electedMapping, classes)[0],
112
+ 'Compatible class expected for mapping',
113
+ );
114
+
115
+ this.executionContextState.mapping = electedMapping;
116
+ this.executionContextState.runtimeValue = runtime;
117
+ }
118
+
119
+ changeConnection(key: string): void {
120
+ const connection = this.compatibleConnections.get(key);
121
+ if (connection) {
122
+ replaceConnectionInEngineRuntime(
123
+ this.engineRuntime,
124
+ connection,
125
+ this.database,
126
+ );
127
+ this.connectionKey = key;
128
+ }
129
+ }
130
+ }
131
+
132
+ export class QueryDatabaseState {
133
+ editorStore: EditorStore;
134
+ database: Database;
135
+
136
+ constructor(database: Database, editorStore: EditorStore) {
137
+ this.database = database;
138
+ this.editorStore = editorStore;
139
+
140
+ makeObservable(this, {
141
+ init: flow,
142
+ });
143
+ }
144
+ *init(): GeneratorFn<void> {
145
+ try {
146
+ const compConnections = new Map<string, RelationalDatabaseConnection>();
147
+ this.editorStore.graphManagerState.usableConnections.forEach((conn) => {
148
+ const val = conn.connectionValue;
149
+ if (val instanceof RelationalDatabaseConnection) {
150
+ compConnections.set(conn.path, val);
151
+ }
152
+ });
153
+ assertTrue(
154
+ compConnections.size > 0,
155
+ `No compatible connections found for database ${this.database.path}`,
156
+ );
157
+ const embeddedQueryBuilderState =
158
+ this.editorStore.embeddedQueryBuilderState;
159
+ const databaseGraphManagerState = new GraphManagerState(
160
+ this.editorStore.applicationStore.pluginManager,
161
+ this.editorStore.applicationStore.logService,
162
+ );
163
+ yield databaseGraphManagerState.graphManager.initialize(
164
+ {
165
+ env: this.editorStore.applicationStore.config.env,
166
+ tabSize: DEFAULT_TAB_SIZE,
167
+ clientConfig: {
168
+ baseUrl: this.editorStore.applicationStore.config.engineServerUrl,
169
+ queryBaseUrl:
170
+ this.editorStore.applicationStore.config.engineQueryServerUrl,
171
+ enableCompression: true,
172
+ payloadDebugger,
173
+ },
174
+ },
175
+ {
176
+ tracerService: this.editorStore.applicationStore.tracerService,
177
+ },
178
+ );
179
+ databaseGraphManagerState.graph =
180
+ this.editorStore.graphManagerState.createNewGraph();
181
+ const copiedDb = new Database(this.database.name);
182
+ databaseGraphManagerState.graph.addElement(
183
+ copiedDb,
184
+ guaranteeNonNullable(this.database.package?.path),
185
+ );
186
+ copiedDb.schemas = this.database.schemas;
187
+ copiedDb.joins = this.database.joins;
188
+ copiedDb.filters = this.database.filters;
189
+ const entities =
190
+ (yield this.editorStore.graphManagerState.graphManager.generateModelsFromDatabaseSpecification(
191
+ this.database.path,
192
+ DEFAULT_GENERATION_PACKAGE,
193
+ this.editorStore.graphManagerState.graph,
194
+ )) as Entity[];
195
+ yield this.editorStore.graphManagerState.graphManager.buildGraph(
196
+ databaseGraphManagerState.graph,
197
+ entities,
198
+ ActionState.create(),
199
+ );
200
+ const engineRuntime = new EngineRuntime();
201
+ engineRuntime.mappings = databaseGraphManagerState.graph.mappings.map(
202
+ (e) => PackageableElementExplicitReference.create(e),
203
+ );
204
+ const connectionEntry = guaranteeNonNullable(
205
+ Array.from(compConnections.entries())[0],
206
+ );
207
+ const connection = connectionEntry[1];
208
+ replaceConnectionInEngineRuntime(engineRuntime, connection, copiedDb);
209
+ const config = new QueryBuilderConfig();
210
+ const queryBuilderState = new IsolatedDatabaseBuilderState(
211
+ this.editorStore.applicationStore,
212
+ databaseGraphManagerState,
213
+ this.editorStore.graphManagerState,
214
+ copiedDb,
215
+ connectionEntry[0],
216
+ engineRuntime,
217
+ compConnections,
218
+ entities.map((e) => e.path),
219
+ config,
220
+ );
221
+ yield flowResult(
222
+ embeddedQueryBuilderState.setEmbeddedQueryBuilderConfiguration({
223
+ setupQueryBuilderState: () => queryBuilderState,
224
+ actionConfigs: [],
225
+ }),
226
+ );
227
+ } catch (error) {
228
+ assertErrorThrown(error);
229
+ this.editorStore.applicationStore.notificationService.notifyError(
230
+ `Unable to query database: ${error.message}`,
231
+ );
232
+ }
233
+ }
234
+ }
@@ -274,6 +274,7 @@ export class ProjectViewerStore {
274
274
  yield Promise.all([
275
275
  this.editorStore.sdlcState.fetchProjectVersions(),
276
276
  this.editorStore.sdlcState.fetchPublishedProjectVersions(),
277
+ this.editorStore.sdlcState.fetchAuthorizedActions(),
277
278
  ]);
278
279
 
279
280
  // fetch entities
package/tsconfig.json CHANGED
@@ -101,6 +101,7 @@
101
101
  "./src/stores/editor/editor-state/element-editor-state/connection/PostProcessorEditorState.ts",
102
102
  "./src/stores/editor/editor-state/element-editor-state/data/DataEditorState.ts",
103
103
  "./src/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.ts",
104
+ "./src/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.ts",
104
105
  "./src/stores/editor/editor-state/element-editor-state/external-format/DSL_ExternalFormat_BindingEditorState.ts",
105
106
  "./src/stores/editor/editor-state/element-editor-state/external-format/DSL_ExternalFormat_SchemaSetEditorState.ts",
106
107
  "./src/stores/editor/editor-state/element-editor-state/mapping/DEPRECATED__MappingTestState.ts",
@@ -206,6 +207,7 @@
206
207
  "./src/components/editor/editor-group/data-editor/DataElementEditor.tsx",
207
208
  "./src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx",
208
209
  "./src/components/editor/editor-group/data-editor/RelationalCSVDataEditor.tsx",
210
+ "./src/components/editor/editor-group/database/IsolatedQueryDatabase.tsx",
209
211
  "./src/components/editor/editor-group/diff-editor/EntityChangeConflictEditor.tsx",
210
212
  "./src/components/editor/editor-group/diff-editor/EntityDiffView.tsx",
211
213
  "./src/components/editor/editor-group/element-generation-editor/ElementGenerationEditor.tsx",