From d360a4f706be186f6bdbad9a5ed1c18eeedf2832 Mon Sep 17 00:00:00 2001 From: gs-gunjan <72594207+gs-gunjan@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:02:42 +0530 Subject: [PATCH] support weighted average aggregation function (#3052) * support wavg aggregate function * fixing function handlers for wavg * fixing pct java standard test * updating data for wavg function * reusing processing of aggregation function * fixing compilation of empty list * Improving wavg functionality with documentation and tests * fixing pct test for java binding adapter --- .../toPureGraph/handlers/Handlers.java | 10 +- .../corefunctions/tests/math/testWavg.pure | 19 +++ .../pure/router/routing/router_routing.pure | 5 +- .../math/aggregator/wavg.pure | 111 ++++++++++++++++++ .../Test_JAVA_StandardFunction_PCT.java | 4 +- .../tests/executionPlanTest.pure | 4 +- .../functions/tests/testModelGroupBy.pure | 22 ++++ .../pureToSQLQuery/pureToSQLQuery.pure | 25 +++- .../relational/tds/tests/testGroupBy.pure | 62 ++++++++++ .../relational/tests/relationalSetUp.pure | 25 ++++ .../tests/testModel/simpleTestModel.pure | 10 ++ 11 files changed, 287 insertions(+), 10 deletions(-) create mode 100644 legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/math/testWavg.pure create mode 100644 legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-standard/legend-engine-pure-functions-standard-pure/src/main/resources/core_functions_standard/math/aggregator/wavg.pure 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 e8e49f75643..01702844c37 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 @@ -1828,6 +1828,11 @@ private void registerAggregations() h("meta::pure::functions::math::sum_Integer_MANY__Integer_1_", false, ps -> res("Integer", "one"), ps -> typeMany(ps.get(0), "Integer")), h("meta::pure::functions::math::sum_Number_MANY__Number_1_", false, ps -> res("Number", "one"), ps -> typeMany(ps.get(0), "Number"))); + register(m(m(h("meta::pure::functions::math::wavg_Number_MANY__Number_MANY__Float_1_", false, ps -> res("Float", "one"), ps -> typeMany(ps.get(0), "Number"))), + m(h("meta::pure::functions::math::wavg_WavgRowMapper_MANY__Float_1_", false, ps -> res("Float", "one"), ps -> typeMany(ps.get(0), "meta::pure::functions::math::wavgUtility::WavgRowMapper"))))); + + register(h("meta::pure::functions::math::wavgUtility::wavgRowMapper_Number_$0_1$__Number_$0_1$__WavgRowMapper_1_", false, ps -> res("meta::pure::functions::math::wavgUtility::WavgRowMapper", "one"), ps -> typeZeroOne(ps.get(0), "Number"))); + register(h("meta::pure::functions::math::variance_Number_MANY__Boolean_1__Number_1_", false, ps -> res("Number", "one"))); register(m(m(h("meta::pure::functions::math::percentile_Number_MANY__Float_1__Boolean_1__Boolean_1__Number_$0_1$_", false, ps -> res("Number", "zeroOne"), ps -> ps.size() == 4)), @@ -2919,7 +2924,6 @@ private Map buildDispatch() 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()))); map.put("meta::pure::functions::relation::pivot_Relation_1__ColSpec_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()) || "ColSpec".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()))); map.put("meta::pure::functions::relation::pivot_Relation_1__ColSpec_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()) || "ColSpec".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::cumulativeDistribution_Relation_1___Window_1__T_1__Float_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()) || "_Window".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity())); map.put("meta::pure::functions::relation::denseRank_Relation_1___Window_1__T_1__Integer_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()) || "_Window".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity())); map.put("meta::pure::functions::relation::first_Relation_1___Window_1__T_1__T_$0_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()) || "_Window".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity())); @@ -2933,7 +2937,9 @@ private Map buildDispatch() map.put("meta::pure::functions::relation::percentRank_Relation_1___Window_1__T_1__Float_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()) || "_Window".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity())); map.put("meta::pure::functions::relation::rank_Relation_1___Window_1__T_1__Integer_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()) || "_Window".equals(ps.get(1)._genericType()._rawType()._name())) && isOne(ps.get(2)._multiplicity())); map.put("meta::pure::functions::relation::rowNumber_Relation_1__T_1__Integer_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())); - + map.put("meta::pure::functions::math::wavg_Number_MANY__Number_MANY__Float_1_", (List ps) -> ps.size() == 2 && Sets.immutable.with("Nil","Number","Integer","Decimal","Float").contains(ps.get(0)._genericType()._rawType()._name()) && Sets.immutable.with("Nil","Number","Integer","Decimal","Float").contains(ps.get(1)._genericType()._rawType()._name())); + map.put("meta::pure::functions::math::wavg_WavgRowMapper_MANY__Float_1_", (List ps) -> ps.size() == 1 && ("Nil".equals(ps.get(0)._genericType()._rawType()._name()) || "WavgRowMapper".equals(ps.get(0)._genericType()._rawType()._name()))); + map.put("meta::pure::functions::math::wavgUtility::wavgRowMapper_Number_$0_1$__Number_$0_1$__WavgRowMapper_1_", (List ps) -> ps.size() == 2 && matchZeroOne(ps.get(0)._multiplicity()) && Sets.immutable.with("Nil","Number","Integer","Decimal","Float").contains(ps.get(0)._genericType()._rawType()._name()) && matchZeroOne(ps.get(1)._multiplicity()) && Sets.immutable.with("Nil","Number","Integer","Decimal","Float").contains(ps.get(1)._genericType()._rawType()._name())); // ------------------------------------------------------------------------------------------------ // Please do not update the following code manually! Please check with the team when introducing diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/math/testWavg.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/math/testWavg.pure new file mode 100644 index 00000000000..a0b0bcb7542 --- /dev/null +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/corefunctions/tests/math/testWavg.pure @@ -0,0 +1,19 @@ + +// Copyright 2022 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. + +function <> meta::pure::functions::math::tests::wavg::testWavg():Boolean[1] +{ + assertEq(292.5, [200,300,250,850,100]->wavg([0.25,0.35,0.15,0.1,0.15])); +} \ No newline at end of file diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure index 3698befe0ac..305771c1e5c 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure @@ -511,7 +511,7 @@ function meta::pure::router::routing::processLambda(i:InstanceValue[1], routed:E f:FunctionDefinition[1]| if($state.shouldBeRouted, |$func->functionType().parameters->evaluateAndDeactivate()->map( p | let class = $p.genericType.rawType; - if (!$class->toOne()->instanceOf(DataType) && $class != TDSRow && (!$class->toOne()->instanceOf(RelationType)), + if (!$class->toOne()->instanceOf(DataType) && $class != TDSRow && $class != meta::pure::functions::math::wavgUtility::WavgRowMapper && (!$class->toOne()->instanceOf(RelationType)), | let map = $routed->filter(v|$v->evaluateAndDeactivate().value.genericType.rawType->toOne()->_subTypeOf($class->toOne());); assert(!$map->isEmpty(),| 'Error mapping not found for class '+$class.name->toOne()+' cache:\''+$routed->cast(@meta::pure::router::store::metamodel::StoreMappingRoutedValueSpecification).sets.class.name->joinStrings(', ')+'\''); pair($p.name, $map->at(0)->cast(@Any));, @@ -785,6 +785,9 @@ function meta::pure::router::routing::shouldStopFunctions(extensions:meta::pure: averageRank_Any_MANY__Map_1_, denseRank_Any_MANY__Map_1_, rank_Any_MANY__Map_1_, + wavg_Number_MANY__Number_MANY__Float_1_, + wavg_WavgRowMapper_MANY__Float_1_, + meta::pure::functions::math::wavgUtility::wavgRowMapper_Number_$0_1$__Number_$0_1$__WavgRowMapper_1_, rowNumber_Any_MANY__Map_1_, max_Float_MANY__Float_$0_1$_, max_Integer_MANY__Integer_$0_1$_, diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-standard/legend-engine-pure-functions-standard-pure/src/main/resources/core_functions_standard/math/aggregator/wavg.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-standard/legend-engine-pure-functions-standard-pure/src/main/resources/core_functions_standard/math/aggregator/wavg.pure new file mode 100644 index 00000000000..4e5314710f5 --- /dev/null +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-functions-standard/legend-engine-pure-functions-standard-pure/src/main/resources/core_functions_standard/math/aggregator/wavg.pure @@ -0,0 +1,111 @@ +// Copyright 2024 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. + +import meta::pure::test::pct::*; + +function +<> + { + doc.doc='Performs weighted average on a given data field with its respective weight field', + PCT.grammarDoc='wavg is used by wavg(Number[*], Number[*])' + } +meta::pure::functions::math::wavg(numbers:Number[*], weights:Number[*]):Float[1] +{ + if($numbers->isEmpty() || $weights->isEmpty(), + |fail('Error: Mean of an empty set.');0.0;, + | if ($numbers->size() != $weights->size(), + |fail('Error: The data and weight column must have the same number of values');0.0;, + |let weightedQuantitySum = $numbers->zip($weights)->map(p | $p.first * $p.second)->sum(); + let weightsSum = $weights->sum(); + assert($weightsSum != 0.0,|'Weighted Average can\'t be performed as sum of weight column values equal 0'); + $weightedQuantitySum/$weightsSum;)); +} + +function meta::pure::functions::math::wavg(wavgRows: meta::pure::functions::math::wavgUtility::WavgRowMapper[*]):Float[1] +{ + meta::pure::functions::math::wavg($wavgRows.quantity, $wavgRows.weight); +} + +Class meta::pure::functions::math::wavgUtility::WavgRowMapper +{ + quantity: Number[0..1]; + weight: Number[0..1]; +} + +function meta::pure::functions::math::wavgUtility::wavgRowMapper(quantity:Number[0..1], weight:Number[0..1]):meta::pure::functions::math::wavgUtility::WavgRowMapper[1] +{ + ^meta::pure::functions::math::wavgUtility::WavgRowMapper( + quantity= $quantity, + weight= $weight + ) +} + +function <> meta::pure::functions::math::tests::wavg::testSimpleGroupByWavg(f:Function<{Function<{->T[m]}>[1]->T[m]}>[1]):Boolean[1] +{ + let expr = { + |#TDS + id, grp, name, quantity, weight + 1, 2, A, 200, 0.5 + 2, 1, B, 100, 0.45 + 3, 3, C, 250, 0.25 + 4, 4, D, 700, 1 + 5, 2, E, 100, 0.5 + 6, 1, F, 500, 0.15 + 7, 3, G, 400, 0.75 + 8, 1, H, 150, 0.4 + 9, 5, I, 350, 1 + #->groupBy(~grp, ~wavgCol : x | meta::pure::functions::math::wavgUtility::wavgRowMapper($x.quantity, $x.weight) : y | $y->wavg()) + }; + + let res = $f->eval($expr); + + assertEquals( '#TDS\n'+ + ' grp,wavgCol\n'+ + ' 1,180.0\n'+ + ' 2,150.0\n'+ + ' 3,362.5\n'+ + ' 4,700.0\n'+ + ' 5,350.0\n'+ + '#', $res->sort(~grp->ascending())->toString()); +} + +function <> meta::pure::functions::math::tests::wavg::testSimpleGroupByMultipleWavg(f:Function<{Function<{->T[m]}>[1]->T[m]}>[1]):Boolean[1] +{ + let expr = { + |#TDS + id, grp, name, quantity, weight, weight1 + 1, 2, A, 200, 0.5, 0.75 + 2, 1, B, 100, 0.45, 0.35 + 3, 3, C, 250, 0.25, 0.50 + 4, 4, D, 700, 1, 1 + 5, 2, E, 100, 0.5, 0.25 + 6, 1, F, 500, 0.15, 0.25 + 7, 3, G, 400, 0.75, 0.50 + 8, 1, H, 150, 0.4, 0.4 + 9, 5, I, 350, 1, 1 + #->groupBy(~grp, ~[wavgCol1 : x | meta::pure::functions::math::wavgUtility::wavgRowMapper($x.quantity, $x.weight) : y | $y->wavg(), + wavgCol2 : x | meta::pure::functions::math::wavgUtility::wavgRowMapper($x.quantity, $x.weight1) : y | $y->wavg()]) + }; + + let res = $f->eval($expr); + + assertEquals( '#TDS\n'+ + ' grp,wavgCol1,wavgCol2\n'+ + ' 1,180.0,220.0\n'+ + ' 2,150.0,175.0\n'+ + ' 3,362.5,325.0\n'+ + ' 4,700.0,700.0\n'+ + ' 5,350.0,350.0\n'+ + '#', $res->sort(~grp->ascending())->toString()); +} diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-PCT/src/test/java/org/finos/legend/engine/pure/code/core/java/binding/Test_JAVA_StandardFunction_PCT.java b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-PCT/src/test/java/org/finos/legend/engine/pure/code/core/java/binding/Test_JAVA_StandardFunction_PCT.java index c940dc75dc7..6d936e09e26 100644 --- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-PCT/src/test/java/org/finos/legend/engine/pure/code/core/java/binding/Test_JAVA_StandardFunction_PCT.java +++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-PCT/src/test/java/org/finos/legend/engine/pure/code/core/java/binding/Test_JAVA_StandardFunction_PCT.java @@ -36,7 +36,9 @@ public class Test_JAVA_StandardFunction_PCT extends PCTReportConfiguration one("meta::pure::functions::math::tests::stdDev::testSimpleGroupByStandardDeviationSample_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_ is not supported yet!\""), one("meta::pure::functions::math::tests::variance::testSimpleGroupByVariancePopulation_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_ is not supported yet!\""), - one("meta::pure::functions::math::tests::variance::testSimpleGroupByVarianceSample_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_ is not supported yet!\"") + one("meta::pure::functions::math::tests::variance::testSimpleGroupByVarianceSample_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpecArray_1__AggColSpecArray_1__Relation_1_ is not supported yet!\""), + one("meta::pure::functions::math::tests::wavg::testSimpleGroupByWavg_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpec_1__Relation_1_ is not supported yet!\""), + one("meta::pure::functions::math::tests::wavg::testSimpleGroupByMultipleWavg_Function_1__Boolean_1_", "\"meta::pure::functions::relation::groupBy_Relation_1__ColSpec_1__AggColSpecArray_1__Relation_1_ is not supported yet!\"") ); public static Test suite() diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/executionPlan/tests/executionPlanTest.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/executionPlan/tests/executionPlanTest.pure index 5de73bd7537..8203420d137 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/executionPlan/tests/executionPlanTest.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/executionPlan/tests/executionPlanTest.pure @@ -1665,7 +1665,7 @@ function <> meta::pure::executionPlan::tests::testDatabaseConnectionS let resultConnection = $result.rootExecutionNode->cast(@RelationalInstantiationExecutionNode).executionNodes->at(0)->cast(@SQLExecutionNode).connection->cast(@meta::external::store::relational::runtime::TestDatabaseConnection); - assertSize($resultConnection.testDataSetupSqls, 56); + assertSize($resultConnection.testDataSetupSqls, 58); } function <> meta::pure::executionPlan::tests::testDatabaseConnectionSQLPopulation():Boolean[1] @@ -1685,7 +1685,7 @@ function <> meta::pure::executionPlan::tests::testDatabaseConnectionS .connection->cast(@meta::external::store::relational::runtime::RelationalDatabaseConnection).datasourceSpecification ->cast(@meta::pure::alloy::connections::alloy::specification::LocalH2DatasourceSpecification); - assertSize($resultConnection.testDataSetupSqls, 56); + assertSize($resultConnection.testDataSetupSqls, 58); } function <> meta::pure::executionPlan::tests::tdsJoinOneDBOneExpression():Boolean[1] diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/testModelGroupBy.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/testModelGroupBy.pure index cf71a6f79e1..594d23a05b0 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/testModelGroupBy.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/testModelGroupBy.pure @@ -1269,3 +1269,25 @@ function <> meta::relational::tests::groupBy::testGroupByEmptyColsNon assertEquals([], $result.values.rows->map(r|$r.values->makeString('|'))); assertSameSQL('select "Firm Count" as "Firm Count" from (select count("root".LEGALNAME) as "Firm Count" from firmTable as "root") as "subselect" where "Firm Count" > 10', $result); } + +function <> meta::relational::tests::groupBy::testGroupByWithWavgAggregation() : Boolean[1] +{ + let mapping = meta::relational::tests::simpleRelationalMapping; + let runtime = meta::external::store::relational::tests::testRuntime(); + + let result = execute({| + WeightedTrade.all() + ->groupBy( + [ x | $x.tradeDate->adjust(1, DurationUnit.DAYS)], + [ + agg(x| $x.id, y|$y->count()), + agg(x | $x.quantity->meta::pure::functions::math::wavgUtility::wavgRowMapper($x.weight), y | $y->wavg()) + ], + ['tradeDate', 'id count', 'Weighted Average (Trade)'] + ) + ->sort(asc('tradeDate'))}, $mapping, $runtime, meta::relational::extension::relationalExtensions()); + + assertEquals(4, $result.values->at(0).rows->size()); + assertSameSQL('select dateadd(DAY, 1, "root".tradeDate) as "tradeDate", count("root".ID) as "id count", ((1.0 * sum(("root".quantity * "root".weight))) / sum("root".weight)) as "Weighted Average (Trade)" from weightedTradeTable as "root" group by "tradeDate" order by "tradeDate"',$result); + assertSameElements(['2014-12-02,3,138.8', '2014-12-03,2,27.5', '2014-12-04,2,33.8', '2014-12-05,2,33.49999999999999'],$result.values->at(0).rows->map(r| $r.values->makeString(','))); +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-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/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure index 9fe1365cf47..275924eb368 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-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/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery.pure @@ -3251,6 +3251,11 @@ function meta::relational::functions::pureToSqlQuery::processAggregation(f:Funct manageAggregation($mergedSQL, $dynaFunction, $operation, $state, $nodeId, list($moreAggregationKeys->concatenate($aggFromMap.values)), $context, $extensions); } +function meta::relational::functions::pureToSqlQuery::processWavgRowMapper(f:FunctionExpression[1], 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[1] +{ + processAggregation($f, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, list([]->cast(@ColumnGroup)), $context, $extensions); +} + function meta::relational::functions::pureToSqlQuery::manageAggregation(leftSql:SelectSQLQuery[1], relationalOperation:RelationalOperationElement[1], operation:SelectWithCursor[1], state:State[1], nodeId:String[1], aggFromMap:List[1], context:DebugContext[1], extensions:Extension[*]):SelectWithCursor[1] { let mergedSQL = $leftSql; @@ -4921,10 +4926,17 @@ function meta::relational::functions::pureToSqlQuery::processAggFn(v:ValueSpecif pair($f.func == or_Boolean_MANY__Boolean_1_ && $singleArgument, 'boolor'), pair(true, $fn) ]->filter(p | $p.first)->first()->toOne().second; - let aggFunc = newDynaFunction( + + let aggFunc = if ($f.func == wavg_WavgRowMapper_MANY__Float_1_, + | let parameters = $f.parametersValues->map(p|$p->processAggFn($params, $state)); + if ($parameters->size() == 1 && $parameters->toOne()->instanceOf(DynaFunction) && $parameters->cast(@DynaFunction).parameters->size()== 2 && $parameters->cast(@DynaFunction).name == 'wavgRowMapper', + | let mapperParameters = $parameters->cast(@DynaFunction).parameters; + newDynaFunction('divide',[newDynaFunction('sum', newDynaFunction('times', [$mapperParameters->at(0), $mapperParameters->at(1)])),newDynaFunction('sum', $mapperParameters->at(1))]);, + | newDynaFunction('divide',[newDynaFunction('sum', newDynaFunction('times', [$parameters->at(0), $parameters->at(1)])),newDynaFunction('sum', $parameters->at(1))]););, + | newDynaFunction( $name, $f.parametersValues->map(p|$p->processAggFn($params, $state)) - ); + )); if ($state.currentWindow->isEmpty(), |$aggFunc, |let win = $state.currentWindow->toOne(); @@ -5812,8 +5824,10 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val parameters = $f.parametersValues->tail()->map(p|$p->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context)) ) );, - |newDynaFunction($f.func.functionName->toOne(), $f.parametersValues->map(p|$p->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context))); - ); + | if ($supportedFunction == meta::relational::functions::pureToSqlQuery::processWavgRowMapper_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_, + | $f.parametersValues->map(p|$p->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context));, + | newDynaFunction($f.func.functionName->toOne(), $f.parametersValues->map(p|$p->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $paths, $context))); + );); ); );, | fail('function ' + $f.func.name->makeString() + ' is not yet supported'); ^DynaFunction(name='fail'); @@ -8353,6 +8367,7 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::collection::sortBy_T_m__Function_$0_1$__T_m_, second=meta::relational::functions::pureToSqlQuery::processSortBy_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::collection::isEmpty_Any_MANY__Boolean_1_, second=meta::relational::functions::pureToSqlQuery::processNotExists_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::collection::count_Any_MANY__Integer_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::wavgUtility::wavgRowMapper_Number_$0_1$__Number_$0_1$__WavgRowMapper_1_, second=meta::relational::functions::pureToSqlQuery::processWavgRowMapper_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::collection::slice_T_MANY__Integer_1__Integer_1__T_MANY_, second=meta::relational::functions::pureToSqlQuery::processSlice_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::collection::take_T_MANY__Integer_1__T_MANY_, 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::collection::limit_T_MANY__Integer_1__T_MANY_, 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_), @@ -8474,6 +8489,8 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::math::average_Integer_MANY__Float_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::average_Float_MANY__Float_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::average_Number_MANY__Float_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::wavg_Number_MANY__Number_MANY__Float_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::wavg_WavgRowMapper_MANY__Float_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::max_Integer_MANY__Integer_$0_1$_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::max_Integer_$1_MANY$__Integer_1_, second=meta::relational::functions::pureToSqlQuery::processAggregation_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::math::max_Float_MANY__Float_$0_1$_, second=meta::relational::functions::pureToSqlQuery::processAggregation_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tds/tests/testGroupBy.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tds/tests/testGroupBy.pure index b08a890ca5c..aa67deee27d 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tds/tests/testGroupBy.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tds/tests/testGroupBy.pure @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import meta::pure::functions::math::wavgUtility::*; import meta::relational::functions::sqlQueryToString::h2::*; import meta::relational::mapping::*; import meta::external::store::relational::runtime::*; @@ -524,3 +525,64 @@ function <> meta::relational::tests::tds::groupBy: meta::relational::functions::asserts::assertSameSQL('select dateadd(WEEK, 1, max("root".tradeDate)) as "Date Adjust" from tradeTable as "root"', $result); } + +function <> meta::relational::tests::tds::groupBy::testGroupByWithWavgAggregation(): Boolean[1] +{ + let mapping = meta::relational::tests::simpleRelationalMapping; + let runtime = meta::external::store::relational::tests::testRuntime(); + + let result = execute({| + WeightedTrade.all() + ->project( + [ x | $x.id, + x | $x.quantity, + x | $x.weight, + x | $x.tradeDate->adjust(1, DurationUnit.DAYS)], + [ 'Trade ID', + 'Quantity', + 'Weight', + 'tradeDate']) + ->groupBy(['tradeDate'], + [ + agg('ID count', x | $x.getInteger('Trade ID'), y | $y->count()), + agg('Trade Weighted Average', x | $x.getFloat('Quantity')->wavgRowMapper($x.getFloat('Weight')), y | $y->wavg()) + ] + ) + ->sort(asc('tradeDate'))}, $mapping, $runtime, meta::relational::extension::relationalExtensions()); + + assertEquals(4, $result.values->at(0).rows->size()); + meta::relational::functions::asserts::assertSameSQL('select dateadd(DAY, 1, "root".tradeDate) as "tradeDate", count("root".ID) as "ID count", ((1.0 * sum(("root".quantity * "root".weight))) / sum("root".weight)) as "Trade Weighted Average" from weightedTradeTable as "root" group by "tradeDate" order by "tradeDate"',$result); + assertSameElements(['2014-12-02,3,138.8', '2014-12-03,2,27.5', '2014-12-04,2,33.8', '2014-12-05,2,33.49999999999999'],$result.values->at(0).rows->map(r| $r.values->makeString(','))); +} + +function <> meta::relational::tests::tds::groupBy::testGroupByWithMultipleWavgAggregation(): Boolean[1] +{ + let mapping = meta::relational::tests::simpleRelationalMapping; + let runtime = meta::external::store::relational::tests::testRuntime(); + + let result = execute({| + WeightedTrade.all() + ->project( + [ x | $x.id, + x | $x.quantity, + x | $x.weight, + x | $x.weight2, + x | $x.tradeDate->adjust(1, DurationUnit.DAYS)], + [ 'Trade ID', + 'Quantity', + 'Weight', + 'Weight2', + 'tradeDate']) + ->groupBy(['tradeDate'], + [ + agg('ID count', x | $x.getInteger('Trade ID'), y | $y->count()), + agg('Trade Weighted Average', x | $x.getFloat('Quantity')->wavgRowMapper($x.getFloat('Weight')), y | $y->wavg()), + agg('Trade Weighted Average1', x | $x.getFloat('Quantity')->wavgRowMapper($x.getFloat('Weight2')), y | $y->wavg()) + ] + ) + ->sort(asc('tradeDate'))}, $mapping, $runtime, meta::relational::extension::relationalExtensions()); + + assertEquals(4, $result.values->at(0).rows->size()); + meta::relational::functions::asserts::assertSameSQL('select dateadd(DAY, 1, "root".tradeDate) as "tradeDate", count("root".ID) as "ID count", ((1.0 * sum(("root".quantity * "root".weight))) / sum("root".weight)) as "Trade Weighted Average", ((1.0 * sum(("root".quantity * "root".weight2))) / sum("root".weight2)) as "Trade Weighted Average1" from weightedTradeTable as "root" group by "tradeDate" order by "tradeDate"',$result); + assertSameElements(['2014-12-02,3,138.8,107.9', '2014-12-03,2,27.5,27.5', '2014-12-04,2,33.8,38.05', '2014-12-05,2,33.49999999999999,39.25'],$result.values->at(0).rows->map(r| $r.values->makeString(','))); +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/relationalSetUp.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/relationalSetUp.pure index 044ae7ef887..a73f2cad8bf 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/relationalSetUp.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/relationalSetUp.pure @@ -106,6 +106,7 @@ Database meta::relational::tests::db Table interactionTable(ID INT PRIMARY KEY, sourceId INT, targetId INT, time INT, active VARCHAR(1)) Table tradeTable(ID INT PRIMARY KEY, prodId INT, accountID INT, quantity FLOAT, tradeDate DATE, settlementDateTime TIMESTAMP) + Table weightedTradeTable(ID INT PRIMARY KEY, prodId INT, accountID INT, quantity FLOAT, weight FLOAT, weight2 FLOAT, tradeDate DATE, settlementDateTime TIMESTAMP) Table accountTable(ID INT PRIMARY KEY, name VARCHAR(200), createDate DATE) Table tradeEventTable(EVENT_ID INT PRIMARY KEY, trade_id INT, eventType VARCHAR(10), eventDate DATE, person_id INT) Table orderTable(ID INT PRIMARY KEY, prodId INT, accountID INT, quantity INT, orderDate DATE, settlementDateTime TIMESTAMP) @@ -702,6 +703,17 @@ Mapping meta::relational::tests::simpleRelationalMapping events : [db]@Trade_TradeEvent } + + WeightedTrade : Relational + { + id : [db]weightedTradeTable.ID, + quantity : [db]weightedTradeTable.quantity, + tradeDate : [db]weightedTradeTable.tradeDate, + settlementDateTime : [db]weightedTradeTable.settlementDateTime, + weight: [db]weightedTradeTable.weight, + weight2: [db]weightedTradeTable.weight2 + } + Order : Relational { id : [db]orderTable.ID, @@ -1150,6 +1162,19 @@ function meta::relational::tests::createTradeTableAndFillDb(connection : Databas //Wrong Trade data without a product or account executeInDb('insert into tradeTable (id, prodid, accountId, quantity, tradeDate) values (11, -3, -4, 5, \'2014-12-05\');', $connection); + + executeInDb('Drop table if exists weightedTradeTable;', $connection); + executeInDb('Create Table weightedTradeTable(id INT, prodid INT, accountId INT, quantity FLOAT, weight FLOAT, weight2 FLOAT, tradeDate DATE, settlementDateTime TIMESTAMP(9));', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (1, 1, 1, 25, 0.3, 0.3, \'2014-12-01\', \'2014-12-02 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (2, 1, 2, 320, 0.4, 0.3, \'2014-12-01\',\'2014-12-02 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (3, 2, 1, 11, 0.3, 0.4, \'2014-12-01\', \'2014-12-02 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (4, 2, 2, 23, 0.5, 0.5, \'2014-12-02\', \'2014-12-03 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (5, 2, 1, 32, 0.5, 0.5, \'2014-12-02\', \'2014-12-03 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (6, 3, 1, 27, 0.6, 0.35, \'2014-12-03\', \'2014-12-04 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (7, 3, 1, 44, 0.4, 0.65, \'2014-12-03\', \'2014-12-04 15:22:23.123456789\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (8, 3, 2, 22, 0.35, 0.25, \'2014-12-04\', \'2014-12-05 21:00:00\');', $connection); + executeInDb('insert into weightedTradeTable (id, prodid, accountId, quantity, weight, weight2, tradeDate, settlementDateTime) values (9, 3, 2, 45, 0.35, 0.75, \'2014-12-04\', \'2014-12-05 21:00:00\');', $connection); + true; } diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/testModel/simpleTestModel.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/testModel/simpleTestModel.pure index 6076465dcf3..063cadfdd70 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/testModel/simpleTestModel.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/testModel/simpleTestModel.pure @@ -673,3 +673,13 @@ Class meta::relational::tests::model::simple::Employee division: String[1]; org() {if(1==1,|if($this.category->isEmpty(),|'',|'A'), |if($this.division->isEmpty(),|'',|'B'))}: String[0..1]; } + +Class meta::relational::tests::model::simple::WeightedTrade +{ + id : Integer[1]; + tradeDate : StrictDate[1]; + quantity : Float[1]; + settlementDateTime : DateTime[0..1]; + weight: Float[1]; + weight2: Float[1]; +}