@finos/legend-application-studio 28.7.1 → 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.
- 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/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 +8 -2
- 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/index.css +1 -1
- package/lib/package.json +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/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/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/package.json +5 -5
- package/src/application/LegendStudioApplicationConfig.ts +0 -7
- 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 +21 -6
- package/src/components/editor/side-bar/ProjectOverview.tsx +0 -19
- package/src/stores/editor/EditorSDLCState.ts +6 -19
- 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/project-view/ProjectViewerStore.ts +1 -0
- 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
|
-
|
178
|
-
|
179
|
-
|
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
|
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
|
|
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
|
+
}
|
@@ -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",
|