UNPKG

@finos/legend-application-studio

Version:
223 lines (206 loc) 7.37 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 { type GeneratorFn, assertErrorThrown, LogEvent, } from '@finos/legend-shared'; import { observable, makeObservable, flow, flowResult } from 'mobx'; import { type PackageableElement, V1_DataProductArtifact, DataProduct, IngestDefinition, type TEMPORARY_IngestContent, type ArtifactGenerationExtensionResult, TDSExecutionResult, type RawLambda, type ExecutionResultWithMetadata, LakehouseRuntime, GRAPH_MANAGER_EVENT, } from '@finos/legend-graph'; import type { EditorStore } from './EditorStore.js'; import { LegendSQLPlaygroundState, DEFAULT_SQL_TEXT, buildDefaultDataProductQuery, buildDefaultIngestQuery, QueryExecutionResult, } from '@finos/legend-query-builder'; const DATA_PRODUCT_ARTIFACT_EXTENSION = 'dataProduct'; export class LegendSQLStudioPlaygroundState extends LegendSQLPlaygroundState { readonly editorStore: EditorStore; targetElement?: PackageableElement | undefined; isOpen = false; constructor(editorStore: EditorStore) { super(); makeObservable(this, { targetElement: observable, isOpen: observable, executeRawSQL: flow, initializeAccessorExplorer: flow, }); this.editorStore = editorStore; } open(element: PackageableElement): void { this.isOpen = true; this.targetElement = element; this.accessorExplorerState = undefined; flowResult(this.initializeAccessorExplorer()).catch( this.editorStore.applicationStore.alertUnhandledError, ); if (element instanceof DataProduct) { const firstAccessPointId = element.accessPointGroups[0]?.accessPoints[0]?.id; this.setSQLQuery( `${DEFAULT_SQL_TEXT}${buildDefaultDataProductQuery(element.path, firstAccessPointId)}`, ); } else if (element instanceof IngestDefinition) { const content = element.content as unknown as | TEMPORARY_IngestContent | undefined; const firstDatasetName = content?.datasets?.[0]?.name; this.setSQLQuery( `${DEFAULT_SQL_TEXT}${buildDefaultIngestQuery(element.path, firstDatasetName)}`, ); } else { this.setSQLQuery(DEFAULT_SQL_TEXT); } } close(): void { this.isOpen = false; this.targetElement = undefined; this.accessorExplorerState = undefined; this.setSQLQuery(DEFAULT_SQL_TEXT); } *initializeAccessorExplorer(): GeneratorFn<void> { if (this.accessorExplorerState || !this.targetElement) { return; } try { const entities = this.editorStore.graphManagerState.graph.allElements .filter( (element) => element instanceof DataProduct || element instanceof IngestDefinition, ) .map((element) => this.editorStore.graphManagerState.graphManager.elementToEntity( element, ), ); yield flowResult( this.initializeExplorer( entities, this.editorStore.graphManagerState.graphManager.pluginManager.getPureProtocolProcessorPlugins(), (path) => this.fetchDataProductArtifact(path), ), ); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error( LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), error, ); this.editorStore.applicationStore.notificationService.notifyError(error); } } private async fetchDataProductArtifact( dataProductPath: string, ): Promise<V1_DataProductArtifact | undefined> { try { const generatedArtifacts = (await this.editorStore.graphManagerState.graphManager.generateArtifacts( this.editorStore.graphManagerState.graph, this.editorStore.graphEditorMode.getGraphTextInputOption(), [dataProductPath], )) as unknown as ArtifactGenerationExtensionResult; const dataProductArtifactResults = generatedArtifacts.values.filter( (artifact) => artifact.extension === DATA_PRODUCT_ARTIFACT_EXTENSION, ); for (const artifactResult of dataProductArtifactResults) { for (const artifactByElement of artifactResult.artifactsByExtensionElements) { const dataProductContent = artifactByElement.files[0]?.content; if (dataProductContent) { return V1_DataProductArtifact.serialization.fromJson( JSON.parse(dataProductContent), ); } } } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notificationService.notifyError( `Error fetching artifact for ${dataProductPath}: ${error}`, ); } return undefined; } override *executeRawSQL(): GeneratorFn<void> { if (this.executeRawSQLState.isInProgress || !this.targetElement) { return; } try { this.executeRawSQLState.inProgress(); const sql = this.getSelectedSQL(); const sqlQuery = `#SQL{${sql}}#`; const runtimes = this.editorStore.graphManagerState.graph.ownRuntimes; const packageableRuntime = runtimes[0]; if (!packageableRuntime) { this.editorStore.applicationStore.notificationService.notifyError( new Error('No runtime found in the graph'), ); return; } if (!(packageableRuntime.runtimeValue instanceof LakehouseRuntime)) { this.editorStore.applicationStore.notificationService.notifyError( new Error('Runtime must be a LakehouseRuntime'), ); return; } const runtime = packageableRuntime.runtimeValue; const queryToExecute = `${sqlQuery}->from(${packageableRuntime.path})`; const lambda = (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda( queryToExecute, )) as RawLambda; const executionResult = (yield this.editorStore.graphManagerState.graphManager.runQuery( lambda, undefined, runtime, this.editorStore.graphManagerState.graph, )) as ExecutionResultWithMetadata; const result = executionResult.executionResult; if (result instanceof TDSExecutionResult) { this.setSqlExecutionResult(new QueryExecutionResult(result)); } else { this.editorStore.applicationStore.notificationService.notifyError( 'Expected TDS execution result, got unsupported result type', ); } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.logService.error( LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), error, ); this.editorStore.applicationStore.notificationService.notifyError(error); } finally { this.executeRawSQLState.complete(); } } }