diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/DataQualityCompilerExtension.java b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/DataQualityCompilerExtension.java index 9d6826d2b44..681da43a01a 100644 --- a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/DataQualityCompilerExtension.java +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/DataQualityCompilerExtension.java @@ -36,6 +36,7 @@ import org.finos.legend.engine.shared.core.operational.errorManagement.EngineException; import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQuality; import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQualityExecutionContext; +import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQualityPropertyGraphFetchTree; import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQualityPropertyGraphFetchTree_Impl; import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQualityRootGraphFetchTree; import org.finos.legend.pure.generated.Root_meta_external_dataquality_DataQualityRootGraphFetchTree_Impl; @@ -45,6 +46,7 @@ import org.finos.legend.pure.generated.Root_meta_external_dataquality_MappingAndRuntimeDataQualityExecutionContext; import org.finos.legend.pure.generated.Root_meta_external_dataquality_MappingAndRuntimeDataQualityExecutionContext_Impl; import org.finos.legend.pure.generated.Root_meta_pure_metamodel_constraint_Constraint_Impl; +import org.finos.legend.pure.generated.Root_meta_pure_metamodel_type_Class_Impl; import org.finos.legend.pure.generated.Root_meta_pure_metamodel_type_generics_GenericType_Impl; import org.finos.legend.pure.m3.coreinstance.meta.pure.graphFetch.GraphFetchTree; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.constraint.Constraint; @@ -180,13 +182,17 @@ private static GraphFetchTree buildPropertyGraphFetchTree(DataQualityPropertyGra Type returnType = subType == null ? property._genericType()._rawType() : subType; ListIterable children = ListIterate.collect(propertyGraphFetchTree.subTrees, subTree -> buildPropertyGraphFetchTree((DataQualityPropertyGraphFetchTree) subTree, context, (Class) returnType, openVariables, processingContext)); - return new Root_meta_external_dataquality_DataQualityPropertyGraphFetchTree_Impl("", SourceInformationHelper.toM3SourceInformation(propertyGraphFetchTree.sourceInformation), context.pureModel.getClass("meta::external::dataquality::DataQualityPropertyGraphFetchTree")) + Root_meta_external_dataquality_DataQualityPropertyGraphFetchTree root_meta_external_dataquality_dataQualityPropertyGraphFetchTree = new Root_meta_external_dataquality_DataQualityPropertyGraphFetchTree_Impl("", SourceInformationHelper.toM3SourceInformation(propertyGraphFetchTree.sourceInformation), context.pureModel.getClass("meta::external::dataquality::DataQualityPropertyGraphFetchTree")) ._property(property) ._parameters(pureParameters) ._alias(propertyGraphFetchTree.alias) ._subType(subType) - ._subTrees(children) - ._constraints(resolveNodeConstraints(context, parentClass, propertyGraphFetchTree.constraints)); // returnType - current property type - for constraints + ._subTrees(children); + if (returnType instanceof Root_meta_pure_metamodel_type_Class_Impl) + { + root_meta_external_dataquality_dataQualityPropertyGraphFetchTree._constraints(resolveNodeConstraints(context, (Class) returnType, propertyGraphFetchTree.constraints)); + } + return root_meta_external_dataquality_dataQualityPropertyGraphFetchTree; // returnType - current property type - for constraints } private static Root_meta_external_dataquality_DataQualityRootGraphFetchTree buildRootGraphFetchTree(DataQualityRootGraphFetchTree rootGraphFetchTree, CompileContext context, Class parentClass, MutableList openVariables, ProcessingContext processingContext) diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/pom.xml b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/pom.xml index c02ad7aa68f..d2c81f38732 100644 --- a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/pom.xml +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/pom.xml @@ -62,6 +62,10 @@ + + org.finos.legend.engine + legend-engine-language-pure-grammar + org.finos.legend.engine legend-engine-pure-code-core-extension diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/src/test/java/org/finos/legend/engine/generation/dataquality/TestDataQualityLambdaGenerator.java b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/src/test/java/org/finos/legend/engine/generation/dataquality/TestDataQualityLambdaGenerator.java new file mode 100644 index 00000000000..a5f7597b41d --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-generation/src/test/java/org/finos/legend/engine/generation/dataquality/TestDataQualityLambdaGenerator.java @@ -0,0 +1,150 @@ +// Copyright 2020 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. + +package org.finos.legend.engine.generation.dataquality; + +import org.finos.legend.engine.language.pure.compiler.Compiler; +import org.finos.legend.engine.language.pure.compiler.toPureGraph.PureModel; +import org.finos.legend.engine.language.pure.grammar.from.PureGrammarParser; +import org.finos.legend.engine.protocol.pure.v1.model.context.PureModelContextData; +import org.finos.legend.engine.shared.core.deployment.DeploymentMode; +import org.finos.legend.engine.shared.core.identity.Identity; +import org.finos.legend.pure.m3.exception.PureAssertFailException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +public class TestDataQualityLambdaGenerator +{ + @Test + public void testAssertionForNestedConstraints() + { + String validation = COMPILATION_PREREQUISITE_CODE + + "###DataQualityValidation\n" + + "DataQualityValidation meta::dataquality::PersonDataQualityValidation\n" + + "{\n" + + " context: fromMappingAndRuntime(meta::dataquality::dataqualitymappings, meta::dataquality::DataQualityRuntime);\n" + + " filter: p:meta::dataquality::Person[1] | $p.name=='John';\n" + + " validationTree: $[\n" + + " meta::dataquality::Person{\n" + + " name,\n" + + " addresses{\n" + + " addressId\n" + + " }\n" + + " }\n" + + " ]$;\n" + + "}"; + PureModelContextData modelData = PureGrammarParser.newInstance().parseModel(validation); + PureModel model = Compiler.compile(modelData, DeploymentMode.TEST_IGNORE_FUNCTION_MATCH, Identity.getAnonymousIdentity().getName()); + assertEquals("Nested constraints are not currently supported!", + assertThrows(PureAssertFailException.class, () -> DataQualityLambdaGenerator.generateLambda(model, "meta::dataquality::PersonDataQualityValidation")).getInfo()); + + } + + + private static final String COMPILATION_PREREQUISITE_CODE = "###Connection\n" + + "RelationalDatabaseConnection meta::dataquality::H2\n" + + "{\n" + + " store: meta::dataquality::db;\n" + + " type: H2;\n" + + " specification: LocalH2\n" + + " { \n" + + " testDataSetupSqls: [];\n" + + " };\n" + + " auth: DefaultH2;\n" + + "}\n" + + "\n" + + "###Relational\n" + + "Database meta::dataquality::db\n" + + "(\n" + + " Table personTable (ID INT PRIMARY KEY, FIRSTNAME VARCHAR(200), LASTNAME VARCHAR(200), AGE INT, ADDRESSID INT, FIRMID INT)\n" + + " Table addressTable (ID INT PRIMARY KEY, LOCATIONID INT, TYPE INT)\n" + + " Table locationTable (ID INT PRIMARY KEY, STREET VARCHAR(200), LOCALITY VARCHAR(200))\n" + + "\n" + + " Join Address_Person(addressTable.ID = personTable.ADDRESSID)\n" + + " Join Address_Location(addressTable.LOCATIONID = locationTable.ID)\n" + + ")\n" + + "\n" + + "\n" + + "###Mapping\n" + + "Mapping meta::dataquality::dataqualitymappings\n" + + "(\n" + + "\n" + + " meta::dataquality::Person : Relational\n" + + " {\n" + + " name : [meta::dataquality::db]personTable.FIRSTNAME,\n" + + " age : [meta::dataquality::db]personTable.AGE,\n" + + " addresses : [meta::dataquality::db]@Address_Person\n" + + " }\n" + + "\n" + + " meta::dataquality::Address : Relational\n" + + " {\n" + + " addressId : [meta::dataquality::db]addressTable.ID,\n" + + " location : [meta::dataquality::db]@Address_Location\n" + + " }\n" + + "\n" + + " meta::dataquality::Location : Relational\n" + + " {\n" + + " street : [meta::dataquality::db]locationTable.STREET,\n" + + " locality : [meta::dataquality::db]locationTable.LOCALITY\n" + + " }\n" + + ")\n" + + "\n" + + "###Runtime\n" + + "Runtime meta::dataquality::DataQualityRuntime\n" + + "{\n" + + " mappings:\n" + + " [\n" + + " meta::dataquality::dataqualitymappings\n" + + " ];\n" + + " connections:\n" + + " [\n" + + " meta::dataquality::db:\n" + + " [\n" + + " connection_1: meta::dataquality::H2\n" + + " ]\n" + + " ];\n" + + "}\n" + + "\n" + + "\n" + + "\n" + + "###Pure\n" + + "Class meta::dataquality::Person\n" + + "[\n" + + " mustBeOfLegalAge: $this.age >= 18\n" + + "]\n" + + "{\n" + + " name : String[1];\n" + + " age : Integer[1];\n" + + " addresses : meta::dataquality::Address[*];\n" + + "}\n" + + "\n" + + "Class meta::dataquality::Address\n" + + "[\n" + + " validAddressId: $this.addressId->isNotEmpty()\n" + + "]\n" + + "{\n" + + " location: meta::dataquality::Location[1];\n" + + " locationStreet: String[1];\n" + + " addressId: String[1];\n" + + "}\n" + + "\n" + + "Class meta::dataquality::Location\n" + + "{\n" + + " street: String[1];\n" + + " locality: String[1];\n" + + "}\n"; + +} diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/pom.xml b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/pom.xml new file mode 100644 index 00000000000..f3d24934936 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/pom.xml @@ -0,0 +1,249 @@ + + + + legend-engine-xts-dataquality + org.finos.legend.engine + 4.52.2-SNAPSHOT + + 4.0.0 + + legend-engine-xt-dataquality-pure-test + jar + Legend Engine - XT - DataQuality - PAR/JAVA Test + + + 11 + 11 + + + + + + org.finos.legend.pure + legend-pure-maven-generation-par + + src/main/resources + ${legend.pure.version} + + core_dataquality_test + + + ${project.basedir}/src/main/resources/core_dataquality_test.definition.json + + + + + generate-sources + + build-pure-jar + + + + + + org.finos.legend.engine + legend-engine-xt-functionActivator-pure + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-store-pure + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-pure-runtime-java-extension-compiled-functions-planExecution + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-javaGeneration-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-dataquality-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-pure-platform-dsl-graph-java + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-store-relational-pure + ${legend.pure.version} + + + + + org.finos.legend.pure + legend-pure-maven-generation-java + + + compile + + build-pure-compiled-jar + + + true + true + modular + true + + core_dataquality_test + + + + + + + org.finos.legend.pure + legend-pure-m2-dsl-store-pure + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-xt-functionActivator-pure + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-diagram-grammar + ${legend.pure.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-pure-runtime-java-extension-compiled-functions-planExecution + ${project.version} + + + org.finos.legend.engine + legend-engine-pure-runtime-java-extension-compiled-functions-legendCompiler + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-javaGeneration-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-xt-dataquality-pure + ${project.version} + + + org.finos.legend.engine + legend-engine-pure-platform-dsl-graph-java + ${project.version} + + + org.finos.legend.pure + legend-pure-m2-store-relational-pure + ${legend.pure.version} + + + + + + + + + org.finos.legend.pure + legend-pure-m2-store-relational-pure + + + org.finos.legend.engine + legend-engine-xt-relationalStore-pure + + + org.finos.legend.pure + legend-pure-m4 + + + org.finos.legend.pure + legend-pure-m3-core + + + org.finos.legend.pure + legend-pure-m2-dsl-mapping-pure + + + org.finos.legend.pure + legend-pure-runtime-java-extension-compiled-dsl-graph + runtime + + + org.finos.legend.pure + legend-pure-runtime-java-engine-compiled + + + org.finos.legend.engine + legend-engine-pure-code-compiled-core + + + org.eclipse.collections + eclipse-collections + + + org.eclipse.collections + eclipse-collections-api + + + org.finos.legend.engine + legend-engine-pure-platform-java + + + org.finos.legend.engine + legend-engine-xt-dataquality-pure + ${project.version} + + + + junit + junit + + + com.fasterxml.jackson.core + jackson-annotations + test + + + com.fasterxml.jackson.core + jackson-databind + test + + + com.fasterxml.jackson.core + jackson-core + test + + + + \ No newline at end of file diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/java/org/finos/legend/pure/code/core/CoreDataQualityTestCodeRepositoryProvider.java b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/java/org/finos/legend/pure/code/core/CoreDataQualityTestCodeRepositoryProvider.java new file mode 100644 index 00000000000..cc1b55e97c9 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/java/org/finos/legend/pure/code/core/CoreDataQualityTestCodeRepositoryProvider.java @@ -0,0 +1,29 @@ +// Copyright 2023 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. + +package org.finos.legend.pure.code.core; + +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider; +import org.finos.legend.pure.m3.serialization.filesystem.repository.GenericCodeRepository; + +public class CoreDataQualityTestCodeRepositoryProvider implements CodeRepositoryProvider +{ + @Override + public CodeRepository repository() + { + return GenericCodeRepository.build("core_dataquality_test.definition.json"); + } +} + diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider new file mode 100644 index 00000000000..78b3ed36206 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider @@ -0,0 +1 @@ +org.finos.legend.pure.code.core.CoreDataQualityTestCodeRepositoryProvider \ No newline at end of file diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test.definition.json b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test.definition.json new file mode 100644 index 00000000000..3ada292dae1 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test.definition.json @@ -0,0 +1,15 @@ +{ + "name": "core_dataquality_test", + "pattern": "(meta::external::dataquality::tests|meta::protocols)(::.*)?", + "dependencies": [ + "core", + "core_relational", + "core_data_space_metamodel", + "platform", + "platform_dsl_store", + "platform_dsl_graph", + "platform_dsl_mapping", + "platform_store_relational", + "core_dataquality" + ] +} \ No newline at end of file diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test/dataquality_test.pure b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test/dataquality_test.pure new file mode 100644 index 00000000000..8caf9a94576 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/main/resources/core_dataquality_test/dataquality_test.pure @@ -0,0 +1,81 @@ +import meta::pure::router::platform::execution::*; +import meta::pure::graphFetch::*; +import meta::external::dataquality::*; +import meta::external::dataquality::tests::*; +import meta::pure::metamodel::dataSpace::*; +import meta::pure::mapping::*; +import meta::core::runtime::*; +import meta::external::store::relational::tests::*; +import meta::relational::metamodel::*; +import meta::pure::executionPlan::*; +import meta::relational::tests::milestoning::*; +import meta::pure::profiles::*; +import meta::pure::metamodel::serialization::grammar::*; + + +function <> meta::external::dataquality::tests::testPlanGeneration():Boolean[1] +{ let dqRootConstraints = meta::external::dataquality::tests::Person->getAllTypeGeneralisations()->filter(x| $x->instanceOf(ElementWithConstraints))->cast(@ElementWithConstraints).constraints->filter(x| $x.name == 'addressIDGreaterThan2'); + + let validationTree = ^DataQualityRootGraphFetchTree( + class=meta::external::dataquality::tests::Person, + constraints=$dqRootConstraints->at(0), + subTrees=meta::external::dataquality::tests::Person->hierarchicalProperties()->filter(p | $p->isPrimitiveValueProperty())->filter(p| $p.name=='age')->map(p | ^DataQualityPropertyGraphFetchTree(property=$p)) + ); + let filter = p:Person[1]| $p.name=='John'; + let dataquality = ^DataQuality(validationTree=$validationTree, + context=^meta::external::dataquality::MappingAndRuntimeDataQualityExecutionContext(runtime=^meta::core::runtime::EngineRuntime(connectionStores = testDatabaseConnection(meta::relational::tests::db, [])), mapping=meta::external::dataquality::tests::dqValidationPersonMapping), + filter=$filter); + + // fetch lambda from DQ func; + let dqLambda = meta::external::dataquality::executeDataQualityValidation($dataquality, []); + assert($dqLambda->isNotEmpty()); +} + + +// -------------------------------------- Test Setup -------------------------------------------------------------------------// +// relational mappings +Class meta::external::dataquality::tests::Person +[ + nameMustNotBeBlank: $this.name->length() > 0, + ageMustBePositive: $this.age > 0, + nameAtLeast4Chars: $this.name->length() > 4, + ageMustBeGreaterThan10: $this.age > 100, + //addressIDGreaterThan1: $this.addresses->filter(a | $a.addressId > 1)->isNotEmpty(), + addressIDGreaterThan2: $this.addresses->filter(a | $a.addressId > 2)->isNotEmpty() +] +{ + name : String[1]; + age : Integer[1]; + addresses : meta::external::dataquality::tests::Address[*]; +} + +Class meta::external::dataquality::tests::Address +[ + addressIDMustNotBeBlank: $this.addressId > 0 +] +{ + // location: Location[1]; + // locationStreet: String[1]; + addressId: Integer[1]; +} + +###Mapping +import meta::relational::validation::complex::*; + +Mapping meta::external::dataquality::tests::dqValidationPersonMapping +( + meta::external::dataquality::tests::Person : Relational + { + // ~filter [db] (INNER)@Address_Person | [db] ActiveAddressFilter + name : [db]personTable.FIRSTNAME, + age : [db]personTable.AGE, + addresses : [db]@Address_Person + } + meta::external::dataquality::tests::Address : Relational + { + // ~filter [db] (INNER)@Address_Location | [db] LocationStreetLengthLessThan10 + addressId : [db]addressTable.ID + // location : [db]@Address_Location + } + +) diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/test/java/com/finos/legned/pure/code/core/dataquality/test/Test_Pure_Dataquality.java b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/test/java/com/finos/legned/pure/code/core/dataquality/test/Test_Pure_Dataquality.java new file mode 100644 index 00000000000..81eb1e55738 --- /dev/null +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure-test/src/test/java/com/finos/legned/pure/code/core/dataquality/test/Test_Pure_Dataquality.java @@ -0,0 +1,38 @@ +// Copyright 2023 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. +// + +package com.finos.legned.pure.code.core.dataquality.test; + +import junit.framework.TestSuite; +import org.finos.legend.pure.m3.execution.test.PureTestBuilder; +import org.finos.legend.pure.m3.execution.test.TestCollection; +import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport; +import org.finos.legend.pure.runtime.java.compiled.testHelper.PureTestBuilderCompiled; + +public class Test_Pure_Dataquality +{ + public static TestSuite suite() + { + TestSuite suite = new TestSuite(); + CompiledExecutionSupport executionSupport = PureTestBuilderCompiled.getClassLoaderExecutionSupport(); + suite.addTest(PureTestBuilderCompiled.buildSuite( + TestCollection.collectTests("meta::external::dataquality::tests", + executionSupport.getProcessorSupport(), + ci -> PureTestBuilder.satisfiesConditions(ci, executionSupport.getProcessorSupport())), + executionSupport) + ); + return suite; + } +} diff --git a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure/src/main/resources/core_dataquality/generation/dataquality.pure b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure/src/main/resources/core_dataquality/generation/dataquality.pure index b4de9253fa1..f1233c46180 100644 --- a/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure/src/main/resources/core_dataquality/generation/dataquality.pure +++ b/legend-engine-xts-dataquality/legend-engine-xt-dataquality-pure/src/main/resources/core_dataquality/generation/dataquality.pure @@ -17,7 +17,8 @@ import meta::pure::lineage::scanProperties::propertyTree::*; function meta::external::dataquality::executeDataQualityValidation(dataquality:meta::external::dataquality::DataQuality[1], limit: Integer[*]): LambdaFunction[1] { - // 1. enrich tree with selected constraint properties + $dataquality.validationTree->validateTreeForNestedConstraints(true); + // 1. enrich tree with selected constraint properties let enrichedTree = $dataquality.validationTree->ensureFunctionRequirementsForDataQuality($dataquality.validationTree.constraints, $dataquality.validationTree.class, [], true)->cast(@RootGraphFetchTree); // 2. build query @@ -69,6 +70,14 @@ function meta::external::dataquality::executeDataQualityValidation(dataquality:m ); } +function meta::external::dataquality::validateTreeForNestedConstraints(node:GraphFetchTree[1], isRoot:Boolean[1]): Boolean[1] +{ + if ($isRoot->isFalse() && $node->cast(@DataQualityPropertyGraphFetchTree).constraints->isNotEmpty(), + | fail('Nested constraints are not currently supported!'), + | '' + ); + $node.subTrees->fold({subtree, isValid | $isValid && $subtree->validateTreeForNestedConstraints(false)}, true); +} function meta::external::dataquality::ensureFunctionRequirementsForDataQuality(node:GraphFetchTree[1], constraints:Constraint[*], class:Class[1], processed:Class[*], ensureConstraintsForSubTrees:Boolean[1]): GraphFetchTree[1] { diff --git a/legend-engine-xts-dataquality/pom.xml b/legend-engine-xts-dataquality/pom.xml index f3a23f9d079..fa1f16959a0 100644 --- a/legend-engine-xts-dataquality/pom.xml +++ b/legend-engine-xts-dataquality/pom.xml @@ -18,6 +18,7 @@ legend-engine-xt-dataquality-api legend-engine-xt-dataquality-compiler legend-engine-xt-dataquality-generation + legend-engine-xt-dataquality-pure-test