@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.
- package/lib/__lib__/LegendStudioNavigation.d.ts +6 -0
- package/lib/__lib__/LegendStudioNavigation.d.ts.map +1 -1
- package/lib/__lib__/LegendStudioNavigation.js +5 -0
- package/lib/__lib__/LegendStudioNavigation.js.map +1 -1
- package/lib/application/LegendStudioApplicationConfig.d.ts +0 -5
- package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
- package/lib/application/LegendStudioApplicationConfig.js +0 -6
- package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
- package/lib/components/LegendStudioWebApplication.d.ts.map +1 -1
- package/lib/components/LegendStudioWebApplication.js +4 -1
- package/lib/components/LegendStudioWebApplication.js.map +1 -1
- package/lib/components/ShowcaseManager.d.ts.map +1 -1
- package/lib/components/ShowcaseManager.js +6 -1
- package/lib/components/ShowcaseManager.js.map +1 -1
- package/lib/components/editor/editor-group/GrammarTextEditor.js +1 -1
- package/lib/components/editor/editor-group/GrammarTextEditor.js.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.d.ts.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js +41 -4
- package/lib/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.js.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts +2 -0
- package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.d.ts.map +1 -1
- package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js +13 -3
- package/lib/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.js.map +1 -1
- package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts +18 -0
- package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.d.ts.map +1 -0
- package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js +54 -0
- package/lib/components/editor/editor-group/database/IsolatedQueryDatabase.js.map +1 -0
- package/lib/components/editor/panel-group/PanelGroup.d.ts.map +1 -1
- package/lib/components/editor/panel-group/PanelGroup.js +1 -5
- package/lib/components/editor/panel-group/PanelGroup.js.map +1 -1
- package/lib/components/editor/side-bar/Explorer.d.ts.map +1 -1
- package/lib/components/editor/side-bar/Explorer.js +11 -4
- package/lib/components/editor/side-bar/Explorer.js.map +1 -1
- package/lib/components/editor/side-bar/ProjectOverview.d.ts.map +1 -1
- package/lib/components/editor/side-bar/ProjectOverview.js +1 -1
- package/lib/components/editor/side-bar/ProjectOverview.js.map +1 -1
- package/lib/components/project-view/ProjectViewer.d.ts.map +1 -1
- package/lib/components/project-view/ProjectViewer.js +37 -5
- package/lib/components/project-view/ProjectViewer.js.map +1 -1
- package/lib/components/showcase/ShowcaseViewer.d.ts +18 -0
- package/lib/components/showcase/ShowcaseViewer.d.ts.map +1 -0
- package/lib/components/showcase/ShowcaseViewer.js +147 -0
- package/lib/components/showcase/ShowcaseViewer.js.map +1 -0
- package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts +23 -0
- package/lib/components/showcase/ShowcaseViewerStoreProvider.d.ts.map +1 -0
- package/lib/components/showcase/ShowcaseViewerStoreProvider.js +36 -0
- package/lib/components/showcase/ShowcaseViewerStoreProvider.js.map +1 -0
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +1 -1
- package/lib/stores/LegendStudioBaseStore.d.ts.map +1 -1
- package/lib/stores/LegendStudioBaseStore.js +1 -0
- package/lib/stores/LegendStudioBaseStore.js.map +1 -1
- package/lib/stores/editor/EditorMode.d.ts +4 -0
- package/lib/stores/editor/EditorMode.d.ts.map +1 -1
- package/lib/stores/editor/EditorMode.js +9 -0
- package/lib/stores/editor/EditorMode.js.map +1 -1
- package/lib/stores/editor/EditorSDLCState.d.ts +1 -2
- package/lib/stores/editor/EditorSDLCState.d.ts.map +1 -1
- package/lib/stores/editor/EditorSDLCState.js +3 -14
- package/lib/stores/editor/EditorSDLCState.js.map +1 -1
- package/lib/stores/editor/EditorStore.d.ts.map +1 -1
- package/lib/stores/editor/EditorStore.js +1 -3
- package/lib/stores/editor/EditorStore.js.map +1 -1
- package/lib/stores/editor/StandardEditorMode.d.ts +1 -0
- package/lib/stores/editor/StandardEditorMode.d.ts.map +1 -1
- package/lib/stores/editor/StandardEditorMode.js +4 -0
- package/lib/stores/editor/StandardEditorMode.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts +5 -2
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js +209 -2
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts +1 -2
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js +2 -2
- package/lib/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts +37 -0
- package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.d.ts.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js +127 -0
- package/lib/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.js.map +1 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js +20 -4
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts +3 -0
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js +17 -2
- package/lib/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.js.map +1 -1
- package/lib/stores/project-view/ProjectViewerEditorMode.d.ts +3 -0
- package/lib/stores/project-view/ProjectViewerEditorMode.d.ts.map +1 -1
- package/lib/stores/project-view/ProjectViewerEditorMode.js +10 -0
- package/lib/stores/project-view/ProjectViewerEditorMode.js.map +1 -1
- package/lib/stores/project-view/ProjectViewerStore.d.ts.map +1 -1
- package/lib/stores/project-view/ProjectViewerStore.js +1 -0
- package/lib/stores/project-view/ProjectViewerStore.js.map +1 -1
- package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts +28 -0
- package/lib/stores/showcase/ShowcaseViewerEditorMode.d.ts.map +1 -0
- package/lib/stores/showcase/ShowcaseViewerEditorMode.js +40 -0
- package/lib/stores/showcase/ShowcaseViewerEditorMode.js.map +1 -0
- package/lib/stores/showcase/ShowcaseViewerStore.d.ts +32 -0
- package/lib/stores/showcase/ShowcaseViewerStore.d.ts.map +1 -0
- package/lib/stores/showcase/ShowcaseViewerStore.js +189 -0
- package/lib/stores/showcase/ShowcaseViewerStore.js.map +1 -0
- package/package.json +7 -7
- package/src/__lib__/LegendStudioNavigation.ts +11 -0
- package/src/application/LegendStudioApplicationConfig.ts +0 -7
- package/src/components/LegendStudioWebApplication.tsx +11 -1
- package/src/components/ShowcaseManager.tsx +26 -2
- package/src/components/editor/editor-group/GrammarTextEditor.tsx +1 -1
- package/src/components/editor/editor-group/connection-editor/DatabaseBuilderWizard.tsx +117 -16
- package/src/components/editor/editor-group/connection-editor/DatabaseSchemaExplorer.tsx +40 -1
- package/src/components/editor/editor-group/database/IsolatedQueryDatabase.tsx +138 -0
- package/src/components/editor/panel-group/PanelGroup.tsx +3 -8
- package/src/components/editor/side-bar/Explorer.tsx +41 -18
- package/src/components/editor/side-bar/ProjectOverview.tsx +0 -19
- package/src/components/project-view/ProjectViewer.tsx +139 -4
- package/src/components/showcase/ShowcaseViewer.tsx +418 -0
- package/src/components/showcase/ShowcaseViewerStoreProvider.tsx +56 -0
- package/src/stores/LegendStudioBaseStore.ts +1 -0
- package/src/stores/editor/EditorMode.ts +14 -0
- package/src/stores/editor/EditorSDLCState.ts +6 -19
- package/src/stores/editor/EditorStore.ts +1 -8
- package/src/stores/editor/StandardEditorMode.ts +7 -0
- package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts +288 -2
- package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts +2 -5
- package/src/stores/editor/editor-state/element-editor-state/database/QueryDatabaseState.ts +234 -0
- package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts +31 -9
- package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts +23 -0
- package/src/stores/project-view/ProjectViewerEditorMode.ts +17 -0
- package/src/stores/project-view/ProjectViewerStore.ts +1 -0
- package/src/stores/showcase/ShowcaseViewerEditorMode.ts +51 -0
- package/src/stores/showcase/ShowcaseViewerStore.ts +285 -0
- package/tsconfig.json +6 -0
package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseBuilderState.ts
CHANGED
@@ -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
|
-
|
47
|
-
|
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;
|
package/src/stores/editor/editor-state/element-editor-state/connection/DatabaseModelBuilderState.ts
CHANGED
@@ -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
|
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 ??
|
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
|
+
}
|
package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestableState.ts
CHANGED
@@ -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
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
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);
|
package/src/stores/editor/editor-state/element-editor-state/mapping/testable/MappingTestingHelper.ts
CHANGED
@@ -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,
|