@finos/legend-studio
Version:
566 lines • 25.2 kB
JavaScript
/**
* 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