@finos/legend-extension-dsl-data-quality
Version:
Legend extension for Data Quality
284 lines • 14.1 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 { action, computed, flow, makeObservable, observable } from 'mobx';
import { CORE_PURE_PATH, FunctionType, GenericType, GenericTypeExplicitReference, getMilestoneTemporalStereotype, LambdaFunction, LambdaFunctionInstanceValue, MILESTONING_STEREOTYPE, Multiplicity, observe_ValueSpecification, PackageableElementExplicitReference, ParameterValue, PRIMITIVE_TYPE, buildRawLambdaFromLambdaFunction, VariableExpression, PROCESSING_DATE_MILESTONING_PROPERTY_NAME, BUSINESS_DATE_MILESTONING_PROPERTY_NAME, V1_RawValueSpecificationType, } from '@finos/legend-graph';
import { ElementEditorState, } from '@finos/legend-application-studio';
import { DataQualityGraphFetchTreeState } from './DataQualityGraphFetchTreeState.js';
import { DataQualityPropertyGraphFetchTree, } from '../../graph/metamodel/pure/packageableElements/data-quality/DataQualityGraphFetchTree.js';
import { buildDefaultDataQualityRootGraphFetchTree, buildGraphFetchTreeData, } from '../utils/DataQualityGraphFetchTreeUtil.js';
import { ActionState, guaranteeNonNullable, guaranteeType, hashArray, isNonNullable, assertType, at, } from '@finos/legend-shared';
import {} from '@finos/legend-application';
import { DataQualityResultState } from './DataQualityResultState.js';
import { DATA_QUALITY_HASH_STRUCTURE } from '../../graph/metamodel/DSL_DataQuality_HashUtils.js';
import { buildFilterConditionExpression, generateDefaultValueForPrimitiveType, processFilterLambda, QueryBuilderAdvancedWorkflowState, } from '@finos/legend-query-builder';
import { DataQualityQueryBuilderState } from './DataQualityQueryBuilderState.js';
import { getDataQualityPureGraphManagerExtension } from '../../graph-manager/protocol/pure/DSL_DataQuality_PureGraphManagerExtension.js';
import { dataQualityClassValidation_setDataQualityGraphFetchTree, dataQualityClassValidation_setFilter, } from '../../graph-manager/DSL_DataQuality_GraphModifierHelper.js';
import {} from '../DSL_DataQuality_LegendStudioPlugin_Extension.js';
export var DATA_QUALITY_TAB;
(function (DATA_QUALITY_TAB) {
DATA_QUALITY_TAB["FILTER"] = "Filter ";
DATA_QUALITY_TAB["CONSTRAINTS_SELECTION"] = "Constraints Selection";
DATA_QUALITY_TAB["TRIAL_RUNS"] = "Trial Runs";
})(DATA_QUALITY_TAB || (DATA_QUALITY_TAB = {}));
export function buildExtensionState(editorStore, dataQualityState) {
const extensionStateBuilders = editorStore.pluginManager
.getApplicationPlugins()
.flatMap((plugin) => plugin.getExtensionStates?.() ?? []);
for (const stateBuilder of extensionStateBuilders) {
const state = stateBuilder(editorStore, dataQualityState);
if (state) {
return state;
}
}
return undefined;
}
export class DataQualityState extends ElementEditorState {
applicationStore;
graphManagerState;
loadDataSpacesState = ActionState.create();
onExecutionContextChange;
onRuntimeChange;
extensionState;
selectedTab;
executionContext;
dataQualityGraphFetchTreeState;
structuralValidationsGraphFetchTreeState;
showRuntimeSelector = false;
dataQualityQueryBuilderState;
resultState;
showStructuralValidations = false;
showDateSelection = false;
processingDate = generateDefaultValueForPrimitiveType(PRIMITIVE_TYPE.STRICTDATE);
businessDate = generateDefaultValueForPrimitiveType(PRIMITIVE_TYPE.STRICTDATE);
constructor(editorStore, element) {
super(editorStore, element);
makeObservable(this, {
selectedTab: observable,
showRuntimeSelector: observable,
dataQualityGraphFetchTreeState: observable,
structuralValidationsGraphFetchTreeState: observable,
dataQualityQueryBuilderState: observable,
showStructuralValidations: observable,
showDateSelection: observable,
processingDate: observable,
businessDate: observable,
constraintsConfigurationElement: computed,
setSelectedTab: action,
setExecutionContext: action,
setShowRuntimeSelector: action,
initializeGraphFetchTreeState: action,
initializeStructuralValidationsGraphFetchTreeState: action,
setShowStructuralValidations: action,
setShowDateSelection: action,
updateElementOnClassChange: action,
checkConstraintsSelectedAtNode: action,
changeClass: action,
setProcessingDate: action,
setBusinessDate: action,
fetchStructuralValidations: flow,
tabsToShow: computed,
areNestedConstraintsSelected: computed,
hashCode: computed,
});
this.applicationStore = this.editorStore.applicationStore;
this.graphManagerState = this.editorStore.graphManagerState;
this.dataQualityQueryBuilderState = new DataQualityQueryBuilderState(this.editorStore.applicationStore, this.editorStore.graphManagerState, QueryBuilderAdvancedWorkflowState.INSTANCE, this.editorStore.applicationStore.config.options.queryBuilderConfig, undefined);
this.selectedTab = DATA_QUALITY_TAB.CONSTRAINTS_SELECTION;
this.dataQualityGraphFetchTreeState = new DataQualityGraphFetchTreeState(this);
this.structuralValidationsGraphFetchTreeState =
new DataQualityGraphFetchTreeState(this);
this.resultState = new DataQualityResultState(this);
this.extensionState = buildExtensionState(this.editorStore, this);
}
setShowStructuralValidations(val) {
this.showStructuralValidations = val;
}
setShowDateSelection(val) {
this.showDateSelection = val;
}
setProcessingDate(val) {
this.processingDate = val;
}
setBusinessDate(val) {
this.businessDate = val;
}
get tabsToShow() {
const tabs = Object.values(DATA_QUALITY_TAB);
const extensionTabGetters = this.editorStore.pluginManager
.getApplicationPlugins()
.flatMap((plugin) => plugin.getAllTabs?.() ?? []);
for (const tabGetter of extensionTabGetters) {
tabs.push(...tabGetter());
}
return tabs;
}
get currentClassMilestoningStrategy() {
const currentclass = this.dataQualityQueryBuilderState.class;
if (currentclass !== undefined) {
return getMilestoneTemporalStereotype(currentclass, this.graphManagerState.graph);
}
return undefined;
}
get isCurrentClassMilestoned() {
return this.currentClassMilestoningStrategy !== undefined;
}
get lambdaParameterValues() {
const parameters = [];
const currentClassMilestoningStrategy = this.currentClassMilestoningStrategy;
if (currentClassMilestoningStrategy ===
MILESTONING_STEREOTYPE.PROCESSING_TEMPORAL ||
currentClassMilestoningStrategy === MILESTONING_STEREOTYPE.BITEMPORAL) {
const parameterValue = new ParameterValue();
parameterValue.name = PROCESSING_DATE_MILESTONING_PROPERTY_NAME;
parameterValue.value = {
_type: V1_RawValueSpecificationType.CSTRICTDATE,
value: this.processingDate,
};
parameters.push(parameterValue);
}
if (currentClassMilestoningStrategy ===
MILESTONING_STEREOTYPE.BUSINESS_TEMPORAL ||
currentClassMilestoningStrategy === MILESTONING_STEREOTYPE.BITEMPORAL) {
const parameterValue = new ParameterValue();
parameterValue.name = BUSINESS_DATE_MILESTONING_PROPERTY_NAME;
parameterValue.value = {
_type: V1_RawValueSpecificationType.CSTRICTDATE,
value: this.businessDate,
};
parameters.push(parameterValue);
}
return parameters;
}
*fetchStructuralValidations() {
const packagePath = this.constraintsConfigurationElement.path;
const model = this.graphManagerState.graph;
const rootGraphFetchTree = (yield getDataQualityPureGraphManagerExtension(this.graphManagerState.graphManager).fetchStructuralValidations(model, packagePath, {}));
this.initializeStructuralValidationsGraphFetchTreeState(rootGraphFetchTree);
}
initializeFilterState(filterLambda) {
if (!filterLambda) {
return;
}
const filterSpec = observe_ValueSpecification(this.graphManagerState.graphManager.buildValueSpecification(this.graphManagerState.graphManager.serializeRawValueSpecification(filterLambda), this.graphManagerState.graph), this.dataQualityQueryBuilderState.observerContext);
const compiledValueSpecification = guaranteeType(filterSpec, LambdaFunctionInstanceValue, `Can't build filter state: data quality filter only support lambda`);
processFilterLambda(at(compiledValueSpecification.values, 0), this.dataQualityQueryBuilderState);
}
initializeGraphFetchTreeState(tree) {
if (!tree) {
return;
}
this.dataQualityGraphFetchTreeState.treeData = buildGraphFetchTreeData(this.editorStore, tree, true, true, false);
}
get areNestedConstraintsSelected() {
const treeData = this.dataQualityGraphFetchTreeState.treeData;
if (!treeData) {
return false;
}
let constraintSelectedAtChildLevel = false;
treeData.tree.subTrees.forEach((subtree) => {
constraintSelectedAtChildLevel =
constraintSelectedAtChildLevel ||
this.checkConstraintsSelectedAtNode(subtree);
});
return constraintSelectedAtChildLevel;
}
checkConstraintsSelectedAtNode(tree) {
assertType(tree, DataQualityPropertyGraphFetchTree);
if (tree.constraints.length > 0) {
return true;
}
let constraintSelectedAtChildLevel = false;
tree.subTrees.forEach((subtree) => {
constraintSelectedAtChildLevel =
constraintSelectedAtChildLevel ||
this.checkConstraintsSelectedAtNode(subtree);
});
return constraintSelectedAtChildLevel;
}
updateFilterElement = () => {
const { filterState } = this.dataQualityQueryBuilderState;
const filterConditionExpressions = filterState.rootIds
.map((e) => guaranteeNonNullable(filterState.nodes.get(e)))
.map((e) => buildFilterConditionExpression(filterState, e))
.filter(isNonNullable);
if (!filterConditionExpressions.length) {
dataQualityClassValidation_setFilter(this
.constraintsConfigurationElement, undefined);
return;
}
const genericType = new GenericType(guaranteeNonNullable(this.dataQualityQueryBuilderState.class));
const genericTypeReference = GenericTypeExplicitReference.create(genericType);
const functionType = new FunctionType(PackageableElementExplicitReference.create(this.dataQualityQueryBuilderState.graphManagerState.graph.getType(CORE_PURE_PATH.ANY)), Multiplicity.ONE);
functionType.parameters.push(new VariableExpression(filterState.lambdaParameterName, Multiplicity.ONE, genericTypeReference));
const lambdaFunction = new LambdaFunction(functionType);
lambdaFunction.expressionSequence = filterConditionExpressions;
dataQualityClassValidation_setFilter(this
.constraintsConfigurationElement, buildRawLambdaFromLambdaFunction(lambdaFunction, this.dataQualityQueryBuilderState.graphManagerState));
};
initializeStructuralValidationsGraphFetchTreeState(tree) {
if (!tree) {
return;
}
this.structuralValidationsGraphFetchTreeState.treeData =
buildGraphFetchTreeData(this.editorStore, tree, true, true, true);
}
get sideBarClassName() {
return this.showRuntimeSelector
? 'data-quality-validation__setup__data-space--with-runtime'
: 'data-quality-validation__setup__data-space';
}
changeClass(val) {
this.dataQualityQueryBuilderState.changeClass(val);
this.structuralValidationsGraphFetchTreeState =
new DataQualityGraphFetchTreeState(this);
this.resultState = new DataQualityResultState(this);
this.initializeGraphFetchTreeState(buildDefaultDataQualityRootGraphFetchTree(guaranteeNonNullable(this.dataQualityQueryBuilderState.class)));
this.updateElementOnClassChange();
}
updateElementOnClassChange() {
dataQualityClassValidation_setDataQualityGraphFetchTree(this
.constraintsConfigurationElement, guaranteeNonNullable(this.dataQualityGraphFetchTreeState.treeData).tree);
dataQualityClassValidation_setFilter(this
.constraintsConfigurationElement, undefined);
}
setExecutionContext(val) {
this.executionContext = val;
}
get isMappingReadOnly() {
return false;
}
get isRuntimeReadOnly() {
return false;
}
get isQuerySupported() {
return true;
}
setSelectedTab(tab) {
this.selectedTab = tab;
}
setShowRuntimeSelector(val) {
this.showRuntimeSelector = val;
}
get hashCode() {
return hashArray([
DATA_QUALITY_HASH_STRUCTURE.DATA_QUALITY_STATE,
this.dataQualityGraphFetchTreeState,
this.dataQualityQueryBuilderState.filterState,
]);
}
}
//# sourceMappingURL=DataQualityState.js.map