Skip to content

Commit

Permalink
Support function descriptors in relation mapping, improve function va…
Browse files Browse the repository at this point in the history
…lidations (#915)
  • Loading branch information
gs-rpant1729 authored Jan 7, 2025
1 parent c0ddc60 commit a2cf79e
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ options
tokenVocab = RelationMappingLexer;
}

mapping: RELATION_FUNCTION qualifiedName
mapping: RELATION_FUNCTION (functionDescriptor | qualifiedName)
(singlePropertyMapping (COMMA singlePropertyMapping)*)?
EOF
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@
import org.eclipse.collections.impl.utility.ListIterate;
import org.finos.legend.pure.m2.dsl.mapping.serialization.grammar.RelationMappingParser;
import org.finos.legend.pure.m2.dsl.mapping.serialization.grammar.RelationMappingParserBaseVisitor;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.multiplicity.Multiplicity;
import org.finos.legend.pure.m3.navigation.ProcessorSupport;
import org.finos.legend.pure.m3.navigation.function.FunctionDescriptor;
import org.finos.legend.pure.m3.navigation.function.InvalidFunctionDescriptorException;
import org.finos.legend.pure.m3.serialization.grammar.m3parser.antlr.AntlrContextToM3CoreInstance;
import org.finos.legend.pure.m3.serialization.grammar.m3parser.antlr.M3AntlrParser;
import org.finos.legend.pure.m4.ModelRepository;
import org.finos.legend.pure.m4.coreinstance.SourceInformation;
import org.finos.legend.pure.m4.serialization.grammar.antlr.AntlrSourceInformation;
import org.finos.legend.pure.m4.serialization.grammar.antlr.PureParserException;

public class RelationMappingGraphBuilder extends RelationMappingParserBaseVisitor<String>
{
Expand All @@ -43,19 +44,27 @@ public RelationMappingGraphBuilder(String importId, ModelRepository repository,

public String visitMapping(RelationMappingParser.MappingContext ctx, String id, String extendsId, String setSourceInfo, boolean root, String classPath, String classSourceInfo, String mappingPath)
{
Token startToken = ctx.qualifiedName().getStart();
String functionPath = ctx.qualifiedName().getText();
String propertyMappings = ctx.singlePropertyMapping() == null ? "" : ListIterate.collect(ctx.singlePropertyMapping(), c -> visitPropertyMapping(c, id)).makeString(",");

return "^meta::pure::mapping::relation::RelationFunctionInstanceSetImplementation" + setSourceInfo + "(" +
(id == null ? "" : "id = '" + id + "',") +
(extendsId == null ? "" : "superSetImplementationId = '" + extendsId + "',") +
"root = " + root + "," +
"class = ^meta::pure::metamodel::import::ImportStub " + classSourceInfo + " (importGroup=system::imports::" + importId + ", idOrPath='" + classPath + "')," +
"parent = ^meta::pure::metamodel::import::ImportStub (importGroup=system::imports::" + importId + ", idOrPath='" + mappingPath + "')," +
"relationFunction = ^meta::pure::metamodel::import::ImportStub " + this.sourceInformation.getPureSourceInformation(startToken, startToken, ctx.qualifiedName().getStop()).toM4String() + " (importGroup=system::imports::" + this.importId + ", idOrPath='" + functionPath + "')," +
"propertyMappings=[" + propertyMappings + "]" +
")";
Token functionStartToken = ctx.functionDescriptor() != null ? ctx.functionDescriptor().getStart() : ctx.qualifiedName().getStart();
Token functionEndToken = ctx.functionDescriptor() != null ? ctx.functionDescriptor().getStop() : ctx.qualifiedName().getStop();
try
{
String functionId = ctx.functionDescriptor() != null ? FunctionDescriptor.functionDescriptorToId(ctx.functionDescriptor().getText()) : ctx.qualifiedName().getText();
String propertyMappings = ctx.singlePropertyMapping() == null ? "" : ListIterate.collect(ctx.singlePropertyMapping(), c -> visitPropertyMapping(c, id)).makeString(",");

return "^meta::pure::mapping::relation::RelationFunctionInstanceSetImplementation" + setSourceInfo + "(" +
(id == null ? "" : "id = '" + id + "',") +
(extendsId == null ? "" : "superSetImplementationId = '" + extendsId + "',") +
"root = " + root + "," +
"class = ^meta::pure::metamodel::import::ImportStub " + classSourceInfo + " (importGroup=system::imports::" + importId + ", idOrPath='" + classPath + "')," +
"parent = ^meta::pure::metamodel::import::ImportStub (importGroup=system::imports::" + importId + ", idOrPath='" + mappingPath + "')," +
"relationFunction = ^meta::pure::metamodel::import::ImportStub " + this.sourceInformation.getPureSourceInformation(functionStartToken, functionStartToken, functionEndToken).toM4String() + " (importGroup=system::imports::" + this.importId + ", idOrPath='" + functionId + "')," +
"propertyMappings=[" + propertyMappings + "]" +
")";
}
catch (InvalidFunctionDescriptorException e)
{
throw new PureParserException(this.sourceInformation.getPureSourceInformation(functionStartToken, functionStartToken, functionEndToken), "Invalid function descriptor specified for relation function mapping!", e);
}
}

private String visitPropertyMapping(RelationMappingParser.SinglePropertyMappingContext ctx, String id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.eclipse.collections.api.factory.Lists;
import org.finos.legend.pure.m2.dsl.mapping.M2MappingPaths;
import org.finos.legend.pure.m2.dsl.mapping.M2MappingProperties;
import org.finos.legend.pure.m2.dsl.mapping.serialization.grammar.v1.validator.RelationFunctionInstanceSetImplementationValidator;
import org.finos.legend.pure.m3.compiler.Context;
import org.finos.legend.pure.m3.compiler.postprocessing.PostProcessor;
import org.finos.legend.pure.m3.compiler.postprocessing.ProcessorState;
Expand All @@ -29,18 +30,15 @@
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.RelationType;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.generics.GenericType;
import org.finos.legend.pure.m3.navigation.Instance;
import org.finos.legend.pure.m3.navigation.M3Paths;
import org.finos.legend.pure.m3.navigation.M3Properties;
import org.finos.legend.pure.m3.navigation.ProcessorSupport;
import org.finos.legend.pure.m3.navigation.importstub.ImportStub;
import org.finos.legend.pure.m3.navigation.relation._Column;
import org.finos.legend.pure.m3.navigation.relation._RelationType;
import org.finos.legend.pure.m3.serialization.runtime.Source;
import org.finos.legend.pure.m3.tools.matcher.Matcher;
import org.finos.legend.pure.m4.ModelRepository;
import org.finos.legend.pure.m4.coreinstance.CoreInstance;
import org.finos.legend.pure.m4.coreinstance.SourceInformation;
import org.finos.legend.pure.m4.exception.PureCompilationException;


public class RelationFunctionInstanceSetImplementationProcessor extends Processor<RelationFunctionInstanceSetImplementation>
Expand All @@ -50,14 +48,9 @@ public void process(RelationFunctionInstanceSetImplementation instance, Processo
{
CoreInstance relationFunction = ImportStub.withImportStubByPass(instance._relationFunctionCoreInstance(), processorSupport);
PostProcessor.processElement(matcher, relationFunction, state, processorSupport);

RelationFunctionInstanceSetImplementationValidator.validateRelationFunction(relationFunction, processorSupport);
GenericType lastExpressionType = (GenericType) relationFunction.getValueForMetaPropertyToMany(M3Properties.expressionSequence).getLast().getValueForMetaPropertyToOne(M3Properties.genericType);
if (!processorSupport.type_subTypeOf(lastExpressionType._rawType(), processorSupport.package_getByUserPath(M3Paths.Relation)))
{
throw new PureCompilationException(relationFunction.getSourceInformation(), "Relation mapping function should return a Relation! Found a " + org.finos.legend.pure.m3.navigation.generictype.GenericType.print(lastExpressionType, processorSupport) + " instead.");
}
RelationType<?> relationType = (RelationType<?>) Instance.getValueForMetaPropertyToOneResolved(lastExpressionType, M3Properties.typeArguments, M3Properties.rawType, processorSupport);

processPropertyMapping(instance, relationType, processorSupport);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.Property;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.multiplicity.Multiplicity;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.Column;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.FunctionType;
import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Type;
import org.finos.legend.pure.m3.navigation.M3Paths;
import org.finos.legend.pure.m3.navigation.ProcessorSupport;
import org.finos.legend.pure.m3.navigation.relation._Column;
import org.finos.legend.pure.m3.tools.matcher.MatchRunner;
import org.finos.legend.pure.m3.tools.matcher.Matcher;
import org.finos.legend.pure.m3.tools.matcher.MatcherState;
import org.finos.legend.pure.m4.ModelRepository;
import org.finos.legend.pure.m4.coreinstance.CoreInstance;
import org.finos.legend.pure.m4.coreinstance.SourceInformation;
import org.finos.legend.pure.m4.exception.PureCompilationException;

Expand All @@ -46,7 +49,7 @@ public void run(RelationFunctionInstanceSetImplementation instance, MatcherState
}
}

private static void validateProperty(Property<?, ?> property, Column<?, ?> column, SourceInformation sourceInformation, ProcessorSupport processorSupport)
private void validateProperty(Property<?, ?> property, Column<?, ?> column, SourceInformation sourceInformation, ProcessorSupport processorSupport)
{
Multiplicity propertyMultiplicity = property._multiplicity();
if (!org.finos.legend.pure.m3.navigation.multiplicity.Multiplicity.isToOne(propertyMultiplicity) && !org.finos.legend.pure.m3.navigation.multiplicity.Multiplicity.isZeroToOne(propertyMultiplicity))
Expand All @@ -66,6 +69,19 @@ private static void validateProperty(Property<?, ?> property, Column<?, ?> colum
throw new PureCompilationException(sourceInformation, "Mismatching property and relation column types. Property type is " + propertyType._name() + ", but relation column it is mapped to has type " + columnType._name() + ".");
}
}

public static void validateRelationFunction(CoreInstance relationFunction, ProcessorSupport processorSupport)
{
FunctionType functionType = (FunctionType) processorSupport.function_getFunctionType(relationFunction);
if (functionType._parameters().size() != 0)
{
throw new PureCompilationException(relationFunction.getSourceInformation(), "Relation mapping function expecting arguments is not supported!");
}
if (!processorSupport.type_subTypeOf(functionType._returnType()._rawType(), processorSupport.package_getByUserPath(M3Paths.Relation)))
{
throw new PureCompilationException(relationFunction.getSourceInformation(), "Relation mapping function should return a Relation! Found a " + org.finos.legend.pure.m3.navigation.generictype.GenericType.print(functionType._returnType(), processorSupport) + " instead.");
}
}

@Override
public String getClassName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public void testDeleteAndReloadEachSourceWithRelationMapping()
" }\n" +
" *my::Firm[firm]: Relation\n" +
" {\n" +
" ~func my::firmFunction__Relation_1_\n" +
" ~func my::firmFunction():Relation<Any>[1]\n" +
" id: ID,\n" +
" legalName: LEGALNAME\n" +
" }\n" +
Expand All @@ -100,7 +100,7 @@ public void testDeleteAndReloadEachSourceWithRelationMappingContainingLocalPrope
"(\n" +
" *my::Firm[firm]: Relation\n" +
" {\n" +
" ~func my::firmFunction__Relation_1_\n" +
" ~func my::firmFunction():Relation<Any>[1]\n" +
" id: ID,\n" +
" +firmName: String[0..1]: LEGALNAME\n" +
" }\n" +
Expand Down Expand Up @@ -182,7 +182,7 @@ public void testRelationMappingWithMismatchingTypes()
"(\n" +
" *my::Firm[firm]: Relation\n" +
" {\n" +
" ~func my::firmFunction__Relation_1_\n" +
" ~func my::firmFunction():Relation<Any>[1]\n" +
" legalName: ID\n" +
" }\n" +
")\n";
Expand Down Expand Up @@ -337,4 +337,37 @@ public void testRelationMappingWithMissingRelationFunction()
}
}

@Test
public void testRelationMappingToRelationFunctionWithArguments()
{
try
{
String mappingSource = "###Pure\n" +
"import meta::pure::metamodel::relation::*;\n" +
"function my::personFunctionWithArg(i:Integer[1]): Relation<Any>[1]\n" +
"{\n" +
" $i->cast(@Relation<(FIRSTNAME:String, AGE:Integer, FIRMID:Integer, CITY:String)>);\n" +
"}\n" +
"###Mapping\n" +
"Mapping my::testMapping\n" +
"(\n" +
" *my::Person[person]: Relation\n" +
" {\n" +
" ~func my::personFunctionWithArg(Integer[1]):Relation<Any>[1]\n" +
" }\n" +
")\n";

new RuntimeTestScriptBuilder().createInMemorySources(Maps.immutable.of("1.pure", RELATION_MAPPING_CLASS_SOURCE,
"2.pure", RELATION_MAPPING_FUNCTION_SOURCE,
"3.pure", mappingSource))
.compile().run(runtime, functionExecution);

Assert.fail("Expected compilation exception");
}
catch (Exception e)
{
assertPureException(PureCompilationException.class, "Relation mapping function expecting arguments is not supported!", "3.pure", 3, 14, 6, 1, e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import meta::pure::tools::*;
import meta::pure::functions::collection::*;
import meta::pure::mapping::aggregationAware::*;
import meta::pure::test::*;
import meta::pure::metamodel::relation::*;

// Mapping
Class meta::pure::mapping::Mapping extends PackageableElement, Testable
Expand Down Expand Up @@ -222,7 +223,7 @@ Class meta::pure::mapping::aggregationAware::AggregateSpecificationValueSpecific

Class meta::pure::mapping::relation::RelationFunctionInstanceSetImplementation extends InstanceSetImplementation
{
relationFunction: FunctionDefinition<Any>[1];
relationFunction: FunctionDefinition<{->Relation<Any>[1]}>[1];
}

Class meta::pure::mapping::relation::RelationFunctionPropertyMapping extends PropertyMapping
Expand Down

0 comments on commit a2cf79e

Please sign in to comment.