UNPKG

@finos/legend-application-studio

Version:
724 lines 33.7 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { assertErrorThrown, LogEvent, addUniqueEntry, guaranteeNonNullable, isNonNullable, filterByType, ActionState, at, guaranteeType, assertNonEmptyString, assertTrue, UnsupportedOperationError, } from '@finos/legend-shared'; import { observable, action, makeObservable, flow, flowResult, computed, } from 'mobx'; import { LEGEND_STUDIO_APP_EVENT } from '../../../../../__lib__/LegendStudioEvent.js'; import { TDSExecutionResult, getColumn, PrimitiveType, PRIMITIVE_TYPE, TDSRow, Table, RelationalDatabaseConnection, DatabaseBuilderInput, DatabasePattern, TargetDatabase, Column, Database, resolvePackagePathAndElementName, getSchema, getNullableSchema, getNullableTable, isStubbed_PackageableElement, isValidFullPath, PackageableElementExplicitReference, getTable, Mapping, EngineRuntime, StoreConnections, IdentifiedConnection, getOrCreateGraphPackage, extractElementNameFromPath, extractPackagePathFromPath, } from '@finos/legend-graph'; import { GraphEditFormModeState } from '../../../GraphEditFormModeState.js'; import { connection_setStore } from '../../../../graph-modifier/DSL_Mapping_GraphModifierHelper.js'; import { getTDSColumnDerivedProperyFromType } from '@finos/legend-query-builder'; import { getPrimitiveTypeFromRelationalType } from '../../../utils/MockDataUtils.js'; const GENERATED_PACKAGE = 'generated'; const TDS_LIMIT = 1000; const buildTableToTDSQueryGrammar = (table) => { const tableName = table.name; const schemaName = table.schema.name; const db = table.schema._OWNER.path; return `|${db}->tableReference( '${schemaName}', '${tableName}' )->tableToTDS()->take(${TDS_LIMIT})`; }; const buildTableToTDSQueryNonNumericWithColumnGrammar = (column) => { const table = guaranteeType(column.owner, Table); const tableName = table.name; const colName = column.name; const schemaName = table.schema.name; const db = table.schema._OWNER.path; const PREVIEW_COLUMN_NAME = 'Count Value'; const columnGetter = getTDSColumnDerivedProperyFromType(getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING); return `|${db}->tableReference( '${schemaName}', '${tableName}' )->tableToTDS()->restrict( ['${colName}'] )->groupBy( ['${colName}'], '${PREVIEW_COLUMN_NAME}'->agg( row|$row.${columnGetter}('${colName}'), y|$y->count() ) )->sort( [ desc('${colName}'), asc('${PREVIEW_COLUMN_NAME}') ] )->take(${TDS_LIMIT})`; }; const buildTableToTDSQueryNumericWithColumnGrammar = (column) => { const table = guaranteeType(column.owner, Table); const tableName = table.name; const colName = column.name; const schemaName = table.schema.name; const db = table.schema._OWNER.path; const columnGetter = getTDSColumnDerivedProperyFromType(getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING); return `|${db}->tableReference( '${schemaName}', '${tableName}' )->tableToTDS()->restrict( ['${colName}'] )->groupBy( [], [ 'Count'->agg( row|$row.${columnGetter}('${colName}'), x|$x->count() ), 'Distinct Count'->agg( row|$row.${columnGetter}('${colName}'), x|$x->distinct()->count() ), 'Sum'->agg( row|$row.${columnGetter}('${colName}'), x|$x->sum() ), 'Min'->agg( row|$row.${columnGetter}('${colName}'), x|$x->min() ), 'Max'->agg( row|$row.${columnGetter}('${colName}'), x|$x->max() ), 'Average'->agg( row|$row.${columnGetter}('${colName}'), x|$x->average() ), 'Std Dev (Population)'->agg( row|$row.${columnGetter}('${colName}'), x|$x->stdDevPopulation() ), 'Std Dev (Sample)'->agg( row|$row.${columnGetter}('${colName}'), x|$x->stdDevSample() ) ] )`; }; const buildTableToTDSQueryColumnQuery = (column) => { const type = getPrimitiveTypeFromRelationalType(column.type) ?? PrimitiveType.STRING; const numerics = [ PRIMITIVE_TYPE.NUMBER, PRIMITIVE_TYPE.INTEGER, PRIMITIVE_TYPE.DECIMAL, PRIMITIVE_TYPE.FLOAT, ]; if (numerics.includes(type.path)) { return [buildTableToTDSQueryNumericWithColumnGrammar(column), true]; } return [buildTableToTDSQueryNonNumericWithColumnGrammar(column), false]; }; // 1. mapping // 2. connection // 3. runtime const buildTDSModel = (graph, connection, db) => { // mapping const mappingName = 'EmptyMapping'; const _mapping = new Mapping(mappingName); graph.addElement(_mapping, GENERATED_PACKAGE); const engineRuntime = new EngineRuntime(); engineRuntime.mappings = [ PackageableElementExplicitReference.create(_mapping), ]; const _storeConnection = new StoreConnections(PackageableElementExplicitReference.create(db)); // copy over new connection const newconnection = new RelationalDatabaseConnection(PackageableElementExplicitReference.create(db), connection.type, connection.datasourceSpecification, connection.authenticationStrategy); newconnection.localMode = connection.localMode; newconnection.timeZone = connection.timeZone; _storeConnection.storeConnections = [ new IdentifiedConnection('connection1', newconnection), ]; engineRuntime.connections = [_storeConnection]; return { runtime: engineRuntime, mapping: _mapping, }; }; export class DatabaseSchemaExplorerTreeNodeData { isOpen; id; label; parentId; childrenIds; isChecked = false; constructor(id, label, parentId) { makeObservable(this, { isChecked: observable, setChecked: action, }); this.id = id; this.label = label; this.parentId = parentId; } setChecked(val) { this.isChecked = val; } } export class DatabaseSchemaExplorerTreeSchemaNodeData extends DatabaseSchemaExplorerTreeNodeData { schema; constructor(id, schema) { super(id, schema.name, undefined); this.schema = schema; } } export class DatabaseSchemaExplorerTreeTableNodeData extends DatabaseSchemaExplorerTreeNodeData { parentId; owner; table; constructor(id, parentId, owner, table) { super(id, table.name, parentId); this.parentId = parentId; this.owner = owner; this.table = table; } } export class DatabaseSchemaExplorerTreeTabularFunctionNodeData extends DatabaseSchemaExplorerTreeNodeData { parentId; owner; tabularFunction; constructor(id, parentId, owner, tabularFunction) { super(id, tabularFunction.name, parentId); this.parentId = parentId; this.owner = owner; this.tabularFunction = tabularFunction; } } export class DatabaseSchemaExplorerTreeColumnNodeData extends DatabaseSchemaExplorerTreeNodeData { parentId; owner; column; constructor(id, parentId, owner, column) { super(id, column.name, parentId); this.parentId = parentId; this.owner = owner; this.column = column; } } export const DEFAULT_DATABASE_PATH = 'store::MyDatabase'; export class DatabaseSchemaExplorerState { editorStore; connection; database; targetDatabasePath; makeTargetDatabasePathEditable; isGeneratingDatabase = false; isUpdatingDatabase = false; treeData; previewer; previewDataState = ActionState.create(); constructor(editorStore, connection) { makeObservable(this, { isGeneratingDatabase: observable, isUpdatingDatabase: observable, database: observable, treeData: observable, targetDatabasePath: observable, previewer: observable, previewDataState: observable, makeTargetDatabasePathEditable: observable, isCreatingNewDatabase: computed, resolveDatabasePackageAndName: computed, setTreeData: action, setTargetDatabasePath: action, setMakeTargetDatabasePathEditable: action, onNodeSelect: flow, fetchDatabaseMetadata: flow, fetchSchemaMetadata: flow, fetchTableMetadata: flow, fetchTabularFunctionMetadata: flow, generateDatabase: flow, updateDatabase: flow, updateDatabaseAndGraph: flow, previewData: flow, }); this.connection = connection; this.database = guaranteeType(connection.store?.value, Database); this.editorStore = editorStore; this.targetDatabasePath = DEFAULT_DATABASE_PATH; } get isCreatingNewDatabase() { if (!this.connection.store) { return false; } return isStubbed_PackageableElement(this.connection.store.value); } setMakeTargetDatabasePathEditable(val) { this.makeTargetDatabasePathEditable = val; } get resolveDatabasePackageAndName() { if (!this.isCreatingNewDatabase && !this.makeTargetDatabasePathEditable) { return [ guaranteeNonNullable(this.database.package).path, this.database.name, ]; } assertNonEmptyString(this.targetDatabasePath, 'Must specify database path'); assertTrue(isValidFullPath(this.targetDatabasePath), 'Invalid database path'); return resolvePackagePathAndElementName(this.targetDatabasePath, this.targetDatabasePath); } setTargetDatabasePath(val) { this.targetDatabasePath = val; } setTreeData(builderTreeData) { this.treeData = builderTreeData; } *onNodeSelect(node, treeData) { if (node instanceof DatabaseSchemaExplorerTreeSchemaNodeData && !node.childrenIds) { yield flowResult(this.fetchSchemaMetadata(node, treeData)); } else if (node instanceof DatabaseSchemaExplorerTreeTableNodeData && !node.childrenIds) { yield flowResult(this.fetchTableMetadata(node, treeData)); } else if (node instanceof DatabaseSchemaExplorerTreeTabularFunctionNodeData && !node.childrenIds) { yield flowResult(this.fetchTabularFunctionMetadata(node, treeData)); } node.isOpen = !node.isOpen; this.setTreeData({ ...treeData }); } getChildNodes(node, treeData) { return node.childrenIds ?.map((childNode) => treeData.nodes.get(childNode)) .filter(isNonNullable); } toggleCheckedNode(node, treeData) { node.setChecked(!node.isChecked); if (node instanceof DatabaseSchemaExplorerTreeSchemaNodeData) { this.getChildNodes(node, treeData)?.forEach((childNode) => { childNode.setChecked(node.isChecked); }); } else if (node instanceof DatabaseSchemaExplorerTreeTableNodeData || node instanceof DatabaseSchemaExplorerTreeTabularFunctionNodeData) { if (node.parentId) { const parent = treeData.nodes.get(node.parentId); if (parent && this.getChildNodes(parent, treeData)?.every((e) => e.isChecked === node.isChecked)) { parent.setChecked(node.isChecked); } } } // TODO: support toggling check for columns this.setTreeData({ ...treeData }); } *fetchDatabaseMetadata() { try { this.isGeneratingDatabase = true; const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, name] = this.resolveDatabasePackageAndName; databaseBuilderInput.targetDatabase = new TargetDatabase(packagePath, name); databaseBuilderInput.config.maxTables = undefined; databaseBuilderInput.config.enrichTables = false; databaseBuilderInput.config.enrichTableFunctions = false; databaseBuilderInput.config.patterns = [ new DatabasePattern(undefined, undefined, undefined), ]; const database = (yield this.buildIntermediateDatabase(databaseBuilderInput)); const rootIds = []; const nodes = new Map(); database.schemas .toSorted((schemaA, schemaB) => schemaA.name.localeCompare(schemaB.name)) .forEach((schema) => { const schemaId = schema.name; rootIds.push(schemaId); const schemaNode = new DatabaseSchemaExplorerTreeSchemaNodeData(schemaId, schema); nodes.set(schemaId, schemaNode); schemaNode.setChecked(Boolean(this.database.schemas.find((cSchema) => cSchema.name === schema.name))); }); const treeData = { rootIds, nodes, database }; this.setTreeData(treeData); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isGeneratingDatabase = false; } } *fetchSchemaMetadata(schemaNode, treeData) { try { this.isGeneratingDatabase = true; const schema = schemaNode.schema; const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, name] = this.resolveDatabasePackageAndName; databaseBuilderInput.targetDatabase = new TargetDatabase(packagePath, name); databaseBuilderInput.config.maxTables = undefined; databaseBuilderInput.config.enrichTables = true; databaseBuilderInput.config.enrichTableFunctions = true; databaseBuilderInput.config.patterns = [ new DatabasePattern(schema.name, undefined, undefined), ]; const database = (yield this.buildIntermediateDatabase(databaseBuilderInput)); const tables = getSchema(database, schema.name).tables; const tabularFunctions = getSchema(database, schema.name).tabularFunctions; const childrenIds = schemaNode.childrenIds ?? []; schema.tables = tables; schema.tabularFunctions = tabularFunctions; tables .toSorted((tableA, tableB) => tableA.name.localeCompare(tableB.name)) .forEach((table) => { table.schema = schema; const tableId = `${schema.name}.${table.name}`; const tableNode = new DatabaseSchemaExplorerTreeTableNodeData(tableId, schemaNode.id, schema, table); treeData.nodes.set(tableId, tableNode); addUniqueEntry(childrenIds, tableId); const matchingSchema = getNullableSchema(this.database, schema.name); tableNode.setChecked(Boolean(matchingSchema ? getNullableTable(matchingSchema, table.name) : undefined)); }); tabularFunctions .toSorted((tabularFunctionA, tabularFunctionB) => tabularFunctionA.name.localeCompare(tabularFunctionB.name)) .forEach((tabularFunction) => { tabularFunction.schema = schema; const tabularFunctionId = `${schema.name}.${tabularFunction.name}`; const tabularFunctionNode = new DatabaseSchemaExplorerTreeTabularFunctionNodeData(tabularFunctionId, schemaNode.id, schema, tabularFunction); treeData.nodes.set(tabularFunctionId, tabularFunctionNode); addUniqueEntry(childrenIds, tabularFunctionId); const matchingSchema = getNullableSchema(this.database, schema.name); tabularFunctionNode.setChecked(Boolean(matchingSchema ? getNullableTable(matchingSchema, tabularFunction.name) : undefined)); }); schemaNode.childrenIds = childrenIds; this.setTreeData({ ...treeData }); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isGeneratingDatabase = false; } } *fetchTableMetadata(tableNode, treeData) { try { this.isGeneratingDatabase = true; const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, name] = this.resolveDatabasePackageAndName; databaseBuilderInput.targetDatabase = new TargetDatabase(packagePath, name); const table = tableNode.table; const config = databaseBuilderInput.config; config.maxTables = undefined; config.enrichTables = true; config.enrichTableFunctions = true; config.enrichColumns = true; config.enrichPrimaryKeys = true; config.patterns = [ new DatabasePattern(table.schema.name, table.name, undefined), ]; const database = (yield this.buildIntermediateDatabase(databaseBuilderInput)); const enrichedTable = database.schemas .find((s) => table.schema.name === s.name) ?.tables.find((t) => t.name === table.name); if (enrichedTable) { table.primaryKey = enrichedTable.primaryKey; const columns = enrichedTable.columns.filter(filterByType(Column)); tableNode.table.columns = columns; tableNode.childrenIds?.forEach((childId) => treeData.nodes.delete(childId)); tableNode.childrenIds = undefined; const childrenIds = []; const tableId = tableNode.id; columns .toSorted((colA, colB) => colA.name.localeCompare(colB.name)) .forEach((column) => { const columnId = `${tableId}.${column.name}`; const columnNode = new DatabaseSchemaExplorerTreeColumnNodeData(columnId, tableId, table, column); column.owner = tableNode.table; treeData.nodes.set(columnId, columnNode); addUniqueEntry(childrenIds, columnId); }); tableNode.childrenIds = childrenIds; } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isGeneratingDatabase = false; } } *fetchTabularFunctionMetadata(tabularFunctionNode, treeData) { try { this.isGeneratingDatabase = true; const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, name] = this.resolveDatabasePackageAndName; databaseBuilderInput.targetDatabase = new TargetDatabase(packagePath, name); const tabularFunction = tabularFunctionNode.tabularFunction; const config = databaseBuilderInput.config; config.maxTables = undefined; config.enrichTables = false; config.enrichTableFunctions = true; config.enrichColumns = true; config.enrichPrimaryKeys = true; config.patterns = [ new DatabasePattern(tabularFunction.schema.name, undefined, tabularFunction.name), ]; const database = (yield this.buildIntermediateDatabase(databaseBuilderInput)); const enrichedTabularFunction = database.schemas .find((s) => tabularFunction.schema.name === s.name) ?.tabularFunctions.find((t) => t.name === tabularFunction.name); if (enrichedTabularFunction) { const columns = enrichedTabularFunction.columns.filter(filterByType(Column)); tabularFunctionNode.tabularFunction.columns = columns; tabularFunctionNode.childrenIds?.forEach((childId) => treeData.nodes.delete(childId)); tabularFunctionNode.childrenIds = undefined; const childrenIds = []; const tabularFunctionId = tabularFunctionNode.id; columns .toSorted((colA, colB) => colA.name.localeCompare(colB.name)) .forEach((column) => { const columnId = `${tabularFunctionId}.${column.name}`; const columnNode = new DatabaseSchemaExplorerTreeColumnNodeData(columnId, tabularFunctionId, tabularFunction, column); column.owner = tabularFunctionNode.tabularFunction; treeData.nodes.set(columnId, columnNode); addUniqueEntry(childrenIds, columnId); }); tabularFunctionNode.childrenIds = childrenIds; } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isGeneratingDatabase = false; } } async buildIntermediateDatabase(databaseBuilderInput) { const entities = await this.editorStore.graphManagerState.graphManager.buildDatabase(databaseBuilderInput); const graph = this.editorStore.graphManagerState.createNewGraph(); await this.editorStore.graphManagerState.graphManager.buildGraph(graph, entities, ActionState.create()); return at(graph.ownDatabases, 0, 'Expected one database to be generated from input'); } *previewData(node) { try { this.previewer = undefined; this.previewDataState.inProgress(); let column; let nodeInstance; if (node instanceof DatabaseSchemaExplorerTreeTableNodeData) { nodeInstance = node.table; } else if (node instanceof DatabaseSchemaExplorerTreeTabularFunctionNodeData) { nodeInstance = node.tabularFunction; } else if (node instanceof DatabaseSchemaExplorerTreeColumnNodeData) { nodeInstance = guaranteeType(node.column.owner, Table); column = node.column; } else { throw new UnsupportedOperationError('Preview data only supported for column, table and tabular function'); } const schemaName = nodeInstance.schema.name; const tableName = nodeInstance.name; const dummyPackage = 'generation'; const dummyName = 'myDB'; const dummyDbPath = `${dummyPackage}::${dummyName}`; const databaseBuilderInput = new DatabaseBuilderInput(this.connection); databaseBuilderInput.targetDatabase = new TargetDatabase(dummyPackage, dummyName); const config = databaseBuilderInput.config; config.maxTables = undefined; config.enrichColumns = true; config.enrichPrimaryKeys = true; if (node instanceof DatabaseSchemaExplorerTreeTableNodeData) { config.enrichTables = true; config.enrichTableFunctions = false; config.patterns.push(new DatabasePattern(schemaName, node.table.name, undefined)); } else if (node instanceof DatabaseSchemaExplorerTreeTabularFunctionNodeData) { config.enrichTables = false; config.enrichTableFunctions = true; config.patterns.push(new DatabasePattern(schemaName, undefined, node.tabularFunction.name)); } const entities = (yield this.editorStore.graphManagerState.graphManager.buildDatabase(databaseBuilderInput)); assertTrue(entities.length === 1); const dbEntity = guaranteeNonNullable(entities[0]); const emptyGraph = this.editorStore.graphManagerState.createNewGraph(); (yield this.editorStore.graphManagerState.graphManager.buildGraph(emptyGraph, [dbEntity], ActionState.create())); const generatedDb = emptyGraph.getDatabase(dummyDbPath); const resolvedTable = getTable(getSchema(generatedDb, schemaName), tableName); let queryGrammar; let resolveResult = false; if (column) { const resolvedColumn = getColumn(resolvedTable, column.name); const grammarResult = buildTableToTDSQueryColumnQuery(resolvedColumn); queryGrammar = grammarResult[0]; resolveResult = grammarResult[1]; } else { queryGrammar = buildTableToTDSQueryGrammar(resolvedTable); } const rawLambda = (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(queryGrammar, 'QUERY')); const { mapping, runtime } = buildTDSModel(emptyGraph, this.connection, generatedDb); const execPlan = (yield this.editorStore.graphManagerState.graphManager.runQuery(rawLambda, mapping, runtime, emptyGraph)).executionResult; let tdsResult = guaranteeType(execPlan, TDSExecutionResult, 'Execution from `tabletoTDS` expected to be TDS'); if (resolveResult) { const newResult = new TDSExecutionResult(); newResult.result.columns = ['Aggregation', 'Value']; newResult.result.rows = tdsResult.result.columns.map((col, idx) => { const _row = new TDSRow(); _row.values = [ col, guaranteeNonNullable(guaranteeNonNullable(tdsResult.result.rows[0]).values[idx]), ]; return _row; }); tdsResult = newResult; } this.previewer = tdsResult; } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notificationService.notifyError(`Unable to preview data: ${error.message}`); } finally { this.previewDataState.complete(); } } *generateDatabase() { try { this.isGeneratingDatabase = true; const treeData = guaranteeNonNullable(this.treeData); const databaseBuilderInput = new DatabaseBuilderInput(this.connection); const [packagePath, name] = this.resolveDatabasePackageAndName; databaseBuilderInput.targetDatabase = new TargetDatabase(packagePath, name); const config = databaseBuilderInput.config; config.maxTables = undefined; config.enrichColumns = true; config.enrichPrimaryKeys = true; config.enrichTables = false; config.enrichTableFunctions = false; treeData.rootIds .map((e) => treeData.nodes.get(e)) .filter(isNonNullable) .forEach((schemaNode) => { if (schemaNode instanceof DatabaseSchemaExplorerTreeSchemaNodeData) { const nodes = this.getChildNodes(schemaNode, treeData); const allChecked = nodes?.every((t) => t.isChecked === true); if (allChecked || (schemaNode.isChecked && !schemaNode.childrenIds)) { config.enrichTables = true; config.enrichTableFunctions = true; config.patterns.push(new DatabasePattern(schemaNode.schema.name, undefined, undefined)); } else { nodes?.forEach((t) => { if (t instanceof DatabaseSchemaExplorerTreeTableNodeData && t.isChecked) { config.enrichTables = true; config.patterns.push(new DatabasePattern(schemaNode.schema.name, t.table.name, undefined)); } else if (t instanceof DatabaseSchemaExplorerTreeTabularFunctionNodeData && t.isChecked) { config.enrichTableFunctions = true; config.patterns.push(new DatabasePattern(schemaNode.schema.name, undefined, t.tabularFunction.name)); } }); } } }); const entities = (yield this.editorStore.graphManagerState.graphManager.buildDatabase(databaseBuilderInput)); return at(entities, 0, 'Expected a database to be generated'); } finally { this.isGeneratingDatabase = false; } } // this method just updates database *updateDatabase(forceRename) { this.isUpdatingDatabase = true; const graph = this.editorStore.graphManagerState.createNewGraph(); (yield this.editorStore.graphManagerState.graphManager.buildGraph(graph, [(yield flowResult(this.generateDatabase()))], ActionState.create())); const database = at(graph.ownDatabases, 0, 'Expected one database to be generated from input'); // remove undefined schemas const schemas = Array.from(guaranteeNonNullable(this.treeData).nodes.values()) .map((schemaNode) => { if (schemaNode instanceof DatabaseSchemaExplorerTreeSchemaNodeData) { return schemaNode.schema; } return undefined; }) .filter(isNonNullable); // update this.database packge and name if (forceRename || this.database.name === '' || !this.database.package) { this.database.package = getOrCreateGraphPackage(graph, extractPackagePathFromPath(this.targetDatabasePath), undefined); this.database.name = extractElementNameFromPath(this.targetDatabasePath); } // update schemas this.database.schemas = this.database.schemas.filter((schema) => { if (schemas.find((item) => item.name === schema.name) && !database.schemas.find((s) => s.name === schema.name)) { return false; } return true; }); // update existing schemas database.schemas.forEach((schema) => { schema._OWNER = this.database; const currentSchemaIndex = this.database.schemas.findIndex((item) => item.name === schema.name); if (currentSchemaIndex !== -1) { this.database.schemas[currentSchemaIndex] = schema; } else { this.database.schemas.push(schema); } }); this.isUpdatingDatabase = false; return database; } // this method updates database and add database to the graph *updateDatabaseAndGraph() { if (!this.treeData) { return; } try { const createDatabase = this.isCreatingNewDatabase && !this.editorStore.graphManagerState.graph.databases.includes(this.database); this.isUpdatingDatabase = true; const database = (yield flowResult(this.updateDatabase())); if (createDatabase) { connection_setStore(this.connection, PackageableElementExplicitReference.create(database)); const packagePath = guaranteeNonNullable(database.package?.name, 'Database package is missing'); yield flowResult(this.editorStore.graphEditorMode.addElement(database, packagePath, false)); } this.editorStore.applicationStore.notificationService.notifySuccess(`Database successfully updated`); yield flowResult(this.editorStore .getGraphEditorMode(GraphEditFormModeState) .globalCompile({ message: `Can't compile graph after editing database. Redirecting you to text mode`, })); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error(LogEvent.create(LEGEND_STUDIO_APP_EVENT.DATABASE_BUILDER_FAILURE), error); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.isUpdatingDatabase = false; } } } //# sourceMappingURL=DatabaseBuilderState.js.map