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

support function descriptors in relation mapping, improve function validations #915

Merged
merged 1 commit into from
Jan 7, 2025
Merged
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 @@ -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
Loading