From ffb8b2a078e28d2be3dc82b96806329059eb48e3 Mon Sep 17 00:00:00 2001 From: John Pentelow Date: Mon, 10 Feb 2025 15:59:57 +0000 Subject: [PATCH] Add Relation Project and fix multiple small type inference issues --- .../ValueSpecificationBuilder.java | 22 +- .../toPureGraph/handlers/Handlers.java | 31 ++- .../TestDomainCompilationFromGrammar.java | 19 ++ .../core/legend/test/handlersTest.pure | 80 +++--- .../vX_X_X/transfers/valueSpecification.pure | 21 +- .../relation/functions/graph/project.pure | 29 ++ .../compiled/RelationExtensionCompiled.java | 1 + .../RelationNativeImplementation.java | 7 +- .../relation/compiled/natives/Extend.java | 7 +- .../compiled/natives/ExtendArray.java | 2 +- .../compiled/natives/ProjectRelation.java | 36 +++ .../RelationExtensionInterpreted.java | 2 + .../relation/interpreted/natives/Extend.java | 236 +--------------- .../interpreted/natives/ProjectRelation.java | 27 ++ .../natives/shared/AggregationShared.java | 3 +- .../natives/shared/ProjectExtend.java | 261 ++++++++++++++++++ .../pureToSQLQuery/pureToSQLQuery.pure | 107 +++---- 17 files changed, 547 insertions(+), 344 deletions(-) create mode 100644 legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ProjectRelation.java create mode 100644 legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/ProjectRelation.java create mode 100644 legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/shared/ProjectExtend.java 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/ValueSpecificationBuilder.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/ValueSpecificationBuilder.java index 5aec1f68db4..0e97563222e 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/ValueSpecificationBuilder.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/ValueSpecificationBuilder.java @@ -18,6 +18,7 @@ import org.eclipse.collections.api.block.function.Function3; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.impl.list.mutable.FastList; import org.eclipse.collections.impl.utility.Iterate; import org.eclipse.collections.impl.utility.LazyIterate; import org.eclipse.collections.impl.utility.ListIterate; @@ -879,17 +880,28 @@ public ValueSpecification processClassInstance(TdsOlapAggregation tdsOlapAggrega return new Root_meta_pure_metamodel_valuespecification_InstanceValue_Impl("", SourceInformationHelper.toM3SourceInformation(tdsOlapAggregation.sourceInformation), this.context.pureModel.getClass(M3Paths.InstanceValue)) ._genericType(this.context.pureModel.getGenericType("meta::pure::tds::TdsOlapAggregation")) ._multiplicity(this.context.pureModel.getMultiplicity("one")) - ._values(Lists.immutable.of(new Root_meta_pure_tds_TdsOlapAggregation_Impl<>("")._func(lambda)._colName(tdsOlapAggregation.columnName))); + ._values(Lists.immutable.of(new Root_meta_pure_tds_TdsOlapAggregation_Impl<>("")._func(lambda)._colName(tdsOlapAggregation.columnName) + ._classifierGenericType(this.context.pureModel.getGenericType("meta::pure::tds::TdsOlapAggregation")._typeArguments(FastList.newListWith( + ((FunctionType) lambda._classifierGenericType()._typeArguments().getFirst()._rawType())._parameters().getFirst()._genericType() + ))))); } public ValueSpecification processClassInstance(TDSAggregateValue tdsAggregateValue) { LambdaFunction l = (LambdaFunction) ((InstanceValue) tdsAggregateValue.mapFn.accept(this))._values().getFirst(); LambdaFunction o = (LambdaFunction) ((InstanceValue) tdsAggregateValue.aggregateFn.accept(this))._values().getFirst(); + return new Root_meta_pure_metamodel_valuespecification_InstanceValue_Impl("", SourceInformationHelper.toM3SourceInformation(tdsAggregateValue.sourceInformation), this.context.pureModel.getClass(M3Paths.InstanceValue)) ._genericType(this.context.pureModel.getGenericType("meta::pure::tds::AggregateValue")) ._multiplicity(this.context.pureModel.getMultiplicity("one")) - ._values(Lists.immutable.of(new Root_meta_pure_tds_AggregateValue_Impl("", SourceInformationHelper.toM3SourceInformation(tdsAggregateValue.sourceInformation), this.context.pureModel.getClass("meta::pure::tds::AggregateValue"))._name(tdsAggregateValue.name)._mapFn(l)._aggregateFn(o))); + ._values(Lists.immutable.of(new Root_meta_pure_tds_AggregateValue_Impl("", SourceInformationHelper.toM3SourceInformation(tdsAggregateValue.sourceInformation), this.context.pureModel.getClass("meta::pure::tds::AggregateValue")) + ._classifierGenericType(this.context.pureModel.getGenericType("meta::pure::tds::AggregateValue")._typeArguments(FastList.newListWith( + ((FunctionType) l._classifierGenericType()._typeArguments().getFirst()._rawType())._returnType(), + ((FunctionType) o._classifierGenericType()._typeArguments().getFirst()._rawType())._returnType() + ))) + ._name(tdsAggregateValue.name) + ._mapFn(l) + ._aggregateFn(o))); } public ValueSpecification processClassInstance(TDSSortInformation tdsSortInformation) @@ -916,7 +928,11 @@ public ValueSpecification processClassInstance(TdsOlapRank tdsOlapRank) return new Root_meta_pure_metamodel_valuespecification_InstanceValue_Impl("", SourceInformationHelper.toM3SourceInformation(tdsOlapRank.sourceInformation), this.context.pureModel.getClass(M3Paths.InstanceValue)) ._genericType(this.context.pureModel.getGenericType("meta::pure::tds::TdsOlapRank")) ._multiplicity(this.context.pureModel.getMultiplicity("one")) - ._values(Lists.immutable.of(new Root_meta_pure_tds_TdsOlapRank_Impl("", SourceInformationHelper.toM3SourceInformation(tdsOlapRank.sourceInformation), this.context.pureModel.getClass("meta::pure::tds::TdsOlapRank"))._func(lambda))); + ._values(Lists.immutable.of(new Root_meta_pure_tds_TdsOlapRank_Impl("", SourceInformationHelper.toM3SourceInformation(tdsOlapRank.sourceInformation), this.context.pureModel.getClass("meta::pure::tds::TdsOlapRank")) + ._func(lambda) + ._classifierGenericType(this.context.pureModel.getGenericType("meta::pure::tds::TdsOlapRank")._typeArguments(FastList.newListWith( + ((FunctionType) lambda._classifierGenericType()._typeArguments().getFirst()._rawType())._parameters().getFirst()._genericType() + ))))); } @Override 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/handlers/Handlers.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/handlers/Handlers.java index 1b82ddf42b4..6aad5d1a4aa 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/handlers/Handlers.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/handlers/Handlers.java @@ -510,7 +510,8 @@ public static org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation GenericType gt = firstProcessedParameter._genericType(); if (parameters.get(1) instanceof ClassInstance) { - ((ColSpecArray) ((ClassInstance) parameters.get(1)).value).colSpecs.forEach(col -> updateSimpleLambda(col.function1, gt, new org.finos.legend.engine.protocol.pure.m3.multiplicity.Multiplicity(1, 1), cc)); + final GenericType gt2 = Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(gt._rawType().getName()) ? gt._typeArguments().getFirst() : gt; + ((ColSpecArray) ((ClassInstance) parameters.get(1)).value).colSpecs.forEach(col -> updateSimpleLambda(col.function1, gt2, new org.finos.legend.engine.protocol.pure.m3.multiplicity.Multiplicity(1, 1), cc)); } else { @@ -603,7 +604,8 @@ private static void processAscendingDescending(AppliedFunction af, RelationType< ValueSpecification firstProcessedParameter = parameters.get(0).accept(valueSpecificationBuilder); List result = Lists.mutable.with(firstProcessedParameter); GenericType gt = firstProcessedParameter._genericType(); - if ("TabularDataSet".equals(gt._rawType()._name())) + String gtName = gt._rawType()._name(); + if ("TabularDataSet".equals(gtName) || "TableTDS".equals(gtName)) { updateSimpleLambda(parameters.get(1), cc.pureModel.getGenericType("meta::pure::tds::TDSRow"), new org.finos.legend.engine.protocol.pure.m3.multiplicity.Multiplicity(1, 1), cc); parameters.stream().skip(1).map(p -> p.accept(valueSpecificationBuilder)).forEach(result::add); @@ -669,7 +671,8 @@ else if (Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS" MutableList result = Lists.mutable.with(firstProcessedParameter); GenericType gt = firstProcessedParameter._genericType(); - if ("TabularDataSet".equals(gt._rawType()._name())) + String gtName = gt._rawType()._name(); + if ("TabularDataSet".equals(gtName) || "TableTDS".equals(gtName)) { aggInferenceAll(parameters, cc.pureModel.getGenericType("meta::pure::tds::TDSRow"), 1, 2, valueSpecificationBuilder); parameters.stream().skip(1).map(p -> p.accept(valueSpecificationBuilder)).forEach(result::add); @@ -882,7 +885,8 @@ public Handlers(PureModel pureModel) // meta::pure::tds::project(set:T[*], columnSpecifications:ColumnSpecification[*]):TabularDataSet[1] h("meta::pure::tds::project_T_MANY__ColumnSpecification_MANY__TabularDataSet_1_", false, ps -> res("meta::pure::tds::TabularDataSet", "one"), ps -> true), //meta::pure::functions::relation::project(cl:C[*], x:FuncColSpecArray<{C[1]->Any[*]},T>[1]):Relation[1]; - h("meta::pure::functions::relation::project_C_MANY__FuncColSpecArray_1__Relation_1_", true, ps -> ProjectReturnInference(ps, this.pureModel), ps -> true) + h("meta::pure::functions::relation::project_C_MANY__FuncColSpecArray_1__Relation_1_", true, ps -> ProjectReturnInference(ps, this.pureModel), ps -> true), + h("meta::pure::functions::relation::project_Relation_1__FuncColSpecArray_1__Relation_1_", true, ps -> ProjectReturnInference(ps, this.pureModel), ps -> true) ) ) ); @@ -964,7 +968,7 @@ public Handlers(PureModel pureModel) // Inference in the context of the parent register(m(m(h("meta::pure::tds::agg_String_1__FunctionDefinition_1__FunctionDefinition_1__AggregateValue_1_", false, ps -> res(CompileContext.newGenericType(this.pureModel.getType("meta::pure::tds::AggregateValue"), Lists.fixedSize.of(funcReturnType(ps.get(1)), funcReturnType(ps.get(2))), this.pureModel), "one"), ps -> Lists.fixedSize.of(funcReturnType(ps.get(1)), funcReturnType(ps.get(2))), ps -> ps.size() == 3 && typeOne(ps.get(0), "String"))), - m(h("meta::pure::functions::collection::agg_FunctionDefinition_1__FunctionDefinition_1__AggregateValue_1_", false, ps -> res("meta::pure::functions::collection::AggregateValue", "one"), ps -> true)))); + m(h("meta::pure::functions::collection::agg_FunctionDefinition_1__FunctionDefinition_1__AggregateValue_1_", false, ps -> res(CompileContext.newGenericType(this.pureModel.getType("meta::pure::functions::collection::AggregateValue"), Lists.fixedSize.of(funcParamType(ps.get(0), 0), funcReturnType(ps.get(0)), funcReturnType(ps.get(1))), this.pureModel), "one"), ps -> true)))); register(m(m(h("meta::pure::tds::col_Function_1__String_1__String_1__BasicColumnSpecification_1_", false, ps -> res(CompileContext.newGenericType(this.pureModel.getType("meta::pure::tds::BasicColumnSpecification"), Lists.fixedSize.of(funcType(ps.get(0)._genericType())._parameters().getOnly()._genericType()), pureModel), @@ -1036,7 +1040,7 @@ public Handlers(PureModel pureModel) ) ); - register("meta::pure::functions::collection::pair_U_1__V_1__Pair_1_", false, ps -> res(CompileContext.newGenericType(this.pureModel.getType("meta::pure::functions::collection::Pair"), Lists.fixedSize.ofAll(ps.stream().map(ValueSpecificationAccessor::_genericType).collect(Collectors.toList())), this.pureModel), "one")); + register(h("meta::pure::functions::collection::pair_U_1__V_1__Pair_1_", false, ps -> res(CompileContext.newGenericType(this.pureModel.getType("meta::pure::functions::collection::Pair"), Lists.fixedSize.ofAll(ps.stream().map(ValueSpecificationAccessor::_genericType).collect(Collectors.toList())), this.pureModel), "one"), ps -> Lists.mutable.with(ps.get(0)._genericType(), ps.get(1)._genericType()), ps -> true)); register(h("meta::pure::functions::multiplicity::toOne_T_MANY__T_1_", true, ps -> res(ps.get(0)._genericType(), "one"), ps -> Lists.mutable.with(ps.get(0)._genericType()), ps -> true)); @@ -1559,12 +1563,17 @@ private void registerDates() register("meta::pure::functions::date::now__DateTime_1_", true, ps -> res("DateTime", "one")); register("meta::pure::functions::date::today__StrictDate_1_", true, ps -> res("StrictDate", "one")); + + register(m(m(h("meta::pure::functions::date::toEpochValue_Date_1__Integer_1_", false, ps -> res("Integer", "one"), ps -> ps.size() == 1)), + m(h("meta::pure::functions::date::toEpochValue_Date_1__DurationUnit_1__Integer_1_", false, ps -> res("Integer", "one"), ps -> ps.size() == 2)))); } private void registerStrings() { register("meta::pure::functions::string::ascii_String_1__Integer_1_", true, ps -> res("Integer", "one")); register("meta::pure::functions::string::char_Integer_1__String_1_", true, ps -> res("String", "one")); + register("meta::pure::functions::string::decodeBase64_String_1__String_1_", true, ps -> res("String", "one")); + register("meta::pure::functions::string::encodeBase64_String_1__String_1_", true, ps -> res("String", "one")); register(h("meta::pure::functions::string::endsWith_String_1__String_1__Boolean_1_", true, ps -> res("Boolean", "one"), ps -> typeOne(ps.get(0), "String")), h("meta::pure::functions::string::endsWith_String_$0_1$__String_1__Boolean_1_", false, ps -> res("Boolean", "one"), ps -> typeZeroOne(ps.get(0), "String"))); register("meta::pure::functions::string::equalIgnoreCase_String_1__String_1__Boolean_1_", false, ps -> res("Boolean", "one")); @@ -2185,6 +2194,12 @@ private GenericType funcReturnType(ValueSpecification vs) return funcType(vs._genericType(), this.pureModel)._returnType(); } + private GenericType funcParamType(ValueSpecification vs, int index) + { + List parameters = FastList.newList(funcType(vs._genericType(), this.pureModel)._parameters()); + return parameters.get(index)._genericType(); + } + private Multiplicity funcReturnMul(ValueSpecification vs) { return funcType(vs._genericType())._returnMultiplicity(); @@ -2620,6 +2635,7 @@ private Map buildDispatch() map.put("meta::pure::functions::date::quarter_Integer_1__Quarter_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "Integer".equals(ps.get(0)._genericType()._rawType()._name()))); map.put("meta::pure::functions::date::second_Date_1__Integer_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Date", "StrictDate", "DateTime", "LatestDate").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::date::today__StrictDate_1_", (List ps) -> ps.size() == 0); + map.put("meta::pure::functions::date::toEpochValue_Date_1__Integer_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil","Date","LatestDate","DateTime","StrictDate","Timestamp").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::date::weekOfYear_Date_$0_1$__Integer_$0_1$_", (List ps) -> ps.size() == 1 && matchZeroOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Date", "StrictDate", "DateTime", "LatestDate").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::date::weekOfYear_Date_1__Integer_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Date", "StrictDate", "DateTime", "LatestDate").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::date::year_Date_$0_1$__Integer_$0_1$_", (List ps) -> ps.size() == 1 && matchZeroOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Date", "StrictDate", "DateTime", "LatestDate").contains(ps.get(0)._genericType()._rawType()._name())); @@ -2737,8 +2753,10 @@ private Map buildDispatch() map.put("meta::pure::functions::string::chunk_String_1__Integer_1__String_MANY_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "Integer".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::string::contains_String_$0_1$__String_1__Boolean_1_", (List ps) -> ps.size() == 2 && matchZeroOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::string::contains_String_1__String_1__Boolean_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name()))); + map.put("meta::pure::functions::string::decodeBase64_String_1__String_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil","String","StringP","Varchar").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::string::decodeUrl_String_1__String_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name()))); map.put("meta::pure::functions::string::decodeUrl_String_1__String_1__String_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name()))); + map.put("meta::pure::functions::string::encodeBase64_String_1__String_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil","String","StringP","Varchar").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::string::encodeUrl_String_1__String_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name()))); map.put("meta::pure::functions::string::encodeUrl_String_1__String_1__String_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::string::endsWith_String_$0_1$__String_1__Boolean_1_", (List ps) -> ps.size() == 2 && matchZeroOne(ps.get(0)._multiplicity()) && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "String".equals(ps.get(0)._genericType()._rawType()._name())) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "String".equals(ps.get(1)._genericType()._rawType()._name()))); @@ -2951,6 +2969,7 @@ private Map buildDispatch() map.put("meta::pure::functions::relation::select_Relation_1__ColSpec_1__Relation_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(ps.get(0)._genericType()._rawType()._name()) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "ColSpec".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::relation::select_Relation_1__ColSpecArray_1__Relation_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(ps.get(0)._genericType()._rawType()._name()) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "ColSpecArray".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::relation::project_C_MANY__FuncColSpecArray_1__Relation_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "FuncColSpecArray".equals(ps.get(1)._genericType()._rawType()._name()))); + map.put("meta::pure::functions::relation::project_Relation_1__FuncColSpecArray_1__Relation_1_", (List ps) -> ps.size() == 2 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil","Relation","RelationElementAccessor","TDS","RelationStoreAccessor","TDSRelationAccessor").contains(ps.get(0)._genericType()._rawType()._name()) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "FuncColSpecArray".equals(ps.get(1)._genericType()._rawType()._name()))); map.put("meta::pure::functions::relation::size_Relation_1__Integer_1_", (List ps) -> ps.size() == 1 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(ps.get(0)._genericType()._rawType()._name())); map.put("meta::pure::functions::relation::pivot_Relation_1__ColSpecArray_1__AggColSpec_1__Relation_1_", (List ps) -> ps.size() == 3 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(ps.get(0)._genericType()._rawType()._name()) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "ColSpecArray".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity()) && ("Nil".equals(ps.get(2)._genericType()._rawType()._name()) || "AggColSpec".equals(ps.get(2)._genericType()._rawType()._name()))); map.put("meta::pure::functions::relation::pivot_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_", (List ps) -> ps.size() == 3 && isOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil", "Relation", "RelationElementAccessor", "TDS", "RelationStoreAccessor").contains(ps.get(0)._genericType()._rawType()._name()) && isOne(ps.get(1)._multiplicity()) && ("Nil".equals(ps.get(1)._genericType()._rawType()._name()) || "ColSpecArray".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity()) && ("Nil".equals(ps.get(2)._genericType()._rawType()._name()) || "AggColSpecArray".equals(ps.get(2)._genericType()._rawType()._name()))); 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/TestDomainCompilationFromGrammar.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/TestDomainCompilationFromGrammar.java index fb3176beec5..d0021ed2e4d 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/TestDomainCompilationFromGrammar.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/TestDomainCompilationFromGrammar.java @@ -905,6 +905,16 @@ public void testMapLambdaInferenceWithPrimitive() "}", "COMPILATION error at [3:23-26]: Can't find a match for function 'plus(Any[2])'"); } + @Test + public void testPairInference() + { + test("Class test::A\n" + + "{\n" + + " p(){pair(1, 'a')}:Pair[1];\n" + + "}" + ); + } + @Test public void testMapLambdaInferenceWithClass() { @@ -1040,6 +1050,15 @@ public void testGroupByLambdaInferenceWithClass() "{\n" + " z(){test::A.all()->groupBy(a|$a.name, agg(x|$x.name, z|$z->count()), ['a', 'b'])}:meta::pure::tds::TabularDataSet[1];\n" + "}"); + test("Class test::A\n" + + "{\n" + + " name : String[1];\n" + + "}\n" + + "\n" + + "Class test::B\n" + + "{\n" + + " z(){agg(x:test::A[1]|$x.name, z:String[1]|$z->count())}:meta::pure::functions::collection::AggregateValue[1];\n" + + "}"); test("Class test::A\n" + "{\n" + " name : String[1];\n" + diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure index f9672ce642a..6fe983a2c87 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/legend/test/handlersTest.pure @@ -97,13 +97,13 @@ Class meta::legend::test::handlers::model::TestMaxMin maxIntegers() {$this.integers->max()}:Integer[0..1]; maxTwoIntegers() {$this.integer->max($this.integer)}:Integer[1]; maxIntegersMinOne() {$this.integersMinOne->max()}:Integer[1]; - + maxDates() {$this.dates->max()}:Date[0..1]; maxTwoDates() {$this.date->max($this.date)}:Date[1]; - + maxStrictDates() {$this.strictDates->max()}:StrictDate[0..1]; maxTwoStrictDates() {$this.strictDate->max($this.strictDate)}:StrictDate[1]; - + maxDateTime() {$this.dateTimes->max()}:DateTime[0..1]; maxTwoDateTime() {$this.dateTime->max($this.dateTime)}:DateTime[1]; @@ -119,13 +119,13 @@ Class meta::legend::test::handlers::model::TestMaxMin minIntegers() {$this.integers->min()}:Integer[0..1]; minTwoIntegers() {$this.integer->min($this.integer)}:Integer[1]; minIntegersMinOne() {$this.integersMinOne->min()}:Integer[1]; - + minDates() {$this.dates->min()}:Date[0..1]; minTwoDates() {$this.date->min($this.date)}:Date[1]; - + minStrictDates() {$this.strictDates->min()}:StrictDate[0..1]; minTwoStrictDates() {$this.strictDate->min($this.strictDate)}:StrictDate[1]; - + minDateTime() {$this.dateTimes->min()}:DateTime[0..1]; minTwoDateTime() {$this.dateTime->min($this.dateTime)}:DateTime[1]; @@ -156,48 +156,48 @@ Class meta::legend::test::handlers::model::TestAlgebra divNumbers() {$this.number/$this.number}:Float[1]; divFloats() {$this.float/$this.float}:Float[1]; divIntegers() {$this.integer/$this.integer}:Float[1]; - + absNumber(){$this.number->abs()}:Number[1]; absFloat(){$this.float->abs()}:Float[1]; absInteger(){$this.integer->abs()}:Integer[1]; - + ceilingNumber(){$this.number->ceiling()}:Number[1]; ceilingFloat(){$this.float->ceiling()}:Number[1]; ceilingInteger(){$this.integer->ceiling()}:Number[1]; - + expNumber(){$this.number->exp()}:Float[1]; - expFloat(){$this.float->exp()}:Float[1]; - expInteger(){$this.integer->exp()}:Float[1]; - + expFloat(){$this.float->exp()}:Float[1]; + expInteger(){$this.integer->exp()}:Float[1]; + floorNumber(){$this.number->floor()}:Integer[1]; floorFloat(){$this.float->floor()}:Integer[1]; floorInteger(){$this.integer->floor()}:Integer[1]; - + logNumber(){$this.number->log()}:Float[1]; logFloat(){$this.float->log()}:Float[1]; logInteger(){$this.integer->log()}:Float[1]; log10Number(){$this.number->log10()}:Float[1]; log10Float(){$this.float->log10()}:Float[1]; - log10Integer(){$this.integer->log10()}:Float[1]; + log10Integer(){$this.integer->log10()}:Float[1]; mod(){$this.integer->mod($this.integer)}:Integer[1]; pow(){$this.number->pow($this.number)}:Number[1]; rem(){$this.number->rem($this.number)}:Number[1]; - + roundNumber(){$this.number->round()}:Integer[1]; roundFloat(){$this.float->round()}:Integer[1]; roundInteger(){$this.integer->round()}:Integer[1]; sign(){$this.integer->sign()}:Integer[1]; - + sqrtNumber(){$this.number->sqrt()}:Float[1]; sqrtFloat(){$this.float->sqrt()}:Float[1]; sqrtInteger(){$this.integer->sqrt()}:Float[1]; cbrtNumber(){$this.number->cbrt()}:Float[1]; cbrtFloat(){$this.float->cbrt()}:Float[1]; - cbrtInteger(){$this.integer->cbrt()}:Float[1]; + cbrtInteger(){$this.integer->cbrt()}:Float[1]; } Class meta::legend::test::handlers::model::TestAggregation @@ -231,7 +231,7 @@ Class meta::legend::test::handlers::model::Trigo cotNumber() {$this.number->cot()}:Float[1]; cotFloat() {$this.float->cot()}:Float[1]; - cotInteger() {$this.integer->cot()}:Float[1]; + cotInteger() {$this.integer->cot()}:Float[1]; sinNumber() {$this.number->sin()}:Float[1]; sinFloat() {$this.float->sin()}:Float[1]; @@ -244,21 +244,21 @@ Class meta::legend::test::handlers::model::Trigo acosNumber() {$this.number->acos()}:Float[1]; acosFloat() {$this.float->acos()}:Float[1]; acosInteger() {$this.integer->acos()}:Float[1]; - + asinNumber() {$this.number->asin()}:Float[1]; asinFloat() {$this.float->asin()}:Float[1]; asinInteger() {$this.integer->asin()}:Float[1]; - + atanNumber() {$this.number->atan()}:Float[1]; atanFloat() {$this.float->atan()}:Float[1]; atanInteger() {$this.integer->atan()}:Float[1]; - + atan2NumberNumber() {$this.number->atan2($this.number)}:Float[1]; atan2FloatFloat() {$this.float->atan2($this.float)}:Float[1]; atan2FloatInteger() {$this.float->atan2($this.integer)}:Float[1]; atan2IntegerInteger() {$this.integer->atan2($this.integer)}:Float[1]; atan2IntegerFloat() {$this.integer->atan2($this.float)}:Float[1]; - + toDegreeNumber(){$this.number->toDegrees()}:Float[1]; toDegreeFloat(){$this.float->toDegrees()}:Float[1]; toDegreeInteger(){$this.integer->toDegrees()}:Float[1]; @@ -266,7 +266,7 @@ Class meta::legend::test::handlers::model::Trigo toRadianNumber(){$this.number->toRadians()}:Float[1]; toRadianFloat(){$this.float->toRadians()}:Float[1]; toRadianInteger(){$this.integer->toRadians()}:Float[1]; - + pi(){pi()}:Float[1]; earthRadius(){earthRadius()}:Float[1]; @@ -288,20 +288,22 @@ Class meta::legend::test::handlers::model::TestString char(){$this.integer->char()}:String[1]; plus() {$this.string+$this.string}:String[1]; - + containsZeroOne() {$this.stringZeroOne->contains($this.string)}:Boolean[1]; containsOne() {$this.string->contains($this.string)}:Boolean[1]; - + decodeBase64() {$this.string->decodeBase64()}:String[1]; + + encodeBase64() {$this.string->decodeBase64()}:String[1]; endsWithZeroOne() {$this.stringZeroOne->endsWith($this.string)}:Boolean[1]; endsWithOne() {$this.string->endsWith($this.string)}:Boolean[1]; - + equalIgnoreCase() {$this.string->equalIgnoreCase($this.string)}:Boolean[1]; - + humanize() {$this.string->humanize()}:String[1]; isUpperCase() {$this.string->isUpperCase()}:Boolean[1]; isLowerCase() {$this.string->isLowerCase()}:Boolean[1]; - + joinStrings() {$this.strings->joinStrings()}:String[1]; joinStringsSep() {$this.strings->joinStrings($this.string)}:String[1]; @@ -309,12 +311,12 @@ Class meta::legend::test::handlers::model::TestString makeCamelCaseParam() {$this.string->makeCamelCase(true)}:String[1]; makeCamelCase() {$this.string->makeCamelCase()}:String[1]; - + makeString(){$this.strings->makeString()}:String[1]; makeStringSep(){$this.strings->makeString($this.string)}:String[1]; makeStringPreSepSuff(){$this.strings->makeString($this.string, $this.string, $this.string)}:String[1]; // makeStringPairs(){makeString([pair($this.string,$this.string),pair($this.string,$this.string)])}:String[1]; - + splitOnCamelCase(){$this.string->splitOnCamelCase()}:String[*]; substringAfter(){$this.string->substringAfter($this.string)}:String[1]; @@ -323,24 +325,24 @@ Class meta::legend::test::handlers::model::TestString chunk(){$this.string->chunk(10)}:String[*]; format(){$this.string->format([1,2])}:String[*]; - + indexOf(){indexOf($this.string, $this.string)}:Integer[1]; indexOfFromIndex(){indexOf($this.string, $this.string, 10)}:Integer[1]; - + length(){$this.string->length()}:Integer[1]; ltrim(){$this.string->ltrim()}:String[1]; lpad(){$this.string->lpad(1)}:String[1]; - lpad2(){$this.string->lpad(1, '0')}:String[1]; + lpad2(){$this.string->lpad(1, '0')}:String[1]; rpad(){$this.string->rpad(1)}:String[1]; rpad2(){$this.string->rpad(1, '0')}:String[1]; left(){$this.string->left(1)}:String[1]; right(){$this.string->right(1)}:String[1]; - + parseBoolean(){$this.string->parseBoolean()}:Boolean[1]; parseDate(){$this.string->parseDate()}:Date[1]; parseFloat(){$this.string->parseFloat()}:Float[1]; parseInteger(){$this.string->parseInteger()}:Integer[1]; - + repeatString(){$this.string->repeatString(2)}:String[0..1]; replace(){$this.string->replace($this.string, $this.string)}:String[1]; reverseString(){$this.string->reverseString()}:String[1]; @@ -367,14 +369,14 @@ Class meta::legend::test::handlers::model::TestDate dateTime_ZeroOne : DateTime[0..1]; strictDate : StrictDate[1]; strictDate_ZeroOne : StrictDate[0..1]; - + dateDiff(){$this.date->dateDiff($this.date, DurationUnit.YEARS)+ $this.dateTime->dateDiff($this.dateTime, DurationUnit.YEARS)+ $this.strictDate->dateDiff($this.strictDate, DurationUnit.YEARS)+ $this.date_ZeroOne->dateDiff($this.date_ZeroOne, DurationUnit.YEARS)->toOne()+ $this.dateTime_ZeroOne->dateDiff($this.dateTime_ZeroOne, DurationUnit.YEARS)->toOne()+ $this.strictDate_ZeroOne->dateDiff($this.strictDate_ZeroOne, DurationUnit.YEARS)->toOne()}:Integer[1]; - + datePart(){[$this.date->datePart(), $this.dateTime->datePart(), $this.strictDate->datePart(), @@ -401,7 +403,7 @@ Class meta::legend::test::handlers::model::TestDate }:Date[*]; hasYear(){$this.date->hasYear() && $this.dateTime->hasYear() && $this.strictDate->hasYear()}:Boolean[1]; - + isAfterDay(){$this.date_ZeroOne->isAfterDay($this.date_ZeroOne) && $this.date_ZeroOne->isAfterDay($this.date) && $this.date->isAfterDay($this.date_ZeroOne) && $this.date->isAfterDay($this.date) && $this.dateTime_ZeroOne->isAfterDay($this.dateTime_ZeroOne) && $this.dateTime_ZeroOne->isAfterDay($this.dateTime) && $this.dateTime->isAfterDay($this.dateTime_ZeroOne) && $this.dateTime->isAfterDay($this.dateTime) && $this.strictDate_ZeroOne->isAfterDay($this.strictDate_ZeroOne) && $this.strictDate_ZeroOne->isAfterDay($this.strictDate) && $this.strictDate->isAfterDay($this.strictDate_ZeroOne) && $this.strictDate->isAfterDay($this.strictDate) @@ -472,6 +474,8 @@ Class meta::legend::test::handlers::model::TestDate }:Integer[1]; pointInTime(){[now(),today()]}:Date[*]; + + toEpochValue(){ $this.date->toEpochValue() + $this.date->toEpochValue(DurationUnit.DAYS)}:Integer[1]; } function <> meta::legend::test::handlers::testAlloyHandlers():Boolean[1] diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure index 409fc7c50f7..955c29ad756 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/protocol/vX_X_X/transfers/valueSpecification.pure @@ -81,7 +81,7 @@ function meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpec _type = 'property', property = $fe.func.name->toOne()->cast(@String), parameters = $fe.parametersValues->evaluateAndDeactivate()->map(pm|$pm->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformValueSpecification($inScope, $open, false, $extensions)) - ), + ), f:Function[1]| let passToTransformAny = [ @@ -338,7 +338,7 @@ function <> meta::protocols::pure::vX_X_X::transformation::fromP value = $c.name->transformColSpec() );, c:meta::pure::metamodel::relation::ColSpecArray[1]| - + ^meta::protocols::pure::vX_X_X::metamodel::valueSpecification::ClassInstance ( _type = 'classInstance', @@ -382,7 +382,7 @@ function <> meta::protocols::pure::vX_X_X::transformation::fromP colSpecs = $a.aggSpecs->map(c|$c->transformAggColSpec($extensions)) ) );, - + r:meta::pure::store::RelationStoreAccessor[1]| ^meta::protocols::pure::vX_X_X::metamodel::valueSpecification::ClassInstance ( @@ -1019,6 +1019,8 @@ function meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGra a :meta::protocols::pure::vX_X_X::metamodel::valueSpecification::raw::Whatever[1]|fail('Unsupported type in alloy protocol ' + $a.class);'';, r : RuntimeInstance[1]|'', e : ExecutionContextInstance[1]|'', + c : meta::protocols::pure::vX_X_X::metamodel::relation::ColSpecArray[1] | '~[%s]'->format($c.colSpecs->map(c | $c->colSpecToPure(true, $state))->joinStrings(', ')), + c : meta::protocols::pure::vX_X_X::metamodel::relation::ColSpec[1] | $c->colSpecToPure(false, $state), pv : meta::protocols::pure::vX_X_X::metamodel::valueSpecification::raw::Pair[1]| let tMatcher = {val:meta::protocols::pure::vX_X_X::metamodel::m3::valuespecification::ValueSpecification[1]| $val->match([ x : EnumValue[1]| $x.fullPath, @@ -1047,6 +1049,19 @@ function meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGra )->joinStrings('', ';\n', if($vs->size() <= 1, | '', | ';')); } +function <> meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::colSpecToPure(c:meta::protocols::pure::vX_X_X::metamodel::relation::ColSpec[1], inArray:Boolean[1], state : AlloyToPureState[1]):String[1] +{ + let name = if($c.name->contains(' '),|'\''+$c.name+'\'',|$c.name); + + let prefix = if ($inArray, | '', | '~'); + + if ($c.function1->isEmpty(), + | '%s%s'->format([$prefix, $name]), + | if ($c.function2->isEmpty(), + | '%s%s : %s'->format([$prefix, $name, toPure($state, $c.function1->toOne())]), + | '%s%s : %s : %s'->format([$prefix, $name, toPure($state, $c.function1->toOne()), toPure($state, $c.function2->toOne())]))); +} + function <> meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::mapToString(m : meta::protocols::pure::vX_X_X::metamodel::m3::multiplicity::Multiplicity[1]):String[1] { [ diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-functions-relation-pure/src/main/resources/core_functions_relation/relation/functions/graph/project.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-functions-relation-pure/src/main/resources/core_functions_relation/relation/functions/graph/project.pure index 5a2c7caca5d..9791456689c 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-functions-relation-pure/src/main/resources/core_functions_relation/relation/functions/graph/project.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-functions-relation-pure/src/main/resources/core_functions_relation/relation/functions/graph/project.pure @@ -17,6 +17,7 @@ import meta::pure::metamodel::relation::*; import meta::pure::functions::relation::tests::project::*; native function <> meta::pure::functions::relation::project(cl:C[*], x:FuncColSpecArray<{C[1]->Any[*]},T>[1]):Relation[1]; +native function <> meta::pure::functions::relation::project(r:Relation[1], fs:FuncColSpecArray<{T[1]->Any[*]},Z>[1]):Relation[1]; Class meta::pure::functions::relation::tests::project::Address { @@ -152,3 +153,31 @@ function <> meta::pure::functions::relation::tests::project::testSimpl ' ok,other,null\n'+ '#', $res->toString()); } + + +function <> meta::pure::functions::relation::tests::project::testSimpleRelationProject(f:Function<{Function<{->T[m]}>[1]->T[m]}>[1]):Boolean[1] +{ + let expr = { + |#TDS + val, str + 1, a + 3, ewe + 4, qw + 5, wwe + 6, weq + #->project(~[ + name:c|$c.str->toOne() + $c.val->toOne()->toString() + ]) + }; + + let res = $f->eval($expr); + + assertEquals( '#TDS\n'+ + ' name\n'+ + ' a1\n'+ + ' ewe3\n'+ + ' qw4\n'+ + ' wwe5\n'+ + ' weq6\n'+ + '#', $res->toString()); +} diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationExtensionCompiled.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationExtensionCompiled.java index b94f7db3e46..2d79cc930f0 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationExtensionCompiled.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationExtensionCompiled.java @@ -66,6 +66,7 @@ public List getExtraNatives() new Sort(), new Rename(), new Project(), + new ProjectRelation(), new GroupBy(), new GroupByArray(), new Pivot(), diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationNativeImplementation.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationNativeImplementation.java index cbd9e674f06..6208b870e17 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationNativeImplementation.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/RelationNativeImplementation.java @@ -26,6 +26,7 @@ import org.eclipse.collections.api.set.MutableSet; import org.eclipse.collections.api.set.primitive.MutableIntSet; import org.eclipse.collections.api.tuple.Pair; +import org.eclipse.collections.impl.list.mutable.FastList; import org.eclipse.collections.impl.set.mutable.primitive.IntHashSet; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.LambdaFunction; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.*; @@ -267,11 +268,13 @@ public Object eval(Object partition, Object frame, Object row, ExecutionSupport } } - public static Relation extend(Relation rel, MutableList colFuncSpecTrans, ExecutionSupport es) + public static Relation projectExtend(Relation rel, MutableList colFuncSpecTrans, boolean includeExistingColumns, ExecutionSupport es) { ProcessorSupport ps = ((CompiledExecutionSupport) es).getProcessorSupport(); TestTDSCompiled tds = RelationNativeImplementation.getTDS(rel); - return new TDSContainer((TestTDSCompiled) colFuncSpecTrans.injectInto((TestTDS) tds, (accTDS, colFuncSpec) -> accTDS.addColumn(performExtend(new Window(), tds.wrapFullTDS(), colFuncSpec, es))), ps); + TestTDSCompiled target = includeExistingColumns ? tds : (TestTDSCompiled) tds.removeColumns(tds.getColumnNames().toSet()); + + return new TDSContainer((TestTDSCompiled) colFuncSpecTrans.injectInto((TestTDS) target, (accTDS, colFuncSpec) -> accTDS.addColumn(performExtend(new Window(), tds.wrapFullTDS(), colFuncSpec, es))), ps); } public static Relation extendAgg(Relation rel, MutableList aggColSpecTrans, ExecutionSupport es) diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/Extend.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/Extend.java index 3927cc492db..820f6874740 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/Extend.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/Extend.java @@ -31,16 +31,17 @@ public Extend() @Override public String build(CoreInstance topLevelElement, CoreInstance functionExpression, ListIterable transformedParams, ProcessorContext processorContext) { - StringBuilder result = buildCode(transformedParams, s -> "Lists.mutable.with(" + transformedParams.get(1) + ")"); + StringBuilder result = buildCode(transformedParams, s -> "Lists.mutable.with(" + transformedParams.get(1) + ")", true); return result.toString(); } - static StringBuilder buildCode(ListIterable transformedParams, Function collection) + static StringBuilder buildCode(ListIterable transformedParams, Function collection, boolean includeExistingColumns) { - StringBuilder result = new StringBuilder("org.finos.legend.pure.runtime.java.extension.external.relation.compiled.RelationNativeImplementation.extend("); + StringBuilder result = new StringBuilder("org.finos.legend.pure.runtime.java.extension.external.relation.compiled.RelationNativeImplementation.projectExtend("); result.append(transformedParams.get(0) + ", "); result.append(collection.valueOf(transformedParams.get(1))); buildCollectFuncSpec(result, false); + result.append(", " + includeExistingColumns); result.append(", es)"); return result; } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ExtendArray.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ExtendArray.java index d407e1b4e9c..1200f020941 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ExtendArray.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ExtendArray.java @@ -30,7 +30,7 @@ public ExtendArray() @Override public String build(CoreInstance topLevelElement, CoreInstance functionExpression, ListIterable transformedParams, ProcessorContext processorContext) { - StringBuilder result = Extend.buildCode(transformedParams, s -> "Lists.mutable.withAll(" + transformedParams.get(1) + "._funcSpecs())"); + StringBuilder result = Extend.buildCode(transformedParams, s -> "Lists.mutable.withAll(" + transformedParams.get(1) + "._funcSpecs())", true); return result.toString(); } } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ProjectRelation.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ProjectRelation.java new file mode 100644 index 00000000000..418d7d9c767 --- /dev/null +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-compiled-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/compiled/natives/ProjectRelation.java @@ -0,0 +1,36 @@ +// Copyright 2025 Goldman Sachs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.finos.legend.pure.runtime.java.extension.external.relation.compiled.natives; + +import org.eclipse.collections.api.list.ListIterable; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.compiled.generation.ProcessorContext; +import org.finos.legend.pure.runtime.java.compiled.generation.processors.natives.AbstractNative; +import org.finos.legend.pure.runtime.java.compiled.generation.processors.natives.Native; + +public class ProjectRelation extends AbstractNative implements Native +{ + public ProjectRelation() + { + super("project_Relation_1__FuncColSpecArray_1__Relation_1_"); + } + + @Override + public String build(CoreInstance topLevelElement, CoreInstance functionExpression, ListIterable transformedParams, ProcessorContext processorContext) + { + StringBuilder result = Extend.buildCode(transformedParams, s -> "Lists.mutable.withAll(" + transformedParams.get(1) + "._funcSpecs())", false); + return result.toString(); + } +} diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/RelationExtensionInterpreted.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/RelationExtensionInterpreted.java index b48d6c2113e..550f516cd34 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/RelationExtensionInterpreted.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/RelationExtensionInterpreted.java @@ -47,6 +47,7 @@ import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.PercentRank; import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.Pivot; import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.Project; +import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.ProjectRelation; import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.Rank; import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.Rename; import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.RowNumber; @@ -105,6 +106,7 @@ public RelationExtensionInterpreted() Tuples.pair("pivot_Relation_1__ColSpec_1__AggColSpecArray_1__Relation_1_", Pivot::new), Tuples.pair("pivot_Relation_1__ColSpec_1__AggColSpec_1__Relation_1_", Pivot::new), Tuples.pair("project_C_MANY__FuncColSpecArray_1__Relation_1_", Project::new), + Tuples.pair("project_Relation_1__FuncColSpecArray_1__Relation_1_", ProjectRelation::new), Tuples.pair("columns_Relation_1__Column_MANY_", Columns::new), Tuples.pair("select_Relation_1__Relation_1_", Select::new), Tuples.pair("select_Relation_1__ColSpec_1__Relation_1_", Select::new), diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/Extend.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/Extend.java index ceed040c42d..d4d083a171a 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/Extend.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/Extend.java @@ -14,244 +14,14 @@ package org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives; -import io.deephaven.csv.parsers.DataType; -import org.eclipse.collections.api.block.procedure.Procedure2; -import org.eclipse.collections.api.list.FixedSizeList; -import org.eclipse.collections.api.list.ListIterable; -import org.eclipse.collections.api.list.MutableList; -import org.eclipse.collections.api.map.MutableMap; -import org.eclipse.collections.api.stack.MutableStack; -import org.eclipse.collections.api.tuple.Pair; -import org.eclipse.collections.impl.factory.Lists; -import org.finos.legend.pure.m3.compiler.Context; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.LambdaFunction; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.LambdaFunctionCoreInstanceWrapper; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.AggColSpec; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.AggColSpecArray; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.FuncColSpec; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.FuncColSpecArray; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.relation.RelationType; -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.coreinstance.meta.pure.metamodel.type.generics.GenericType; -import org.finos.legend.pure.m3.exception.PureExecutionException; -import org.finos.legend.pure.m3.navigation.*; -import org.finos.legend.pure.m3.navigation._package._Package; import org.finos.legend.pure.m4.ModelRepository; -import org.finos.legend.pure.m4.coreinstance.CoreInstance; -import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.shared.AggregationShared; -import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.shared.TDSCoreInstance; -import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.shared.TDSWithCursorCoreInstance; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.ColumnValue; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.Frame; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.FrameType; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.SortDirection; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.SortInfo; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.TestTDS; -import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.Window; -import org.finos.legend.pure.runtime.java.interpreted.ExecutionSupport; +import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.shared.ProjectExtend; import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; -import org.finos.legend.pure.runtime.java.interpreted.VariableContext; -import org.finos.legend.pure.runtime.java.interpreted.natives.InstantiationContext; -import org.finos.legend.pure.runtime.java.interpreted.profiler.Profiler; -import java.util.Arrays; -import java.util.Stack; - -public class Extend extends AggregationShared +public class Extend extends ProjectExtend { public Extend(FunctionExecutionInterpreted functionExecution, ModelRepository repository) { - super(functionExecution, repository); - } - - @Override - public CoreInstance execute(ListIterable params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException - { - try - { - CoreInstance returnGenericType = getReturnGenericType(resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, processorSupport); - - TestTDS tds = getTDS(params, 0, processorSupport); - - RelationType relationType = getRelationType(params, 0); - GenericType sourceRelationType = (GenericType) params.get(0).getValueForMetaPropertyToOne("genericType"); - - CoreInstance secondParameter = Instance.getValueForMetaPropertyToOneResolved(params.get(1), M3Properties.values, processorSupport); - - TestTDS result; - if (secondParameter instanceof FuncColSpec) - { - result = tds.addColumn(processFuncColSpec(tds.wrapFullTDS(), new Window(new Frame(FrameType.rows, true, true)), (FuncColSpec) secondParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, (GenericType) params.get(0).getValueForMetaPropertyToOne("genericType"), false)); - } - else if (secondParameter instanceof FuncColSpecArray) - { - result = ((FuncColSpecArray) secondParameter)._funcSpecs().injectInto( - tds, - (a, funcColSpec) -> a.addColumn(processFuncColSpec(tds.wrapFullTDS(), new Window(new Frame(FrameType.rows, true, true)), funcColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, false)) - ); - } - else if (secondParameter instanceof AggColSpec) - { - Pair>> source = tds.wrapFullTDS(); - result = tds.addColumn(processOneAggColSpec(source, new Window(new Frame(FrameType.rows, true, true)), (AggColSpec) secondParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, false, null)); - } - else if (secondParameter instanceof AggColSpecArray) - { - Pair>> source = tds.wrapFullTDS(); - result = ((AggColSpecArray) secondParameter)._aggSpecs().injectInto( - source.getOne(), - (a, aggColSpec) -> a.addColumn(processOneAggColSpec(source, new Window(new Frame(FrameType.rows, true, true)), aggColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, false, null)) - ); - } - else if (Instance.instanceOf(secondParameter, "meta::pure::functions::relation::_Window", processorSupport)) - { - MutableList partitionIds = secondParameter.getValueForMetaPropertyToMany("partition").collect(PrimitiveUtilities::getStringValue).toList(); - Pair>> source = partitionIds.isEmpty() ? tds.wrapFullTDS() : tds.sort(partitionIds.collect(c -> new SortInfo(c, SortDirection.ASC))); - - ListIterable sortInfos = secondParameter.getValueForMetaPropertyToMany("sortInfo"); - final Pair>> sortedPartitions = TestTDS.sortPartitions(Sort.getSortInfos(sortInfos, processorSupport).toList(), source); - - Window window = Window.build(secondParameter, processorSupport); - - CoreInstance thirdParameter = Instance.getValueForMetaPropertyToOneResolved(params.get(2), M3Properties.values, processorSupport); - if (thirdParameter instanceof AggColSpec) - { - result = sortedPartitions.getOne().addColumn(processOneAggColSpec(sortedPartitions, window, (AggColSpec) thirdParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, true, sourceRelationType)); - } - else if (thirdParameter instanceof AggColSpecArray) - { - result = ((AggColSpecArray) thirdParameter)._aggSpecs().injectInto( - sortedPartitions.getOne(), - (a, aggColSpec) -> a.addColumn(processOneAggColSpec(sortedPartitions, window, aggColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, true, sourceRelationType)) - ); - } - else if (thirdParameter instanceof FuncColSpec) - { - result = sortedPartitions.getOne().addColumn(processFuncColSpec(sortedPartitions, window, (FuncColSpec) thirdParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, true)); - } - else if (thirdParameter instanceof FuncColSpecArray) - { - result = ((FuncColSpecArray) thirdParameter)._funcSpecs().injectInto( - sortedPartitions.getOne(), - (a, funcColSpec) -> a.addColumn(processFuncColSpec(sortedPartitions, window, funcColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, true)) - ); - } - else - { - throw new RuntimeException("Not possible"); - } - } - else - { - throw new RuntimeException("Not possible"); - } - return ValueSpecificationBootstrap.wrapValueSpecification(new TDSCoreInstance(result, returnGenericType, repository, processorSupport), false, processorSupport); - } - catch (Exception e) - { - e.printStackTrace(); - throw e; - } - } - - private ColumnValue processFuncColSpec(Pair>> source, Window window, FuncColSpec funcColSpec, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, ProcessorSupport processorSupport, GenericType relationType, boolean twoParamsFunc) - { - LambdaFunction lambdaFunction = (LambdaFunction) LambdaFunctionCoreInstanceWrapper.toLambdaFunction(funcColSpec.getValueForMetaPropertyToOne(M3Properties.function)); - String name = funcColSpec.getValueForMetaPropertyToOne(M3Properties.name).getName(); - - VariableContext evalVarContext = this.getParentOrEmptyVariableContextForLambda(variableContext, lambdaFunction); - - Type type = ((FunctionType) lambdaFunction._classifierGenericType()._typeArguments().getFirst()._rawType())._returnType()._rawType(); - - if (type == _Package.getByUserPath("String", processorSupport)) - { - String[] finalRes = new String[(int) source.getOne().getRowCount()]; - processOneColumn(source, window, lambdaFunction, (j, val) -> finalRes[j] = val == null ? null : PrimitiveUtilities.getStringValue(val), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); - return new ColumnValue(name, DataType.STRING, finalRes); - } - else if (type == _Package.getByUserPath("Integer", processorSupport)) - { - int[] finalRes = new int[(int) source.getOne().getRowCount()]; - boolean[] nulls = new boolean[(int) source.getOne().getRowCount()]; - Arrays.fill(nulls, Boolean.FALSE); - processOneColumn(source, window, lambdaFunction, (j, val) -> processWithNull(j, val, nulls, () -> finalRes[j] = PrimitiveUtilities.getIntegerValue(val).intValue()), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); - return new ColumnValue(name, DataType.INT, finalRes, nulls); - } - else if (type == _Package.getByUserPath("Float", processorSupport)) - { - double[] finalRes = new double[(int) source.getOne().getRowCount()]; - boolean[] nulls = new boolean[(int) source.getOne().getRowCount()]; - Arrays.fill(nulls, Boolean.FALSE); - processOneColumn(source, window, lambdaFunction, (j, val) -> processWithNull(j, val, nulls, () -> finalRes[j] = PrimitiveUtilities.getFloatValue(val).doubleValue()), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); - return new ColumnValue(name, DataType.DOUBLE, finalRes, nulls); - } - else - { - throw new RuntimeException("The type " + type._name() + " is not supported yet!"); - } - } - - private interface Proc - { - void invoke(); - } - - private void processWithNull(Integer j, CoreInstance val, boolean[] nulls, Proc p) - { - { - if (val == null) - { - nulls[j] = true; - } - else - { - p.invoke(); - } - } - } - - private void processOneColumn(Pair>> source, Window window, LambdaFunction lambdaFunction, Procedure2 setter, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, ProcessorSupport processorSupport, GenericType relationType, VariableContext evalVarContext, boolean twoParamsFunc) - { - FixedSizeList parameters = twoParamsFunc ? Lists.fixedSize.with((CoreInstance) null, (CoreInstance) null, (CoreInstance) null) : Lists.fixedSize.with((CoreInstance) null); - int k = 0; - for (int j = 0; j < source.getTwo().size(); j++) - { - Pair r = source.getTwo().get(j); - TestTDS sourceTDS = source.getOne().slice(r.getOne(), r.getTwo()); - for (int i = 0; i < r.getTwo() - r.getOne(); i++) - { - if (twoParamsFunc) - { - parameters.set(0, ValueSpecificationBootstrap.wrapValueSpecification(new TDSCoreInstance(sourceTDS, relationType, repository, processorSupport), false, processorSupport)); - parameters.set(1, ValueSpecificationBootstrap.wrapValueSpecification(window.convert(processorSupport, new RepoPrimitiveBuilder(repository)), false, processorSupport)); - } - parameters.set(twoParamsFunc ? 2 : 0, ValueSpecificationBootstrap.wrapValueSpecification(new TDSWithCursorCoreInstance(source.getOne(), i, "", null, relationType, -1, repository, false), false, processorSupport)); - CoreInstance newValue = this.functionExecution.executeFunction(false, lambdaFunction, parameters, resolvedTypeParameters, resolvedMultiplicityParameters, evalVarContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport); - setter.value(k++, newValue.getValueForMetaPropertyToOne("values")); - } - } - } - - public static class RepoPrimitiveBuilder implements Frame.PrimitiveBuilder - { - private ModelRepository repository; - - public RepoPrimitiveBuilder(ModelRepository repository) - { - this.repository = repository; - } - - @Override - public CoreInstance build(String val) - { - return this.repository.newStringCoreInstance(val); - } - - @Override - public CoreInstance build(int val) - { - return this.repository.newIntegerCoreInstance(val); - } + super(true, functionExecution, repository); } } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/ProjectRelation.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/ProjectRelation.java new file mode 100644 index 00000000000..a0cc5931d26 --- /dev/null +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/ProjectRelation.java @@ -0,0 +1,27 @@ +// Copyright 2025 Goldman Sachs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives; + +import org.finos.legend.pure.m4.ModelRepository; +import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.shared.ProjectExtend; +import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted; + +public class ProjectRelation extends ProjectExtend +{ + public ProjectRelation(FunctionExecutionInterpreted functionExecution, ModelRepository repository) + { + super(false, functionExecution, repository); + } +} diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/shared/AggregationShared.java b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/shared/AggregationShared.java index 39d1c827246..f017b914734 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/shared/AggregationShared.java +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-relation/legend-engine-pure-runtime-java-extension-interpreted-functions-relation/src/main/java/org/finos/legend/pure/runtime/java/extension/external/relation/interpreted/natives/shared/AggregationShared.java @@ -38,7 +38,6 @@ import org.finos.legend.pure.m3.navigation._package._Package; import org.finos.legend.pure.m4.ModelRepository; import org.finos.legend.pure.m4.coreinstance.CoreInstance; -import org.finos.legend.pure.runtime.java.extension.external.relation.interpreted.natives.Extend; import org.finos.legend.pure.runtime.java.extension.external.relation.shared.ColumnValue; import org.finos.legend.pure.runtime.java.extension.external.relation.shared.TestTDS; import org.finos.legend.pure.runtime.java.extension.external.relation.shared.window.Window; @@ -111,7 +110,7 @@ protected void performAggregation(Pair params, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, Context context, ProcessorSupport processorSupport) throws PureExecutionException + { + try + { + CoreInstance returnGenericType = getReturnGenericType(resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, processorSupport); + + TestTDS tds = getTDS(params, 0, processorSupport); + + TestTDS targetTds = this.includeExistingColumns ? tds : tds.removeColumns(tds.getColumnNames().toSet()); + + RelationType relationType = getRelationType(params, 0); + GenericType sourceRelationType = (GenericType) params.get(0).getValueForMetaPropertyToOne("genericType"); + + CoreInstance secondParameter = Instance.getValueForMetaPropertyToOneResolved(params.get(1), M3Properties.values, processorSupport); + + TestTDS result; + if (secondParameter instanceof FuncColSpec) + { + result = targetTds.addColumn(processFuncColSpec(tds.wrapFullTDS(), new Window(new Frame(FrameType.rows, true, true)), (FuncColSpec) secondParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, (GenericType) params.get(0).getValueForMetaPropertyToOne("genericType"), false)); + } + else if (secondParameter instanceof FuncColSpecArray) + { + result = ((FuncColSpecArray) secondParameter)._funcSpecs().injectInto( + targetTds, + (a, funcColSpec) -> a.addColumn(processFuncColSpec(tds.wrapFullTDS(), new Window(new Frame(FrameType.rows, true, true)), funcColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, false)) + ); + } + else if (secondParameter instanceof AggColSpec) + { + Pair>> source = tds.wrapFullTDS(); + result = targetTds.addColumn(processOneAggColSpec(source, new Window(new Frame(FrameType.rows, true, true)), (AggColSpec) secondParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, false, null)); + } + else if (secondParameter instanceof AggColSpecArray) + { + Pair>> source = tds.wrapFullTDS(); + result = ((AggColSpecArray) secondParameter)._aggSpecs().injectInto( + targetTds, + (a, aggColSpec) -> a.addColumn(processOneAggColSpec(source, new Window(new Frame(FrameType.rows, true, true)), aggColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, false, null)) + ); + } + else if (Instance.instanceOf(secondParameter, "meta::pure::functions::relation::_Window", processorSupport)) + { + MutableList partitionIds = secondParameter.getValueForMetaPropertyToMany("partition").collect(PrimitiveUtilities::getStringValue).toList(); + Pair>> source = partitionIds.isEmpty() ? tds.wrapFullTDS() : tds.sort(partitionIds.collect(c -> new SortInfo(c, SortDirection.ASC))); + + ListIterable sortInfos = secondParameter.getValueForMetaPropertyToMany("sortInfo"); + final Pair>> sortedPartitions = TestTDS.sortPartitions(Sort.getSortInfos(sortInfos, processorSupport).toList(), source); + + Window window = Window.build(secondParameter, processorSupport); + + CoreInstance thirdParameter = Instance.getValueForMetaPropertyToOneResolved(params.get(2), M3Properties.values, processorSupport); + if (thirdParameter instanceof AggColSpec) + { + result = sortedPartitions.getOne().addColumn(processOneAggColSpec(sortedPartitions, window, (AggColSpec) thirdParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, true, sourceRelationType)); + } + else if (thirdParameter instanceof AggColSpecArray) + { + result = ((AggColSpecArray) thirdParameter)._aggSpecs().injectInto( + sortedPartitions.getOne(), + (a, aggColSpec) -> a.addColumn(processOneAggColSpec(sortedPartitions, window, aggColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, false, true, sourceRelationType)) + ); + } + else if (thirdParameter instanceof FuncColSpec) + { + result = sortedPartitions.getOne().addColumn(processFuncColSpec(sortedPartitions, window, (FuncColSpec) thirdParameter, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, true)); + } + else if (thirdParameter instanceof FuncColSpecArray) + { + result = ((FuncColSpecArray) thirdParameter)._funcSpecs().injectInto( + sortedPartitions.getOne(), + (a, funcColSpec) -> a.addColumn(processFuncColSpec(sortedPartitions, window, funcColSpec, resolvedTypeParameters, resolvedMultiplicityParameters, variableContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, sourceRelationType, true)) + ); + } + else + { + throw new RuntimeException("Not possible"); + } + } + else + { + throw new RuntimeException("Not possible"); + } + return ValueSpecificationBootstrap.wrapValueSpecification(new TDSCoreInstance(result, returnGenericType, repository, processorSupport), false, processorSupport); + } + catch (Exception e) + { + e.printStackTrace(); + throw e; + } + } + + private ColumnValue processFuncColSpec(Pair>> source, Window window, FuncColSpec funcColSpec, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, VariableContext variableContext, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, ProcessorSupport processorSupport, GenericType relationType, boolean twoParamsFunc) + { + LambdaFunction lambdaFunction = (LambdaFunction) LambdaFunctionCoreInstanceWrapper.toLambdaFunction(funcColSpec.getValueForMetaPropertyToOne(M3Properties.function)); + String name = funcColSpec.getValueForMetaPropertyToOne(M3Properties.name).getName(); + + VariableContext evalVarContext = this.getParentOrEmptyVariableContextForLambda(variableContext, lambdaFunction); + + Type type = ((FunctionType) lambdaFunction._classifierGenericType()._typeArguments().getFirst()._rawType())._returnType()._rawType(); + + if (type == _Package.getByUserPath("String", processorSupport)) + { + String[] finalRes = new String[(int) source.getOne().getRowCount()]; + processOneColumn(source, window, lambdaFunction, (j, val) -> finalRes[j] = val == null ? null : PrimitiveUtilities.getStringValue(val), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); + return new ColumnValue(name, DataType.STRING, finalRes); + } + else if (type == _Package.getByUserPath("Integer", processorSupport)) + { + int[] finalRes = new int[(int) source.getOne().getRowCount()]; + boolean[] nulls = new boolean[(int) source.getOne().getRowCount()]; + Arrays.fill(nulls, Boolean.FALSE); + processOneColumn(source, window, lambdaFunction, (j, val) -> processWithNull(j, val, nulls, () -> finalRes[j] = PrimitiveUtilities.getIntegerValue(val).intValue()), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); + return new ColumnValue(name, DataType.INT, finalRes, nulls); + } + else if (type == _Package.getByUserPath("Float", processorSupport)) + { + double[] finalRes = new double[(int) source.getOne().getRowCount()]; + boolean[] nulls = new boolean[(int) source.getOne().getRowCount()]; + Arrays.fill(nulls, Boolean.FALSE); + processOneColumn(source, window, lambdaFunction, (j, val) -> processWithNull(j, val, nulls, () -> finalRes[j] = PrimitiveUtilities.getFloatValue(val).doubleValue()), resolvedTypeParameters, resolvedMultiplicityParameters, functionExpressionCallStack, profiler, instantiationContext, executionSupport, processorSupport, relationType, evalVarContext, twoParamsFunc); + return new ColumnValue(name, DataType.DOUBLE, finalRes, nulls); + } + else + { + throw new RuntimeException("The type " + type._name() + " is not supported yet!"); + } + } + + private interface Proc + { + void invoke(); + } + + private void processWithNull(Integer j, CoreInstance val, boolean[] nulls, Proc p) + { + { + if (val == null) + { + nulls[j] = true; + } + else + { + p.invoke(); + } + } + } + + private void processOneColumn(Pair>> source, Window window, LambdaFunction lambdaFunction, Procedure2 setter, Stack> resolvedTypeParameters, Stack> resolvedMultiplicityParameters, MutableStack functionExpressionCallStack, Profiler profiler, InstantiationContext instantiationContext, ExecutionSupport executionSupport, ProcessorSupport processorSupport, GenericType relationType, VariableContext evalVarContext, boolean twoParamsFunc) + { + FixedSizeList parameters = twoParamsFunc ? Lists.fixedSize.with((CoreInstance) null, (CoreInstance) null, (CoreInstance) null) : Lists.fixedSize.with((CoreInstance) null); + int k = 0; + for (int j = 0; j < source.getTwo().size(); j++) + { + Pair r = source.getTwo().get(j); + TestTDS sourceTDS = source.getOne().slice(r.getOne(), r.getTwo()); + for (int i = 0; i < r.getTwo() - r.getOne(); i++) + { + if (twoParamsFunc) + { + parameters.set(0, ValueSpecificationBootstrap.wrapValueSpecification(new TDSCoreInstance(sourceTDS, relationType, repository, processorSupport), false, processorSupport)); + parameters.set(1, ValueSpecificationBootstrap.wrapValueSpecification(window.convert(processorSupport, new RepoPrimitiveBuilder(repository)), false, processorSupport)); + } + parameters.set(twoParamsFunc ? 2 : 0, ValueSpecificationBootstrap.wrapValueSpecification(new TDSWithCursorCoreInstance(source.getOne(), i, "", null, relationType, -1, repository, false), false, processorSupport)); + CoreInstance newValue = this.functionExecution.executeFunction(false, lambdaFunction, parameters, resolvedTypeParameters, resolvedMultiplicityParameters, evalVarContext, functionExpressionCallStack, profiler, instantiationContext, executionSupport); + setter.value(k++, newValue.getValueForMetaPropertyToOne("values")); + } + } + } + + public static class RepoPrimitiveBuilder implements Frame.PrimitiveBuilder + { + private ModelRepository repository; + + public RepoPrimitiveBuilder(ModelRepository repository) + { + this.repository = repository; + } + + @Override + public CoreInstance build(String val) + { + return this.repository.newStringCoreInstance(val); + } + + @Override + public CoreInstance build(int val) + { + return this.repository.newIntegerCoreInstance(val); + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-core-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-core-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure index b57c26ca545..2a923f8ec0f 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-core-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/legend-engine-xt-relationalStore-core-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure @@ -309,12 +309,12 @@ function meta::relational::functions::pureToSqlQuery::defaultState(mapping:Mappi { let initialState = defaultState($mapping,$inScopeVars); let context = if($exeCtx->isEmpty(), - | $initialState, + | $initialState, | if($exeCtx->toOne()->meta::pure::executionPlan::featureFlag::contextHasFlag(meta::pure::executionPlan::features::Feature.PUSH_DOWN_ENUM_TRANSFORM), | ^$initialState(pushDownEnumTransformations=true);, |$initialState ); - ); + ); } @@ -527,7 +527,7 @@ function meta::relational::functions::pureToSqlQuery::processInstanceValue(i:Ins function meta::relational::functions::pureToSqlQuery::processValue(vals:Any[*], currentPropertyMapping:PropertyMapping[*], operation:SelectWithCursor[1], vars:Map[1], state:State[1], joinType:JoinType[1], nodeId:String[1], aggFromMap:List[1], context:DebugContext[1], extensions:Extension[*]):RelationalOperationElement[*] { - let select = $operation.select; + let select = $operation.select; if ($vals->isEmpty(), | ^$operation(select = $state.inFilter->if(|^$select(filteringOperation = ^Literal(value=^SQLNull())),|^$select(columns = ^Literal(value=^SQLNull())))) , | $vals->map(v | $v->match([ @@ -594,7 +594,7 @@ function meta::relational::functions::pureToSqlQuery::processColumnFunctionExpre let foundColumn = if($foundColumnInSelect->isEmpty(), |$tableAlias.relation()->findColumn($colFuncName), |$foundColumnInSelect); let colAlias = $foundColumn->toOne()->match([c:Column[1]|^TableAliasColumn(alias = $tableAlias, column = $c), a:Alias[1]|$a.relationalElement]); let newSelect = $state.inFilter->if(|^$leftSelect(filteringOperation=$colAlias),|^$leftSelect(columns=$colAlias)); - ^$leftSide(element = ^$operation(select=$newSelect)); + ^$leftSide(element = ^$operation(select=$newSelect)); } function meta::relational::functions::pureToSqlQuery::findColumn(relation:Relation[1], name:String[1]):RelationalOperationElement[0..1] @@ -1275,7 +1275,7 @@ function meta::relational::functions::pureToSqlQuery::processColumnsInRelational $srcOperation->validate([], $extensions); let result = $z->match( [ - t:TableAliasColumn[1] | + t:TableAliasColumn[1] | let currentTreeNode = $srcOperation.currentTreeNode->toOne(); let alias = $currentTreeNode.alias; @@ -1549,7 +1549,7 @@ function meta::relational::functions::pureToSqlQuery::doJoinToClass(joinTree: Jo | let getAllSelectWithCursor = processGetAll($setImplementation, $setImplementation.class, $joinType, $nodeId, false, -1, true, [], $state, $context, $extensions); $queryAllFilters->replaceJoinTableWithSelectQuery($getAllSelectWithCursor.select, $queryAllFilters.currentTreeNode->toOne(), '', $nodeId, $context, $extensions); ); - ); + ); } function meta::relational::functions::pureToSqlQuery::isSimpleJoinToPk(join:Join[1], currentTreeNode:RelationalTreeNode[1], extensions:Extension[*]):Boolean[1] @@ -1644,7 +1644,7 @@ Class meta::relational::functions::pureToSqlQuery::MissingColProcessigRes function meta::relational::functions::pureToSqlQuery::processRelationFunctionPropertyMapping(propertyMappings:RelationFunctionPropertyMapping[*], property:AbstractProperty[1], propertyOwnerClass:Class[1], oldSrcOperation:SelectWithCursor[1], state:State[1], joinType:JoinType[1], nodeId:String[1], aggFromMap:List[1], context:DebugContext[1], extensions:Extension[*]):RelationalOperationElement[1] { let propertyMapping = $propertyMappings->toOne('Unions not supported with Relation Expression mappings yet!'); - let transformedRelationalPropertyMapping = $propertyMapping->transformRelationPropertyMappingsToRelational($state->getClassMappingById($propertyMapping.sourceSetImplementationId)->toOne()->cast(@RelationFunctionInstanceSetImplementation)); + let transformedRelationalPropertyMapping = $propertyMapping->transformRelationPropertyMappingsToRelational($state->getClassMappingById($propertyMapping.sourceSetImplementationId)->toOne()->cast(@RelationFunctionInstanceSetImplementation)); processRelationalPropertyMapping($transformedRelationalPropertyMapping, $property, $propertyOwnerClass, $oldSrcOperation, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions); } @@ -2368,7 +2368,7 @@ function meta::relational::functions::pureToSqlQuery::zeroToOneBasedIndex(v:Valu { $v->match([ i:InstanceValue[1] | ^$i(values = $i.values->toOne()->cast(@Integer) + 1), - v:ValueSpecification[1] | ^SimpleFunctionExpression(multiplicity = PureOne, func = plus_Integer_MANY__Integer_1_, functionName = 'plus', + v:ValueSpecification[1] | ^SimpleFunctionExpression(multiplicity = PureOne, func = plus_Integer_MANY__Integer_1_, functionName = 'plus', genericType = ^GenericType(rawType = Integer), importGroup = system::imports::coreImport, parametersValues = ^InstanceValue(multiplicity = ZeroMany, genericType = ^GenericType(rawType = Integer), values = [ $v, @@ -2711,7 +2711,7 @@ function meta::relational::functions::pureToSqlQuery::processSortBy(f:FunctionEx let mainSelect = $mainQuery.select; let rightSide = processValueSpecification($lambdaFunctionExpression, $embeddedMapping, ^$mainQuery(select=^$mainSelect(columns=[])), $vars, ^$inScopeVarsWithPlaceholdersState(inFilter=false), JoinType.LEFT_OUTER, $nodeId, $aggFromMap, $context->shift(), $extensions)->toOne()->cast(@SelectWithCursor); - + let rightSideSelect = $rightSide.select; let rightSideModified = ^$rightSide( select = ^$rightSideSelect( @@ -2880,7 +2880,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsAggColSpecArray( let topQuery = processValueSpecification($f.parametersValues->at(0), $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->toOne()->cast(@SelectWithCursor); let aggColSpec = $f.parametersValues->at(1)->cast(@InstanceValue).values->at(0)->cast(@meta::pure::metamodel::relation::AggColSpecArray); $aggColSpec.aggSpecs->fold({aggSpec,a| - let newColumnName = $aggSpec->extractName(); + let newColumnName = $aggSpec->extractName(); processTdsWindowColumn(true, $f, [], [], $newColumnName, $aggSpec, $currentPropertyMapping, $a, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->cast(@SelectWithCursor); }, $topQuery); } @@ -2904,7 +2904,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsWinAggColSpecArr let topQuery = processValueSpecification($f.parametersValues->at(0), $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->toOne()->cast(@SelectWithCursor); $aggColSpec.aggSpecs->fold({aggSpec,a| - let newColumnName = $aggSpec->extractName(); + let newColumnName = $aggSpec->extractName(); processTdsWindowColumn(true, $f, $partitionKeys, $sortInfo, $newColumnName, $aggSpec, $currentPropertyMapping, $a, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->cast(@SelectWithCursor); }, $topQuery); } @@ -2928,7 +2928,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsWinFuncColSpecAr let topQuery = processValueSpecification($f.parametersValues->at(0), $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->toOne()->cast(@SelectWithCursor); $funcColSpec.funcSpecs->fold({funcSpec,a| - let newColumnName = $funcSpec->extractName(); + let newColumnName = $funcSpec->extractName(); processTdsWindowColumn(true, $f, $partitionKeys, $sortInfo, $newColumnName, $funcSpec, $currentPropertyMapping, $a, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->cast(@SelectWithCursor); }, $topQuery); } @@ -2945,7 +2945,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsWindowColumn( let newColumnName = $name; let selectQuery = $topQuery.select->cast(@TdsSelectSqlQuery); - + let shouldIsolateDistinct = $selectQuery.distinct->defaultIfEmpty(false)->toOne(); let mainQuery = if($shouldIsolateDistinct, |$selectQuery->isolateTdsSelect($topQuery, $extensions), |$topQuery)->cast(@SelectWithCursor); @@ -2989,7 +2989,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsWindowColumn( ] ); let newPath = pair($newColumnName, ^PathInformation(type=$pureType, relationalType= meta::relational::transform::fromPure::pureTypeToDataType($pureType))); - + ^$mainSelect(columns = $mainSelect.columns->concatenate($windowColumn), paths +=$newPath)->isolateSubSelectIfNotLastOperation($operation, $f, $state.functionExpressionStack, $extensions); } @@ -3825,7 +3825,7 @@ function meta::relational::functions::pureToSqlQuery::processRelationalMappingSp let properties = if($requiresAllProperties, | columnNamesWithRelationalElement($viewSpecification, $c, $state)->map(c | let newQuery = $c.second->processColumnsInRelationalOperationElements($state, $base, $nodeId, ^List(), false, $context, $extensions); rebuildSelectWithCursor($c.first, [], $newQuery, $quoteColumnAliases);) , | [] ); - + let pks = if($addPk && $viewSpecification->getGroupBy()->isEmpty() && ($viewSpecification->getDistinct()->isEmpty() || $viewSpecification->getDistinct()->toOne() == false), | let pks = viewSpecificationPrimaryKey($viewSpecification); $pks->map(pm|let offset = $pks->indexOf($pm); @@ -3919,21 +3919,21 @@ function meta::relational::functions::pureToSqlQuery::relationalmappingspecifica r:RootRelationalInstanceSetImplementation[1] | $r->dataTypePropertyMappings() ->filter(x | if($state.graphFetchFlow == true, | $x.property->in($state.graphFetchProperties), | true)) ->map(pm| pair($pm.property.name->toOne(), buildPossibleEnumMappingPushDown($pm->cast(@RelationalPropertyMapping),$state).relationalOperationElement);) - , + , v:View[1] | $v.columnMappings->map(cm|pair($cm.columnName, $cm.relationalOperationElement)); ]); } function meta::relational::functions::pureToSqlQuery::buildPossibleEnumMappingPushDown(mapping: RelationalPropertyMapping[1], state: State[1]): RelationalPropertyMapping[1] -{ +{ let relationalElement = $mapping.relationalOperationElement; - if($state.pushDownEnumTransformations && $mapping.transformer ->isNotEmpty() && $mapping.transformer->toOne()->instanceOf(EnumerationMapping) && !$state.inFilter , + if($state.pushDownEnumTransformations && $mapping.transformer ->isNotEmpty() && $mapping.transformer->toOne()->instanceOf(EnumerationMapping) && !$state.inFilter , |let caseParams = $mapping.transformer->cast(@EnumerationMapping).enumValueMappings ->map(ev | if($ev.sourceValues->size() == 1, | ^DynaFunction(name = 'equal', parameters=[$relationalElement, ^Literal(value=$ev.sourceValues->at(0))]), | ^DynaFunction(name = 'in', parameters = [$relationalElement, ^LiteralList(values=$ev.sourceValues->map(v|^Literal(value=$v)))]); )->concatenate(^Literal(value=$ev.enum.name)); ); - + ^$mapping(transformer = [], relationalOperationElement=^DynaFunction(name = 'case', parameters = $caseParams->concatenate(^DynaFunction(name = 'sqlNull')))); , |$mapping @@ -4838,7 +4838,7 @@ function meta::relational::functions::pureToSqlQuery::processGroupBy(expression: let noSubSelect = $select.groupBy->isEmpty() && $select.pivot->isEmpty() && ($select.distinct->isEmpty() || !$select.distinct->toOne()) && $select.orderBy.column->removeAll($groupByColumns)->isEmpty(); let subSelectAliasName = 'aggreg'; $groupByColumns->map(gc| assert(!$gc.relationalElement->instanceOf(WindowColumn),'Group by columns cannot include window columns');); - let aggVS = $expression.parametersValues->at(2)->reprocessVS()->reactivate($state.inScopeVars)->evaluateAndDeactivate()->match([ + let aggVS = $expression.parametersValues->at(2)->reprocessVS()->reactivate($state.inScopeVars)->evaluateAndDeactivate()->match([ avs:meta::pure::tds::AggregateValue[*]|$avs->map(a|^AggContainer(name=$a.name,map=$a.mapFn,reduce=$a.aggregateFn));, x:meta::pure::metamodel::relation::AggColSpec[1]|^AggContainer(name=$x.name,map=$x.map,reduce=$x.reduce);, z:meta::pure::metamodel::relation::AggColSpecArray[1]|$z.aggSpecs->map(x|^AggContainer(name=$x.name,map=$x.map,reduce=$x.reduce)); @@ -4912,7 +4912,7 @@ function meta::relational::functions::pureToSqlQuery::processPivot(expression:Fu ( name = $n, type = ^meta::relational::metamodel::datatype::Integer() // this type here does not mean much so we set it arbitrarily to Integer - ) + ) )); let noSubSelect = false; let subSelectAliasName = 'pivot_' + $nodeId; @@ -5064,7 +5064,7 @@ function <> meta::relational::functions::pureToSqlQuery::process let mainTable = $f.parametersValues->at(0)->cast(@FunctionExpression)->getTableFromParameter(); let mainTableAliasTDS = ^TableAlias(name = 'root', relationalElement = $mainTable->processRelation([], $joinType, $nodeId, false, 0, false, [], $state, $context, $extensions)); - let joinTreeNode = ^RootJoinTreeNode(alias=$mainTableAliasTDS); + let joinTreeNode = ^RootJoinTreeNode(alias=$mainTableAliasTDS); ^SelectWithCursor( select = ^TdsSelectSqlQuery( data =$joinTreeNode, @@ -5388,7 +5388,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsJoin(asOfJoin:Bo ^Alias(name=if($Q1isVarSetPlaceHolder,|$als.name->addQuotesIfNoQuotes(),|$als.name), relationalElement=^TableAliasColumn(alias=$newAlias, column=^$col(name=$als.name)));), paths = $paths ), - currentTreeNode = $swc1->concatenate($swc2)->filter(q|$q.currentTreeNode->isNotEmpty())->map(q|$q.currentTreeNode->toOne()->findNode($q.select.data->toOne(), $newData))->first() + currentTreeNode = $swc1->concatenate($swc2)->filter(q|$q.currentTreeNode->isNotEmpty())->map(q|$q.currentTreeNode->toOne()->findNode($q.select.data->toOne(), $newData))->first() ); } @@ -5398,7 +5398,7 @@ function meta::relational::functions::pureToSqlQuery::processJoinCondition(join let newOpenVars = $state.inScopeVars->putAll($joinCondition->at(0)->evaluateAndDeactivate()->openVariableValues()); assert($joinCondition.expressionSequence->size() <= 1, 'Lambda with more than one expression are not supported yet'); - + let element_old = processTdsLambda($joinCondition.expressionSequence->at(0)->cast(@ValueSpecification), $leftAliasWithColumns->concatenate($aliases2), false, $vars, ^$state(inScopeVars=$newOpenVars), $currentPropertyMapping, $paths, $context); let element_new = $element_old->match([ i: Literal[1] | let val = $i.value->cast(@Boolean); @@ -5710,11 +5710,11 @@ function <> meta::relational::functions::pureToSqlQuery::getEnum { let name = $f->instanceValueAtParameter(1)->cast(@String); let matchedPath = $paths->filter(p|$p.first->toLower() == $name->toLower()); - if($matchedPath->isEmpty(), + if($matchedPath->isEmpty(), | [], | let pm = $matchedPath->toOne().second; $pm.propertyMapping->cast(@RelationalPropertyMapping); - ); + ); } function <> meta::relational::functions::pureToSqlQuery::isFunctionWithName(r: ValueSpecification[1], functionName: String[1]):Boolean[1] @@ -5741,7 +5741,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val ); //TODO: I think this case can be removed - WindowColumn isn't a subtype of Alias? assertNotEmpty($foundColumn, {|'The column \''+$f.func.name->toOne()+'\' can\'t be found in the TDS ('+$a.name->makeString(',')+')'}); let res = $foundColumn->map(c|$c->match([ a:Alias[1]| $a.relationalElement,r:RelationalOperationElement[1]|$r])); - + // Column application -> Generalize all that... if ($f.parametersValues->size() == 1 && $f.parametersValues->at(0)->instanceOf(FunctionExpression), | let subFuncExpr = $f.parametersValues->at(0)->cast(@FunctionExpression)->evaluateAndDeactivate(); @@ -5797,7 +5797,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val if($params.first.values->isNotEmpty(), | let enumVarParam = $params.first.values->toOne()->evaluateAndDeactivate()->cast(@FunctionExpression); let otherParam = $params.second.values->toOne()->evaluateAndDeactivate(); - + let enumVarProcessedParam = $enumVarParam->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context)->toOne(); let otherProcessedParam = $otherParam->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context)->toOne(); let enumPropertyMapping = getEnumExprPropertyMapping($enumVarParam, $paths); @@ -5811,10 +5811,10 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val newDynaFunction('equal', [$enumVarProcessedParam, $newParam]); ), | newDynaFunction('equal', [$enumVarProcessedParam, $otherProcessedParam]); - );, + );, | newDynaFunction('equal', $f.parametersValues->map(p| $p->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context)->toOne())); ); - }), + }), ^PureFunctionTDSToRelationalFunctionPair(first = extractEnumValue_Enumeration_1__String_1__T_1_, second = {| ^Literal(value=extractEnumValue($f, $currentPropertyMapping, $context)) }), @@ -5824,10 +5824,10 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val ^PureFunctionTDSToRelationalFunctionPair(first = in_Any_1__Any_MANY__Boolean_1_, second = {| let valueParam = $f.parametersValues->at(0); let valueArg = $valueParam->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context)->toOne(); - + let collectionArg = $f.parametersValues->at(1)->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context); let mergedCollectionArg = $collectionArg->match([l:Literal[*] | ^LiteralList(values = $l), ll:LiteralList[1] | $ll]); - + if($valueParam->isFunctionWithName('getEnum'), | let enumPropertyMapping = getEnumExprPropertyMapping($valueParam->cast(@FunctionExpression), $paths); let mappedEnumValues = $mergedCollectionArg.values->map(a|$a.value->match([ @@ -6170,7 +6170,7 @@ function meta::relational::functions::pureToSqlQuery::isSupported(f:FunctionDefi function meta::relational::functions::pureToSqlQuery::processProject(ids:String[*], functions:meta::pure::metamodel::function::Function[*], docs:String[*], expression:FunctionExpression[1], operation:SelectWithCursor[1], vars:Map[1], state:State[1], nodeId:String[1], aggFromMap:List[1], context:DebugContext[1],wc:WindowColumnSpecification[*], extensions:Extension[*]):RelationalOperationElement[1] -{ +{ assertEquals($ids->size(), $functions->size(), | 'The number of column names must match the number of functions. Please provide a column name for each projection function ('+$ids->size()->toString()+' != '+$functions->size()->toString()+')'); assertEquals($ids->size(), $ids->removeDuplicates()->size(), 'The list of Paths provided to project can\'t contain duplicate names. Please use ! to provide an alias. Example:#/Person/lastName!newAlias#'); @@ -6994,10 +6994,10 @@ function meta::relational::functions::pureToSqlQuery::processEqualsForEnum(first $pm->cast(@RelationalPropertyMapping).transformer->toOne()->instanceOf(EnumerationMapping);)->toOne(); let hasEnumVarAndEnumVal = $enumVar.first.values->isNotEmpty() && $enumVar.second.values.processedParam->toOne()->hasEnumValue(); if($hasEnumVarAndEnumProp, - | + | let mapping = $enumVar.second.values.currentPropertyMapping->toOne().currentPropertyMapping->cast(@RelationalPropertyMapping); - if($state.pushDownEnumTransformations && $mapping.transformer ->isNotEmpty() && $mapping.transformer->toOne()->instanceOf(EnumerationMapping), - | + if($state.pushDownEnumTransformations && $mapping.transformer ->isNotEmpty() && $mapping.transformer->toOne()->instanceOf(EnumerationMapping), + | let caseParams = $mapping.transformer->cast(@EnumerationMapping).enumValueMappings ->map(ev | if($ev.sourceValues->size() == 1, | ^DynaFunction(name = 'equal', parameters=[$enumVar.second.values.processedParam->toOne(), ^Literal(value=$ev.sourceValues->at(0))]), @@ -7006,7 +7006,7 @@ function meta::relational::functions::pureToSqlQuery::processEqualsForEnum(first ); let second = ^DynaFunction(name = 'case', parameters = $caseParams->concatenate(^DynaFunction(name = 'sqlNull'))); ^DynaFunction(name = 'equal', parameters = [$enumVar.first.values.processedParam->toOne(), $second]);, - | + | let enumParamFreeMarker = generateFreeMarkerForEnumParam($enumVar.second.values.currentPropertyMapping->toOne(), $enumVar.first.values.processedParam->toOne()); generateFreeMarkerOpSelectorForEnumParam($enumParamFreeMarker, $enumVar.second.values.processedParam->toOne(), $enumVar.first.values.processedParam->toOne()); );, @@ -7678,7 +7678,7 @@ function <> meta::relational::functions::pureToSqlQuery::applyJo let explodeInCurrentNode = explodeInCurrentJoinOperation($joinTreeNode.join.operation); let appliedJoinTreeNode = if($explodeInCurrentNode, | applyJoinWithExplodeInCondition($position, $joinTreeNode, $nodeId, $jt, $reprocess, $state, $milestoningContext, $context, $extensions), | applyOneJoin($position, $joinTreeNode, $nodeId, $jt, $reprocess, $state, $milestoningContext, $context, $extensions)); - + let positionAliasWithExtraJoinCols = $position.alias->addExtraJoinColumns($appliedJoinTreeNode.join); //subselect may not have all cols required for join (prev isolation if applied may take care of this) let uniqueAppliedJoinTreeNode = if($position.childrenData->filter(c|$c->cast(@JoinTreeNode).joinName==$appliedJoinTreeNode.joinName)->isEmpty() ,|^$appliedJoinTreeNode(join = reprocessJoin($appliedJoinTreeNode.join, [^OldAliasToNewAlias(first = $position.alias.name, second = $positionAliasWithExtraJoinCols)], [])) @@ -7775,7 +7775,7 @@ function meta::relational::functions::pureToSqlQuery::applyJoinWithExplodeInCond { let join = $joinTree.join; let targetAliasInJoin = findTarget($join, $currentNode, $extensions); - let sourceAliasInJoin = $join->otherTableFromAlias($targetAliasInJoin)->toOne(); + let sourceAliasInJoin = $join->otherTableFromAlias($targetAliasInJoin)->toOne(); let allExplodeCalls = $join.operation->extractExplodeSemiStructured()->removeDuplicates(); assert($allExplodeCalls->size() == 1, 'only one unique explode allowed in operation in join: ' + $join.name); // This condition needs to be relaxed to support many-to-many @@ -7785,18 +7785,18 @@ function meta::relational::functions::pureToSqlQuery::applyJoinWithExplodeInCond let columnToExplode = $explodeOp.parameters->at(0)->cast(@TableAliasColumn); let pathToExplode = $explodeOp.parameters->at(1)->cast(@Literal).value->cast(@String); let pureReturnType = $explodeOp.parameters->at(2)->cast(@Literal).value->cast(@String)->explodeReturnType(); - let tableToExplodeAlias = $columnToExplode.alias; - + let tableToExplodeAlias = $columnToExplode.alias; + assert($tableToExplodeAlias.relationalElement->instanceOf(Table) || $tableToExplodeAlias.relationalElement->instanceOf(View), 'element to explode: ' + $tableToExplodeAlias.name + ' in join ' + $join.name + ' is not a table/view'); assert($sourceAliasInJoin.relationalElement->instanceOf(Table) || $sourceAliasInJoin.relationalElement->instanceOf(View), 'source ' + $sourceAliasInJoin.name + ' in join ' + $join.name + ' is not a table/view'); let srcPrimaryKeys = if($sourceAliasInJoin.relationalElement->instanceOf(Table), | $sourceAliasInJoin.relationalElement->cast(@Table).primaryKey, | $sourceAliasInJoin.relationalElement->cast(@View).primaryKey); - assert($srcPrimaryKeys->size() >= 1, 'atleast one primary key should be defined on the relation: ' + $sourceAliasInJoin.name); + assert($srcPrimaryKeys->size() >= 1, 'atleast one primary key should be defined on the relation: ' + $sourceAliasInJoin.name); // 1. create a subquery(exploded) for the flattened relation by doing a lateral join between tableToFlatten and the flattened array. let toExplodeRootTreeNode = ^RootJoinTreeNode(alias=^TableAlias(name='root',relationalElement=$tableToExplodeAlias.relationalElement->processRelation([], $joinType, $nodeId, true, -1, true, $milestoningContext, $state, $context, $extensions))); - let pathNavigation = meta::relational::functions::sqlQueryToString::parseSemiStructuredPathNavigation($pathToExplode); + let pathNavigation = meta::relational::functions::sqlQueryToString::parseSemiStructuredPathNavigation($pathToExplode); let initialNavigation = if($pathNavigation->at(0)->isDigit(), | ^SemiStructuredArrayElementAccess(operand=^$columnToExplode(alias = $toExplodeRootTreeNode.alias),index=^Literal(value = $pathNavigation->at(0))), | ^SemiStructuredPropertyAccess(property=^Literal(value = $pathNavigation->at(0)->substring(1, $pathNavigation->at(0)->length()-1)), operand=^$columnToExplode(alias = $toExplodeRootTreeNode.alias))); - let semiStructuredNavigation = $pathNavigation->slice(1, $pathNavigation->size())->fold({property, navigation | if($property->isDigit(), | ^SemiStructuredArrayElementAccess(operand=$navigation,index=^Literal(value = $property)), | ^SemiStructuredPropertyAccess(property=^Literal(value = $property->substring(1, $property->length()-1)), operand=$navigation)) }, $initialNavigation ); + let semiStructuredNavigation = $pathNavigation->slice(1, $pathNavigation->size())->fold({property, navigation | if($property->isDigit(), | ^SemiStructuredArrayElementAccess(operand=$navigation,index=^Literal(value = $property)), | ^SemiStructuredPropertyAccess(property=^Literal(value = $property->substring(1, $property->length()-1)), operand=$navigation)) }, $initialNavigation ); let arrayFlattening = ^SemiStructuredArrayFlatten(navigation = $semiStructuredNavigation); let leftAlias = $toExplodeRootTreeNode.alias; let rightAlias = ^TableAlias(relationalElement = $arrayFlattening, name = 'arrayFlatten_0'); @@ -7817,12 +7817,12 @@ function meta::relational::functions::pureToSqlQuery::applyJoinWithExplodeInCond ); let explodedRootTreeNode = ^$toExplodeRootTreeNode(childrenData = $lateralJoinNode); let flattenOutputAlias = ^Alias(name = 'flattened_prop', relationalElement = ^SemiStructuredArrayFlattenOutput(tableAliasColumn = ^TableAliasColumn(alias = $lateralJoinNode.alias->toOne(), column = ^Column(name = 'VALUE', type = ^meta::relational::metamodel::datatype::SemiStructured())), returnType = $pureReturnType)); - let columnsForInnerJoin = $join.operation->extractTableAliasColumns()->filter(tac|$tac.alias == $tableToExplodeAlias )->map(c|^TableAliasColumn(column = $c.column, alias = $toExplodeRootTreeNode.alias))->removeDuplicates(); + let columnsForInnerJoin = $join.operation->extractTableAliasColumns()->filter(tac|$tac.alias == $tableToExplodeAlias )->map(c|^TableAliasColumn(column = $c.column, alias = $toExplodeRootTreeNode.alias))->removeDuplicates(); let additionalColumnsToFetch = if($tableToExplodeAlias == $sourceAliasInJoin, | $srcPrimaryKeys->map(c|^Alias(name = 'leftJoinKey_' + $srcPrimaryKeys->indexOf($c)->toString(), relationalElement = ^TableAliasColumn(column=$c, alias=$toExplodeRootTreeNode.alias))), // fetch only pks from source - | + | let additionalColumns = if($tableToExplodeAlias.relationalElement->instanceOf(Table), // fetch all columns from target - | $tableToExplodeAlias.relationalElement->cast(@Table).columns->map(c|^TableAliasColumn(alias = $toExplodeRootTreeNode.alias, column = $c->cast(@Column))), + | $tableToExplodeAlias.relationalElement->cast(@Table).columns->map(c|^TableAliasColumn(alias = $toExplodeRootTreeNode.alias, column = $c->cast(@Column))), | $tableToExplodeAlias.relationalElement->cast(@View).columns->map(c |^TableAliasColumn(alias = $toExplodeRootTreeNode.alias, column = $c->cast(@Column))); )); @@ -7848,9 +7848,9 @@ function meta::relational::functions::pureToSqlQuery::applyJoinWithExplodeInCond ); let columnsToFetchFromUnexploded = if($tableToExplodeAlias == $sourceAliasInJoin, | if($targetAliasInJoin.relationalElement->instanceOf(Table), // target is unexploded, fetch all columns from target - | $targetAliasInJoin.relationalElement->cast(@Table).columns->map(c|^TableAliasColumn(alias = $otherTableInJoinUpdated, column = $c->cast(@Column))), + | $targetAliasInJoin.relationalElement->cast(@Table).columns->map(c|^TableAliasColumn(alias = $otherTableInJoinUpdated, column = $c->cast(@Column))), | $targetAliasInJoin.relationalElement->cast(@View).columns->map(c|^TableAliasColumn(alias = $otherTableInJoinUpdated, column = $c->cast(@Column))) - );, + );, | $srcPrimaryKeys->map(c|^Alias(name = 'leftJoinKey_' + $srcPrimaryKeys->indexOf($c)->toString(),relationalElement = ^TableAliasColumn(column = $c, alias = $otherTableInJoinUpdated))) // source is unexploded, fetch pks from source ); let columnsToFetchFromExplodedProcessed = $additionalColumnsToFetch->map(c|$c->match([ @@ -8693,11 +8693,11 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::concatenate_Relation_1__Relation_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processConcatenate_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::drop_Relation_1__Integer_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processDrop_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1__FuncColSpec_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsExtend_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), - ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1__FuncColSpecArray_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsExtend_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1__FuncColSpecArray_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsExtend_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpec_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), - ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), - ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpec_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), - ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpec_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processGroupBy_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::join_Relation_1__Relation_1__JoinKind_1__Function_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsJoin_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::limit_Relation_1__Integer_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processTake_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::rename_Relation_1__ColSpec_1__ColSpec_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsRenameColumns_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), @@ -8714,6 +8714,7 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1___Window_1__AggColSpecArray_1__Relation_1_, second = meta::relational::functions::pureToSqlQuery::processTdsWinAggColSpecArray_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1___Window_1__FuncColSpec_1__Relation_1_, second = meta::relational::functions::pureToSqlQuery::processTdsWinFuncColSpec_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::extend_Relation_1___Window_1__FuncColSpecArray_1__Relation_1_, second = meta::relational::functions::pureToSqlQuery::processTdsWinFuncColSpecArray_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::project_Relation_1__FuncColSpecArray_1__Relation_1_,second=meta::relational::functions::pureToSqlQuery::processTdsProject_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::pivot_Relation_1__ColSpecArray_1__AggColSpec_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processPivot_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::pivot_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processPivot_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::pivot_Relation_1__ColSpec_1__AggColSpec_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processPivot_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_),