diff --git a/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/ClassMappingFirstPassBuilder.java b/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/ClassMappingFirstPassBuilder.java index 552c5bbd9c1..81035b1254b 100644 --- a/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/ClassMappingFirstPassBuilder.java +++ b/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/main/java/org/finos/legend/engine/language/pure/compiler/toPureGraph/ClassMappingFirstPassBuilder.java @@ -100,7 +100,7 @@ public Pair> visit(Op public Pair> visit(PureInstanceClassMapping classMapping) { org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class pureClass = this.context.resolveClass(classMapping._class, classMapping.sourceInformation); - org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class srcClass = classMapping.srcClass == null ? null : this.context.resolveClass(classMapping.srcClass, classMapping.sourceClassSourceInformation); + org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Type srcClass = classMapping.srcClass == null ? null : this.context.resolveType(classMapping.srcClass, classMapping.sourceClassSourceInformation); PureInstanceSetImplementation mappingClass = new Root_meta_external_store_model_PureInstanceSetImplementation_Impl("", SourceInformationHelper.toM3SourceInformation(classMapping.sourceInformation), context.pureModel.getClass("meta::external::store::model::PureInstanceSetImplementation")); String id = HelperMappingBuilder.getClassMappingId(classMapping, this.context); PureInstanceSetImplementation rootSetImpl = mappingClass diff --git a/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestMappingCompilationFromGrammar.java b/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestMappingCompilationFromGrammar.java index 684c2790f36..c37d1491bd8 100644 --- a/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestMappingCompilationFromGrammar.java +++ b/legend-engine-core/legend-engine-core-base/legend-engine-core-language-pure/legend-engine-language-pure-compiler/src/test/java/org/finos/legend/engine/language/pure/compiler/test/fromGrammar/TestMappingCompilationFromGrammar.java @@ -151,6 +151,23 @@ public void testDuplicatedMappingInclude() ); } + @Test + public void testPrimitiveTypeMapping() + { + test("Class test::A\n" + + "{\n" + + " d : StrictDate[1];\n" + + "}\n" + + "###Mapping\n" + + "Mapping test::PrimitiveMapping (\n" + + " test::A : Pure\n" + + " {\n" + + " ~src StrictDate\n" + + " }\n" + + ")\n" + ); + } + @Test public void testFaultyMappingInclude() { @@ -830,7 +847,7 @@ public void testFaultyPureInstanceClassMapping() " date: $src.anotherDate,\n" + " number: $src.oneNumber\n" + " }\n" + - ")\n", "COMPILATION error at [4:4-10:5]: Can't find class 'model::domain::Target'"); + ")\n", "COMPILATION error at [4:4-10:5]: Can't find type 'model::domain::Target'"); // check source class test("Class ui::Person\n" + "{\n" + diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphExtension.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphExtension.pure index 2a04339308d..aa124fd98c8 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphExtension.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphExtension.pure @@ -430,18 +430,21 @@ function <> meta::pure::graphFetch::mergePropertiesFromBaseSubTr function <> meta::pure::graphFetch::enrichSourceTreeNodeForProperty(srcNode:GraphFetchTree[1], setImplementation: PureInstanceSetImplementation[1], tgtPgft:PropertyGraphFetchTree[1], extensions:meta::pure::extension::Extension[*], visitedFunctions:Map[1]): Pair>[1] { - let owner = $srcNode->match([ + let srcNodeOwner = $srcNode->match([ r:RootGraphFetchTree[1] | $r.class, - p:PropertyGraphFetchTree[1] | if ($p.subType->isNotEmpty(), |$p.subType->toOne(), | $p.property->functionReturnType().rawType->cast(@Class)->toOne()) + p:PropertyGraphFetchTree[1] | if ($p.subType->isNotEmpty(), |$p.subType->toOne(), | $p.property->functionReturnType().rawType->toOne()); ]); + println($srcNodeOwner->instanceOf(Class)); + let isPropertyTemporalMilestoned = $tgtPgft.property->hasGeneratedMilestoningPropertyStereotype(); let requiredProperty = if($isPropertyTemporalMilestoned, |$setImplementation.class->propertyByName($tgtPgft.property->edgePointPropertyName()->toOne()), |$tgtPgft.property); let propertyMappings = $setImplementation.propertyMappings->filter(pm|$pm.property == $requiredProperty)->cast(@PurePropertyMapping); - if($propertyMappings->isNotEmpty() || ($requiredProperty->isNotEmpty() && ($requiredProperty->toOne()->isPropertyAutoMapped($setImplementation) || $setImplementation->isNoMappingDefaultToEmpty($requiredProperty->toOne()) || $setImplementation->isPartOfMerge())), + if($srcNodeOwner->instanceOf(Class) && ($propertyMappings->isNotEmpty() || ($requiredProperty->isNotEmpty() && ($requiredProperty->toOne()->isPropertyAutoMapped($setImplementation) || $setImplementation->isNoMappingDefaultToEmpty($requiredProperty->toOne()) || $setImplementation->isPartOfMerge()))), {| + let owner = $srcNodeOwner->cast(@Class); let returnType = $tgtPgft.property->functionReturnType().rawType->toOne(); let childSetImpls = $returnType->match([ @@ -616,11 +619,11 @@ function <> meta::pure::graphFetch::enrichSourceTreeNode(srcNode pair($srcNode, ^Map()) ).first; - let srcClass = $setImplementation.srcClass->toOne()->cast(@Class); + let srcClass = $setImplementation.srcClass->toOne(); let srcNodeOwner = $srcNode->typeFromGraphFetchTree(); - if($setImplementation.filter->isNotEmpty() && $srcClass == $srcNodeOwner, - | $subTrees->enrichSourceTreeNodeForExpression($srcClass, $setImplementation.filter.expressionSequence->at(0)), + if($srcClass->instanceOf(Class) && $setImplementation.filter->isNotEmpty() && $srcClass == $srcNodeOwner, + | $subTrees->enrichSourceTreeNodeForExpression($srcClass->cast(@Class), $setImplementation.filter.expressionSequence->at(0)), | $subTrees ); } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure index 41b8c656385..d0a8fcc073e 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure @@ -53,10 +53,10 @@ Class meta::pure::mapping::TabularDataSetImplementation extends TabularDataSet store : meta::pure::store::Store[1]; } -function meta::pure::mapping::sourceClass(setImplementation:SetImplementation[1], extensions:meta::pure::extension::Extension[*]): Class[1] +function meta::pure::mapping::sourceClass(setImplementation:SetImplementation[1], extensions:meta::pure::extension::Extension[*]): Type[1] { $setImplementation->match([ - pure: PureInstanceSetImplementation[1] | $pure.srcClass->cast(@Class)->toOne() + pure: PureInstanceSetImplementation[1] | $pure.srcClass->toOne() ]->concatenate($extensions.availableStores.extractSourceClassFromSetImplementation)->toOneMany()); } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/store/m2m/tests/legend/simpleObject.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/store/m2m/tests/legend/simpleObject.pure index 7d75f044b08..29c243a461b 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/store/m2m/tests/legend/simpleObject.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/store/m2m/tests/legend/simpleObject.pure @@ -1416,4 +1416,60 @@ Mapping meta::pure::mapping::modelToModel::test::shared::dest::MappingWithNoProp } ) +###Pure +import meta::pure::executionPlan::profiles::*; + +Class meta::pure::mapping::modelToModel::test::shared::src::PrimitiveMappingSource +{ + d : StrictDate[1]; +} + +Class meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDest +{ + c : meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDestInner[1]; +} + +Class meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDestInner +{ + d : StrictDate[1]; +} + +function <> { serverVersion.start='v1_33_0' } meta::pure::mapping::modelToModel::test::alloy::simple::testPrimitiveTypeMapping() : Boolean[1] +{ + let tree = #{meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDest { c {d}}}#; + let query = {| meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDest.all()->meta::pure::graphFetch::execution::graphFetch($tree)->meta::pure::graphFetch::execution::serialize($tree)}; + let mapping = meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingTest; + let runtime = ^meta::core::runtime::Runtime( + connectionStores = [ + ^meta::core::runtime::ConnectionStore( + element=^meta::external::store::model::ModelStore(), + connection = ^meta::external::store::model::JsonModelConnection( + class=meta::pure::mapping::modelToModel::test::shared::src::PrimitiveMappingSource, + url='data:application/json,{"d":"2020-01-01"}' + ) + ) + ] + ); + + let result = execute($query, $mapping, $runtime, meta::pure::extension::defaultExtensions()); + println($result.values); + assert(meta::json::jsonEquivalent('{"c":{"d":"2020-01-01"}}'->meta::json::parseJSON(), $result.values->toOne()->meta::json::parseJSON())); +} + +###Mapping +Mapping meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingTest +( + *meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDest : Pure + { + ~src meta::pure::mapping::modelToModel::test::shared::src::PrimitiveMappingSource + c[mydate] : $src.d + } + + meta::pure::mapping::modelToModel::test::shared::dest::PrimitiveMappingDestInner[mydate] : Pure + { + ~src StrictDate + d : $src + } +) + diff --git a/legend-engine-xts-java/legend-engine-xt-javaGeneration-pure/src/main/resources/core_external_language_java/generation/conventions.pure b/legend-engine-xts-java/legend-engine-xt-javaGeneration-pure/src/main/resources/core_external_language_java/generation/conventions.pure index a64000afef3..d46c3aecb2a 100644 --- a/legend-engine-xts-java/legend-engine-xt-javaGeneration-pure/src/main/resources/core_external_language_java/generation/conventions.pure +++ b/legend-engine-xts-java/legend-engine-xt-javaGeneration-pure/src/main/resources/core_external_language_java/generation/conventions.pure @@ -378,6 +378,14 @@ function meta::external::language::java::transform::className(conventions: Conve ); } +function meta::external::language::java::transform::typeName(conventions: Conventions[1], type:meta::pure::metamodel::type::Type[1]): meta::external::language::java::metamodel::Type[1] +{ + if($type->instanceOf(meta::pure::metamodel::type::Class), + | $conventions->className($type), + | $conventions->pureTypeToJavaType($type, PureOne) + ) +} + function meta::external::language::java::transform::implClassName(conventions: Conventions[1], type:meta::pure::metamodel::type::Type[1]): meta::external::language::java::metamodel::Class[1] { $conventions->generateClassName($type, 'internal', '_Impl'); diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/executionPlanNodes/graphFetch/inMemory/graphFetchInMemory.pure b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/executionPlanNodes/graphFetch/inMemory/graphFetchInMemory.pure index 80ce8a5916f..345cca89d29 100644 --- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/executionPlanNodes/graphFetch/inMemory/graphFetchInMemory.pure +++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/executionPlanNodes/graphFetch/inMemory/graphFetchInMemory.pure @@ -325,7 +325,8 @@ function <> meta::pure::mapping::modelToModel::executionPlan::pl let targetSetTransformers = $propertyMappings->map({pm | let targetSet = $graphFetchTree.sets->filter(x | $x.id == $pm.targetSetImplementationId)->toOne()->cast(@InstanceSetImplementation); - let input = j_parameter($conventions->className($targetSet->sourceClass($extensions)), 'input'); + let setSrc = $targetSet->sourceClass($extensions); + let input = j_parameter($conventions->typeName($targetSet->sourceClass($extensions)), 'input'); j_lambda($input, $input->setTransformerCodes($path,$targetSet, $graphFetchTree, $currentGraphImpl, false, false, $context, $extensions, $debug)->j_block()); }); @@ -344,7 +345,7 @@ function <> meta::pure::mapping::modelToModel::executionPlan::pl let pm = $idxPm.second; let tst = $targetSetTransformers->at($idx); let targetSet = $graphFetchTree.sets->filter(x | $x.id == $pm.targetSetImplementationId)->toOne()->cast(@InstanceSetImplementation); - let targetSrc = $conventions->className($targetSet->sourceClass($extensions)); + let targetSrc = $conventions->typeName($targetSet->sourceClass($extensions)); javaField( ['private', 'static', 'final'], javaFunction($targetSrc, if($targetSet->hasExplodeProperty(),|$currentGraphImpl->javaStream(),|$currentGraphImpl)), 'targetSetTransformer_' + $idx->toString(), $tst @@ -360,7 +361,7 @@ function <> meta::pure::mapping::modelToModel::executionPlan::pl let tsTransformer = $executeClassWithFields->j_field('targetSetTransformer_' + $pmIndex->toString()); let pmtType = $propMappingTransformers->at($pmIndex).type->cast(@meta::external::language::java::metamodel::FunctionType); let targetSet = $graphFetchTree.sets->filter(x | $x.id == $pm.targetSetImplementationId)->toOne()->cast(@InstanceSetImplementation); - let targetSrc = j_parameter($conventions->className($targetSet->sourceClass($extensions)), 'targetSrc'); + let targetSrc = j_parameter($conventions->typeName($targetSet->sourceClass($extensions)), 'targetSrc'); let propertyConcreteType = $pmtType.returnType->at(0)->match([p:ParameterizedType[1]|$p.typeArguments->at(0), t:meta::external::language::java::metamodel::Type[1]|$t ]); let propertyType = j_parameter($propertyConcreteType, 'propertyType'); @@ -428,17 +429,19 @@ function <> meta::pure::mapping::modelToModel::executionPlan::pl } function <> meta::pure::mapping::modelToModel::executionPlan::platformBinding::legendJava::graphFetch::addFilterForSubtype(input:Code[1],propertyType: Code[1],targetSRCType:meta::external::language::java::metamodel::Type[1], targetSet:InstanceSetImplementation[1],context: GenerationContext[1],extensions: Extension[*]):Code[1] { - //if source is a mappingclass skip the filter + //if source is a mappingclass or a primitive type skip the filter (TODO: should we handle filters on primtive sources?) let sourceClass = $targetSet->sourceClass($extensions); - let sourceClassMappings = $targetSet.parent->_classMappingByClass($sourceClass)->filter(i|$i->instanceOf(InstanceSetImplementation))->cast(@InstanceSetImplementation); - let targetSrcJType = $context.conventions->className($sourceClass); - - if($targetSet->instanceOf(PureInstanceSetImplementation) && $sourceClassMappings.mappingClass->isEmpty(), - |let interParam = j_parameter(javaClassType(), 'interParam'); - $input->js_filter(j_lambda($propertyType, j_streamOf( $propertyType->j_invoke('getClass',[],javaClassType())->j_invoke('getInterfaces',[],javaClassType())) - ->j_invoke('anyMatch', j_lambda($interParam, $interParam->j_invoke('equals',[$targetSrcJType-> j_field('class' ,$targetSrcJType)])),javaBoolean())));, - |$input - ); + if($sourceClass->instanceOf(meta::pure::metamodel::type::Class), + | let sourceClassMappings = $targetSet.parent->_classMappingByClass($sourceClass->cast(@meta::pure::metamodel::type::Class))->filter(i|$i->instanceOf(InstanceSetImplementation))->cast(@InstanceSetImplementation); + let targetSrcJType = $context.conventions->className($sourceClass); + + if($targetSet->instanceOf(PureInstanceSetImplementation) && $sourceClassMappings.mappingClass->isEmpty(), + |let interParam = j_parameter(javaClassType(), 'interParam'); + $input->js_filter(j_lambda($propertyType, j_streamOf( $propertyType->j_invoke('getClass',[],javaClassType())->j_invoke('getInterfaces',[],javaClassType())) + ->j_invoke('anyMatch', j_lambda($interParam, $interParam->j_invoke('equals',[$targetSrcJType-> j_field('class' ,$targetSrcJType)])),javaBoolean())));, + |$input + );, + | $input); } @@ -594,7 +597,7 @@ function <> meta::pure::mapping::modelToModel::executionPlan::pl let setHasExplosion = $set->hasExplodeProperty(); let result = j_variable($graphImplClass, 'result'); let srcClass = $set->sourceClass($extensions); - let srcJavaClass = $conventions->className($srcClass); + let srcJavaClass = $conventions->typeName($srcClass); let src = j_variable($srcJavaClass, 'src'); let isMerged = $set->isPartOfMerge(); let transform = if ($setHasExplosion,