UNPKG

@finos/legend-studio

Version:
566 lines 25.2 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 { observable, action, flow, makeObservable, flowResult } from 'mobx'; import { ActionState, assertErrorThrown, LogEvent, losslessStringify, UnsupportedOperationError, filterByType, } from '@finos/legend-shared'; import { decorateRuntimeWithNewMapping, RuntimeEditorState, } from '../../../editor-state/element-editor-state/RuntimeEditorState.js'; import { buildParametersLetLambdaFunc, ExecutionPlanState, LambdaEditorState, LambdaParametersState, LambdaParameterState, PARAMETER_SUBMIT_ACTION, TAB_SIZE, } from '@finos/legend-application'; import { KeyedExecutionParameter, PureSingleExecution, PureMultiExecution, GRAPH_MANAGER_EVENT, RawLambda, EngineRuntime, RuntimePointer, PackageableElementExplicitReference, buildSourceInformationSourceId, QueryProjectCoordinates, QuerySearchSpecification, buildLambdaVariableExpressions, observe_ValueSpecification, VariableExpression, buildRawLambdaFromLambdaFunction, stub_PackageableRuntime, stub_Mapping, } from '@finos/legend-graph'; import { parseGACoordinates } from '@finos/legend-server-depot'; import { runtime_addMapping } from '../../../graphModifier/DSLMapping_GraphModifierHelper.js'; import { keyedExecutionParameter_setKey, pureExecution_setFunction, pureMultiExecution_addExecutionParameter, pureMultiExecution_deleteExecutionParameter, pureMultiExecution_setExecutionKey, pureSingleExecution_setMapping, pureSingleExecution_setRuntime, service_setExecution, } from '../../../graphModifier/DSLService_GraphModifierHelper.js'; export class ServiceExecutionParameterState extends LambdaParametersState { executionState; constructor(executionState) { super(); makeObservable(this, { parameterValuesEditorState: observable, parameterStates: observable, addParameter: action, removeParameter: action, openModal: action, build: action, setParameters: action, }); this.executionState = executionState; } openModal(query) { this.parameterStates = this.build(query); this.parameterValuesEditorState.open(() => flowResult(this.executionState.execute()).catch(this.executionState.editorStore.applicationStore.alertUnhandledError), PARAMETER_SUBMIT_ACTION.EXECUTE); } build(query) { const parameters = buildLambdaVariableExpressions(query, this.executionState.editorStore.graphManagerState) .map((p) => observe_ValueSpecification(p, this.executionState.editorStore.changeDetectionState.observerContext)) .filter(filterByType(VariableExpression)); const states = parameters.map((p) => { const parmeterState = new LambdaParameterState(p, this.executionState.editorStore.changeDetectionState.observerContext); parmeterState.mockParameterValue(); return parmeterState; }); return states; } } export class ServiceExecutionState { editorStore; serviceEditorState; execution; constructor(editorStore, serviceEditorState, execution) { makeObservable(this, { execution: observable, }); this.editorStore = editorStore; this.execution = execution; this.serviceEditorState = serviceEditorState; } } export class UnsupportedServiceExecutionState extends ServiceExecutionState { get serviceExecutionParameters() { return undefined; } } export class ServicePureExecutionQueryState extends LambdaEditorState { editorStore; execution; isInitializingLambda = false; openQueryImporter = false; queries = []; selectedQueryInfo; loadQueriesState = ActionState.create(); loadQueryInfoState = ActionState.create(); importQueryState = ActionState.create(); constructor(editorStore, execution) { super('', ''); makeObservable(this, { execution: observable, isInitializingLambda: observable, openQueryImporter: observable, queries: observable, selectedQueryInfo: observable, setOpenQueryImporter: action, setIsInitializingLambda: action, setLambda: action, updateLamba: flow, loadQueries: flow, setSelectedQueryInfo: flow, importQuery: flow, }); this.editorStore = editorStore; this.execution = execution; } get lambdaId() { return buildSourceInformationSourceId([ this.execution._OWNER.path, 'execution', ]); } get query() { return this.execution.func; } setIsInitializingLambda(val) { this.isInitializingLambda = val; } setLambda(val) { pureExecution_setFunction(this.execution, val); } setOpenQueryImporter(val) { this.openQueryImporter = val; } *setSelectedQueryInfo(query) { if (query) { try { this.loadQueryInfoState.inProgress(); const content = (yield this.editorStore.graphManagerState.graphManager.lambdaToPureCode((yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda((yield this.editorStore.graphManagerState.graphManager.getQueryContent(query.id)))), true)); this.selectedQueryInfo = { query, content, }; } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notifyError(error); } finally { this.loadQueryInfoState.reset(); } } else { this.selectedQueryInfo = undefined; } } *importQuery() { if (this.selectedQueryInfo) { try { this.importQueryState.inProgress(); const lambda = (yield this.editorStore.graphManagerState.graphManager.pureCodeToLambda(this.selectedQueryInfo.content)); yield flowResult(this.updateLamba(lambda)); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notifyError(error); } finally { this.setOpenQueryImporter(false); this.importQueryState.reset(); } } } *loadQueries(searchText) { const isValidSearchString = searchText.length >= 3; this.loadQueriesState.inProgress(); try { const searchSpecification = new QuerySearchSpecification(); const currentProjectCoordinates = new QueryProjectCoordinates(); currentProjectCoordinates.groupId = this.editorStore.projectConfigurationEditorState.currentProjectConfiguration.groupId; currentProjectCoordinates.artifactId = this.editorStore.projectConfigurationEditorState.currentProjectConfiguration.artifactId; searchSpecification.searchTerm = isValidSearchString ? searchText : undefined; searchSpecification.limit = 10; searchSpecification.projectCoordinates = [ // either get queries for the current project currentProjectCoordinates, // or any of its dependencies ...Array.from((yield flowResult(this.editorStore.graphState.getIndexedDependencyEntities())).keys()).map((coordinatesInText) => { const { groupId, artifactId } = parseGACoordinates(coordinatesInText); const coordinates = new QueryProjectCoordinates(); coordinates.groupId = groupId; coordinates.artifactId = artifactId; return coordinates; }), ]; this.queries = (yield this.editorStore.graphManagerState.graphManager.searchQueries(searchSpecification)); this.loadQueriesState.pass(); } catch (error) { assertErrorThrown(error); this.loadQueriesState.fail(); this.editorStore.applicationStore.notifyError(error); } } *updateLamba(val) { this.setLambda(val); yield flowResult(this.convertLambdaObjectToGrammarString(true)); } *convertLambdaObjectToGrammarString(pretty) { if (this.execution.func.body) { try { const lambdas = new Map(); lambdas.set(this.lambdaId, new RawLambda(this.execution.func.parameters, this.execution.func.body)); const isolatedLambdas = (yield this.editorStore.graphManagerState.graphManager.lambdasToPureCode(lambdas, pretty)); const grammarText = isolatedLambdas.get(this.lambdaId); this.setLambdaString(grammarText !== undefined ? this.extractLambdaString(grammarText) : ''); this.clearErrors(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.log.error(LogEvent.create(GRAPH_MANAGER_EVENT.PARSING_FAILURE), error); } } else { this.clearErrors(); this.setLambdaString(''); } } // NOTE: since we don't allow edition in text mode, we don't need to implement this *convertLambdaGrammarStringToObject() { throw new UnsupportedOperationError(); } } export class ServiceExecutionContextState { executionContext; executionState; constructor(executionContext, executionState) { this.executionContext = executionContext; this.executionState = executionState; } } export class SingleExecutionContextState extends ServiceExecutionContextState { constructor(executionContext, executionState) { super(executionContext, executionState); makeObservable(this, { executionContext: observable, setMapping: action, setRuntime: action, }); } setMapping(value) { pureSingleExecution_setMapping(this.executionContext, value, this.executionState.editorStore.changeDetectionState.observerContext); } setRuntime(value) { pureSingleExecution_setRuntime(this.executionContext, value, this.executionState.editorStore.changeDetectionState.observerContext); } } export class KeyedExecutionContextState extends ServiceExecutionContextState { setMapping(value) { pureSingleExecution_setMapping(this.executionContext, value, this.executionState.editorStore.changeDetectionState.observerContext); } setRuntime(value) { pureSingleExecution_setRuntime(this.executionContext, value, this.executionState.editorStore.changeDetectionState.observerContext); } } export class ServicePureExecutionState extends ServiceExecutionState { queryState; selectedExecutionContextState; runtimeEditorState; isExecuting = false; isGeneratingPlan = false; isOpeningQueryEditor = false; executionResultText; // NOTE: stored as lossless JSON string executionPlanState; parameterState; showChangeExecModal = false; constructor(editorStore, serviceEditorState, execution) { super(editorStore, serviceEditorState, execution); this.execution = execution; this.queryState = new ServicePureExecutionQueryState(this.editorStore, execution); this.executionPlanState = new ExecutionPlanState(this.editorStore.applicationStore, this.editorStore.graphManagerState); this.parameterState = new ServiceExecutionParameterState(this); } isChangeExecutionDisabled() { return false; } setShowChangeExecModal(val) { this.showChangeExecModal = val; } setOpeningQueryEditor(val) { this.isOpeningQueryEditor = val; } setExecutionResultText = (executionResult) => { this.executionResultText = executionResult; }; setQueryState = (queryState) => { this.queryState = queryState; }; *generatePlan(debug) { if (!this.selectedExecutionContextState || this.isGeneratingPlan) { return; } try { const query = this.queryState.query; this.isGeneratingPlan = true; let rawPlan; if (debug) { const debugResult = (yield this.editorStore.graphManagerState.graphManager.debugExecutionPlanGeneration(query, this.selectedExecutionContextState.executionContext.mapping.value, this.selectedExecutionContextState.executionContext.runtime, this.editorStore.graphManagerState.graph)); rawPlan = debugResult.plan; this.executionPlanState.setDebugText(debugResult.debug); } else { rawPlan = (yield this.editorStore.graphManagerState.graphManager.generateExecutionPlan(query, this.selectedExecutionContextState.executionContext.mapping.value, this.selectedExecutionContextState.executionContext.runtime, this.editorStore.graphManagerState.graph)); } try { this.executionPlanState.setRawPlan(rawPlan); const plan = this.editorStore.graphManagerState.graphManager.buildExecutionPlan(rawPlan, this.editorStore.graphManagerState.graph); this.executionPlanState.setPlan(plan); } catch { // do nothing } } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.log.error(LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), error); this.editorStore.applicationStore.notifyError(error); } finally { this.isGeneratingPlan = false; } } *handleExecute() { if (!this.selectedExecutionContextState || this.isExecuting) { return; } const query = this.queryState.query; const parameters = (query.parameters ?? []); if (parameters.length) { this.parameterState.openModal(query); } else { this.execute(); } } *execute() { if (!this.selectedExecutionContextState || this.isExecuting) { return; } try { this.isExecuting = true; const query = this.getExecutionQuery(); const result = (yield this.editorStore.graphManagerState.graphManager.executeMapping(query, this.selectedExecutionContextState.executionContext.mapping.value, this.selectedExecutionContextState.executionContext.runtime, this.editorStore.graphManagerState.graph, { useLosslessParse: true, })); this.setExecutionResultText(losslessStringify(result, undefined, TAB_SIZE)); this.parameterState.setParameters([]); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.log.error(LogEvent.create(GRAPH_MANAGER_EVENT.EXECUTION_FAILURE), error); this.editorStore.applicationStore.notifyError(error); } finally { this.isExecuting = false; } } getExecutionQuery() { if (this.parameterState.parameterStates.length) { const letlambdaFunction = buildParametersLetLambdaFunc(this.editorStore.graphManagerState.graph, this.parameterState.parameterStates); const letRawLambda = buildRawLambdaFromLambdaFunction(letlambdaFunction, this.editorStore.graphManagerState); // reset parameters if (Array.isArray(this.queryState.query.body) && Array.isArray(letRawLambda.body)) { letRawLambda.body = [ ...letRawLambda.body, ...this.queryState.query.body, ]; return letRawLambda; } } return this.queryState.query; } get serviceExecutionParameters() { if (!this.selectedExecutionContextState || this.isExecuting) { return undefined; } const query = this.queryState.query; return { query, mapping: this.selectedExecutionContextState.executionContext.mapping.value, runtime: this.selectedExecutionContextState.executionContext.runtime, }; } closeRuntimeEditor() { this.runtimeEditorState = undefined; } openRuntimeEditor() { if (this.selectedExecutionContextState && !(this.selectedExecutionContextState.executionContext.runtime instanceof RuntimePointer)) { this.runtimeEditorState = new RuntimeEditorState(this.editorStore, this.selectedExecutionContextState.executionContext.runtime, true); } } useCustomRuntime() { if (this.selectedExecutionContextState) { const customRuntime = new EngineRuntime(); runtime_addMapping(customRuntime, PackageableElementExplicitReference.create(this.selectedExecutionContextState.executionContext.mapping.value)); decorateRuntimeWithNewMapping(this.selectedExecutionContextState.executionContext.runtime, this.selectedExecutionContextState.executionContext.mapping.value, this.editorStore); this.selectedExecutionContextState.setRuntime(customRuntime); } } autoSelectRuntimeOnMappingChange(mapping) { if (this.selectedExecutionContextState) { const runtimes = this.editorStore.graphManagerState.graph.ownRuntimes.filter((runtime) => runtime.runtimeValue.mappings.map((m) => m.value).includes(mapping)); if (runtimes.length) { this.selectedExecutionContextState.setRuntime(runtimes[0].runtimeValue); } else { this.useCustomRuntime(); } } } updateExecutionQuery() { pureExecution_setFunction(this.execution, this.queryState.query); } } export class SingleServicePureExecutionState extends ServicePureExecutionState { multiExecutionKey = 'key'; constructor(editorStore, serviceEditorState, execution) { super(editorStore, serviceEditorState, execution); makeObservable(this, { queryState: observable, getInitiallySelectedExecutionContextState: observable, runtimeEditorState: observable, isExecuting: observable, isGeneratingPlan: observable, isOpeningQueryEditor: observable, executionResultText: observable, executionPlanState: observable, showChangeExecModal: observable, parameterState: observable, multiExecutionKey: observable, setExecutionResultText: action, closeRuntimeEditor: action, openRuntimeEditor: action, useCustomRuntime: action, setQueryState: action, autoSelectRuntimeOnMappingChange: action, updateExecutionQuery: action, setOpeningQueryEditor: action, changeExecution: action, setMultiExecutionKey: action, setShowChangeExecModal: action, generatePlan: flow, handleExecute: flow, execute: flow, }); this.selectedExecutionContextState = this.getInitiallySelectedExecutionContextState(); } isChangeExecutionDisabled() { return this.multiExecutionKey === ''; } getInitiallySelectedExecutionContextState() { return new SingleExecutionContextState(this.execution, this); } setMultiExecutionKey(val) { this.multiExecutionKey = val; } changeExecution() { const _execution = new PureMultiExecution(this.multiExecutionKey, this.execution.func, this.serviceEditorState.service); const _parameter = new KeyedExecutionParameter(`execContext_1`, this.execution.mapping, this.execution.runtime); _execution.executionParameters = [_parameter]; service_setExecution(this.serviceEditorState.service, _execution, this.editorStore.changeDetectionState.observerContext); this.serviceEditorState.resetExecutionState(); } } export class MultiServicePureExecutionState extends ServicePureExecutionState { newKeyParameterModal = false; renameKey; singleExecutionKey; constructor(editorStore, serviceEditorState, execution) { super(editorStore, serviceEditorState, execution); makeObservable(this, { queryState: observable, selectedExecutionContextState: observable, runtimeEditorState: observable, isExecuting: observable, isGeneratingPlan: observable, isOpeningQueryEditor: observable, executionResultText: observable, executionPlanState: observable, newKeyParameterModal: observable, renameKey: observable, singleExecutionKey: observable, showChangeExecModal: observable, setExecutionResultText: action, closeRuntimeEditor: action, openRuntimeEditor: action, useCustomRuntime: action, setQueryState: action, autoSelectRuntimeOnMappingChange: action, updateExecutionQuery: action, setOpeningQueryEditor: action, deleteKeyExecutionParameter: action, setNewKeyParameterModal: action, changeKeyedExecutionParameter: action, setRenameKey: action, addExecutionParameter: action, setExecutionKey: action, changeKeyValue: action, setSingleExecutionKey: action, setShowChangeExecModal: action, changeExecution: action, generatePlan: flow, execute: flow, }); this.execution = execution; this.selectedExecutionContextState = this.getInitiallySelectedExecutionContextState(); this.queryState = new ServicePureExecutionQueryState(this.editorStore, execution); this.executionPlanState = new ExecutionPlanState(this.editorStore.applicationStore, this.editorStore.graphManagerState); } setSingleExecutionKey(val) { this.singleExecutionKey = val; } changeExecution() { const mappingExecution = this.singleExecutionKey; // stub const _mapping = mappingExecution?.mapping.value ?? stub_Mapping(); const mapping = PackageableElementExplicitReference.create(_mapping); const runtime = mappingExecution?.runtime ?? stub_PackageableRuntime(); const _execution = new PureSingleExecution(this.execution.func, this.serviceEditorState.service, mapping, runtime); service_setExecution(this.serviceEditorState.service, _execution, this.editorStore.changeDetectionState.observerContext); this.serviceEditorState.resetExecutionState(); } setRenameKey(key) { this.renameKey = key; } setNewKeyParameterModal(val) { this.newKeyParameterModal = val; } setExecutionKey(val) { pureMultiExecution_setExecutionKey(this.execution, val); } getInitiallySelectedExecutionContextState() { const parameter = this.execution.executionParameters[0]; return parameter ? new KeyedExecutionContextState(parameter, this) : undefined; } changeKeyedExecutionParameter(value) { this.selectedExecutionContextState = new KeyedExecutionContextState(value, this); } deleteKeyExecutionParameter(value) { pureMultiExecution_deleteExecutionParameter(this.execution, value); if (value === this.selectedExecutionContextState?.executionContext) { this.selectedExecutionContextState = this.getInitiallySelectedExecutionContextState(); } } addExecutionParameter(value) { const _mapping = this.editorStore.mappingOptions[0]?.value ?? stub_Mapping(); const _key = new KeyedExecutionParameter(value, PackageableElementExplicitReference.create(_mapping), stub_PackageableRuntime()); pureMultiExecution_addExecutionParameter(this.execution, _key, this.editorStore.changeDetectionState.observerContext); this.selectedExecutionContextState = new KeyedExecutionContextState(_key, this); } changeKeyValue(key, value) { keyedExecutionParameter_setKey(key, value); } } //# sourceMappingURL=ServiceExecutionState.js.map