Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

M2M: Allow primitive types to be used as a source for mappings #3246

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public Pair<SetImplementation, RichIterable<EmbeddedSetImplementation>> visit(Op
public Pair<SetImplementation, RichIterable<EmbeddedSetImplementation>> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down Expand Up @@ -844,7 +861,7 @@ public void testFaultyPureInstanceClassMapping()
" ~src ui::Person2\n" +
" name: 'aa'\n" +
" }\n" +
")\n", "COMPILATION error at [10:10-20]: Can't find class 'ui::Person2'");
")\n", "COMPILATION error at [10:10-20]: Can't find type 'ui::Person2'");
// check set implementation root resolution
test("Class ui::Person\n" +
"{\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,18 +430,21 @@ function <<access.private>> meta::pure::graphFetch::mergePropertiesFromBaseSubTr

function <<access.private>> meta::pure::graphFetch::enrichSourceTreeNodeForProperty(srcNode:GraphFetchTree[1], setImplementation: PureInstanceSetImplementation[1], tgtPgft:PropertyGraphFetchTree[1], extensions:meta::pure::extension::Extension[*], visitedFunctions:Map<String,ScanPropertiesState>[1]): Pair<GraphFetchTree, Map<String, ScanPropertiesState>>[1]
{
let owner = $srcNode->match([
let srcNodeOwner = $srcNode->match([
r:RootGraphFetchTree<Any>[1] | $r.class,
p:PropertyGraphFetchTree[1] | if ($p.subType->isNotEmpty(), |$p.subType->toOne(), | $p.property->functionReturnType().rawType->cast(@Class<Any>)->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<Any>);
let returnType = $tgtPgft.property->functionReturnType().rawType->toOne();

let childSetImpls = $returnType->match([
Expand Down Expand Up @@ -616,11 +619,11 @@ function <<access.private>> meta::pure::graphFetch::enrichSourceTreeNode(srcNode
pair($srcNode, ^Map<String,ScanPropertiesState>())
).first;

let srcClass = $setImplementation.srcClass->toOne()->cast(@Class<Any>);
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<Any>), $setImplementation.filter.expressionSequence->at(0)),
| $subTrees
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Any>[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<Any>)->toOne()
pure: PureInstanceSetImplementation[1] | $pure.srcClass->toOne()
]->concatenate($extensions.availableStores.extractSourceClassFromSetImplementation)->toOneMany());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,14 @@ function <<access.protected>> meta::protocols::pure::v1_33_0::transformation::fr

function meta::protocols::pure::v1_33_0::transformation::fromPureGraph::findTypesFromPureInstanceSetImplementation(p:PureInstanceSetImplementation[1]):Type[*]
{
let srcClass = $p.srcClass->cast(@Class<Any>);
$p.class->concatenate($srcClass)
->concatenate($srcClass.constraints->map(c|$c.functionDefinition.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($srcClass.constraints->map(c|$c.messageFunction.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($p.propertyMappings->filter(x | $x->instanceOf(PurePropertyMapping))->cast(@PurePropertyMapping).transform.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan()));
if($p.srcClass->isNotEmpty() && $p.srcClass->toOne()->instanceOf(Class),
| let srcClass = $p.srcClass->cast(@Class<Any>);
$p.class->concatenate($srcClass)
->concatenate($srcClass.constraints->map(c|$c.functionDefinition.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($srcClass.constraints->map(c|$c.messageFunction.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($p.propertyMappings->filter(x | $x->instanceOf(PurePropertyMapping))->cast(@PurePropertyMapping).transform.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan()));,
| $p.class->concatenate($p.srcClass);
)
}

function <<access.private>> meta::protocols::pure::v1_33_0::transformation::fromPureGraph::buildDomain(found:AllTypes[1], associations:Association[*], extensions:meta::pure::extension::Extension[*]):meta::protocols::pure::v1_33_0::metamodel::PackageableElement[*]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,14 @@ function <<access.protected>> meta::protocols::pure::vX_X_X::transformation::fro

function meta::protocols::pure::vX_X_X::transformation::fromPureGraph::findTypesFromPureInstanceSetImplementation(p:PureInstanceSetImplementation[1]):Type[*]
{
let srcClass = $p.srcClass->cast(@Class<Any>);
$p.class->concatenate($srcClass)
->concatenate($srcClass.constraints->map(c|$c.functionDefinition.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($srcClass.constraints->map(c|$c.messageFunction.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($p.propertyMappings->filter(x | $x->instanceOf(PurePropertyMapping))->cast(@PurePropertyMapping).transform.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan()));
if($p.srcClass->isNotEmpty() && $p.srcClass->toOne()->instanceOf(Class),
| let srcClass = $p.srcClass->cast(@Class<Any>);
$p.class->concatenate($srcClass)
->concatenate($srcClass.constraints->map(c|$c.functionDefinition.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($srcClass.constraints->map(c|$c.messageFunction.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan())))
->concatenate($p.propertyMappings->filter(x | $x->instanceOf(PurePropertyMapping))->cast(@PurePropertyMapping).transform.expressionSequence->evaluateAndDeactivate()->map(e|$e->scan()));,
| $p.class->concatenate($p.srcClass);
)
}

function <<access.private>> meta::protocols::pure::vX_X_X::transformation::fromPureGraph::buildDomain(found:AllTypes[1], associations:Association[*], extensions:meta::pure::extension::Extension[*]):meta::protocols::pure::vX_X_X::metamodel::PackageableElement[*]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<meta::pure::profiles::test.Test, meta::pure::profiles::test.AlloyOnly>> { 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
}
)


Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ function <<access.private>> 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());
});

Expand All @@ -344,7 +345,7 @@ function <<access.private>> 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
Expand All @@ -360,7 +361,7 @@ function <<access.private>> 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');
Expand Down Expand Up @@ -428,17 +429,19 @@ function <<access.private>> meta::pure::mapping::modelToModel::executionPlan::pl
}
function <<access.private>> 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<Any>))->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);

}

Expand Down Expand Up @@ -594,7 +597,7 @@ function <<access.private>> 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,
Expand Down
Loading