Skip to content

Commit

Permalink
M2M: Allow primitive types to be used as a source for mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
aziemchawdhary-gs committed Nov 12, 2024
1 parent 0cd8dda commit 560f806
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 24 deletions.
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 @@ -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" +
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 @@ -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

0 comments on commit 560f806

Please sign in to comment.