@finos/legend-application-studio 28.7.1 → 28.9.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 (132) hide show
  1. package/lib/__lib__/LegendStudioNavigation.d.ts +6 -0
  2. package/lib/__lib__/LegendStudioNavigation.d.ts.map +1 -1
  3. package/lib/__lib__/LegendStudioNavigation.js +5 -0
  4. package/lib/__lib__/LegendStudioNavigation.js.map +1 -1
  5. package/lib/application/LegendStudioApplicationConfig.d.ts +0 -5
  6. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  7. package/lib/application/LegendStudioApplicationConfig.js +0 -6
  8. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  9. package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
  10. package/lib/components/LegendStudioWebApplication.js +4 -1
  11. package/lib/components/LegendStudioWebApplication.js.map +1 -1
  12. package/lib/components/ShowcaseManager.d.ts.map +1 -1
  13. package/lib/components/ShowcaseManager.js +6 -1
  14. package/lib/components/ShowcaseManager.js.map +1 -1
  15. package/lib/components/editor/editor-group/GrammarTextEditor.js +1 -1
  16. package/lib/components/editor/editor-group/GrammarTextEditor.js.map +1 -1
  17. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts.map +1 -1
  18. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js +41 -4
  19. package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js.map +1 -1
  20. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts +2 -0
  21. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts.map +1 -1
  22. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js +13 -3
  23. package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js.map +1 -1
  24. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts +18 -0
  25. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts.map +1 -0
  26. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js +54 -0
  27. package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js.map +1 -0
  28. package/lib/components/editor/panel-group/PanelGroup.d.ts.map +1 -1
  29. package/lib/components/editor/panel-group/PanelGroup.js +1 -5
  30. package/lib/components/editor/panel-group/PanelGroup.js.map +1 -1
  31. package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
  32. package/lib/components/editor/side-bar/Explorer.js +11 -4
  33. package/lib/components/editor/side-bar/Explorer.js.map +1 -1
  34. package/lib/components/editor/side-bar/ProjectOverview.d.ts.map +1 -1
  35. package/lib/components/editor/side-bar/ProjectOverview.js +1 -1
  36. package/lib/components/editor/side-bar/ProjectOverview.js.map +1 -1
  37. package/lib/components/project-view/ProjectViewer.d.ts.map +1 -1
  38. package/lib/components/project-view/ProjectViewer.js +37 -5
  39. package/lib/components/project-view/ProjectViewer.js.map +1 -1
  40. package/lib/components/showcase/ShowcaseViewer.d.ts +18 -0
  41. package/lib/components/showcase/ShowcaseViewer.d.ts.map +1 -0
  42. package/lib/components/showcase/ShowcaseViewer.js +147 -0
  43. package/lib/components/showcase/ShowcaseViewer.js.map +1 -0
  44. package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts +23 -0
  45. package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts.map +1 -0
  46. package/lib/components/showcase/ShowcaseViewerStoreProvider.js +36 -0
  47. package/lib/components/showcase/ShowcaseViewerStoreProvider.js.map +1 -0
  48. package/lib/index.css +2 -2
  49. package/lib/index.css.map +1 -1
  50. package/lib/package.json +1 -1
  51. package/lib/stores/LegendStudioBaseStore.d.ts.map +1 -1
  52. package/lib/stores/LegendStudioBaseStore.js +1 -0
  53. package/lib/stores/LegendStudioBaseStore.js.map +1 -1
  54. package/lib/stores/editor/EditorMode.d.ts +4 -0
  55. package/lib/stores/editor/EditorMode.d.ts.map +1 -1
  56. package/lib/stores/editor/EditorMode.js +9 -0
  57. package/lib/stores/editor/EditorMode.js.map +1 -1
  58. package/lib/stores/editor/EditorSDLCState.d.ts +1 -2
  59. package/lib/stores/editor/EditorSDLCState.d.ts.map +1 -1
  60. package/lib/stores/editor/EditorSDLCState.js +3 -14
  61. package/lib/stores/editor/EditorSDLCState.js.map +1 -1
  62. package/lib/stores/editor/EditorStore.d.ts.map +1 -1
  63. package/lib/stores/editor/EditorStore.js +1 -3
  64. package/lib/stores/editor/EditorStore.js.map +1 -1
  65. package/lib/stores/editor/StandardEditorMode.d.ts +1 -0
  66. package/lib/stores/editor/StandardEditorMode.d.ts.map +1 -1
  67. package/lib/stores/editor/StandardEditorMode.js +4 -0
  68. package/lib/stores/editor/StandardEditorMode.js.map +1 -1
  69. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +5 -2
  70. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
  71. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +209 -2
  72. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
  73. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts +1 -2
  74. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts.map +1 -1
  75. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js +2 -2
  76. package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js.map +1 -1
  77. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts +37 -0
  78. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts.map +1 -0
  79. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js +127 -0
  80. package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js.map +1 -0
  81. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
  82. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +20 -4
  83. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
  84. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts +3 -0
  85. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts.map +1 -1
  86. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js +17 -2
  87. package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js.map +1 -1
  88. package/lib/stores/project-view/ProjectViewerEditorMode.d.ts +3 -0
  89. package/lib/stores/project-view/ProjectViewerEditorMode.d.ts.map +1 -1
  90. package/lib/stores/project-view/ProjectViewerEditorMode.js +10 -0
  91. package/lib/stores/project-view/ProjectViewerEditorMode.js.map +1 -1
  92. package/lib/stores/project-view/ProjectViewerStore.d.ts.map +1 -1
  93. package/lib/stores/project-view/ProjectViewerStore.js +1 -0
  94. package/lib/stores/project-view/ProjectViewerStore.js.map +1 -1
  95. package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts +28 -0
  96. package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts.map +1 -0
  97. package/lib/stores/showcase/ShowcaseViewerEditorMode.js +40 -0
  98. package/lib/stores/showcase/ShowcaseViewerEditorMode.js.map +1 -0
  99. package/lib/stores/showcase/ShowcaseViewerStore.d.ts +32 -0
  100. package/lib/stores/showcase/ShowcaseViewerStore.d.ts.map +1 -0
  101. package/lib/stores/showcase/ShowcaseViewerStore.js +189 -0
  102. package/lib/stores/showcase/ShowcaseViewerStore.js.map +1 -0
  103. package/package.json +7 -7
  104. package/src/__lib__/LegendStudioNavigation.ts +11 -0
  105. package/src/application/LegendStudioApplicationConfig.ts +0 -7
  106. package/src/components/LegendStudioWebApplication.tsx +11 -1
  107. package/src/components/ShowcaseManager.tsx +26 -2
  108. package/src/components/editor/editor-group/GrammarTextEditor.tsx +1 -1
  109. package/src/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.tsx +117 -16
  110. package/src/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.tsx +40 -1
  111. package/src/components/editor/editor-group/database/IsolatedQueryDatabase.tsx +138 -0
  112. package/src/components/editor/panel-group/PanelGroup.tsx +3 -8
  113. package/src/components/editor/side-bar/Explorer.tsx +41 -18
  114. package/src/components/editor/side-bar/ProjectOverview.tsx +0 -19
  115. package/src/components/project-view/ProjectViewer.tsx +139 -4
  116. package/src/components/showcase/ShowcaseViewer.tsx +418 -0
  117. package/src/components/showcase/ShowcaseViewerStoreProvider.tsx +56 -0
  118. package/src/stores/LegendStudioBaseStore.ts +1 -0
  119. package/src/stores/editor/EditorMode.ts +14 -0
  120. package/src/stores/editor/EditorSDLCState.ts +6 -19
  121. package/src/stores/editor/EditorStore.ts +1 -8
  122. package/src/stores/editor/StandardEditorMode.ts +7 -0
  123. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +288 -2
  124. package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts +2 -5
  125. package/src/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.ts +234 -0
  126. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +31 -9
  127. package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts +23 -0
  128. package/src/stores/project-view/ProjectViewerEditorMode.ts +17 -0
  129. package/src/stores/project-view/ProjectViewerStore.ts +1 -0
  130. package/src/stores/showcase/ShowcaseViewerEditorMode.ts +51 -0
  131. package/src/stores/showcase/ShowcaseViewerStore.ts +285 -0
  132. package/tsconfig.json +6 -0
@@ -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
+ }
@@ -81,6 +81,7 @@ import {
81
81
  createBareMappingTest,
82
82
  createGraphFetchQueryFromMappingAnalysis,
83
83
  generateStoreTestDataFromSetImpl,
84
+ isRelationalMappingTestSuite,
84
85
  } from './MappingTestingHelper.js';
85
86
  import { LEGEND_STUDIO_APP_EVENT } from '../../../../../../__lib__/LegendStudioEvent.js';
86
87
 
@@ -729,15 +730,36 @@ export class MappingTestableState {
729
730
  this.selectedTestSuite?.testStates.forEach((t) =>
730
731
  t.runningTestAction.inProgress(),
731
732
  );
732
- const input = new RunTestsTestableInput(this.mapping);
733
- suite.tests.forEach((t) =>
734
- input.unitTestIds.push(new UniqueTestId(suite, t)),
735
- );
736
- const testResults =
737
- (yield this.editorStore.graphManagerState.graphManager.runTests(
738
- [input],
739
- this.editorStore.graphManagerState.graph,
740
- )) as TestResult[];
733
+ let testResults: TestResult[];
734
+ if (isRelationalMappingTestSuite(suite)) {
735
+ // TEMPORARY RUN each test separately. This is done to help with performance
736
+ // specifically with running realtional mapping tests as we generate a plan during each test.
737
+ // with this change we would still do this but in parallel reducing the time to run the suite
738
+ const inputs = suite.tests.map((t) => {
739
+ const input = new RunTestsTestableInput(this.mapping);
740
+ input.unitTestIds.push(new UniqueTestId(suite, t));
741
+ return input;
742
+ });
743
+ const _testResults = (yield Promise.all(
744
+ inputs.map((i) =>
745
+ this.editorStore.graphManagerState.graphManager.runTests(
746
+ [i],
747
+ this.editorStore.graphManagerState.graph,
748
+ ),
749
+ ),
750
+ )) as TestResult[][];
751
+ testResults = _testResults.flat();
752
+ } else {
753
+ const input = new RunTestsTestableInput(this.mapping);
754
+ suite.tests.forEach((t) =>
755
+ input.unitTestIds.push(new UniqueTestId(suite, t)),
756
+ );
757
+ testResults =
758
+ (yield this.editorStore.graphManagerState.graphManager.runTests(
759
+ [input],
760
+ this.editorStore.graphManagerState.graph,
761
+ )) as TestResult[];
762
+ }
741
763
  this.handleNewResults(testResults);
742
764
  } catch (error) {
743
765
  assertErrorThrown(error);
@@ -45,6 +45,7 @@ import {
45
45
  PropertyGraphFetchTree,
46
46
  PropertyExplicitReference,
47
47
  type ObserverContext,
48
+ Database,
48
49
  } from '@finos/legend-graph';
49
50
  import {
50
51
  buildGetAllFunction,
@@ -61,6 +62,7 @@ import {
61
62
  import {
62
63
  assertErrorThrown,
63
64
  assertTrue,
65
+ filterByType,
64
66
  guaranteeNonNullable,
65
67
  } from '@finos/legend-shared';
66
68
  import type { DSL_Data_LegendStudioApplicationPlugin_Extension } from '../../../../../extensions/DSL_Data_LegendStudioApplicationPlugin_Extension.js';
@@ -103,6 +105,27 @@ export const createStoreBareModelStoreData = (
103
105
  return testData;
104
106
  };
105
107
 
108
+ export const isRelationalStoreTestData = (val: StoreTestData): boolean =>
109
+ val.store.value instanceof Database;
110
+
111
+ export const isRelationalMappingTest = (val: MappingTest): boolean => {
112
+ if (!val.storeTestData.length) {
113
+ return false;
114
+ }
115
+ return val.storeTestData.some((e) => isRelationalStoreTestData(e));
116
+ };
117
+
118
+ export const isRelationalMappingTestSuite = (
119
+ val: MappingTestSuite,
120
+ ): boolean => {
121
+ if (!val.tests.length) {
122
+ return false;
123
+ }
124
+ return val.tests
125
+ .filter(filterByType(MappingTest))
126
+ .some((e) => isRelationalMappingTest(e));
127
+ };
128
+
106
129
  export const generateStoreTestDataFromSetImpl = (
107
130
  setImpl: SetImplementation,
108
131
  editorStore: EditorStore,