@finos/legend-studio
Version:
406 lines (377 loc) • 12.7 kB
text/typescript
/**
* 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 ServiceTest,
type Service,
type ValueSpecification,
type RawLambda,
observe_ValueSpecification,
ParameterValue,
buildLambdaVariableExpressions,
VariableExpression,
generateVariableExpressionMockValue,
} from '@finos/legend-graph';
import { action, flow, makeObservable, observable } from 'mobx';
import { TestableTestEditorState } from '../../testable/TestableEditorState.js';
import type { ServiceTestSuiteState } from './ServiceTestableState.js';
import {
service_addParameterValue,
service_deleteParameterValue,
service_setParameterName,
service_setParameterValues,
service_setParameterValueSpec,
service_setSerializationFormat,
} from '../../../../graphModifier/DSLService_GraphModifierHelper.js';
import {
assertErrorThrown,
deleteEntry,
filterByType,
guaranteeNonNullable,
isNonNullable,
returnUndefOnError,
uuid,
} from '@finos/legend-shared';
import type { EditorStore } from '../../../../EditorStore.js';
export enum SERIALIZATION_FORMAT {
PURE = 'PURE',
// Temporary remove this option as it is currently not being read correctly.
// See https://github.com/finos/legend-engine/pull/799
// DEFAULT = 'DEFAULT',
PURE_TDSOBJECT = 'PURE_TDSOBJECT',
}
export enum SERIALIZATION_FORMAT_LABEL {
PURE = 'PURE',
TDS = 'TDS',
}
const getSerializationFormatLabel = (val: string): string => {
switch (val) {
case SERIALIZATION_FORMAT.PURE:
return SERIALIZATION_FORMAT.PURE;
case SERIALIZATION_FORMAT.PURE_TDSOBJECT:
return SERIALIZATION_FORMAT_LABEL.TDS;
default:
return val;
}
};
export type SerializationFormatOption = {
value: string;
label: string;
};
export class ServiceTestParameterState {
readonly uuid = uuid();
readonly editorStore: EditorStore;
readonly setupState: ServiceTestSetupState;
parameterValue: ParameterValue;
constructor(
parameterValue: ParameterValue,
editorStore: EditorStore,
setupState: ServiceTestSetupState,
) {
this.editorStore = editorStore;
this.setupState = setupState;
this.parameterValue = parameterValue;
}
}
export class ServiceValueSpecificationTestParameterState extends ServiceTestParameterState {
valueSpec: ValueSpecification;
varExpression: VariableExpression;
constructor(
parameterValue: ParameterValue,
editorStore: EditorStore,
setupState: ServiceTestSetupState,
valueSpec: ValueSpecification,
varExpression: VariableExpression,
) {
super(parameterValue, editorStore, setupState);
makeObservable(this, {
setName: observable,
valueSpec: observable,
parameterValue: observable,
resetValueSpec: action,
updateValueSpecification: action,
updateParameterValue: action,
});
this.valueSpec = valueSpec;
this.varExpression = varExpression;
}
updateValueSpecification(val: ValueSpecification): void {
this.valueSpec = observe_ValueSpecification(
val,
this.editorStore.changeDetectionState.observerContext,
);
this.updateParameterValue();
}
updateParameterValue(): void {
const updatedValueSpec =
this.editorStore.graphManagerState.graphManager.serializeValueSpecification(
this.valueSpec,
);
service_setParameterValueSpec(this.parameterValue, updatedValueSpec);
}
setName(val: string): void {
service_setParameterName(this.parameterValue, val);
}
resetValueSpec(): void {
const mockValue = generateVariableExpressionMockValue(this.varExpression);
if (mockValue) {
this.updateValueSpecification(mockValue);
}
}
}
export class ServiceTestSetupState {
readonly editorStore: EditorStore;
readonly testState: ServiceTestState;
parameterValueStates: ServiceTestParameterState[] = [];
newParameterValueName = '';
showNewParameterModal = false;
constructor(testState: ServiceTestState) {
this.testState = testState;
this.editorStore = testState.editorStore;
makeObservable(this, {
changeSerializationFormat: action,
parameterValueStates: observable,
buildParameterStates: action,
newParameterValueName: observable,
showNewParameterModal: observable,
setNewParameterValueName: action,
setShowNewParameterModal: action,
openNewParamModal: action,
addParameterValue: action,
syncWithQuery: action,
removeParamValueState: action,
});
this.parameterValueStates = this.buildParameterStates();
}
get serviceQuery(): RawLambda | undefined {
return this.testState.suiteState.testableState.serviceEditorState
.executionState.serviceExecutionParameters?.query;
}
get queryVariableExpressions(): VariableExpression[] {
return this.serviceQuery
? buildLambdaVariableExpressions(
this.serviceQuery,
this.editorStore.graphManagerState,
).filter(filterByType(VariableExpression))
: [];
}
get options(): SerializationFormatOption[] {
return Object.values(SERIALIZATION_FORMAT).map((e) => ({
value: e,
label: getSerializationFormatLabel(e),
}));
}
get newParamOptions(): { value: string; label: string }[] {
const queryVarExpressions = this.queryVariableExpressions;
const currentParams = this.testState.test.parameters;
return queryVarExpressions
.filter((v) => !currentParams.find((i) => i.name === v.name))
.map((e) => ({ value: e.name, label: e.name }));
}
syncWithQuery(): void {
// remove non existing params
this.parameterValueStates.forEach((paramState) => {
const expression = this.queryVariableExpressions.find(
(v) => v.name === paramState.parameterValue.name,
);
if (!expression) {
deleteEntry(this.parameterValueStates, paramState);
service_deleteParameterValue(
this.testState.test,
paramState.parameterValue,
);
}
});
// add new required params
this.queryVariableExpressions.forEach((v) => {
const multiplicity = v.multiplicity;
const isRequired = multiplicity.lowerBound > 0;
const paramState = this.parameterValueStates.find(
(p) => p.parameterValue.name === v.name,
);
if (!paramState && isRequired) {
this.addExpressionParameterValue(v);
}
});
}
setNewParameterValueName(val: string): void {
this.newParameterValueName = val;
}
setShowNewParameterModal(val: boolean): void {
this.showNewParameterModal = val;
}
openNewParamModal(): void {
this.setShowNewParameterModal(true);
const option = this.newParamOptions[0];
if (option) {
this.newParameterValueName = option.value;
}
}
addParameterValue(): void {
try {
const expressions = this.queryVariableExpressions;
const expression = guaranteeNonNullable(
expressions.find((v) => v.name === this.newParameterValueName),
);
this.addExpressionParameterValue(expression);
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.notifyError(error);
} finally {
this.setShowNewParameterModal(false);
}
}
addExpressionParameterValue(expression: VariableExpression): void {
try {
const mockValue = guaranteeNonNullable(
generateVariableExpressionMockValue(expression),
);
const paramValue = new ParameterValue();
paramValue.name = expression.name;
paramValue.value =
this.editorStore.graphManagerState.graphManager.serializeValueSpecification(
mockValue,
);
service_addParameterValue(this.testState.test, paramValue);
const paramValueState = new ServiceValueSpecificationTestParameterState(
paramValue,
this.editorStore,
this,
observe_ValueSpecification(
mockValue,
this.editorStore.changeDetectionState.observerContext,
),
expression,
);
this.parameterValueStates.push(paramValueState);
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.notifyError(error);
}
}
removeParamValueState(paramState: ServiceTestParameterState): void {
deleteEntry(this.parameterValueStates, paramState);
service_deleteParameterValue(
this.testState.test,
paramState.parameterValue,
);
}
buildParameterStates(): ServiceTestParameterState[] {
const varExpressions = this.queryVariableExpressions;
const paramValues = this.testState.test.parameters;
return paramValues.map((pValue) => {
const spec = returnUndefOnError(() =>
this.editorStore.graphManagerState.graphManager.buildValueSpecification(
pValue.value as Record<PropertyKey, unknown>,
this.editorStore.graphManagerState.graph,
),
);
const expression = varExpressions.find((e) => e.name === pValue.name);
return spec && expression
? new ServiceValueSpecificationTestParameterState(
pValue,
this.editorStore,
this,
observe_ValueSpecification(
spec,
this.editorStore.changeDetectionState.observerContext,
),
expression,
)
: new ServiceTestParameterState(pValue, this.editorStore, this);
});
}
getSelectedFormatOption(): SerializationFormatOption | undefined {
const test = this.testState.test;
if (test.serializationFormat) {
return {
value: test.serializationFormat,
label: getSerializationFormatLabel(test.serializationFormat),
};
}
return undefined;
}
changeSerializationFormat(val: string | undefined): void {
service_setSerializationFormat(this.testState.test, val);
}
generateTestParameterValues(): void {
try {
const varExpressions = this.queryVariableExpressions;
const parameterValueStates = varExpressions
.map((varExpression) => {
const mockValue = generateVariableExpressionMockValue(varExpression);
if (mockValue) {
const paramValue = new ParameterValue();
paramValue.name = varExpression.name;
paramValue.value =
this.editorStore.graphManagerState.graphManager.serializeValueSpecification(
mockValue,
);
return new ServiceValueSpecificationTestParameterState(
paramValue,
this.editorStore,
this,
mockValue,
varExpression,
);
}
return undefined;
})
.filter(isNonNullable);
service_setParameterValues(
this.testState.test,
parameterValueStates.map((s) => s.parameterValue),
);
this.parameterValueStates = parameterValueStates;
} catch (error) {
assertErrorThrown(error);
this.editorStore.applicationStore.notifyError(
`Unable to generate param values: ${error.message}`,
);
}
}
}
export class ServiceTestState extends TestableTestEditorState {
readonly suiteState: ServiceTestSuiteState;
override test: ServiceTest;
override testable: Service;
setupState: ServiceTestSetupState;
constructor(suiteState: ServiceTestSuiteState, test: ServiceTest) {
super(
suiteState.testableState.serviceEditorState.service,
test,
suiteState.testableState.serviceEditorState.isReadOnly,
suiteState.editorStore,
);
makeObservable(this, {
selectedAsertionState: observable,
selectedTab: observable,
assertionToRename: observable,
assertionEditorStates: observable,
testResultState: observable,
runningTestAction: observable,
setupState: observable,
addAssertion: action,
setAssertionToRename: action,
handleTestResult: action,
setSelectedTab: action,
runTest: flow,
});
this.test = test;
this.suiteState = suiteState;
this.testable = suiteState.testableState.serviceEditorState.service;
this.setupState = new ServiceTestSetupState(this);
}
}