From 1c096336a36a770e96007e6fe38fdd0f9cc57994 Mon Sep 17 00:00:00 2001 From: Pierre De Belen Date: Tue, 12 Dec 2023 17:12:27 -0500 Subject: [PATCH] Stable point --- .gitignore | 2 +- h2Console.sh | 1 + h2Server.sh | 2 +- .../core/pure/extensions/extension.pure | 2 +- .../core/pure/mapping/mappingExtension.pure | 5 + .../pure/router/metamodel/clustering.pure | 38 +- .../core/pure/router/metamodel/diagram.pure | 16 +- .../core/pure/router/metamodel/routing.pure | 8 + .../core/pure/router/preeval/preeval.pure | 45 +- .../core/pure/router/printer/printer.pure | 3 + .../core/pure/router/router_main.pure | 4 +- .../pure/router/routing/router_routing.pure | 77 +- .../core/pure/router/store/cluster.pure | 55 +- .../core/pure/router/store/metamodel.pure | 1 + .../core/pure/router/store/routing.pure | 170 +++-- .../pure/serialization/toPureGrammar.pure | 26 +- .../legend-engine-pure-ide-light-pure/pom.xml | 21 + .../src/main/resources/pure_ide/concepts.pure | 3 +- .../finos/legend/engine/ide/PureIDELight.java | 11 +- .../pom.xml | 101 +++ .../pom.xml | 121 +++ .../pom.xml | 2 + .../LegendCompileMixedProcessorSupport.java | 8 +- .../java/generation/GenerateJavaProject.java | 2 +- .../platform/tests/javaGenerationTest.pure | 12 +- .../RelationalStoreExecutorBuilder.java | 2 +- .../pom.xml | 50 ++ .../resources/core_relational.definition.json | 2 + .../relational/contract/storeContract.pure | 53 +- .../projection/testGroupWithWindowSubset.pure | 8 +- .../pureToSQLQuery/pureToSQLQuery.pure | 371 ++++++---- .../pureToSQLQuery/pureToSQLQuery_union.pure | 10 +- .../relational/relation/tests.pure | 687 ++++++++++++++++++ .../relationalMappingExecution.pure | 106 +-- .../advanced/testContractMoneyScenario.pure | 6 +- pom.xml | 32 +- 36 files changed, 1708 insertions(+), 355 deletions(-) create mode 100755 h2Console.sh create mode 100644 legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml create mode 100644 legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relation/tests.pure diff --git a/.gitignore b/.gitignore index ef6ab288758..446aa40abb7 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,5 @@ /legend-engine-xt-graphQL-grammar/gen/ /welcome.pure /legend-engine-xt-nonrelationalStore-mongodb-grammar/gen/ +/legend-engine-core-shared/legend-engine-shared-core/src/main/resources/legendExecutionVersion.json /legend-engine-core/legend-engine-core-shared/legend-engine-shared-core/src/main/resources/legendExecutionVersion.json -temp diff --git a/h2Console.sh b/h2Console.sh new file mode 100755 index 00000000000..3e38267a725 --- /dev/null +++ b/h2Console.sh @@ -0,0 +1 @@ +java -jar ~/.m2/repository/com/h2database/h2/2.1.214/h2-2.1.214.jar \ No newline at end of file diff --git a/h2Server.sh b/h2Server.sh index 40cec646011..f355d9d0533 100755 --- a/h2Server.sh +++ b/h2Server.sh @@ -1 +1 @@ -java -cp ~/.m2/repository/com/h2database/h2/1.4.200/h2-1.4.200.jar org.h2.tools.Server -tcp -tcpPort 9092 -ifNotExists \ No newline at end of file +java -cp ~/.m2/repository/com/h2database/h2/2.1.214/h2-2.1.214.jar org.h2.tools.Server -tcp -tcpPort 1975 -ifNotExists \ No newline at end of file diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/extensions/extension.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/extensions/extension.pure index 9a1600ccd0e..97eee275633 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/extensions/extension.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/extensions/extension.pure @@ -161,7 +161,7 @@ function meta::pure::extension::print::printExtensions(extensions: Extension[*]) $extensions->sortBy(x | $x.type->toLower())->map(ext | $ext->printExtension(1))->joinStrings('[\n', ',\n\n', '\n]') } -function <> meta::pure::extension::print::printExtension(extension: Extension[1], depth: Integer[1]): String[1] +function meta::pure::extension::print::printExtension(extension: Extension[1], depth: Integer[1]): String[1] { let indent = indent($depth); diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure index 9c99e3835c7..178f41edb7b 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/mapping/mappingExtension.pure @@ -258,6 +258,11 @@ function <> meta::pure::router::operations::getMappedLeafClasses if($specs->isEmpty(), | $mappedClass, | $specs->map(s | $s->getMappedLeafClasses_recursive($mappedClass, $mapping, $state))); } +function <> meta::pure::mapping::from(t:T[m], runtime:Runtime[1]):T[m] +{ + $t +} + function <> meta::pure::mapping::from(t:T[m], m:meta::pure::mapping::Mapping[1], runtime:Runtime[1]):T[m] { $t diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/clustering.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/clustering.pure index f39ae0e0eed..de3f096c2e3 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/clustering.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/clustering.pure @@ -50,17 +50,11 @@ function meta::pure::router::clustering::generateExecutionNodeFromCluster(cluste sc:StoreMappingClusteredValueSpecification[1] | //This is required to populate the setup sql for test connections where csv data has been supplied. It is done here to ensure that the plan generation is always //the only place where sql is generated for this case. - let rt = $sc.runtime->match([ - r:Runtime[1] | ^$r(connectionStores = $r.connectionStores->map(c | if ($sc.s.reprocessConnection->isEmpty(),|$c,|^$c(connection=$sc.s.reprocessConnection->toOne()->eval($c))))), - r:Runtime[0..1] | $r - ]); - - - - - let query = ^meta::pure::mapping::StoreQuery(store=$sc.store, fe=$fe, inScopeVars=$inScopeVars); - let res = $sc.s.planExecution->toOne()->eval($query, $sc.val->match([r:RoutedValueSpecification[1]|$r, a:Any[*]|[]])->cast(@RoutedValueSpecification), $sc.mapping, $rt, if ($sc.exeCtx->isEmpty(), | $context, | $sc.exeCtx->toOne()), $extensions, $debugContext); - ^$res(fromCluster=$cluster);, + $sc->buildExecutionNodeForStoreClusteredVS($fe, $sc.mapping, $inScopeVars, $context, $extensions, $debugContext), + sc:StoreClusteredValueSpecification[1] | + //This is required to populate the setup sql for test connections where csv data has been supplied. It is done here to ensure that the plan generation is always + //the only place where sql is generated for this case. + $sc->buildExecutionNodeForStoreClusteredVS($fe, [], $inScopeVars, $context, $extensions, $debugContext), ef:ExternalFormatClusteredValueSpecification[1] | let state = ^meta::external::format::shared::executionPlan::ExternalFormatPlanGenerationState(inScopeVars = $inScopeVars, exeCtx = $ef.exeCtx->toOne(), binding = $ef.binding); $fe->meta::external::format::shared::executionPlan::processValueSpecification($state, $extensions, $debugContext)->toOne();, @@ -70,6 +64,19 @@ function meta::pure::router::clustering::generateExecutionNodeFromCluster(cluste ]); } +function meta::pure::router::clustering::buildExecutionNodeForStoreClusteredVS(sc:StoreClusteredValueSpecification[1], fe:FunctionExpression[1], mapping:meta::pure::mapping::Mapping[0..1], inScopeVars:Map>[1], context:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debugContext:DebugContext[1]):ExecutionNode[1] +{ + //This is required to populate the setup sql for test connections where csv data has been supplied. It is done here to ensure that the plan generation is always + //the only place where sql is generated for this case. + let rt = $sc.runtime->match([ + r:Runtime[1] | ^$r(connectionStores = $r.connectionStores->map(c | if ($sc.s.reprocessConnection->isEmpty(),|$c,|^$c(connection=$sc.s.reprocessConnection->toOne()->eval($c))))), + r:Runtime[0..1] | $r + ]); + let query = ^meta::pure::mapping::StoreQuery(store=$sc.store, fe=$fe, inScopeVars=$inScopeVars); + let res = $sc.s.planExecution->toOne()->eval($query, $sc.val->match([r:RoutedValueSpecification[1]|$r, a:Any[*]|[]])->cast(@RoutedValueSpecification), $mapping, $rt, if ($sc.exeCtx->isEmpty(), | $context, | $sc.exeCtx->toOne()), $extensions, $debugContext); + ^$res(fromCluster=$sc); +} + function meta::pure::router::clustering::areClustersCompatible(cluster1:ClusteredValueSpecification[1], cluster2:ClusteredValueSpecification[1], extensions:meta::pure::extension::Extension[*]):Boolean[1] { $cluster1->match([ @@ -99,6 +106,8 @@ function meta::pure::router::clustering::streamSupportedFunctionEvaluator(cluste $cluster->match([ sc:StoreMappingClusteredValueSpecification[1] | $sc.s.supportsStream, + sc:StoreClusteredValueSpecification[1] | + $sc.s.supportsStream, ef:ExternalFormatClusteredValueSpecification[1] | {fxn:FunctionExpression[1] | false}, pl:PlatformClusteredValueSpecification[1] | @@ -111,6 +120,8 @@ function meta::pure::router::clustering::elementPathForCluster(cluster:Clustered $cluster->match([ sc:StoreMappingClusteredValueSpecification[1] | $sc.store->elementToPath(), + sc:StoreClusteredValueSpecification[1] | + $sc.store->elementToPath(), ef:ExternalFormatClusteredValueSpecification[1] | $ef.binding->elementToPath(), pl:PlatformClusteredValueSpecification[1] | @@ -126,6 +137,11 @@ function meta::pure::router::clustering::toString(cluster:ClusteredValueSpecific | let start = '{'+$sc.store->toOne()->elementToPath()+'> '; $start + $sc.val->asString($pref)->replace('\n','\n'+space($start->length()))+'}'; );, + sc:StoreClusteredValueSpecification[1] | if($pref.useClusterIndex, + | '[Node Index:'+$pref.clusterIndex->indexOf($sc)->toString()+']', + | let start = '{'+$sc.store->toOne()->elementToPath()+'> '; + $start + $sc.val->asString($pref)->replace('\n','\n'+space($start->length()))+'}'; + );, p:PlatformClusteredValueSpecification[1] | if($pref.useClusterIndex, |'[Node Index:'+$pref.clusterIndex->indexOf($p)->toString()+']', |'{Platform> '+$p.val->asString($pref)->replace('\n','\n'+space('{Platform>'->length()))+'}'; diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/diagram.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/diagram.pure index 38b64776793..62a0a0b5a9f 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/diagram.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/diagram.pure @@ -78,8 +78,8 @@ Diagram meta::pure::router::metamodel::RouterMetaModelDiagram(width=0.0, height= TypeView cview_4( type=meta::pure::router::metamodel::RoutingStrategy, position=(-623.81836, -111.50000), - width=203.98145, - height=142.00000, + width=313.31667, + height=184.00000, stereotypesVisible=true, attributesVisible=true, attributeStereotypesVisible=true, @@ -228,7 +228,7 @@ Diagram meta::pure::router::metamodel::RouterMetaModelDiagram(width=0.0, height= GeneralizationView gview_2( source=cview_6, target=cview_4, - points=[(-720.13867,168.50000),(-521.82764,-40.50000)], + points=[(-720.13867,168.50000),(-467.16003,-19.50000)], label='', color=#000000, lineWidth=-1.0, @@ -255,7 +255,7 @@ Diagram meta::pure::router::metamodel::RouterMetaModelDiagram(width=0.0, height= GeneralizationView gview_5( source=cview_9, target=cview_4, - points=[(-519.81445,247.50000),(-521.82764,-40.50000)], + points=[(-519.81445,247.50000),(-467.16003,-19.50000)], label='', color=#000000, lineWidth=-1.0, @@ -291,7 +291,7 @@ Diagram meta::pure::router::metamodel::RouterMetaModelDiagram(width=0.0, height= GeneralizationView gview_9( source=cview_13, target=cview_4, - points=[(-331.81445,174.50000),(-521.82764,-40.50000)], + points=[(-331.81445,174.50000),(-467.16003,-19.50000)], label='', color=#000000, lineWidth=-1.0, @@ -324,11 +324,11 @@ Diagram meta::pure::router::metamodel::RouterMetaModelDiagram(width=0.0, height= lineWidth=-1.0, lineStyle=SIMPLE) - PropertyView pview_1( + PropertyView pview_0( property=meta::pure::router::metamodel::ExtendedRoutedValueSpecification.routingStrategy, source=cview_2, - target=cview_4 -, points=[(160.08545,-41.50000),(-521.82764,-40.50000)], + target=cview_4, + points=[(160.08545,-41.50000),(-467.16003,-19.50000)], label='', propertyPosition=(0.0,0.0), multiplicityPosition=(0.0,0.0), diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/routing.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/routing.pure index 13f69edab3e..adad135181f 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/routing.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/metamodel/routing.pure @@ -29,6 +29,7 @@ Class <> meta::pure::router::metamodel::ExtendedRoutedVa // ========================================================================================= ###Pure +import meta::pure::metamodel::relation::*; import meta::pure::extension::*; import meta::pure::router::metamodel::*; import meta::pure::router::routing::*; @@ -44,6 +45,12 @@ Class <> meta::pure::router::metamodel::RoutingStrategy $this.processClass->eval($c, $i, $state, $executionContext, $debug) }: RoutingState[1]; + processRelationStoreAccessor : Function<{RelationStoreAccessor[1], InstanceValue[1], RoutingState[1], ExecutionContext[1], DebugContext[1] -> RoutingState[1]}>[0..1]; + processRelationStoreAccessor(c:RelationStoreAccessor[1], i:InstanceValue[1], state:RoutingState[1], executionContext:ExecutionContext[1], debug:DebugContext[1]) + { + $this.processRelationStoreAccessor->toOne()->eval($c, $i, $state, $executionContext, $debug) + }: RoutingState[1]; + // Process Property processProperty : Function<{Property[1], FunctionExpression[1], RoutingState[1], ExecutionContext[1], Map[1], Map>[1], Extension[*], DebugContext[1] -> RoutingState[1]}>[1]; processProperty(p:Property[1], fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:Extension[*], debug:DebugContext[1]) @@ -81,6 +88,7 @@ function meta::pure::router::routing::toString(evs:ExtendedRoutedValueSpecificat { $evs->match([ sc:StoreMappingRoutedValueSpecification[1] | '['+$sc.id+' '+if($sc.propertyMapping->isEmpty(),|'',|'@'+$sc.propertyMapping->map(p|$p.property.name->toOne()+'('+$p.sourceSetImplementationId+'->'+$p.targetSetImplementationId+')')->joinStrings(',')+'@ ')+$sc.sets.id->joinStrings(', ')+'/'+$sc.value->asString($pref)+']', + s:StoreRoutedValueSpecification[1] | '['+$s.id+' '+$s.value->asString($pref)+']', p:PlatformRoutedValueSpecification[1] | '['+$p.id+' /'+$p.value->asString($pref)+']', e:ExternalFormatRoutedValueSpecification[1] | '['+$e.id+' /'+$e.value->asString($pref)+']' ]); diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure index 65fa9e1bbfb..6f6571d56db 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import meta::pure::metamodel::relation::*; import meta::pure::router::preeval::*; import meta::pure::extension::*; import meta::pure::metamodel::path::*; @@ -82,18 +83,11 @@ function <> meta::pure::router::preeval::preval(f : FunctionDefin if(!$r->anyModified(), | $state->printDebug(|'No changes made for: '); - $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions));, + $state->printDebug(|$f->meta::pure::metamodel::serialization::grammar::printFunctionDefinition(''));, | let res = $r.value->toOne(); - - // $state->printDebug('Transformed From:'); - // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000)); - // $state->printDebug(|$f->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::toPureGrammar::toPure($extensions)); - $state->printDebug('Transformed To:'); - $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::json::toJSON(50000)); - $state->printDebug(|$res->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::valueSpecification::transformFunctionBody($extensions)->meta::protocols::pure::vX_X_X::transformation::fromPureGraph::toPureGrammar::toPure($extensions)); - + $state->printDebug(|$res->meta::pure::metamodel::serialization::grammar::printFunctionDefinition('')); $state->printDebug($res); ); @@ -270,6 +264,7 @@ function <> meta::pure::router::preeval::prevalInternal(item : A {r: meta::pure::graphFetch::RootGraphFetchTree[1] | ^PrevalWrapper(value = $r, canPreval = true, modified = false);}, {b: meta::external::format::shared::binding::Binding[1] | ^PrevalWrapper(value = $b, canPreval = true, modified = false);}, {s: meta::pure::store::Store[1] | ^PrevalWrapper(value = $s, canPreval = true, modified = false);}, + {s: meta::pure::metamodel::relation::RelationStoreAccessor[1] | ^PrevalWrapper(value = $s, canPreval = false, modified = false);}, {a : Any[1]| assert($state.stopPreeval->eval($a), | 'Unsupported type: ' + $a->type()->match([pe:PackageableElement[1]|$pe->elementToPath(), t:Type[1]|$t->makeString()])); ^PrevalWrapper(value = $a, canPreval = true, modified = false); @@ -312,7 +307,6 @@ function <> meta::pure::router::preeval::prevalFunctionDefinitio | pair($state, list(if($p.second.values->isEmpty(), | $r, | $p.second.values->concatenate($r)))), | let fe = $r.value->cast(@FunctionExpression); - let varName = $fe.parametersValues->at(0)->reactivate($state.inScopeVars)->cast(@String)->toOne(); let varValue = $fe.parametersValues->at(1) ->match([ @@ -414,7 +408,11 @@ function <> meta::pure::router::preeval::prevalGenericSimpleFunc { let newParamWrappers = if($sfe.parametersValues->isEmpty(), | [], - | $sfe.func->match([p:Property[1]|'this', f:Function[1]|$f->functionType().parameters.name]) + | $sfe.func->match([ + p:Property[1]|'this', + c:Column[1]|'this', + f:Function[1]|$f->functionType().parameters.name + ]) ->zip($sfe.parametersValues) ->evaluateAndDeactivate() ->map(p| $state->printDebugWithDepth(|'Processing parameter: ' + $p.first); @@ -885,12 +883,16 @@ function <> meta::pure::router::preeval::resolveGenericType(in : { if($in.typeParameter->isEmpty(), | - let newTypeArgsWrappers = $in.typeArguments->map(ta|$ta->resolveGenericType($state)); - if(!$newTypeArgsWrappers->anyModified(), - | ^PrevalWrapper(value = $in, canPreval=true, modified = false), - | let value = ^$in(typeArguments = $newTypeArgsWrappers.value); - ^PrevalWrapper(value = $value, canPreval=$newTypeArgsWrappers->canPreval(), modified = $newTypeArgsWrappers->anyModified()); - );, + if($in.rawType->isNotEmpty() && $in.rawType->toOne()->instanceOf(FunctionType), + |^PrevalWrapper(value = ^$in(rawType=$in.rawType->cast(@FunctionType)->toOne()->resolveFunctionType($state)), canPreval=false, modified = true);, + |let newTypeArgsWrappers = $in.typeArguments->map(ta|$ta->resolveGenericType($state)); + if(!$newTypeArgsWrappers->anyModified(), + | ^PrevalWrapper(value = $in, canPreval=true, modified = false), + | let value = ^$in(typeArguments = $newTypeArgsWrappers.value); + ^PrevalWrapper(value = $value, canPreval=$newTypeArgsWrappers->canPreval(), modified = $newTypeArgsWrappers->anyModified()); + ); + ); + , | let value = $state.inScopeTypeParams->get($in.typeParameter->toOne().name); if($value->isEmpty(), @@ -900,6 +902,15 @@ function <> meta::pure::router::preeval::resolveGenericType(in : ); } +function <> meta::pure::router::preeval::resolveFunctionType(in : FunctionType[1], state : meta::pure::router::preeval::State[1]):FunctionType[1] +{ + ^$in + ( + parameters = $in.parameters->map(x|^$x(genericType = $x.genericType->resolveGenericType($state).value)), + returnType = $in.returnType->resolveGenericType($state).value + ); +} + function <> meta::pure::router::preeval::shouldInline(f:Function[1], state : meta::pure::router::preeval::State[1]):Boolean[1] { ($f->instanceOf(FunctionDefinition) && ($f->cast(@FunctionDefinition).expressionSequence->size() == 1 )) diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/printer/printer.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/printer/printer.pure index f869e650c02..a2f6ce2da58 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/printer/printer.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/printer/printer.pure @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import meta::pure::metamodel::relation::*; import meta::pure::metamodel::serialization::grammar::*; import meta::pure::metamodel::path::*; import meta::pure::router::clustering::*; @@ -47,6 +48,7 @@ function meta::pure::router::printer::asString(f:Function[1]):String[1] function meta::pure::router::printer::asString(f:Function[1], pref:Pref[1]):String[1] { $f->match([ + c:Column[1]|$c.name->toOne(), q:AbstractProperty[1] | $q.name->toOne(), f:LambdaFunction[1]| let start = $f->functionType().parameters->evaluateAndDeactivate()->map(v|$v.name+':'+$v.genericType->printGenericType()+'['+$v.multiplicity->printMultiplicity()+']')->makeString(',')+' | '; $start + $f.expressionSequence->evaluateAndDeactivate()->map(e|$e->asString($pref)->replace('\n','\n'+space($start->length())))->makeString(';\n'+space($start->length()))+';';, @@ -98,6 +100,7 @@ function meta::pure::router::printer::asString(f:FunctionExpression[1], pref:Pre $f.func->match( [ p:Property[1] | $f.parametersValues->at(0)->asString($pref)+'.'+$p->id(), + c:Column[1]| $f.parametersValues->at(0)->asString($pref)+'.'+$c.name->toOne(), fd:Function[1] | let dispatch = [ pair('getAll', f:FunctionExpression[1]|$f.parametersValues->at(0)->asString($pref)+'.all('+$f.parametersValues->tail()->map(v|$v->asString($pref))->joinStrings(', ')+')'), pair('equal', f:FunctionExpression[1]|$f.parametersValues->at(0)->asString($pref)+' == '+$f.parametersValues->at(1)->asString($pref)), diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/router_main.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/router_main.pure index 42f81ecb0e5..1e1b6da77de 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/router_main.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/router_main.pure @@ -135,7 +135,7 @@ function meta::pure::router::routeFunction(f:FunctionDefinition[1], routing let enrichedExpressionsAfterStrategyBasedEnrichment = $enrichedExpressions->map(exp | $exp->enrichExpressionWithStrategyBasedEnrichment($exeCtx, $extensions, $debug)); // Clustering Function Expressions into clusters - print(if($debug.debug,|'\n'+$debug.space+'Clustering Function Expressions:\n',|'')); + print(if($debug.debug,|'\n'+$debug.space+'Clustering Function Expressions:',|'')); let clusters = $enrichedExpressionsAfterStrategyBasedEnrichment->map(exp| $exp->clusterFunctionExpressions($openVariables, $exeCtx, $extensions, ^$debug(space = $debug.space + ' '))); // Wrapping Clustered Function Expressions into original function structure @@ -149,6 +149,7 @@ function meta::pure::router::enrichExpressionWithStrategyBasedEnrichment(vs: Ext { $vs->match([ sm: StoreMappingRoutedValueSpecification[1] | $sm->enrichStoreMappingRoutedValueSpecification($exeCtx, $extensions, $debug), + s: StoreRoutedValueSpecification[1] | $s, ef: ExternalFormatRoutedValueSpecification[1] | ^$ef(value = $ef.value->enrichExternalFormatRoutedValueSpecification($exeCtx, $extensions, $debug)), pl: PlatformRoutedValueSpecification[1] | ^$pl(value = $pl.value->enrichPlatformRoutedValueSpecification($exeCtx, $extensions, $debug)), er: ExtendedRoutedValueSpecification[1] | fail('Unexpected ExtendedRoutedValueSpecification encountered. Please raise the issue with dev team!'); @ExtendedRoutedValueSpecification; @@ -161,6 +162,7 @@ function meta::pure::router::clusterFunctionExpressions(vs:ExtendedRoutedValueSp $vs->match([ sm: StoreMappingRoutedValueSpecification[1] | $sm->doCluster($sm.mapping, $sm.runtime, $openVariables, $exeCtx, $extensions, $debug), + s : StoreRoutedValueSpecification[1] | $s->doCluster([], $s.runtime, $openVariables, $exeCtx, $extensions, $debug), ef: ExternalFormatRoutedValueSpecification[1] | let clusteredVal = $ef.value->meta::pure::router::externalFormat::clustering::cluster($ef.binding, $openVariables, $exeCtx, $extensions, $debug)->toOne(); if($clusteredVal->instanceOf(ClusteredValueSpecification), |let cluster = $clusteredVal->cast(@ClusteredValueSpecification); diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure index 1c9b3b0c9be..5e40195236a 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/routing/router_routing.pure @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import meta::pure::metamodel::relation::*; import meta::pure::graphFetch::routing::*; import meta::pure::graphFetch::*; import meta::pure::mapping::*; @@ -131,9 +132,26 @@ function <> meta::pure::router::routing::routeValueSpecification f:FunctionRoutedValueSpecification[1] | ^$state(value=$f.value)->routeValueSpecification($executionContext, $vars, $inScopeVars, $extensions, $debug), r:NoSetRoutedValueSpecification[1] | ^$state(value=$r.value)->routeValueSpecification($executionContext, $vars, $inScopeVars, $extensions, $debug), fe:FunctionExpression[1] | $fe->routeFunctionExpression($state, $executionContext, $vars, $inScopeVars, $extensions, $debug), - i:InstanceValue[1] | if($i->isOneClass() || ($i.values->isEmpty() && $i.multiplicity == PureOne && $i.genericType.rawType->isNotEmpty() && $i.genericType.rawType->toOne()->instanceOf(Class)), - | let c = if($i.values->isEmpty(), | $i.genericType.rawType->toOne()->cast(@Class), | $i.values->at(0)->cast(@Class)); - $state.routingStrategy.processClass($c, $i, $state, $executionContext, $debug);, + i:InstanceValue[1] | if( + [ + pair( + | $i.values->size() == 1 && $i.values->at(0)->instanceOf(RelationStoreAccessor) || ($i.values->isEmpty() && $i.multiplicity == PureOne && $i.genericType.rawType->isNotEmpty() && $i.genericType.rawType->toOne()->subTypeOf(Relation)), + | // We match cast to Relation & RelationStoreAccessor.. However we're only processing the Accessor + if($i.values->size() == 1 && $i.values->at(0)->instanceOf(RelationStoreAccessor), + | $state.routingStrategy.processRelationStoreAccessor($i.values->at(0)->cast(@RelationStoreAccessor), $i, $state, $executionContext, $debug);, + | $state + ); + ), + pair( + |$i->isOneClass() || ($i.values->isEmpty() && $i.multiplicity == PureOne && $i.genericType.rawType->isNotEmpty() && $i.genericType.rawType->toOne()->instanceOf(Class)), + | // Process for cast or Class.all() + let c = if($i.values->isEmpty(), + | $i.genericType.rawType->toOne()->cast(@Class), + | $i.values->at(0)->cast(@Class) + ); + $state.routingStrategy.processClass($c, $i, $state, $executionContext, $debug); + ) + ], | if($i.values->isEmpty(), |$state, |let processedValues = processCollection($state, $i.values->evaluateAndDeactivate(), $executionContext, $vars, $inScopeVars, v:Any[1]|true, $extensions, $debug); @@ -144,11 +162,10 @@ function <> meta::pure::router::routing::routeValueSpecification | ^$i(values = $processedValues->evaluateAndDeactivate().value->cast(@InstanceValue)->map(e|$e.values)), | ^$i(values = $processedValues->evaluateAndDeactivate().value))); ); - );, + );, cs:ClassSetImplementationHolder[1] | let param = $cs.value->cast(@InstanceValue).values->at(0)->cast(@Class); // TODO: cleanup needed let currentStrategy = $state.routingStrategy->cast(@meta::pure::router::store::metamodel::StoreMappingRoutingStrategy); let updatedStrategy = ^$currentStrategy(toChooseSet = $cs.set); - let resolvedState = $updatedStrategy.processClass($param, $cs.value->cast(@InstanceValue), ^$state(routingStrategy = $updatedStrategy), $executionContext, $debug); let resStrategy = $resolvedState.routingStrategy->cast(@meta::pure::router::store::metamodel::StoreMappingRoutingStrategy); ^$resolvedState(routingStrategy = ^$resStrategy(toChooseSet = []));, @@ -169,31 +186,40 @@ function <> meta::pure::router::routing::routeValueSpecification ); } -function meta::pure::router::routing::prevalFunctionExpressionIfRequired(fe:FunctionExpression[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]) : FunctionExpression[1] +function meta::pure::router::routing::prevalFunctionExpressionIfRequired(fe:FunctionExpression[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]) : ValueSpecification[1] { $fe.func->match( [ f : FunctionDefinition[1] | if($f->hasStereotype('NormalizeRequiredFunction', functionType), - | $fe->meta::pure::router::preeval::preval($inScopeVars->putAll($f->openVariableValues()), $extensions, noDebug()), - | $fe), + | $fe->meta::pure::router::preeval::preval($inScopeVars->putAll($f->openVariableValues()), $extensions, $debug), + | $fe + ), a:Any[*] | $fe; ] - )->cast(@FunctionExpression); + )->cast(@ValueSpecification); } function meta::pure::router::routing::routeFunctionExpression(fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):RoutingState[1] { - let newFe = prevalFunctionExpressionIfRequired($fe,$inScopeVars, $extensions, $debug); - - $newFe.func->match([ - p:Property[1] | $state.routingStrategy.processProperty($p, $newFe, $state, $executionContext, $vars, $inScopeVars, $extensions, $debug);, - f:Function[1] | print(if($debug.debug,|$debug.space+if($f->instanceOf(NativeFunction),|'NativeFunction',|'FunctionDefinition')+' : '+$f->asString()+'\n',|'')); - let specializedFunctionProcessor = specializedFunctionExpressionRouterProcessor($extensions)->filter(e|$e.first->eval($newFe)).second; - if($specializedFunctionProcessor->isNotEmpty(), - | assert($specializedFunctionProcessor->size() == 1, | 'Only one match is authorized for specializedFunctionProcessor'); - $specializedFunctionProcessor->toOne()->evaluate([list($f), list($newFe), list($state), list($executionContext), list($vars), list($inScopeVars), list($extensions), list($debug)])->toOne()->cast(@RoutingState);, - | $f->routeFunctionExpressionFunctionDefinition($newFe, $state, $executionContext, $vars, $inScopeVars->putAll($f->openVariableValues()), $extensions, $debug);); - ]); + let newFe = prevalFunctionExpressionIfRequired($fe,$inScopeVars, $extensions, $debug)->evaluateAndDeactivate(); + + $newFe->match([ + nfe : FunctionExpression[1]| + $nfe.func->match([ + p:Property[1] | $state.routingStrategy.processProperty($p, $nfe, $state, $executionContext, $vars, $inScopeVars, $extensions, $debug);, + c:Column[1] | print(if($debug.debug,|$debug.space+' Column: '+$c.name->toOne()+'\n',|'')); + $c->routeFunctionExpressionColumn($nfe, $state, $executionContext, $vars, $inScopeVars, $extensions, $debug);, + f:Function[1] | print(if($debug.debug,|$debug.space+if($f->instanceOf(NativeFunction),|'NativeFunction',|'FunctionDefinition')+' : '+$f->asString()+'\n',|'')); + let specializedFunctionProcessor = specializedFunctionExpressionRouterProcessor($extensions)->filter(e|$e.first->eval($nfe)).second; + if($specializedFunctionProcessor->isNotEmpty(), + | assert($specializedFunctionProcessor->size() == 1, | 'Only one match is authorized for specializedFunctionProcessor'); + $specializedFunctionProcessor->toOne()->evaluate([list($f), list($nfe), list($state), list($executionContext), list($vars), list($inScopeVars), list($extensions), list($debug)])->toOne()->cast(@RoutingState);, + | $f->routeFunctionExpressionFunctionDefinition($nfe, $state, $executionContext, $vars, $inScopeVars->putAll($f->openVariableValues()), $extensions, $debug);); + ]);, + i : InstanceValue[1]|^$state(value=$i) + ] + + ); } function meta::pure::router::routing::specializedFunctionExpressionRouterProcessor(extensions:meta::pure::extension::Extension[*]):PairBoolean[1]}>, Function<{Function[1], FunctionExpression[1], RoutingState[1], ExecutionContext[1], Map[1], Map>[1], meta::pure::extension::Extension[*], DebugContext[1]->RoutingState[1]}>>[*] @@ -203,6 +229,13 @@ function meta::pure::router::routing::specializedFunctionExpressionRouterProcess ->concatenate($extensions.routerExtensions().routeFunctionExpressions) } +function meta::pure::router::routing::routeFunctionExpressionColumn(c:Column[1], fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):RoutingState[1] +{ + let p = ^$state(value=$fe.parametersValues->evaluateAndDeactivate()->at(0)); + let nstate = $p->meta::pure::router::routing::routeValueSpecification($executionContext, $vars, $inScopeVars, $extensions, ^$debug(space = $debug.space+' ')); + ^$state(value=^$fe(parametersValues = $nstate.value->cast(@ValueSpecification))); +} + function meta::pure::router::routing::routeFunctionExpressionFunctionDefinition(f:Function[1], fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):RoutingState[1] { if ($fe.parametersValues->isEmpty(), @@ -338,7 +371,7 @@ function meta::pure::router::routing::routeFunctionExpressionFunctionDefinition( | if(isGetAllFunction($f), |$routed->filter(v|let ta = $v.value.genericType.typeArguments; $ta->isNotEmpty() && $ta->at(0).rawType->toOne()->_subTypeOf($returnClass->toOne());), - |$newSet->filter(v|if ($v.value.genericType.rawType == Property || $v.value.genericType.rawType == Path, + |$newSet->filter(v|if ($v.value.genericType.rawType == Property || $v.value.genericType.rawType == Path || $v.value.genericType.rawType == Column, |$v.value.genericType.typeArguments->at(1).rawType->toOne()->_subTypeOf($returnClass->toOne()), |if ($v.value.genericType.rawType == LambdaFunction, | $v.value.genericType.typeArguments->at(0).rawType->cast(@FunctionType).returnType.rawType->toOne()->_subTypeOf($returnClass->toOne()), @@ -465,7 +498,7 @@ function meta::pure::router::routing::routeSubFunction(state:RoutingState[1], ex function meta::pure::router::routing::processColumnSpecification(v:ValueSpecification[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):RoutingState[1] { let i = $v->match([i:InstanceValue[1]| $i, - v:VariableExpression[1]|^InstanceValue(genericType=$v.genericType, multiplicity=$v.multiplicity, values=$inScopeVars->get($v.name).values)->evaluateAndDeactivate(), + v:VariableExpression[1]| ^InstanceValue(genericType=$v.genericType, multiplicity=$v.multiplicity, values=$inScopeVars->get($v.name).values)->evaluateAndDeactivate(), f:FunctionExpression[1]| ^InstanceValue(genericType=$f.genericType, multiplicity=$f.multiplicity, values=$f)->evaluateAndDeactivate()]); $i.values->fold({v,a| $v->match([ diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/cluster.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/cluster.pure index b341f47866a..2e7730b2cce 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/cluster.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/cluster.pure @@ -71,7 +71,7 @@ Class meta::pure::router::clustering::ClusterResponse executableSetOperations: Pair[*]; } -function meta::pure::router::doCluster(enrichedExpression:StoreMappingRoutedValueSpecification[1], mapping:Mapping[1], runtime: Runtime[1], openVariables:Map>[1], exeCtx: ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ClusteredValueSpecification[*] +function meta::pure::router::doCluster(enrichedExpression:StoreRoutedValueSpecification[1], mapping:Mapping[0..1], runtime: Runtime[1], openVariables:Map>[1], exeCtx: ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ClusteredValueSpecification[*] { let clusterResult = $enrichedExpression->cluster($mapping, $runtime, $openVariables, $exeCtx, $extensions, $debug); if($clusterResult.cluster->instanceOf(ClusteredValueSpecification), @@ -86,10 +86,11 @@ function meta::pure::router::doCluster(enrichedExpression:StoreMappingRoutedValu )); } -function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mapping:Mapping[1], runtime: Runtime[1], openVariables:Map>[1], exeCtx:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ClusterResponse[1] +function meta::pure::router::clustering::cluster(v:ValueSpecification[1], _mapping:Mapping[0..1], runtime: Runtime[1], openVariables:Map>[1], exeCtx:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ClusterResponse[1] { if($exeCtx->instanceOf(AnalyticsExecutionContext) && ($exeCtx->cast(@AnalyticsExecutionContext).useAnalytics == true), - | let allPropertyAccesses = meta::pure::router::analytics::getAllPropertyAccesses($v, $mapping, $extensions); + | let mapping = $_mapping->toOne(); + let allPropertyAccesses = meta::pure::router::analytics::getAllPropertyAccesses($v, $mapping, $extensions); let crossPropertyAccesses = $allPropertyAccesses->meta::pure::router::analytics::filterCrossPropertyAccesses(); if($crossPropertyAccesses->size() == 0, | cluster($v, $mapping, $openVariables, $exeCtx, $debug, [], $extensions), @@ -200,7 +201,7 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin ); ^$finalCluster(letFunctions = $createdLetFns->concatenate($finalCluster.letFunctions)); );, - | cluster($v, $mapping, $openVariables, $exeCtx, $debug, [], $extensions); + | cluster($v, $_mapping, $openVariables, $exeCtx, $debug, [], $extensions); ); } @@ -239,14 +240,14 @@ function meta::pure::router::clustering::specializedFunctionExpressionClustering } -function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mapping:Mapping[1], openVariables:Map>[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], analyticsDecision: AnalyticsDecision[0..1], extensions:meta::pure::extension::Extension[*]):ClusterResponse[1] +function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mapping:Mapping[0..1], openVariables:Map>[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], analyticsDecision: AnalyticsDecision[0..1], extensions:meta::pure::extension::Extension[*]):ClusterResponse[1] { - cluster($v, $mapping, $openVariables, $exeCtx, '', $debug, $analyticsDecision, $extensions) + cluster($v, $mapping, $openVariables, $exeCtx, '', $debug, $analyticsDecision, $extensions); } -function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mapping:Mapping[1], openVariables:Map>[1], exeCtx:ExecutionContext[1], paramSuffix: String[1], debug:DebugContext[1], analyticsDecision: AnalyticsDecision[0..1], extensions:meta::pure::extension::Extension[*]):ClusterResponse[1] +function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mapping:Mapping[0..1], openVariables:Map>[1], exeCtx:ExecutionContext[1], paramSuffix: String[1], debug:DebugContext[1], analyticsDecision: AnalyticsDecision[0..1], extensions:meta::pure::extension::Extension[*]):ClusterResponse[1] { - $v->match([f:FunctionExpression[1]| + $v->match([f:FunctionExpression[1]| let specializedFunctionProcessor = specializedFunctionExpressionClustering()->filter(spec | $spec.first->eval($f->evaluateAndDeactivate())).second; if($specializedFunctionProcessor->isNotEmpty(), | assert($specializedFunctionProcessor->size() == 1, | 'Only one match is authorized for specializedFunctionProcessor'); @@ -254,7 +255,7 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin | let childClustersResponse = $f.parametersValues->evaluateAndDeactivate()->map(v|$v->cluster($mapping, $openVariables, $exeCtx, $paramSuffix + '_' + indexOf($f.parametersValues,$v)->toString(), $debug, $analyticsDecision, $extensions)); let pre_params = $childClustersResponse.cluster->evaluateAndDeactivate(); let paramsExecutablePairs = if($analyticsDecision->isNotEmpty(), - | let crossPropertyAccesses = meta::pure::router::analytics::getAllCrossPropertyAccesses($f, $mapping, $extensions); + | let crossPropertyAccesses = meta::pure::router::analytics::getAllCrossPropertyAccesses($f, $mapping->toOne(), $extensions); if($crossPropertyAccesses->isNotEmpty(), | let newExecutables = $pre_params->map(p | $p->match([ c:StoreMappingClusteredValueSpecification[1] | if($c.executable && $c.val->instanceOf(StoreMappingRoutedValueSpecification) && $c.val->cast(@StoreMappingRoutedValueSpecification).sets->size() == 1 && $analyticsDecision.replacedSets.first.id->contains($c.val->cast(@StoreMappingRoutedValueSpecification).sets.id->toOne()), @@ -274,16 +275,15 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin let childExecutables = $childClustersResponse.executableSetOperations; let unique = getDistinctClusterVSByStore($params, $extensions); - if ($unique->size() == 1 && $unique->toOne()->instanceOf(StoreMappingClusteredValueSpecification) && ($f.func->instanceOf(Property) || $f.func->instanceOf(QualifiedProperty) || $unique->at(0)->cast(@StoreMappingClusteredValueSpecification).s.supports->toOne()->eval($f->evaluateAndDeactivate())), + if ($unique->size() == 1 && $unique->toOne()->instanceOf(StoreClusteredValueSpecification) && ($f.func->instanceOf(Property) || $f.func->instanceOf(QualifiedProperty) || $unique->at(0)->cast(@StoreClusteredValueSpecification).s.supports->toOne()->eval($f->evaluateAndDeactivate())), | let one = $unique->toOne(); print(if($debug.debug,|$f->evaluateAndDeactivate()->asString()->debug($debug.space+'Func Expression(merge): '),|'')); let res =^$one( genericType = $f.genericType, multiplicity = $f.multiplicity, - val = ^$f(parametersValues = $params->evaluateAndDeactivate()->map(p|$p->match([c:StoreMappingClusteredValueSpecification[1]|$c.val;, a:ValueSpecification[1]|$a]))), - executable = $params->evaluateAndDeactivate()->map(p|$p->match([c:StoreMappingClusteredValueSpecification[1]|$c.executable;, a:ValueSpecification[1]|[]]))->concatenate(false)->toOneMany()->or() || $f.functionName == 'getAll' + val = ^$f(parametersValues = $params->evaluateAndDeactivate()->map(p|$p->match([c:StoreClusteredValueSpecification[1]|$c.val;, a:ValueSpecification[1]|$a]))), + executable = $params->evaluateAndDeactivate()->map(p|$p->match([c:StoreClusteredValueSpecification[1]|$c.executable;, a:ValueSpecification[1]|[]]))->concatenate(false)->toOneMany()->or() || $f.functionName == 'getAll' ); - print(if($debug.debug,|$res->evaluateAndDeactivate()->asString()->debug($debug.space+'~> '),|'')); ^ClusterResponse(cluster=$res,letFunctions=$letFunctions,executableSetOperations=$executables->concatenate($childExecutables));, | print(if($debug.debug,|$f->evaluateAndDeactivate()->asString()->debug($debug.space+'Func Expression(non unique: '+$unique->size()->toString()+'): '),|'')); let k = if ($unique->size() == 0, @@ -350,8 +350,7 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin print(if($debug.debug,|$k.cluster->last()->evaluateAndDeactivate()->cast(@ValueSpecification)->toOne()->asString()->debug($debug.space+'~> '),|'')); $k; ););, - - r:StoreMappingRoutedValueSpecification[1]| + r:StoreMappingRoutedValueSpecification[1]| print(if($debug.debug,|$r->evaluateAndDeactivate()->asString()->debug($debug.space+'Routed: '),|'')); let crossPropertyAccesses = $analyticsDecision->isEmpty()->if(|[], |meta::pure::router::analytics::getAllCrossPropertyAccesses($r, $r.mapping, $extensions)); let clusterResponse = $r.value->cluster($r.mapping, $openVariables, $r.executionContext, ^$debug(space = $debug.space+' '), $analyticsDecision, $extensions); @@ -360,7 +359,7 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin c: ClusteredValueSpecification[1]|^$c(val = ^$r(value = $c.val)), a: Any[1]| if($r.sets->isEmpty(), // This check is needed for expressions (like : let x = 1->from($mapping, $runtime)) where there are no sets found | $clusterResponse.cluster, - | $r->meta::pure::router::clustering::getClusterVSFromSets($r.sets, $openVariables, $mapping, $extensions)); + | $r->meta::pure::router::clustering::getClusterVSFromSets($r.sets, $openVariables, $mapping->toOne(), $extensions)); ] ); let y = if($crossPropertyAccesses->isNotEmpty(), @@ -402,9 +401,9 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin );, | print(if($debug.debug,|$i->asString()->debug($debug.space+'Constant: '),|'')); let potentialClusterResponses = $i.values->evaluateAndDeactivate()->map(m|if($m->instanceOf(ValueSpecification), - | $m->cast(@ValueSpecification)->cluster($mapping, $openVariables, $exeCtx, ^$debug(space = $debug.space+' '), $analyticsDecision, $extensions), + | $m->cast(@ValueSpecification)->cluster($mapping, $openVariables, $exeCtx, ^$debug(space = $debug.space+' '), $analyticsDecision, $extensions), | $m->match([ - g : meta::pure::graphFetch::routing::RoutedGraphFetchTree[1] | $g->meta::pure::graphFetch::routing::clusterRoutedGraphFetchTree([], $mapping, [], $openVariables, $exeCtx, $extensions, $debug), + g : meta::pure::graphFetch::routing::RoutedGraphFetchTree[1] | $g->meta::pure::graphFetch::routing::clusterRoutedGraphFetchTree([], $mapping->toOne(), [], $openVariables, $exeCtx, $extensions, $debug), a : Any[1] | $a ]))); let values = $potentialClusterResponses->map(r|if($r->instanceOf(ClusterResponse),| $r->cast(@ClusterResponse).cluster,|$r)); @@ -421,7 +420,7 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin );, | ^$i(values = $values); ); - print(if($debug.debug,|$res->asString()->debug($debug.space+'~> '),|'')); + print(if($debug.debug,|$res->asString()->debug($debug.space+' ~> '),|'')); ^ClusterResponse(cluster=$res, letFunctions = $letFunctions, executableSetOperations=$executables); );, r:FunctionRoutedValueSpecification[1]|let clusterResponse = $r.value->cluster($mapping, $openVariables, $exeCtx,^$debug(space = $debug.space+' '), $analyticsDecision, $extensions); @@ -443,6 +442,20 @@ function meta::pure::router::clustering::cluster(v:ValueSpecification[1], mappin exeCtx = $t.executionContext, executable = true )), + s:StoreRoutedValueSpecification[1]| + ^ClusterResponse( cluster = ^StoreClusteredValueSpecification( + genericType = $s.genericType, + multiplicity = $s.multiplicity, + s = meta::pure::extension::storeContractFromStore($extensions, $s.store->toOne()), + store = $s.store->toOne(), + runtime = $s.runtime, + openVars = $openVariables, + val = $s.value->cluster([], $openVariables, $s.executionContext, ^$debug(space = $debug.space+' '), $analyticsDecision, $extensions).cluster, + exeCtx = $s.executionContext, + executable = true + ) + ) + , e:ExtendedRoutedValueSpecification[1] | ^ClusterResponse(cluster=$e->clusterFunctionExpressions($openVariables, $exeCtx, $extensions, $debug)->toOne()) ] @@ -499,12 +512,12 @@ function meta::pure::router::clustering::getDistinctClusterVSByStore(params:Valu | []); let p_unique = $allClusters->concatenate($params)->filter(p|$p->instanceOf(ClusteredValueSpecification))->cast(@ClusteredValueSpecification)->removeDuplicates({x, y | ($x->instanceOf(PlatformClusteredValueSpecification) && $y->instanceOf(PlatformClusteredValueSpecification)) - || ($x->instanceOf(StoreMappingClusteredValueSpecification) && $y->instanceOf(StoreMappingClusteredValueSpecification) && areStoreMappingClustersCompatible($x->cast(@StoreMappingClusteredValueSpecification), $y->cast(@StoreMappingClusteredValueSpecification), $extensions))}); + || ($x->instanceOf(StoreClusteredValueSpecification) && $y->instanceOf(StoreClusteredValueSpecification) && areStoreMappingClustersCompatible($x->cast(@StoreClusteredValueSpecification), $y->cast(@StoreClusteredValueSpecification), $extensions))}); let n_unique = if ($p_unique->size() > 1,|$p_unique->filter(p|!$p.val->isOneFunction()),|$p_unique); $n_unique; } -function meta::pure::router::store::clustering::areStoreMappingClustersCompatible(cluster1:StoreMappingClusteredValueSpecification[1], cluster2:StoreMappingClusteredValueSpecification[1], extensions:meta::pure::extension::Extension[*]):Boolean[1] +function meta::pure::router::store::clustering::areStoreMappingClustersCompatible(cluster1:StoreClusteredValueSpecification[1], cluster2:StoreClusteredValueSpecification[1], extensions:meta::pure::extension::Extension[*]):Boolean[1] { ($cluster1.store->elementToPath() == $cluster2.store->elementToPath()) && meta::core::runtime::runtimeEquality($cluster1.runtime, $cluster2.runtime, $extensions) && ($cluster1.exeCtx == $cluster2.exeCtx); } diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/metamodel.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/metamodel.pure index 88f99a06b20..51d5c6f1242 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/metamodel.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/metamodel.pure @@ -45,6 +45,7 @@ Class meta::pure::router::store::metamodel::PermutationSet Class meta::pure::router::store::metamodel::StoreRoutingStrategy extends RoutingStrategy { + store : Store[0..1]; runtime : Runtime[1]; } diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/routing.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/routing.pure index bb57daf24cc..044ee59f7d3 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/routing.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/routing.pure @@ -10,8 +10,9 @@ // 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. +// limitations under the License. +import meta::pure::metamodel::relation::*; import meta::pure::graphFetch::*; import meta::pure::mapping::*; import meta::pure::router::builder::*; @@ -36,54 +37,95 @@ function meta::pure::router::store::routing::getRoutingStrategyFromMappingAndRun setsByDepth = ^Map(), classMappingsByClass = $mapping->buildClassMappingsByClassMap(), processClass = processClass_Class_1__InstanceValue_1__RoutingState_1__ExecutionContext_1__DebugContext_1__RoutingState_1_, + processRelationStoreAccessor = processRelationStoreAccessor_RelationStoreAccessor_1__InstanceValue_1__RoutingState_1__ExecutionContext_1__DebugContext_1__RoutingState_1_, processProperty = routeFunctionExpressionProperty_Property_1__FunctionExpression_1__RoutingState_1__ExecutionContext_1__Map_1__Map_1__Extension_MANY__DebugContext_1__RoutingState_1_, - wrapValueSpec = wrapValueSpecification_ValueSpecification_1__RoutingStrategy_1__String_1__ExecutionContext_1__Extension_MANY__DebugContext_1__ExtendedRoutedValueSpecification_1_, + wrapValueSpec = wrapValueSpecificationStoreMapping_ValueSpecification_1__RoutingStrategy_1__String_1__ExecutionContext_1__Extension_MANY__DebugContext_1__ExtendedRoutedValueSpecification_1_, toString = {strategy:RoutingStrategy[1] | $strategy->cast(@StoreMappingRoutingStrategy).sets->size()->toString()}); } +function meta::pure::router::store::routing::getRoutingStrategyFromRuntime(runtime:Runtime[1]):StoreRoutingStrategy[1] +{ + ^StoreRoutingStrategy(runtime = $runtime, + processRelationStoreAccessor = processRelationStoreAccessor_RelationStoreAccessor_1__InstanceValue_1__RoutingState_1__ExecutionContext_1__DebugContext_1__RoutingState_1_, + + processClass = processClassPassThrough_Class_1__InstanceValue_1__RoutingState_1__ExecutionContext_1__DebugContext_1__RoutingState_1_, + processProperty = routeFunctionExpressionProperty_Property_1__FunctionExpression_1__RoutingState_1__ExecutionContext_1__Map_1__Map_1__Extension_MANY__DebugContext_1__RoutingState_1_, + + wrapValueSpec = wrapValueSpecificationStore_ValueSpecification_1__RoutingStrategy_1__String_1__ExecutionContext_1__Extension_MANY__DebugContext_1__ExtendedRoutedValueSpecification_1_, + toString = {strategy:RoutingStrategy[1] | 'StoreRoutingStrategy'}); +} + +function <> meta::pure::router::store::routing::processRelationStoreAccessor(c:RelationStoreAccessor[1], i:InstanceValue[1], s:RoutingState[1], executionContext:ExecutionContext[1], debug:DebugContext[1]):RoutingState[1] +{ + let strategy = $s.routingStrategy->cast(@StoreRoutingStrategy); + let nStrategy = ^$strategy(store=$c.store); + let runtime = $strategy.runtime; + let id = $s.counter + 1; + let routed = ^StoreRoutedValueSpecification(genericType = $i.genericType, + multiplicity = $i.multiplicity, + id = $id->toString(), + store = $c.store, + runtime = $runtime, + executionContext = $executionContext, + value = $i, + routingStrategy = $nStrategy); + ^$s( + counter = $id, + routingStrategy = $nStrategy, + value = $routed + ); +} + +function <> meta::pure::router::store::routing::processClassPassThrough(c:Class[1], i:InstanceValue[1], s:RoutingState[1], executionContext:ExecutionContext[1], debug:DebugContext[1]):RoutingState[1] +{ + ^$s(depth = $s.depth + $c->varToString()); +} + function <> meta::pure::router::store::routing::processClass(c:Class[1], i:InstanceValue[1], s:RoutingState[1], executionContext:ExecutionContext[1], debug:DebugContext[1]):RoutingState[1] { - let strategy = $s.routingStrategy->cast(@StoreMappingRoutingStrategy); - let mapping = $strategy.mapping; - let runtime = $strategy.runtime; - - let state = ^$s(depth = $s.depth + $c->varToString()); - let classMapping = if($strategy.toChooseSet->isEmpty(), |$mapping->rootClassMappingByClass($c)->potentiallyResolveOperation($mapping), |$strategy.toChooseSet); - // Possible when the mapping is 'embedded' - if ($classMapping->isEmpty(), - | print(if($debug.debug,|$debug.space+'~>C) ('+$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->size()->toString()+') '+$state.value->toOne()->toString()+'\n',|'')); - $state;, - | let existingSet = $state->findExistingPemutationSet($debug); - let existingSetCanBeUsed = $existingSet->permutationSetOnlyHasImplementation($classMapping); - let newID = if($existingSetCanBeUsed, - | $existingSet->toOne().id->cast(@Integer), - | $state.counter+1 - )->toString(); - let newSet = if (!$existingSetCanBeUsed,|^PermutationSet(id = $state.counter+1, sets = $classMapping),|[]); - let currentRoutingStrategy = $state.routingStrategy->cast(@StoreMappingRoutingStrategy)->toOne(); - let updatedRoutingStrategy = ^$currentRoutingStrategy(setsByDepth = if (!$existingSetCanBeUsed, - |let setByD = $state.routingStrategy->cast(@StoreMappingRoutingStrategy).setsByDepth; - $setByD->put(getSetPath($state), $newSet->toOne());, - |$state.routingStrategy->cast(@StoreMappingRoutingStrategy).setsByDepth - ), - sets = if (!$existingSetCanBeUsed,|$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->add($newSet->toOne()),|$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets)); - let routed = ^StoreMappingRoutedValueSpecification(genericType = $i.genericType, - multiplicity = $i.multiplicity, - id = $newID, - sets = $classMapping, - runtime = $runtime, - mapping = $mapping, - executionContext = $executionContext, - value = $i, - routingStrategy = $updatedRoutingStrategy); - let res = ^$state( - counter = if (!$existingSetCanBeUsed,|$state.counter+1,|$state.counter), - routingStrategy = $updatedRoutingStrategy, - value = $routed - ); - print(if($debug.debug,|$debug.space+'~>C) ('+$res.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->size()->toString()+') '+$routed->evaluateAndDeactivate()->asString()+'\n',|'')); - $res; - ); + // Route a Class using the Mapping + let strategy = $s.routingStrategy->cast(@StoreMappingRoutingStrategy); + let mapping = $strategy.mapping; + let runtime = $strategy.runtime; + let state = ^$s(depth = $s.depth + $c->varToString()); + let classMapping = if($strategy.toChooseSet->isEmpty(), |$mapping->rootClassMappingByClass($c)->potentiallyResolveOperation($mapping), |$strategy.toChooseSet); + + + // Possible when the mapping is 'embedded' + if ($classMapping->isEmpty(), + | print(if($debug.debug,|$debug.space+'~>C) ('+$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->size()->toString()+') '+$state.value->toOne()->toString()+'\n',|'')); + $state;, + | let existingSet = $state->findExistingPemutationSet($debug); + let existingSetCanBeUsed = $existingSet->permutationSetOnlyHasImplementation($classMapping); + let newID = if($existingSetCanBeUsed, + | $existingSet->toOne().id->cast(@Integer), + | $state.counter+1 + )->toString(); + let newSet = if (!$existingSetCanBeUsed,|^PermutationSet(id = $state.counter+1, sets = $classMapping),|[]); + let currentRoutingStrategy = $state.routingStrategy->cast(@StoreMappingRoutingStrategy)->toOne(); + let updatedRoutingStrategy = ^$currentRoutingStrategy(setsByDepth = if (!$existingSetCanBeUsed, + |let setByD = $state.routingStrategy->cast(@StoreMappingRoutingStrategy).setsByDepth; + $setByD->put(getSetPath($state), $newSet->toOne());, + |$state.routingStrategy->cast(@StoreMappingRoutingStrategy).setsByDepth + ), + sets = if (!$existingSetCanBeUsed,|$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->add($newSet->toOne()),|$state.routingStrategy->cast(@StoreMappingRoutingStrategy).sets)); + let routed = ^StoreMappingRoutedValueSpecification(genericType = $i.genericType, + multiplicity = $i.multiplicity, + id = $newID, + sets = $classMapping, + runtime = $runtime, + mapping = $mapping, + executionContext = $executionContext, + value = $i, + routingStrategy = $updatedRoutingStrategy); + let res = ^$state( + counter = if (!$existingSetCanBeUsed,|$state.counter+1,|$state.counter), + routingStrategy = $updatedRoutingStrategy, + value = $routed + ); + print(if($debug.debug,|$debug.space+'~>C) ('+$res.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->size()->toString()+') '+$routed->evaluateAndDeactivate()->asString()+'\n',|'')); + $res; + ); } function <> meta::pure::router::store::routing::routeFunctionExpressionProperty(p:Property[1], fe:FunctionExpression[1], v:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):RoutingState[1] @@ -194,7 +236,7 @@ function <> meta::pure::router::store::routing::routeFunctionExp $res; } -function <> meta::pure::router::store::routing::wrapValueSpecification(value:ValueSpecification[1], routingStrategy:RoutingStrategy[1], id:String[1], executionContext:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ExtendedRoutedValueSpecification[1] +function <> meta::pure::router::store::routing::wrapValueSpecificationStoreMapping(value:ValueSpecification[1], routingStrategy:RoutingStrategy[1], id:String[1], executionContext:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ExtendedRoutedValueSpecification[1] { let strategy = $routingStrategy->cast(@StoreMappingRoutingStrategy); @@ -211,6 +253,21 @@ function <> meta::pure::router::store::routing::wrapValueSpecifi ); } +function <> meta::pure::router::store::routing::wrapValueSpecificationStore(value:ValueSpecification[1], routingStrategy:RoutingStrategy[1], id:String[1], executionContext:ExecutionContext[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1]):ExtendedRoutedValueSpecification[1] +{ + let strategy = $routingStrategy->cast(@StoreRoutingStrategy); + ^StoreRoutedValueSpecification + ( + genericType = $value.genericType, + multiplicity = $value.multiplicity, + store = $strategy.store, + id = $id, + runtime = $strategy.runtime, + executionContext = $executionContext, + value = $value, + routingStrategy = $strategy + ); +} // =================================================================================== // Special Functions @@ -219,7 +276,28 @@ function <> meta::pure::router::store::routing::wrapValueSpecifi function meta::pure::router::store::routing::specializedFunctionExpressionRouterProcessorForStore(extensions:meta::pure::extension::Extension[*]):PairBoolean[1]}>, Function<{Function[1], FunctionExpression[1], RoutingState[1], ExecutionContext[1], Map[1], Map>[1], meta::pure::extension::Extension[*], DebugContext[1]->RoutingState[1]}>>[*] { [ - pair(fe:FunctionExpression[1] | $fe.func->in([meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__TabularDataSet_1_, meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__ExecutionContext_1__TabularDataSet_1_, meta::pure::mapping::from_T_m__Mapping_1__Runtime_1__T_m_]), + pair(fe:FunctionExpression[1] | $fe.func->in([meta::pure::mapping::from_T_m__Runtime_1__T_m_]), + {f:Function[1], fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1] | + let resolvedParameters = $fe.parametersValues->tail()->map(p|$p->evaluateAndDeactivate()->match([v:VariableExpression[1] |let iv = meta::pure::functions::meta::resolve($v, $vars, $inScopeVars)->cast(@InstanceValue).values, + f:FunctionExpression[1] |let r = $f->meta::pure::router::preeval::preval($inScopeVars, $extensions, $debug); + $r->reactivate($inScopeVars);, + i:InstanceValue[1] |$i.values])); + + let fromRuntime = $resolvedParameters->at(0)->cast(@Runtime); + routeFunctionExpression( + $fe.parametersValues->at(0)->cast(@FunctionExpression), + ^$state(routingStrategy = getRoutingStrategyFromRuntime($fromRuntime)), + $executionContext, + $vars, + $inScopeVars, + $extensions, + $debug + ); + } + ), + pair(fe:FunctionExpression[1] | $fe.func->in([meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__TabularDataSet_1_, + meta::pure::mapping::from_TabularDataSet_1__Mapping_1__Runtime_1__ExecutionContext_1__TabularDataSet_1_, + meta::pure::mapping::from_T_m__Mapping_1__Runtime_1__T_m_]), {f:Function[1], fe:FunctionExpression[1], state:RoutingState[1], executionContext:ExecutionContext[1], vars:Map[1], inScopeVars:Map>[1], extensions:meta::pure::extension::Extension[*], debug:DebugContext[1] | let resolvedParameters = $fe.parametersValues->tail()->map(p|$p->evaluateAndDeactivate()->match([v:VariableExpression[1] |let iv = meta::pure::functions::meta::resolve($v, $vars, $inScopeVars)->cast(@InstanceValue).values, f:FunctionExpression[1] |let r = $f->meta::pure::router::preeval::preval($inScopeVars, $extensions, $debug); @@ -306,7 +384,7 @@ function meta::pure::router::store::routing::specializedFunctionExpressionRoute value = $routedSave); } ) - ] + ]; } // =================================================================================== diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/serialization/toPureGrammar.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/serialization/toPureGrammar.pure index d238e57f433..4d869eb78d9 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/serialization/toPureGrammar.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/serialization/toPureGrammar.pure @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import meta::pure::metamodel::relation::*; import meta::pure::mapping::*; import meta::pure::metamodel::serialization::grammar::*; @@ -92,6 +93,7 @@ function meta::pure::metamodel::serialization::grammar::printPropertyOrFunctionE $functionExpression.func->match([ p:Property[1] | printProperty($p, $functionExpression.parametersValues->at(0), $space), q:QualifiedProperty[1]| printProperty($q, $functionExpression.parametersValues, $space), + c:Column[1] | printColumn($c, $functionExpression.parametersValues->at(0), $space), a:Any[1] | printFunctionExpression($functionExpression, $space) ]) } @@ -145,6 +147,11 @@ function meta::pure::metamodel::serialization::grammar::printProperty(p:Property $o->printValueSpecification($space) + '.' + $p.name->toOne(); } +function meta::pure::metamodel::serialization::grammar::printColumn(c:Column[1], o:ValueSpecification[1], space:String[1]):String[1] +{ + $c.name->toOne(); +} + function meta::pure::metamodel::serialization::grammar::printProperty(p:QualifiedProperty[1], params:ValueSpecification[*], space:String[1]):String[1] { $params->at(0)->printValueSpecification($space) + '.' + $p.name->toOne() + '(%s)'->format($params->tail()->map(x | $x->printValueSpecification($space))->joinStrings(', ')); @@ -225,11 +232,18 @@ function meta::pure::metamodel::serialization::grammar::printProperty(p:Property function meta::pure::metamodel::serialization::grammar::printGenericType(genericType:GenericType[1]):String[1] { - if ($genericType.rawType->isEmpty(), - |$genericType.typeParameter->toOne().name->toOne(), - |$genericType.rawType->toOne()->match( + if ($genericType->instanceOf(GenericTypeOperation), + |let go = $genericType->cast(@GenericTypeOperation); + $go.left->printGenericType()+if($go.type == GenericTypeOperationType.Union,|'+',|'-')+$go.right->printGenericType();, + |if ($genericType.rawType->isEmpty(), + |if ($genericType.typeParameter->isEmpty(), + |'', + |$genericType.typeParameter->toOne().name->toOne() + ), + |$genericType.rawType->toOne()->match( [ f:FunctionType[1]|printFunctionType($f), + x:meta::pure::metamodel::relation::RelationType[1]|printRelationType($x), c:Class[1]|if ($c.name->isEmpty(),|'?MappingClass?',|$c->elementToPath()), e:Enumeration[1]|$e->elementToPath(), a:Any[1]|$a->id() @@ -241,6 +255,7 @@ function meta::pure::metamodel::serialization::grammar::printGenericType(generic |if($genericType.multiplicityArguments->isNotEmpty(), |$genericType.multiplicityArguments->map(m | $m->printMultiplicity())->joinStrings('<|', ',', '>'), |''))) + ) } function meta::pure::metamodel::serialization::grammar::printFunctionType(functionType:FunctionType[1]):String[1] @@ -250,6 +265,11 @@ function meta::pure::metamodel::serialization::grammar::printFunctionType(functi +printGenericType($functionType.returnType)+'['+printMultiplicity($functionType.returnMultiplicity)+']}'; } +function meta::pure::metamodel::serialization::grammar::printRelationType(rType:meta::pure::metamodel::relation::RelationType[1]):String[1] +{ + '('+$rType.columns->map(x|if($x.nameWildCard,|'?',|$x.name->toOne())+':'+$x.classifierGenericType.typeArguments->at(1)->printGenericType())->joinStrings(', ')+')'; +} + function meta::pure::metamodel::serialization::grammar::printFunctionSignature(func:Function[1]):String[1] { let funcType = $func->genericType().typeArguments->at(0).rawType->toOne()->cast(@FunctionType); diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml index 571591499ae..c2768c2b7d9 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml @@ -135,6 +135,27 @@ org.finos.legend.pure legend-pure-m2-dsl-mapping-pure + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + runtime + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-grammar + runtime + + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + runtime + + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + ${legend.pure.version} + runtime + org.finos.legend.engine diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure index 3309013c1cf..b194a1c5e13 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure @@ -157,8 +157,7 @@ function <> meta::pure::ide::display_ide(elem:Any[1]):String[1] f:FunctionDefinition[1] | let icon = if($f->hasStereotype('externalizable', meta::pure::profiles::access), |'"/ide/pure/icons/play.png"', |'"/ide/pure/icons/modelElements/function.png"' - ); - + ); '{"li_attr":' + display_ide_attr($f) + ', "id":"'+$p->buildKey()+ '","text":"' + printFunctionSignature($f) + '", "icon":'+$icon+'}';, f:NativeFunction[1] | '{"li_attr":' + display_ide_attr($f) + ', "id":"'+$p->buildKey()+ '","text":"' + printFunctionSignature($f) + '", "icon":"/ide/pure/icons/modelElements/function_parenthesis.png"}', e:Enumeration[1] | '{"li_attr":' + display_ide_attr($e) + ', "id":"'+$p->buildKey()+ '","text":"' + $e->id() + '", "icon":"/ide/pure/icons/modelElements/enumeration.gif"}', diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java index 185551de86c..965298afdf2 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java @@ -30,6 +30,7 @@ public class PureIDELight extends PureIDEServer { public static void main(String[] args) throws Exception { + System.setProperty("legend.test.h2.port", "1975"); new PureIDELight().run(args.length == 0 ? new String[]{"server", "legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/resources/ideLightConfig.json"} : args); } @@ -102,13 +103,13 @@ protected MutableList buildRepositories(SourceLocationCon .with(this.buildCore("legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-pure-specification-metamodel", "elasticsearch_specification_metamodel")) .with(this.buildCore("legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-executionPlan-test", "elasticsearch_execution_test")) .with(this.buildCore("legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-pure-metamodel", "elasticsearch_seven_metamodel")) - .with(this.buildCore("legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure","nonrelational-mongodb")) - .with(this.buildCore("legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure","nonrelational-mongodb-java-platform-binding")) - .with(this.buildCore("legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure","service")) - .with(this.buildCore("legend-engine-xts-iceberg/legend-engine-xt-iceberg-pure","external-tableformat-iceberg")) + .with(this.buildCore("legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure", "nonrelational-mongodb")) + .with(this.buildCore("legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure", "nonrelational-mongodb-java-platform-binding")) + .with(this.buildCore("legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure", "service")) + .with(this.buildCore("legend-engine-xts-iceberg/legend-engine-xt-iceberg-pure", "external-tableformat-iceberg")) .with(this.buildCore("legend-engine-xts-arrow/legend-engine-xt-arrow-pure", "external-format-arrow")) .with(this.buildCore("legend-engine-xts-relationalai/legend-engine-xt-relationalai-pure", "external-query-relationalai")) - ; + ; } @Override diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml new file mode 100644 index 00000000000..9a02a0a74f1 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml @@ -0,0 +1,101 @@ + + + + + + 4.0.0 + + + org.finos.legend.engine + legend-engine-pure-platform-modular-generation + 4.36.1-SNAPSHOT + + + legend-engine-pure-platform-dsl-tds-java + jar + Legend Engine - Pure - Platform - DSL - TDS - JAVA + + + + + org.finos.legend.pure + legend-pure-maven-generation-java + + + compile + + build-pure-compiled-jar + + + true + true + modular + true + + platform_dsl_tds + + + + + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-grammar + ${legend.pure.version} + + + + + + + + + org.finos.legend.pure + legend-pure-m4 + + + org.finos.legend.pure + legend-pure-m3-core + + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + ${legend.pure.version} + + + + org.finos.legend.pure + legend-pure-runtime-java-engine-compiled + + + + org.finos.legend.engine + legend-engine-pure-platform-java + + + + org.eclipse.collections + eclipse-collections-api + + + org.eclipse.collections + eclipse-collections + + + + diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml new file mode 100644 index 00000000000..58925ab2b41 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml @@ -0,0 +1,121 @@ + + + + + + 4.0.0 + + + org.finos.legend.engine + legend-engine-pure-platform-modular-generation + 4.36.1-SNAPSHOT + + + legend-engine-pure-platform-functions-relation-java + jar + Legend Engine - Pure - Platform - Function - Relation - JAVA + + + + + org.finos.legend.pure + legend-pure-maven-generation-java + + + compile + + build-pure-compiled-jar + + + true + true + modular + true + + platform_functions_relation + + + + + + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + ${legend.pure.version} + + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + ${legend.pure.version} + + + + + + + + + org.finos.legend.pure + legend-pure-m4 + + + org.finos.legend.pure + legend-pure-m3-core + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + + + + org.finos.legend.pure + legend-pure-runtime-java-engine-compiled + + + + + + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + + + + + org.finos.legend.engine + legend-engine-pure-platform-java + + + org.finos.legend.engine + legend-engine-pure-platform-functions-java + + + + + + + + org.eclipse.collections + eclipse-collections-api + + + org.eclipse.collections + eclipse-collections + + + + diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/pom.xml index e1f15ec6fcb..d8b83ae0a63 100644 --- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/pom.xml +++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/pom.xml @@ -33,9 +33,11 @@ legend-engine-pure-platform-dsl-graph-java legend-engine-pure-platform-dsl-mapping-java legend-engine-pure-platform-dsl-path-java + legend-engine-pure-platform-dsl-tds-java legend-engine-pure-platform-functions-java legend-engine-pure-platform-functions-json-java legend-engine-pure-platform-java legend-engine-pure-platform-store-relational-java + legend-engine-pure-platform-functions-relation-java \ No newline at end of file diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/src/main/java/org/finos/legend/engine/pure/runtime/compiler/interpreted/natives/LegendCompileMixedProcessorSupport.java b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/src/main/java/org/finos/legend/engine/pure/runtime/compiler/interpreted/natives/LegendCompileMixedProcessorSupport.java index e16961f6e12..88dc8d987a5 100644 --- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/src/main/java/org/finos/legend/engine/pure/runtime/compiler/interpreted/natives/LegendCompileMixedProcessorSupport.java +++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/src/main/java/org/finos/legend/engine/pure/runtime/compiler/interpreted/natives/LegendCompileMixedProcessorSupport.java @@ -22,11 +22,7 @@ import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Any; 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.navigation.Instance; -import org.finos.legend.pure.m3.navigation.M3Paths; -import org.finos.legend.pure.m3.navigation.M3ProcessorSupport; -import org.finos.legend.pure.m3.navigation.M3Properties; -import org.finos.legend.pure.m3.navigation.ProcessorSupport; +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; @@ -79,7 +75,7 @@ public CoreInstance getClassifier(CoreInstance instance) @Override public CoreInstance newGenericType(SourceInformation sourceInformation, CoreInstance source, boolean inferred) { - CoreInstance coreInstance = _Package.getByUserPath(M3Paths.GenericType, this.originalProcessorSupport); + CoreInstance coreInstance = _Package.getByUserPath(inferred ? M3Paths.InferredGenericType : M3Paths.GenericType, this.originalProcessorSupport); return this.modelRepository.newCoreInstance("", coreInstance, null); } diff --git a/legend-engine-xts-java/legend-engine-external-language-java/src/main/java/org/finos/legend/engine/external/language/java/generation/GenerateJavaProject.java b/legend-engine-xts-java/legend-engine-external-language-java/src/main/java/org/finos/legend/engine/external/language/java/generation/GenerateJavaProject.java index ff58ed88901..db4dd0e5d46 100644 --- a/legend-engine-xts-java/legend-engine-external-language-java/src/main/java/org/finos/legend/engine/external/language/java/generation/GenerateJavaProject.java +++ b/legend-engine-xts-java/legend-engine-external-language-java/src/main/java/org/finos/legend/engine/external/language/java/generation/GenerateJavaProject.java @@ -50,7 +50,7 @@ protected GenerateJavaProject(String outputDirectory) ClassLoader classLoader = Pure.class.getClassLoader(); this.executionSupport = new CompiledExecutionSupport( new JavaCompilerState(null, classLoader), - new CompiledProcessorSupport(classLoader, MetadataLazy.fromClassLoader(classLoader, CodeRepositoryProviderHelper.findCodeRepositories().collect(CodeRepository::getName)), Sets.mutable.empty()), + new CompiledProcessorSupport(classLoader, MetadataLazy.fromClassLoader(classLoader, CodeRepositoryProviderHelper.findCodeRepositories(classLoader).collect(CodeRepository::getName)), Sets.mutable.empty()), null, new CompositeCodeStorage(new VersionControlledClassLoaderCodeStorage(classLoader, Lists.mutable.of( CodeRepositoryProviderHelper.findPlatformCodeRepository() diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/platform/executionPlanNodes/platform/tests/javaGenerationTest.pure b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/platform/executionPlanNodes/platform/tests/javaGenerationTest.pure index 2254b4e607a..aedcf565594 100644 --- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/platform/executionPlanNodes/platform/tests/javaGenerationTest.pure +++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/platform/executionPlanNodes/platform/tests/javaGenerationTest.pure @@ -39,7 +39,8 @@ function <> meta::pure::executionPlan::platformBinding::legendJa meta::pure::functions::asserts, meta::pure::functions::meta, meta::pure::functions::multiplicity, - meta::pure::functions::test + meta::pure::functions::test, + meta::pure::functions::relation ]; } @@ -65,7 +66,8 @@ function <> meta::pure::executionPlan::platformBinding::legendJa meta::pure::functions::tests::collection::newMultiValueMap2Test__Boolean_1_, // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ meta::pure::functions::tests::collection::newMultiValueMapTest__Boolean_1_, // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ meta::pure::functions::tests::collection::toIndexed__Boolean_1_, // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ - meta::pure::functions::tests::collection::toNumbered__Boolean_1_ // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ + meta::pure::functions::tests::collection::toNumbered__Boolean_1_, // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ + meta::pure::functions::lang::tests::if::testMultiIf__Boolean_1_ // requires meta::pure::functions::collection::pair_U_1__V_1__Pair_1_ ]; let translationNotSupported = [ @@ -84,7 +86,11 @@ function <> meta::pure::executionPlan::platformBinding::legendJa meta::pure::functions::lang::tests::letFn::testAssignNewInstance__Boolean_1_, // requires meta::pure::functions::meta::genericType_Any_MANY__GenericType_1_ meta::pure::functions::lang::tests::match::testMatchWithExtraParam__Boolean_1_, // requires meta::pure::functions::lang::match_Any_MANY__Function_$1_MANY$__P_o__T_m_ meta::pure::functions::lang::tests::match::testMatchWithExtraParamsAndFunctionsAsParam__Boolean_1_, // requires meta::pure::functions::lang::match_Any_MANY__Function_$1_MANY$__P_o__T_m_ - meta::pure::functions::lang::tests::new::testDynamicInstance__Boolean_1_ // requires meta::pure::functions::meta::genericType_Any_MANY__GenericType_1_ + meta::pure::functions::lang::tests::new::testDynamicInstance__Boolean_1_, // requires meta::pure::functions::meta::genericType_Any_MANY__GenericType_1_, + meta::pure::functions::collection::tests::find::testFindInstance__Boolean_1_, + meta::pure::functions::collection::tests::find::testFindLiteralFromVar__Boolean_1_, + meta::pure::functions::collection::tests::find::testFindLiteral__Boolean_1_, + meta::pure::functions::collection::tests::find::testFindUsingVarForFunction__Boolean_1_ ]; let prohibitedFunctionAccess = [ diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/src/main/java/org/finos/legend/engine/plan/execution/stores/relational/plugin/RelationalStoreExecutorBuilder.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/src/main/java/org/finos/legend/engine/plan/execution/stores/relational/plugin/RelationalStoreExecutorBuilder.java index ef8f38b04d6..a9843e2b2d8 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/src/main/java/org/finos/legend/engine/plan/execution/stores/relational/plugin/RelationalStoreExecutorBuilder.java +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/src/main/java/org/finos/legend/engine/plan/execution/stores/relational/plugin/RelationalStoreExecutorBuilder.java @@ -28,7 +28,7 @@ public class RelationalStoreExecutorBuilder implements StoreExecutorBuilder { - private static final int DEFAULT_PORT = -1; + private static final int DEFAULT_PORT = Integer.parseInt(System.getProperty("legend.test.h2.port", "-1")); public static final String DEFAULT_TEMP_PATH = "/tmp/"; @Override diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml index a9010c62160..e5b8628b990 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml @@ -56,6 +56,11 @@ legend-pure-m2-functions-pure ${legend.pure.version} + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + ${legend.pure.version} + org.finos.legend.pure @@ -77,6 +82,11 @@ legend-pure-m2-dsl-graph-grammar ${legend.pure.version} + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + ${legend.pure.version} + org.finos.legend.pure @@ -117,6 +127,12 @@ + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + ${legend.pure.version} + + org.finos.legend.pure legend-pure-m2-dsl-mapping-grammar @@ -137,6 +153,11 @@ legend-pure-m2-dsl-path-grammar ${legend.pure.version} + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + ${legend.pure.version} + org.finos.legend.pure @@ -161,6 +182,13 @@ legend-pure-runtime-java-extension-store-relational ${legend.pure.version} + + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + ${legend.pure.version} + + @@ -213,6 +241,15 @@ legend-pure-m2-store-relational-grammar runtime + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + runtime + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + org.finos.legend.engine @@ -242,6 +279,10 @@ org.finos.legend.engine legend-engine-pure-platform-functions-java + + org.finos.legend.engine + legend-engine-pure-platform-functions-relation-java + org.finos.legend.engine legend-engine-pure-platform-functions-json-java @@ -254,6 +295,11 @@ org.finos.legend.engine legend-engine-pure-platform-dsl-graph-java + + org.finos.legend.engine + legend-engine-pure-platform-dsl-tds-java + runtime + org.finos.legend.pure @@ -268,6 +314,10 @@ org.finos.legend.pure legend-pure-runtime-java-extension-functions-json + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + org.finos.legend.pure legend-pure-runtime-java-extension-dsl-mapping diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational.definition.json index d0ad8800aa4..4b7befc37ac 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational.definition.json +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational.definition.json @@ -7,7 +7,9 @@ "platform_dsl_mapping", "platform_dsl_graph", "platform_dsl_path", + "platform_dsl_tds", "platform_functions_json", + "platform_functions_relation", "platform_store_relational", "core_functions", "core_service", diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/contract/storeContract.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/contract/storeContract.pure index bd9037fccfc..ae50bb947c7 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/contract/storeContract.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/contract/storeContract.pure @@ -212,33 +212,34 @@ function meta::relational::contract::planExecution(sq:meta::pure::mapping::Store { let store = $sq.store->cast(@Database); let fe = $sq.fe->evaluateAndDeactivate(); - if($fe.func->in([meta::pure::graphFetch::execution::graphFetchFunctions()]), - | - // Graph Fetch Flow - $sq->meta::pure::graphFetch::executionPlan::planGraphFetchExecution($ext, $m->toOne(), $runtime->toOne(), $exeCtx, $extensions, $debug);, + if([ + pair( + |$fe.func->in([meta::pure::graphFetch::execution::graphFetchFunctions()]), + | // Graph Fetch Flow + $sq->meta::pure::graphFetch::executionPlan::planGraphFetchExecution($ext, $m->toOne(), $runtime->toOne(), $exeCtx, $extensions, $debug); + ), + pair( + |$fe.func->in(meta::pure::mutation::mutationFunctions()), + | // Write Flow + $sq->meta::relational::mutation::executionPlan::planMutationExecution($ext, $m->toOne(), $runtime->toOne(), $exeCtx, $extensions, $debug); + ) + ] + ,| + // Normal Flow + let connections = $runtime.connectionStores->filter(c | $c.connection->instanceOf(DatabaseConnection)); + let storeRuntime = if($connections->size() <= 1, + | $runtime->toOne(), + | let oldRuntime = $runtime->toOne(); + let dbConn = $oldRuntime->connectionByElement($store)->cast(@DatabaseConnection); + let dbConnectionStore = $oldRuntime.connectionStores->filter(c|$c.connection==$dbConn); + ^$oldRuntime(connectionStores = $dbConnectionStore); + ); - | - if($fe.func->in(meta::pure::mutation::mutationFunctions()), - | - // Write Flow - $sq->meta::relational::mutation::executionPlan::planMutationExecution($ext, $m->toOne(), $runtime->toOne(), $exeCtx, $extensions, $debug);, - | - // Normal Flow - let connections = $runtime.connectionStores->filter(c | $c.connection->instanceOf(DatabaseConnection)); - let storeRuntime = if($connections->size() <= 1, - | $runtime->toOne(), - | let oldRuntime = $runtime->toOne(); - let dbConn = $oldRuntime->connectionByElement($store)->cast(@DatabaseConnection); - let dbConnectionStore = $oldRuntime.connectionStores->filter(c|$c.connection==$dbConn); - ^$oldRuntime(connectionStores = $dbConnectionStore); - ); - - let queryExeCtx = if($exeCtx->instanceOf(RelationalExecutionContext),|$exeCtx,|[])->cast(@RelationalExecutionContext); - let originalQuery = $sq.fe->toSQLQuery($m->toOne(), $sq.inScopeVars, $queryExeCtx, $debug, $extensions); - $originalQuery->postProcessSQLQuery($store, $ext, $m->toOne(), $storeRuntime, $exeCtx, $extensions) - ->generateExecutionNodeForPostProcessedResult($sq, $store, $ext, $m->toOne(), $storeRuntime, $exeCtx, $debug, $extensions); - ); - ); + let queryExeCtx = if($exeCtx->instanceOf(RelationalExecutionContext),|$exeCtx,|[])->cast(@RelationalExecutionContext); + let originalQuery = $sq.fe->toSQLQuery($m, $sq.inScopeVars, $queryExeCtx, $debug, $extensions); + $originalQuery->postProcessSQLQuery($store, $ext, $m, $storeRuntime, $exeCtx, $extensions) + ->generateExecutionNodeForPostProcessedResult($sq, $store, $ext, $m, $storeRuntime, $exeCtx, $debug, $extensions); + ); } function meta::relational::contract::postProcessorsMatch(postProcessors1: meta::pure::alloy::connections::PostProcessor[*], postProcessors2: meta::pure::alloy::connections::PostProcessor[*]): 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/projection/testGroupWithWindowSubset.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/projection/testGroupWithWindowSubset.pure index ff31e7706a8..7eedd4132eb 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/projection/testGroupWithWindowSubset.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/functions/tests/projection/testGroupWithWindowSubset.pure @@ -62,8 +62,8 @@ function <> meta::relational::tests::projection::testGroupByWithWindo //check for base table attributes are being selected only assertEqualsH2Compatible( - 'select "root".price as "Amount", "fx_0".rate as "Rate", sum("root".price) as "Amount-Sum", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1)) group by "Amount","Rate"', - 'select "root".price as "Amount", "fx_0".rate as "Rate", sum("root".price) as "Amount-Sum", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1)) group by "Amount","Rate"', + 'select "root".price as "Amount", "fx_0".rate as "Rate", sum("root".price) as "Amount-Sum", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1)) group by "Amount","Rate"', + 'select "root".price as "Amount", "fx_0".rate as "Rate", sum("root".price) as "Amount-Sum", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1)) group by "Amount","Rate"', $results2->sqlRemoveFormatting() ); assertEquals( 'Amount | Rate | Amount-Sum | Rate-Average',$results2.values.columns->map(r|$r.name->makeString(','))->makeString(' | ')->cast(@String) ); @@ -88,8 +88,8 @@ function <> meta::relational::tests::projection::testGroupByWithWindo //check for attributes that are in different order than the input parmeters assertEqualsH2Compatible( - 'select "fx_0".rate as "Rate", "root".price as "Amount", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average", sum("root".price) as "Amount-Sum" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1)) group by "Rate","Amount"', - 'select "fx_0".rate as "Rate", "root".price as "Amount", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average", sum("root".price) as "Amount-Sum" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1)) group by "Rate","Amount"', + 'select "fx_0".rate as "Rate", "root".price as "Amount", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average", sum("root".price) as "Amount-Sum" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1)) group by "Rate","Amount"', + 'select "fx_0".rate as "Rate", "root".price as "Amount", avg(1.0 * case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end) as "Rate-Average", sum("root".price) as "Amount-Sum" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1)) group by "Rate","Amount"', $results3->sqlRemoveFormatting() ); assertEquals( $results.values.rows->filter ( x| $x.getFloat('Amount-Sum') == 10.0 && $x.getFloat('Amount') == 5.0 )->size() , 1 ); 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 2a5ea04a2ed..0cdc1603378 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 @@ -78,7 +78,7 @@ Class meta::relational::functions::pureToSqlQuery::State inScopeVars:Map>[1]; supportedFunctions:Map,meta::pure::metamodel::function::Function<{FunctionExpression[1], PropertyMapping[0..1], SelectWithCursor[1], Map[1], State[1], JoinType[1], String[1], List[1], DebugContext[1], Extension[*]->RelationalOperationElement[1]}>>[1]; contextBasedSupportedFunctions:Map, PairBoolean[1]}>, meta::pure::metamodel::function::Function<{FunctionExpression[1], PropertyMapping[0..1], SelectWithCursor[1], Map[1], State[1], JoinType[1], String[1], List[1], DebugContext[1], Extension[*]->RelationalOperationElement[1]}>>>[1]; - mapping:Mapping[1]; + mapping:Mapping[0..1]; inProject:Boolean[1]; // should we fetch all properties in getAll ('NOT'ed) inProjectFunctions:Boolean[1]; filterChainDepth:Integer[1]; @@ -155,7 +155,7 @@ Class meta::relational::functions::pureToSqlQuery::ColumnGroup columns : RelationalOperationElement[*]; } -function meta::relational::functions::pureToSqlQuery::toSQLQuery(functionExpression:FunctionExpression[1], mapping:Mapping[1], inScopeVars:Map>[1], execCtx: RelationalExecutionContext[0..1], debug:DebugContext[1], extensions:Extension[*]):SQLQuery[1] +function meta::relational::functions::pureToSqlQuery::toSQLQuery(functionExpression:FunctionExpression[1], mapping:Mapping[0..1], inScopeVars:Map>[1], execCtx: RelationalExecutionContext[0..1], debug:DebugContext[1], extensions:Extension[*]):SQLQuery[1] { toSQLQuery($functionExpression, $mapping, $inScopeVars, $debug, $execCtx->relationalExecutionContextToState(defaultState($mapping, $inScopeVars)), $extensions); } @@ -183,7 +183,7 @@ function <> meta::relational::functions::pureToSqlQuery::applyPo ]); } -function meta::relational::functions::pureToSqlQuery::toSQLQuery(functionExpression:FunctionExpression[1], mapping:Mapping[1], inScopeVars:Map>[1], debug:DebugContext[1], state:State[1], extensions:Extension[*]):SQLQuery[1] +function meta::relational::functions::pureToSqlQuery::toSQLQuery(functionExpression:FunctionExpression[1], mapping:Mapping[0..1], inScopeVars:Map>[1], debug:DebugContext[1], state:State[1], extensions:Extension[*]):SQLQuery[1] { $functionExpression ->processQuery($state, $debug, $extensions) @@ -277,7 +277,7 @@ function <> meta::relational::functions::pureToSqlQuery::relatio ) } -function meta::relational::functions::pureToSqlQuery::defaultState(mapping:Mapping[1], inScopeVars:Map>[1]):State[1] +function meta::relational::functions::pureToSqlQuery::defaultState(mapping:Mapping[0..1], inScopeVars:Map>[1]):State[1] { ^State(inScopeVars=$inScopeVars, supportedFunctions=getSupportedFunctions(), mapping=$mapping, inProject=false, inProjectFunctions=false, inFilter=false, filterChainDepth=0, processingProjectionThread=false, shouldIsolate=true, contextBasedSupportedFunctions=getContextBasedSupportedFunctions()); } @@ -354,6 +354,7 @@ function meta::relational::functions::pureToSqlQuery::processValueSpecificationR let res = $vs->evaluateAndDeactivate()->match( [ r:StoreMappingRoutedValueSpecification[1] | $r.value->processValueSpecificationReturnPropertyMapping($currentPropertyMapping, $operation, $vars, ^$state(propertyMappingFromRouter = $r.propertyMapping), $joinType, $nodeId, $aggFromMap, $context, $extensions), + r:StoreRoutedValueSpecification[1] | $r.value->processValueSpecificationReturnPropertyMapping($currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions), r:FunctionRoutedValueSpecification[1] | $r.value->processValueSpecificationReturnPropertyMapping($currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions), f:FunctionExpression[1] | processFunctionExpression($f, $currentPropertyMapping, $operation, $vars, ^$state(functionExpressionStack+=$f), $joinType, buildNodeId($nodeId,'_d'), $aggFromMap, $context, $extensions), i:InstanceValue[1] | let elements = processInstanceValue($i, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions); @@ -509,6 +510,20 @@ function meta::relational::functions::pureToSqlQuery::processValue(vals:Any[*], v:PlanVarPlaceHolder[1] |^$operation(select = $state.inFilter->if(|^$select(filteringOperation = ^Literal(value=^VarPlaceHolder(name=$v.name,type = $v.type, multiplicity = $v.multiplicity))),|^$select(columns = ^Literal(value=^VarPlaceHolder(name=$v.name,type = $v.type, multiplicity = $v.multiplicity)))));, v:ValueSpecification[1] | processValueSpecification($v, $currentPropertyMapping, $operation, $vars, $state, $joinType, buildNodeId($nodeId,'_i'+$vals->indexOf($v)->toString()), $aggFromMap, $context, $extensions), l:LambdaFunction[1] | $l.expressionSequence->at(0)->processValueSpecification($currentPropertyMapping, $operation, $vars, $state, $joinType, buildNodeId($nodeId,'_i'+$vals->indexOf($v)->toString()), $aggFromMap, $context, $extensions), + x:RelationDatabaseAccessor[1] | + let tableAlias = ^TableAlias(name='dbAccessor', relationalElement=$x.relation); + let res = ^$operation + ( + select = ^TdsSelectSqlQuery + ( + columns = $x.relation.columns->map(c|^Alias(name='"'+$c->cast(@Column).name->toOne()+'"', relationalElement=^TableAliasColumn(alias=$tableAlias, column=$c->cast(@Column)))), + data = ^RootJoinTreeNode(alias = $tableAlias) + ) + ); + print(if(!$context.debug, |'', | $context.space+'>Processing Relation Database Accessor: '+$res.select->meta::relational::functions::sqlQueryToString::sqlQueryToString(DatabaseType.H2, $extensions) + '\n')); + // let node = ^RootJoinTreeNode(alias = ^TableAlias(name='dbAccessor', relationalElement=$x.relation)); + // ^$operation(select = ^TdsSelectSqlQuery(data = $node), currentTreeNode = $node); + $res;, a:Any[1] | ^ClassInstanceHolder(value=$a); ])) ); } @@ -519,14 +534,23 @@ function meta::relational::functions::pureToSqlQuery::processFunctionExpression( let res = $functionExpression.func->match ([ p:Property[1] | processPropertyFunctionExpression($functionExpression, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions);, q:QualifiedProperty[1] | processQualifiedPropertyFunctionExpression($functionExpression, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions);, + c:meta::pure::metamodel::relation::Column[1] | processColumnFunctionExpression($functionExpression, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions);, a:Any[1]| processFunctionExpressionForNonPropertyFunction($functionExpression, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions); ]); - print(if(!$context.debug, |'', | $context.space+'>End Process Function Expression: '+ $functionExpression.func.name->toOne() + '\n'+$res.element->cast(@SelectWithCursor).select->map(s | $s->printDebugQuery($context.space, $extensions))->joinStrings(', '))); - + print(if(!$context.debug, |'', | $context.space+'>End Process Function Expression: '+ $functionExpression.func.name->toOne() + '\n ' + $context.space + $res.element->cast(@SelectWithCursor).select->map(s | $s->printDebugQuery($context.space, $extensions))->joinStrings(', '))); $res; } +function meta::relational::functions::pureToSqlQuery::processColumnFunctionExpression(fe: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[*]):OperationWithParentPropertyMapping[1] +{ + let leftSide = processValueSpecificationReturnPropertyMapping($fe.parametersValues->at(0), $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions)->toOne(); + let leftSelect = $leftSide.element->cast(@SelectWithCursor).select; + let colAlias = ^TableAliasColumn(alias = $leftSelect.data->toOne().alias, column = ^Column(name =$fe.func.name->toOne(), type =^meta::relational::metamodel::datatype::Integer())); + let newSelect = $state.inFilter->if(|^$leftSelect(filteringOperation=$colAlias),|^$leftSelect(columns=$colAlias)); + ^$leftSide(element = ^$operation(select=$newSelect)); +} + function meta::relational::functions::pureToSqlQuery::processPropertyFunctionExpression(fe: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[*]):OperationWithParentPropertyMapping[1] { let propertyOwner = $fe.parametersValues->at(0)->map(p|$p->byPassRouterInfo()); @@ -553,7 +577,7 @@ function meta::relational::functions::pureToSqlQuery::processPropertyFunctionExp let baseOperation = if($currentPropertyMapping->isEmpty() ,| $leftSide.currentPropertyMapping ,| $currentPropertyMapping - )->match([ + )->match([ o:OtherwiseEmbeddedRelationalInstanceSetImplementation[1] | let navigateToOtherwiseMapping = $o->propertyMappingsByPropertyName($property.name->toOne())->isEmpty(); if($navigateToOtherwiseMapping ,|let leftVS = if($state.leftSideOfQualifier->isEmpty(), @@ -1360,7 +1384,7 @@ function meta::relational::functions::pureToSqlQuery::doJoinToClass(relationalPr let joinTree = $relationalPropertyMapping.relationalOperationElement->cast(@RelationalOperationElementWithJoin).joinTreeNode->toOne(); let className = $c.name->toOne(); - let classMappings = $state.mapping->classMappingById($relationalPropertyMapping.targetSetImplementationId); + let classMappings = $state.mapping->toOne()->classMappingById($relationalPropertyMapping.targetSetImplementationId); assertSize($classMappings, 1, 'Expected 1 class mapping for \'%s\' in \'%s\', found %d', [$className, $state.mapping.name->toOne(), $classMappings->size()]); let setImplementation = $classMappings->toOne()->match([a : meta::pure::mapping::aggregationAware::AggregationAwareSetImplementation[1] | $a.mainSetImplementation, s: SetImplementation[1] | $s])->cast(@RootRelationalInstanceSetImplementation); @@ -1504,11 +1528,11 @@ function meta::relational::functions::pureToSqlQuery::findUnionPropertyMapping(u let allSourceSetImplementationIds = $setImpl->cast(@PropertyMappingsImplementation)->allPropertyMappings().sourceSetImplementationId->distinct(); if ($setImpl->instanceOf(EmbeddedRelationalInstanceSetImplementation), | $setImpl->cast(@EmbeddedRelationalInstanceSetImplementation)->_propertyMappingsByPropertyName($property.name->toOne())->filter(r|$r->instanceOf(RelationalPropertyMapping))->cast(@RelationalPropertyMapping), - | let propMappings = $relationalPropertyMappings->filter(r|$state.mapping->classMappingById($r.sourceSetImplementationId)->match([r:RootRelationalInstanceSetImplementation[1]|$r,e:EmbeddedRelationalInstanceSetImplementation[1]|$e.setMappingOwner])->cast(@InstanceSetImplementation).id->in($allSourceSetImplementationIds)); + | let propMappings = $relationalPropertyMappings->filter(r|$state.mapping->toOne()->classMappingById($r.sourceSetImplementationId)->match([r:RootRelationalInstanceSetImplementation[1]|$r,e:EmbeddedRelationalInstanceSetImplementation[1]|$e.setMappingOwner])->cast(@InstanceSetImplementation).id->in($allSourceSetImplementationIds)); // Filtering overriden property mappings let propertyMappingToSuperSetIdsMap = $propMappings->map({pm | let pmSourceSetId = $pm.sourceSetImplementationId; - pair($pm, list($state.mapping->allSuperSetImplementationIds($pmSourceSetId)->remove($pmSourceSetId))); + pair($pm, list($state.mapping->toOne()->allSuperSetImplementationIds($pmSourceSetId)->remove($pmSourceSetId))); })->newMap(); $propMappings->filter({pm | let pmSourceSetId = $pm.sourceSetImplementationId; @@ -1638,14 +1662,14 @@ function meta::relational::functions::pureToSqlQuery::processRelationalPropertyM let currentTreeNodeElement = $srcOperation.currentTreeNode.alias.relationalElement->toOne(); let extractParentMappingId = {rpm: RelationalPropertyMapping[1] | - $state.mapping->classMappingById($rpm.sourceSetImplementationId)->match([ + $state.mapping->toOne()->classMappingById($rpm.sourceSetImplementationId)->match([ r:RootRelationalInstanceSetImplementation[1] | $r.id, e:EmbeddedRelationalInstanceSetImplementation[1] | $e.setMappingOwner.id ]) }; let shouldUpdatePropertyMappings = if ($currentTreeNodeElement->isUnionOrNestedUnion(), - | let allSourceSetIdsForUnionSets = $currentTreeNodeElement->resolveUnion().setImplementations->map(s | $state.mapping->allSuperSetImplementationIds($s.id)); + | let allSourceSetIdsForUnionSets = $currentTreeNodeElement->resolveUnion().setImplementations->map(s | $state.mapping->toOne()->allSuperSetImplementationIds($s.id)); !$relationalPropertyMappings->exists({rpm | !$extractParentMappingId->eval($rpm)->in($allSourceSetIdsForUnionSets) });, @@ -1656,7 +1680,7 @@ function meta::relational::functions::pureToSqlQuery::processRelationalPropertyM let union = $currentTreeNodeElement->resolveUnion(); let nullAlias = ^Alias(name = $property.name->toOne(), relationalElement = ^Literal(value = ^SQLNull())); $union.setImplementations->map({currentSet | - let superSetIds = $state.mapping->allSuperSetImplementationIds($currentSet.id); + let superSetIds = $state.mapping->toOne()->allSuperSetImplementationIds($currentSet.id); let filteredRpms = $relationalPropertyMappings->filter(rpm | $extractParentMappingId->eval($rpm)->in($superSetIds)); let newRpms = if ($filteredRpms->isNotEmpty(), | $filteredRpms, @@ -1807,7 +1831,7 @@ function meta::relational::functions::pureToSqlQuery::processCrossPropertyMappin | $crossPropertyMappings->at(0).owner->toOne()); let targetSet = $crossPropertyMappings->at(0)->instanceOf(CrossSetImplementationReverseComplexPropertyMapping)->if( | $crossPropertyMappings->at(0)->cast(@CrossSetImplementationReverseComplexPropertyMapping).targetSet->cast(@CrossSetImplementation)->convertCrossSetImplToRelationalSetImpl(), - | $state.mapping->classMappingById($crossPropertyMappings->at(0).targetSetImplementationId)->cast(@RootRelationalInstanceSetImplementation)->toOne()); + | $state.mapping->toOne()->classMappingById($crossPropertyMappings->at(0).targetSetImplementationId)->cast(@RootRelationalInstanceSetImplementation)->toOne()); let propertypairs = $crossPropertyMappings->at(0)->cast(@CrossSetImplementationComplexPropertyMapping).crossExperssionPropertyPairs; let currentAlias = $oldSrcOperation.currentTreeNode.alias; let targetAlias = $targetSet.mainTableAlias->createJoinTableAlias($nodeId, $state, [], $context, $extensions); @@ -1967,19 +1991,22 @@ function meta::relational::functions::pureToSqlQuery::replaceJoinTableWithSelect function meta::relational::functions::pureToSqlQuery::processFunctionExpressionForNonPropertyFunction(functionExpression: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[*]):OperationWithParentPropertyMapping[*] { let func = findSupportedFunction($functionExpression, $state.supportedFunctions, $state.contextBasedSupportedFunctions); - if ( (!$func->isEmpty()), | let params1 = [^List(values=$functionExpression), ^List(values=$currentPropertyMapping)]; - let params = $params1->concatenate([$operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context]->map(v | ^List(values=$v)))->concatenate(^List(values = $extensions)); - $func->toOne()->evaluate($params)->cast(@RelationalOperationElement)->toOne()->wrapIfNecessary(); - , | - - - if($functionExpression.func->instanceOf(FunctionDefinition), - |let expression = $functionExpression.func->cast(@FunctionDefinition).expressionSequence; - assertEquals(1, $expression->size(), | 'Functions with more than one functionExpression are not supported yet! The function \'' + $functionExpression.func->toString() + '\' has ' + $expression->size()->toString() + ' expressions.'); - processValueSpecificationReturnPropertyMapping($expression->toOne(), $currentPropertyMapping, $operation, $functionExpression->mapVariables($vars, $state.inScopeVars), ^$state(inScopeVars=^Map>()), $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions); - , - |fail('No SQL translation exists for the PURE function \''+$functionExpression.func.name->toOne()+'\'. \nIf you would like to add a SQL translation for the function then follow the step-by-step guide on the PURE wiki.'); $operation->wrapIfNecessary(); - ); + + if ([ + pair( + |!$func->isEmpty(), + | let params1 = [^List(values=$functionExpression), ^List(values=$currentPropertyMapping)]; + let params = $params1->concatenate([$operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context]->map(v | ^List(values=$v)))->concatenate(^List(values = $extensions)); + $func->toOne()->evaluate($params)->cast(@RelationalOperationElement)->toOne()->wrapIfNecessary(); + ), + pair( + |$functionExpression.func->instanceOf(FunctionDefinition), + | let expression = $functionExpression.func->cast(@FunctionDefinition).expressionSequence; + assertEquals(1, $expression->size(), | 'Functions with more than one functionExpression are not supported yet! The function \'' + $functionExpression.func->toString() + '\' has ' + $expression->size()->toString() + ' expressions.'); + processValueSpecificationReturnPropertyMapping($expression->toOne(), $currentPropertyMapping, $operation, $functionExpression->mapVariables($vars, $state.inScopeVars), ^$state(inScopeVars=^Map>()), $joinType, $nodeId, $aggFromMap, $context->shift(), $extensions); + ) + ], + |fail('No SQL translation exists for the PURE function \''+$functionExpression.func.name->toOne()+'\'. \nIf you would like to add a SQL translation for the function then follow the step-by-step guide on the PURE wiki.'); $operation->wrapIfNecessary(); ); } @@ -1989,7 +2016,8 @@ function meta::relational::functions::pureToSqlQuery::flattenConcatenate(f:Value fe:FunctionExpression[1] | if ($fe.func->in([ concatenate_T_MANY__T_MANY__T_MANY_, union_T_MANY__T_MANY__T_MANY_, concatenate_TabularDataSet_1__TabularDataSet_1__TabularDataSet_1_, - concatenate_TabularDataSet_1__TabularDataSet_MANY__TabularDataSet_1_ + concatenate_TabularDataSet_1__TabularDataSet_MANY__TabularDataSet_1_, + concatenate_Relation_1__Relation_1__Relation_1_ ]), | $fe.parametersValues->at(0)->flattenConcatenate()->concatenate($fe.parametersValues->at(1)->flattenConcatenate()), | $fe @@ -2026,7 +2054,7 @@ function meta::relational::functions::pureToSqlQuery::processConcatenate(f:Funct ^$p(element = $newSelectWithCursor); ); - let setImpl = if($isDataType || $targetType ->_subTypeOf(TabularDataSet),|[],|$elements->map(e|$e->cast(@StoreMappingRoutedValueSpecification).sets->toOne())->removeDuplicates()); + let setImpl = if($isDataType || $targetType ->_subTypeOf(TabularDataSet) || $targetType ->_subTypeOf(meta::pure::metamodel::relation::Relation),|[],|$elements->map(e|$e->cast(@StoreMappingRoutedValueSpecification).sets->toOne())->removeDuplicates()); // Fix columns ---------------- let columns = $processed.element->cast(@SelectWithCursor).select.columns; @@ -2034,7 +2062,7 @@ function meta::relational::functions::pureToSqlQuery::processConcatenate(f:Funct | $processed->map(p|let selectWithCursor = $p.element->cast(@SelectWithCursor); let select = $selectWithCursor.select->alignJoinAndPkColumnsForUnion($columns); let element = $elements->at($processed->indexOf($p)); - let type = if($isDataType || $targetType ->_subTypeOf(TabularDataSet), + let type = if($isDataType || $targetType ->_subTypeOf(TabularDataSet) || $targetType ->_subTypeOf(meta::pure::metamodel::relation::Relation), |[], |^Alias ( @@ -2116,7 +2144,7 @@ function meta::relational::functions::pureToSqlQuery::processConcatenate(f:Funct |[], |$t.currentPropertyMapping->match([ e:EmbeddedRelationalInstanceSetImplementation[1]| $e, - p:PropertyMapping[1]| $state.mapping->classMappingById($t.currentPropertyMapping.targetSetImplementationId->toOne())->toOne() + p:PropertyMapping[1]| $state.mapping->toOne()->classMappingById($t.currentPropertyMapping.targetSetImplementationId->toOne())->toOne() ]) ) )); @@ -2446,7 +2474,10 @@ function meta::relational::functions::pureToSqlQuery::findAliasOrFail(columnName function meta::relational::functions::pureToSqlQuery::findAliasOrFail(f:FunctionExpression[1], select:SelectSQLQuery[1], vars:Map[1], state:State[1]):Alias[*] { - $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->cast(@String)->map(s| $s->findAliasOrFail($select)); + $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->match([ + s:String[*]|$s, + x:meta::pure::metamodel::relation::ColSpecArray[1]|$x.names + ])->map(s| $s->findAliasOrFail($select)); } function meta::relational::functions::pureToSqlQuery::processTDSSortSingular(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] @@ -2463,6 +2494,12 @@ function meta::relational::functions::pureToSqlQuery::processTDSSortColumns(f:Fu $f->processTDSSort($currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $sortInfo, $extensions); } +function meta::relational::functions::pureToSqlQuery::processTDSSortSortInfo(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] +{ + let sortInfo = $f->instanceValuesAtParameter(1,$vars, $state.inScopeVars)->cast(@SortInfo)->map(s | ^SortInformation(column = $s.column.name, direction = if($s.direction == SortType.ASC, |meta::pure::tds::SortDirection.ASC,|meta::pure::tds::SortDirection.DESC))); + $f->processTDSSort($currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $sortInfo, $extensions); +} + function meta::relational::functions::pureToSqlQuery::processTDSSortInformation(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] { let sortInfo = $f.parametersValues->at(1)->reactivate($state.inScopeVars)->cast(@SortInformation); @@ -2490,11 +2527,11 @@ function meta::relational::functions::pureToSqlQuery::processSortBy(f:FunctionEx let leftSidePure = $f.parametersValues->at(0); let leftSideOp = processValueSpecificationReturnPropertyMapping($leftSidePure, $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->toOne(); let mainQuery = $leftSideOp.element->cast(@SelectWithCursor); - let mainSelect = $mainQuery.select->pushSavedFilteringOperation($extensions); + let mainSelect = $mainQuery.select->pushSavedFilteringOperation($extensions); let sortByFunc = $f.parametersValues->evaluateAndDeactivate()->at(1)->byPassRouterInfo()->cast(@InstanceValue).values->at(0); - + $sortByFunc->match([ - path: Path[1] | + path: Path[1] | let pathName = 'o_'+$path->buildColumnNameOutOfPath(); let joinResult = processPath($path, $pathName, '1', $mainQuery, $vars, ^$state(inFilter=false), $nodeId, $aggFromMap, $context->shift(), $extensions).element->cast(@SelectWithCursor).select; @@ -2512,10 +2549,10 @@ function meta::relational::functions::pureToSqlQuery::processSortBy(f:FunctionEx orderBy = ^OrderBy(column=$joinResult.columns->at(0)->cast(@Alias).relationalElement, direction=meta::relational::metamodel::SortDirection.ASC) ) );, - l: LambdaFunction[1] | + l: LambdaFunction[1] | /* - already have a mainQuery - select ... - - process the lambda function inside sortBy with the state to generate a sql query + - process the lambda function inside sortBy with the state to generate a sql query select as "generated_order_key" from ... where is a sql representation for lambda function and "generated_order_key" is a temporary alias introduced - merge these two queries @@ -2530,7 +2567,7 @@ function meta::relational::functions::pureToSqlQuery::processSortBy(f:FunctionEx let lambdaFunctionExpression = $lambdaFunction.expressionSequence->at(0); let inScopeVarsWithPlaceholdersState = $lambdaFunction->addPlaceHoldersForLambdaOpenVariables($vars, $updatedState); let embeddedMapping = if($leftSideOp.currentPropertyMapping->isEmpty(), | $currentPropertyMapping, | $leftSideOp.currentPropertyMapping); - + let rightSide = processValueSpecification($lambdaFunctionExpression, $embeddedMapping, $mainQuery, $vars, ^$inScopeVarsWithPlaceholdersState(inFilter=false), JoinType.LEFT_OUTER, $nodeId, $aggFromMap, $context->shift(), $extensions)->toOne()->cast(@SelectWithCursor); let rightSideSelect = $rightSide.select; let rightSideModified = ^$rightSide( @@ -2538,7 +2575,7 @@ function meta::relational::functions::pureToSqlQuery::processSortBy(f:FunctionEx columns = if($rightSideSelect.columns->isEmpty(), | [], |^Alias(name = $generated_order_key, relationalElement = $rightSideSelect.columns->toOne())) ) ); - + let revisedLeftRightSelects = pair($mainSelect,$rightSideModified.select); let merge = [$revisedLeftRightSelects.first, $revisedLeftRightSelects.second]->cast(@SelectSQLQuery)->mergeSQLQueryData($nodeId, $updatedState, $context, $extensions); ^$operation( @@ -2790,7 +2827,7 @@ function meta::relational::functions::pureToSqlQuery::addPkForAggregation(f:Func |if($f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->instanceOf(RootRelationalInstanceSetImplementation), |let rs = $f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@RootRelationalInstanceSetImplementation); let pk = $rs->resolvePrimaryKey(); - let valid = if ($pk->isEmpty(), | fail('There is no primary key defined on the table ' + $rs->mainTable()->toOne().name + '. A primary key must be defined in the table definition in PURE to use this feature'); false; ,| true); + let valid = if ($pk->isEmpty(), | fail('There is no primary key defined on the table ' + $rs->mainTable()->toOne().name + '. A primary key must be defined in the table definition in PURE to use this feature'); false; ,| true); let existingSelect = $existingQuery.select; let all = $pk->filter(p|$p->instanceOf(TableAliasColumn))->map(p|$p->processColumnsInRelationalOperationElements(^$state(inFilter=false), ^$existingQuery(select=^$existingSelect(leftSideOfFilter=[]), positionBeforeLastApplyJoinTreeNode=[]), $nodeId, ^List(), false, $context, $extensions)); let sel = $all->map(c|$c.select)->cast(@SelectSQLQuery)->mergeSQLQueryData($nodeId, $state, $context, $extensions); @@ -2807,8 +2844,8 @@ function meta::relational::functions::pureToSqlQuery::addPkForAggregation(f:Func ); $result->validate([], $extensions); $result;, - |if($f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->instanceOf(OperationSetImplementation) && ($f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping)->size() > 1) && $f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping)->forAll(set | $set->instanceOf(RootRelationalInstanceSetImplementation)) && $existingQuery.currentTreeNode->isNotEmpty() && $existingQuery.currentTreeNode->toOne().alias.relationalElement->instanceOf(Union), - |addPkForAggregationInUnion($existingQuery, $f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping)->cast(@RootRelationalInstanceSetImplementation), $state, $extensions), + |if($f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->instanceOf(OperationSetImplementation) && ($f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping->toOne())->size() > 1) && $f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping->toOne())->forAll(set | $set->instanceOf(RootRelationalInstanceSetImplementation)) && $existingQuery.currentTreeNode->isNotEmpty() && $existingQuery.currentTreeNode->toOne().alias.relationalElement->instanceOf(Union), + |addPkForAggregationInUnion($existingQuery, $f.parametersValues->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne()->cast(@OperationSetImplementation)->resolveOperation($state.mapping->toOne())->cast(@RootRelationalInstanceSetImplementation), $state, $extensions), |$existingQuery ); ); @@ -3205,7 +3242,7 @@ function <> meta::relational::functions::pureToSqlQuery::process let classPropertyPair = $e->findPropertySequence()->first(); if(!$classPropertyPair->isEmpty(),| let class = $classPropertyPair.first; let propertyName = $classPropertyPair.second.name->toOne(); - let classMapping = $state.mapping->_classMappingByClass($class->toOne()); + let classMapping = $state.mapping->toOne()->_classMappingByClass($class->toOne()); $classMapping->cast(@PropertyMappingsImplementation)->map(x|$x->_propertyMappingsByPropertyName($propertyName)); ,|[]); ); @@ -3391,7 +3428,7 @@ function meta::relational::functions::pureToSqlQuery::processGetAll(expression: r:meta::pure::router::clustering::CrossSetImplementation[1]| let newTable = ^VarCrossSetPlaceHolder(varName=$r.varName, name=$r.varName, schema=^Schema(name='default', database=^Database()), crossSetImplementation = $r); let treeNode = ^RootJoinTreeNode(alias = ^TableAlias(name = 'root', relationalElement = $newTable)); ^SelectWithCursor(select = ^SelectSQLQuery(data = $treeNode), currentTreeNode = $treeNode);, - o:OperationSetImplementation[1]|let setImpls = $o->resolveOperation($state.mapping)->cast(@RootRelationalInstanceSetImplementation); + o:OperationSetImplementation[1]|let setImpls = $o->resolveOperation($state.mapping->toOne())->cast(@RootRelationalInstanceSetImplementation); if($setImpls->size()==1,| $processRootSetImpl->eval($setImpls->at(0)) ,| let milestoningContext = getMilestoningContextForAll($expression,$o, $parameters, $state, $vars, $context, $extensions); let union = buildUnion($setImpls, [], false, $state.inProject, $milestoningContext, $nodeId, $state, $context, $extensions); @@ -3529,7 +3566,7 @@ function meta::relational::functions::pureToSqlQuery::processRelationalMappingSp let merged = $pksAndProperties->concatenate($filterQuery.select)->mergeSQLQueryData($nodeId, $state, $context, $extensions); let fks = if ($viewSpecification->getDistinct() == true && !$viewSpecification->instanceOf(View), - | collectAdditionalJoinColumnsForSource($viewSpecification, $state.mapping, $merged.data->toOne(), $merged.columns->cast(@Alias)), + | collectAdditionalJoinColumnsForSource($viewSpecification, $state.mapping->toOne(), $merged.data->toOne(), $merged.columns->cast(@Alias)), | if ($state.importDataFlowAddFks == true, |$state.importDataFlowFksByTable->toOne()->get($mainTable).values->map(c|^Alias(name=$c.name, relationalElement=^TableAliasColumn(alias=$merged.data.alias->toOne(), columnName=$c.name, column=$c))), |[] @@ -4279,7 +4316,7 @@ function meta::relational::functions::pureToSqlQuery::processObjectReferenceIn(f let setImplementation = $leftSide->match([ e:StoreMappingRoutedValueSpecification[1] | $e.sets, - v:ValueSpecification[1] | $state.mapping->rootClassMappingByClass($mainClass); + v:ValueSpecification[1] | $state.mapping->toOne()->rootClassMappingByClass($mainClass); ])->toOne(); assert($setImplementation->instanceOf(RelationalInstanceSetImplementation), | 'OperationInstanceSetImplementation not supported yet!!'); @@ -4411,6 +4448,13 @@ function <> meta::relational::functions::pureToSqlQuery::reproce ]) } +Class <> meta::relational::functions::pureToSqlQuery::AggContainer +{ + name:String[1]; + map:meta::pure::metamodel::function::Function[1]; + reduce:meta::pure::metamodel::function::Function[1]; +} + function meta::relational::functions::pureToSqlQuery::processGroupBy(expression: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] { let nestedQuery = processValueSpecification($expression.parametersValues->at(0), [], $operation, $vars, $state, JoinType.LEFT_OUTER, $nodeId, $aggFromMap, $context, $extensions)->toOne()->cast(@SelectWithCursor); @@ -4418,18 +4462,26 @@ function meta::relational::functions::pureToSqlQuery::processGroupBy(expression: let groupByColumns = findAliasOrFail($expression, $select, $vars, $state); let noSubSelect = $select.groupBy->isEmpty() && ($select.distinct->isEmpty() || !$select.distinct->toOne()) && $select.orderBy.column->removeAll($groupByColumns)->isEmpty(); $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()->cast(@meta::pure::tds::AggregateValue); - let newColumns= $aggVS->map(a|let aggFn = $a.aggregateFn->cast(@FunctionDefinition).expressionSequence->at(0); - let params = if($a.mapFn.expressionSequence->at(0)->instanceOf(FunctionExpression) || $a.mapFn.expressionSequence->at(0)->instanceOf(InstanceValue), - |let inScopeVarsWithPlaceholdersState = $a.mapFn->addPlaceHoldersForLambdaOpenVariables($vars, $state); - processTdsLambda($a.mapFn.expressionSequence->at(0)->evaluateAndDeactivate(), $select.columns->filter(c|!$c->instanceOf(WindowColumn))->cast(@Alias),!$noSubSelect, $vars, $inScopeVarsWithPlaceholdersState, $currentPropertyMapping, $context);, + 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); + ]); + let newColumns= $aggVS->map(a|let aggFn = $a.reduce->cast(@FunctionDefinition).expressionSequence->at(0)->evaluateAndDeactivate(); + let params = if($a.map->cast(@FunctionDefinition).expressionSequence->at(0)->instanceOf(FunctionExpression) || $a.map->cast(@FunctionDefinition).expressionSequence->at(0)->instanceOf(InstanceValue), + |let inScopeVarsWithPlaceholdersState = $a.map->cast(@FunctionDefinition)->addPlaceHoldersForLambdaOpenVariables($vars, $state); + processTdsLambda($a.map->cast(@FunctionDefinition).expressionSequence->at(0)->evaluateAndDeactivate(), $select.columns->filter(c|!$c->instanceOf(WindowColumn))->cast(@Alias),!$noSubSelect, $vars, $inScopeVarsWithPlaceholdersState, $currentPropertyMapping, $context);, |[] ); ^Alias(name='"'+$a.name+'"', relationalElement=$aggFn->processAggFn($params)->at(0)); ); let existingPaths = $select.paths; - let pathInfos = $expression->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->cast(@String)->map(n|$existingPaths->filter(p|$p.first == $n)) - ->concatenate($aggVS->map(a| let pureType = $a.aggregateFn->functionReturnType().rawType->toOne(); + let pathInfos = $expression->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->match( + [ + s:String[*]|$s, + x:meta::pure::metamodel::relation::ColSpecArray[1]|$x.names + ] + )->map(n|$existingPaths->filter(p|$p.first == $n)) + ->concatenate($aggVS->map(a| let pureType = $a.reduce->functionReturnType().rawType->toOne(); pair($a.name, ^PathInformation(type=$pureType, relationalType= meta::relational::transform::fromPure::pureTypeToDataTypeMap()->get($pureType)));)); if($noSubSelect @@ -4531,21 +4583,19 @@ function <> meta::relational::functions::pureToSqlQuery::process let select = $mainQuery.select->cast(@TdsSelectSqlQuery); let funcParams = $f->genericType().typeArguments.rawType->cast(@FunctionType).parameters->tail(); let updatedState = if(!$vars->keys()->isEmpty(),|updateFunctionParamScope($state, $funcParams->evaluateAndDeactivate(),$operation),|$state); - let cols = $f->instanceValuesAtParameter(1, $vars, $updatedState.inScopeVars)->map(col | - $col->match([ - b:BasicColumnSpecification[1] | $b, - s:SimpleFunctionExpression[1] | $s->reactivate()->cast(@BasicColumnSpecification) - ]) + let newCols = $f->instanceValuesAtParameter(1, $vars, $updatedState.inScopeVars)->map(col | + $col->match([ + b:BasicColumnSpecification[1] | processBasicColumnSpecification($b, $mainQuery, $currentPropertyMapping, $vars, $updatedState, $context), + s:SimpleFunctionExpression[1] | processBasicColumnSpecification($s->reactivate()->cast(@BasicColumnSpecification)->toOne(), $mainQuery, $currentPropertyMapping, $vars, $updatedState, $context), + col : meta::pure::metamodel::relation::FuncColSpec[1] | + let newElement = processTdsLambda($col.function->cast(@FunctionDefinition).expressionSequence->at(0), $mainQuery.select.columns->cast(@Alias), false, $vars, $updatedState, $currentPropertyMapping, $context)->at(0); + let alias = ^Alias(name='"'+$col.name+'"', relationalElement=$newElement); + let path = pair($col.name, ^PathInformation(type=$col.function->functionReturnType().rawType->toOne(), + relationalType = $newElement->getRelationalTypeFromRelationalPropertyMapping())); + pair($alias,$path); + ]) ); - let newCols = $cols->map(cs| - let newElement = processTdsLambda($cs.func->cast(@FunctionDefinition).expressionSequence->at(0), $mainQuery.select.columns->cast(@Alias), false, $vars, $updatedState, $currentPropertyMapping, $context)->at(0); - let alias = ^Alias(name='"'+$cs.name+'"', relationalElement=$newElement); - let path = pair($cs.name, ^PathInformation(type=$cs.func->functionReturnType().rawType->toOne(), - relationalType = $newElement->getRelationalTypeFromRelationalPropertyMapping())); - pair($alias,$path); - ); - ^$mainQuery( select = ^$select( columns = if($includeOriginalColumns, | $mainQuery.select.columns, | [])->concatenate($newCols.first), @@ -4554,6 +4604,17 @@ function <> meta::relational::functions::pureToSqlQuery::process ); } +function <> meta::relational::functions::pureToSqlQuery::processBasicColumnSpecification(cols:BasicColumnSpecification[1], mainQuery:SelectWithCursor[1], currentPropertyMapping:PropertyMapping[*], vars:Map[1], updatedState:State[1], context:DebugContext[1]):Pair>[1] +{ + $cols->map(cs| + let newElement = processTdsLambda($cs.func->cast(@FunctionDefinition).expressionSequence->at(0), $mainQuery.select.columns->cast(@Alias), false, $vars, $updatedState, $currentPropertyMapping, $context)->at(0); + let alias = ^Alias(name='"'+$cs.name+'"', relationalElement=$newElement); + let path = pair($cs.name, ^PathInformation(type=$cs.func->functionReturnType().rawType->toOne(), + relationalType = $newElement->getRelationalTypeFromRelationalPropertyMapping())); + pair($alias,$path); + ); +} + function <> meta::relational::functions::pureToSqlQuery::processTableToTDS(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] { @@ -4592,9 +4653,14 @@ function meta::relational::functions::pureToSqlQuery::processTdsRenameColumns(ex let select = $mainQuery.select->cast(@TdsSelectSqlQuery); let projectColPairNames = $expression->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->match([ - p:Pair[*] | $p, - vss:ValueSpecification[*] | $vss->map(vs|$vs->reprocessVS()->reactivate($state.inScopeVars)->evaluateAndDeactivate()->cast(@Pair)); + c:meta::pure::metamodel::relation::ColSpec[1] |pair ( + $expression->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->cast(@meta::pure::metamodel::relation::ColSpec).name->toOne(), + $expression->instanceValuesAtParameter(2, $vars, $state.inScopeVars)->cast(@meta::pure::metamodel::relation::ColSpec).name->toOne() + ), + p:Pair[*] | $p, + vss:ValueSpecification[*] | $vss->map(vs|$vs->reprocessVS()->reactivate($state.inScopeVars)->evaluateAndDeactivate()->cast(@Pair)); ]); + let projectColNamesMap = $projectColPairNames->map(p|^$p(first = $p.first->addQuotesIfNecessary(), second = $p.second->addQuotesIfNecessary()))->newMap(); let noWrappedProjectColNamesMap = $projectColPairNames->map(p|^$p(first = $p.first->stripMatchingQuotes(), second = $p.second))->newMap(); @@ -4787,6 +4853,16 @@ function <> meta::relational::functions::pureToSqlQuery::process ); } +function meta::relational::functions::pureToSqlQuery::joinKindToType(jk:JoinKind[1]):JoinType[1] +{ + if ([ + pair(|$jk == JoinKind.INNER, |JoinType.INNER)//, + // pair(|$jk == JoinKind.RIGHT_OUTER, |JoinType.RIGHT_OUTER) + ], + |JoinType.LEFT_OUTER + ); +} + function meta::relational::functions::pureToSqlQuery::processTdsJoin(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] { let swc1 = processValueSpecification($f.parametersValues->at(0), $currentPropertyMapping, $operation, $vars, $state, $joinType, $nodeId, $aggFromMap, $context, $extensions)->toOne()->cast(@SelectWithCursor); @@ -4795,12 +4871,13 @@ function meta::relational::functions::pureToSqlQuery::processTdsJoin(f:FunctionE let type = $f->instanceValuesAtParameter(2, $vars, $state.inScopeVars) ->match([ j: JoinType[1] | $j, + k: JoinKind[1] | $k, a: Any[1] | let jt = $a->cast(@FunctionExpression).parametersValues; - extractEnumValue($jt->at(0)->cast(@InstanceValue).values->toOne()->cast(@Enumeration), $jt->at(1)->cast(@InstanceValue).values->cast(@String)->toOne())->cast(@JoinType); + extractEnumValue($jt->at(0)->cast(@InstanceValue).values->toOne()->cast(@Enumeration), $jt->at(1)->cast(@InstanceValue).values->cast(@String)->toOne()); ]); let joinCondition = $f->instanceValuesAtParameter(3, $vars, $state.inScopeVars); - let joinOp = $joinCondition->cast(@FunctionDefinition<{TDSRow[1],TDSRow[1]->Boolean[1]}>); + let joinOp = $joinCondition->cast(@FunctionDefinition); let newOpenVars = $state.inScopeVars->putAll($joinCondition->cast(@meta::pure::metamodel::function::Function)->at(0)->evaluateAndDeactivate()->openVariableValues()); assert($joinOp->cast(@FunctionDefinition).expressionSequence->size() <= 1, 'Lambda with more than one expression are not supported yet'); @@ -4810,7 +4887,6 @@ function meta::relational::functions::pureToSqlQuery::processTdsJoin(f:FunctionE let query1 = if($Q1isVarSetPlaceHolder,| $query1WithFilter.data.alias.relationalElement->cast(@VarSetPlaceHolder)->toOne(),| $query1WithFilter); let leftTableAlias = ^TableAlias(name='"joinleft_"'+$nodeId, relationalElement=$query1); - let leftAliasWithColumns = createAliasWithColumns($query1,'"joinleft_"'+$nodeId); let rightAlias = ^TableAlias(name='"joinright_"'+$nodeId, relationalElement=$query2); let aliases2 = $rightAlias->switchAliasForJoinInput($query2.columns); @@ -4828,7 +4904,7 @@ function meta::relational::functions::pureToSqlQuery::processTdsJoin(f:FunctionE , | $leftTableAlias); let join = ^Join(name='tdsJoin', target=$rightAlias, aliases=[pair($leftAliasForJoinNode,$rightAlias),pair($rightAlias,$leftAliasForJoinNode)],operation=$element_new->cast(@Operation)->toOne()); - let child = ^JoinTreeNode(alias=$rightAlias, join=$join, joinType=$type, database=^Database(), joinName='tdsJoin'); + let child = ^JoinTreeNode(alias=$rightAlias, join=$join, joinType=if($type->instanceOf(JoinType),|$type->cast(@JoinType),|meta::relational::functions::pureToSqlQuery::joinKindToType($type->cast(@JoinKind))), database=^Database(), joinName='tdsJoin'); let root = ^RootJoinTreeNode(alias=$leftAliasForJoinNode, childrenData=$child); let newAlias = ^TableAlias(name = 'tdsJoined_' + $nodeId, relationalElement=^TdsSelectSqlQuery(data=$root, columns=if($Q1isVarSetPlaceHolder,|[],|$leftAliasWithColumns->concatenate($aliases2)))); let newData = ^RootJoinTreeNode(alias = $newAlias); @@ -5122,7 +5198,6 @@ function meta::relational::functions::pureToSqlQuery::findColumnInTdsFromGetter( if($returnColumnName, {| assert($funcName->isEmpty() || !['isNull', 'isNotNull']->contains($funcName->toOne()), | $funcName->makeString() + ' can not be used to return column name'); - $foundColumn->map(c|^ColumnName(name=$c->match([a:Alias[1]|$a.name ,w:WindowColumn[1]| $w.columnName,t:TableAliasColumn[1]| $t.column.name]))); }, {| @@ -5149,27 +5224,39 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val [ r:FunctionRoutedValueSpecification[1]|$r.value->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $context), f:FunctionExpression[1]| - let dispatch = [ - pair('getNumber', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getInteger', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getDecimal', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getString', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getFloat', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getDate', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getDateTime', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getStrictDate', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getBoolean', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('getEnum', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('isNull', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), - pair('isNotNull', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)) - ]; - - let func = $dispatch->filter(d|$d.first == $f.func.functionName); - - if($func->isNotEmpty(), - |$func->toOne().second->cast(@meta::pure::metamodel::function::Function<{->RelationalOperationElement[*]}>)->eval(), - | - let supportedFunction = findSupportedFunction($f, $state.supportedFunctions, $state.contextBasedSupportedFunctions); + if ($f.func->instanceOf(meta::pure::metamodel::relation::Column), + | let foundColumn = $a->filter(alias| + $alias->match( + [ + al:Alias[1]|$al.name->addQuotesIfNecessary(), + t:TableAliasColumn[1]| $t.column.name->addQuotesIfNecessary(), + w:WindowColumn[1]| $w.columnName->addQuotesIfNecessary() + ] + ) == $f.func.name->toOne()->addQuotesIfNecessary() + ); //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(',')+')'}); + $foundColumn->map(c|$c->match([ a:Alias[1]| $a.relationalElement,r:RelationalOperationElement[1]|$r]));, + | let dispatch = [ + pair('getNumber', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getInteger', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getDecimal', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getString', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getFloat', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getDate', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getDateTime', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getStrictDate', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getBoolean', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('getEnum', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('isNull', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)), + pair('isNotNull', | findColumnInTdsFromGetter($f, $a,$returnColumnName, $vars, $state)) + ]; + + let func = $dispatch->filter(d|$d.first == $f.func.functionName); + + if($func->isNotEmpty(), + |$func->toOne().second->cast(@meta::pure::metamodel::function::Function<{->RelationalOperationElement[*]}>)->eval(), + | + let supportedFunction = findSupportedFunction($f, $state.supportedFunctions, $state.contextBasedSupportedFunctions); if($supportedFunction->isNotEmpty(), @@ -5211,35 +5298,37 @@ function meta::relational::functions::pureToSqlQuery::processTdsLambda(mapFn:Val let type = $f.parametersValues->at(1)->reactivate()->cast(@meta::pure::functions::hash::HashType)->toOne(); let name = meta::relational::functions::pureToSqlQuery::hashTypeToHashDynaFuncName($type); - let value = $f.parametersValues->at(0)->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $context); - - newDynaFunction($name, $value); - }) - ]->concatenate( - [ - meta::pure::functions::string::joinStrings_String_MANY__String_1_, - meta::pure::functions::string::joinStrings_String_MANY__String_1__String_1_, - meta::pure::functions::string::joinStrings_String_MANY__String_1__String_1__String_1__String_1_ - ]->map(func| - ^PureFunctionTDSToRelationalFunctionPair(first = $func, second = {| - ^DynaFunction( - name = 'concat', - parameters =$f.parametersValues->map(p|$p->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $context)) - ) - }) - ) - ); + let value = $f.parametersValues->at(0)->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $context); + + newDynaFunction($name, $value); + }) + ]->concatenate( + [ + meta::pure::functions::string::joinStrings_String_MANY__String_1_, + meta::pure::functions::string::joinStrings_String_MANY__String_1__String_1_, + meta::pure::functions::string::joinStrings_String_MANY__String_1__String_1__String_1__String_1_ + ]->map(func| + ^PureFunctionTDSToRelationalFunctionPair(first = $func, second = {| + ^DynaFunction( + name = 'concat', + parameters =$f.parametersValues->map(p|$p->processTdsLambda($a, $returnColumnName, $vars, $state, $currentPropertyMapping, $context)) + ) + }) + ) + ); - let override = $overrides->filter(o | $o.first == $f.func)->first(); - if ($override->isNotEmpty(), - | $override->toOne().second->eval(), - | if ($supportedFunction == processNoOp_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_, - | $f.parametersValues->at(0)->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $context), - | newDynaFunction($f.func.functionName->toOne(), $f.parametersValues->map(p|$p->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $context)))));, + let override = $overrides->filter(o | $o.first == $f.func)->first(); + if ($override->isNotEmpty(), + | $override->toOne().second->eval(), + | if ($supportedFunction == processNoOp_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_, + | $f.parametersValues->at(0)->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $context), + | newDynaFunction($f.func.functionName->toOne(), $f.parametersValues->map(p|$p->processTdsLambda($a,$returnColumnName, $vars, $state, $currentPropertyMapping, $context)))));, - | fail('function ' + $f.func.name->makeString() + ' is not yet supported'); ^DynaFunction(name='fail'); - ); - ); + | fail('function ' + $f.func.name->makeString() + ' is not yet supported'); ^DynaFunction(name='fail'); + ); + ); + + ); ,i:InstanceValue[1]| let transformedValues = $i.values->map(v | $v->match([ s:String[1] | ^Literal(value=$s), n:Number[1] | ^Literal(value=$n), @@ -5411,11 +5500,27 @@ function meta::relational::functions::pureToSqlQuery::processProjectWithColumnSu processProject($filteredFunctionIDPairs.second , $filteredFunctionIDPairs.first, [], $f, $operation, $vars, $state, $nodeId, $aggFromMap, $context,[], $extensions); } +Class meta::relational::functions::pureToSqlQuery::IntermediateColumn +{ + name : String[1]; + func : meta::pure::metamodel::function::Function[1]; + documentation : String[0..1]; +} + function meta::relational::functions::pureToSqlQuery::processProjectColumns(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] { - let columns = $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->filter(c|$c->instanceOf(BasicColumnSpecification))->cast(@BasicColumnSpecification); + let columns = $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars) + ->filter(c|$c->instanceOf(BasicColumnSpecification))->cast(@BasicColumnSpecification) + ->map(c|^IntermediateColumn(name=$c.name, func = $c.func, documentation = $c.documentation)); + + let colSpecArray = $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars) + ->filter(c|$c->instanceOf(meta::pure::metamodel::relation::FuncColSpecArray))->cast(@meta::pure::metamodel::relation::FuncColSpecArray<{Nil[1]->Any[*]},Any>); + + let _columns = $columns->concatenate($colSpecArray.names->zip($colSpecArray.functions)->map(c|^IntermediateColumn(name=$c.first, func = $c.second, documentation = ''))); + + let windowColumns = $f->instanceValuesAtParameter(1, $vars, $state.inScopeVars)->filter(c|$c->instanceOf(WindowColumnSpecification))->cast(@WindowColumnSpecification); - processProject($columns.name, $columns.func, $columns->map(c|if($c.documentation->isEmpty(),|'', |$c.documentation)), $f, $operation, $vars, $state, $nodeId, $aggFromMap, $context,$windowColumns, $extensions); + processProject($_columns.name, $_columns.func, $_columns->map(c|if($c.documentation->isEmpty(),|'', |$c.documentation)), $f, $operation, $vars, $state, $nodeId, $aggFromMap, $context,$windowColumns, $extensions); } function meta::relational::functions::pureToSqlQuery::getRootPrimaryKeyCols(source: SelectSQLQuery[1], sourceColumns: RelationalOperationElement[*], state:State[1], expression:FunctionExpression[1]):Pair, RootJoinTreeNode>[1] @@ -7893,7 +7998,6 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::tds::tdsContains_T_1__Function_MANY__TabularDataSet_1__Boolean_1_, second = meta::relational::functions::pureToSqlQuery::processTdsContains_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::tds::tdsContains_T_1__Function_MANY__String_MANY__TabularDataSet_1__Function_1__Boolean_1_, second = meta::relational::functions::pureToSqlQuery::processTdsContainsWithLambda_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::tds::extensions::firstNotNull_T_MANY__T_$0_1$_,second=meta::relational::functions::pureToSqlQuery::processFirstNotNull_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::relational::functions::columnProjectionsFromRoot_Any_MANY__NamedRelation_1__String_MANY__Boolean_$0_1$__Integer_$0_1$__RelationData_1_, second = meta::relational::functions::pureToSqlQuery::processColumnProjectionsFromRoot_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::tds::tdsRows_TabularDataSet_1__TDSRow_MANY_, second = meta::relational::functions::pureToSqlQuery::processNoOp_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::graphFetch::execution::graphFetch_T_MANY__RootGraphFetchTree_1__T_MANY_, second=meta::relational::functions::pureToSqlQuery::processNoOp_FunctionExpression_1__PropertyMapping_MANY__SelectWithCursor_1__Map_1__State_1__JoinType_1__String_1__List_1__DebugContext_1__Extension_MANY__RelationalOperationElement_1_), @@ -7907,6 +8011,23 @@ function meta::relational::functions::pureToSqlQuery::getSupportedFunctions():Ma ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::math::percentile_Number_MANY__Float_1__Boolean_1__Boolean_1__Number_$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::collection::isDistinct_T_MANY__Boolean_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::mutation::save_T_MANY__RootGraphFetchTree_1__Mapping_1__Runtime_1__T_MANY_, second=meta::relational::functions::pureToSqlQuery::processNoOp_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::hash::hash_String_1__HashType_1__String_1_, second=meta::relational::functions::pureToSqlQuery::processHash_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::hash::hash_String_1__HashType_1__String_1_, second=meta::relational::functions::pureToSqlQuery::processHash_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::filter_Relation_1__Function_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processTdsFilter_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::distinct_Relation_1__ColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processDistinct_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::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::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::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_), + ^PureFunctionToRelationalFunctionPair(first=meta::pure::functions::relation::slice_Relation_1__Integer_1__Integer_1__Relation_1_,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::relation::sort_Relation_1__SortInfo_MANY__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processTDSSortSortInfo_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_C_MANY__FuncColSpecArray_1__Relation_1_, second=meta::relational::functions::pureToSqlQuery::processProjectColumns_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/pureToSQLQuery/pureToSQLQuery_union.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery_union.pure index 0731717154c..af386cca3e7 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery_union.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/pureToSQLQuery/pureToSQLQuery_union.pure @@ -199,7 +199,7 @@ function meta::relational::functions::pureToSqlQuery::union::buildUnion(setImpls // 1. buildUnion is called as part of building the target of an association (in which case the 'source' flag is false) // 2. Used in the 'importDataFlow' use case on the source (getAll on the type itself) let avoidModeledProperties = $relationalPropertyMappings->exists(rpm | $rpm->isNullJoinPropertyMapping()); - let targetCols = findFkListForEachSet($propertyMappingsInScope, $state.importDataFlow==true, $state.mapping, $avoidModeledProperties); + let targetCols = findFkListForEachSet($propertyMappingsInScope, $state.importDataFlow==true, $state.mapping->toOne(), $avoidModeledProperties); let missingFks = $targetCols->map(c|list($c.second.values->map(z|pair($z.name+'_'+$targetCols->indexOf($c)->toString(), $z)))); let mappedFkPropertyNames = $targetCols.first.values.first->removeDuplicates(); @@ -359,9 +359,9 @@ function meta::relational::functions::pureToSqlQuery::union::buildSQLQueryOutMan print(if(!$context.debug, |'', | $context.space+'*>Build SQL query out many set implementations (and join) (propertyMappings:'+$relationalPropertyMappings->size()->toString()+'):\n')); let avoidModeledProperties = $relationalPropertyMappings->exists(rpm | $rpm->isNullJoinPropertyMapping()); - let sourceCols = findFkListForEachSet($relationalPropertyMappings, true, $state.mapping, $avoidModeledProperties); + let sourceCols = findFkListForEachSet($relationalPropertyMappings, true, $state.mapping->toOne(), $avoidModeledProperties); let srcMap = $sourceCols->buildColumnToNameMapForMappedFks(); - let targetCols = findFkListForEachSet($relationalPropertyMappings, false, $state.mapping, $avoidModeledProperties); + let targetCols = findFkListForEachSet($relationalPropertyMappings, false, $state.mapping->toOne(), $avoidModeledProperties); let targetMap = $targetCols->buildColumnToNameMapForMappedFks(); let sourceAlias = $srcOperation.currentTreeNode.alias; @@ -420,7 +420,7 @@ function meta::relational::functions::pureToSqlQuery::union::buildSQLQueryOutMan // New Queries let targetSetImplementationIds = $relationalPropertyMappings.targetSetImplementationId->removeDuplicates(); - let targetSetImplementations = $targetSetImplementationIds->map(t|$state.mapping->classMappingById($t)->cast(@RootRelationalInstanceSetImplementation)->toOne()); + let targetSetImplementations = $targetSetImplementationIds->map(t|$state.mapping->toOne()->classMappingById($t)->cast(@RootRelationalInstanceSetImplementation)->toOne()); print(if(!$context.debug, |'', | $context.space+' - sourceSetImplIds: ['+$sourceSetImplementationIds->joinStrings(',')+']\n'+$context.space+' - targetSetImplIds: ['+$targetSetImplementationIds->joinStrings(',')+']\n')); @@ -436,7 +436,7 @@ function meta::relational::functions::pureToSqlQuery::union::buildSQLQueryOutMan let unionTargetAlias = ^TableAlias(name='unionAlias', relationalElement=$newTargetOperation); - let unionJoin = buildUnionJoin($relationalPropertyMappings, $state.mapping, $srcMap, $targetMap, $sourceNode.alias, $unionTargetAlias, $newSourceOperation, $nodeId, $state, $context, $extensions); + let unionJoin = buildUnionJoin($relationalPropertyMappings, $state.mapping->toOne(), $srcMap, $targetMap, $sourceNode.alias, $unionTargetAlias, $newSourceOperation, $nodeId, $state, $context, $extensions); print(if(!$context.debug, |'', | $context.space+' [Merged]: '+$unionJoin.second->printRelationalTreeNode($extensions)+'\n')); diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relation/tests.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relation/tests.pure new file mode 100644 index 00000000000..13ee9e08f0c --- /dev/null +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relation/tests.pure @@ -0,0 +1,687 @@ +// Copyright 2023 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::relational::functions::sqlQueryToString::*; +import meta::relational::metamodel::execute::*; +import meta::relational::metamodel::relation::*; +import meta::relational::runtime::*; +import meta::external::store::relational::runtime::*; +import meta::core::runtime::*; +import meta::relational::metamodel::*; +import meta::pure::mapping::*; +import meta::pure::metamodel::relation::*; +import meta::relational::relation::testUtils::*; + +function meta::relational::relation::testUtils::reprocess(f:Function<{->Any[*]}>[1]):PairAny[*]}>,List,RelationStoreAccessor>>>[1] +{ + $f->match( + [ + z:FunctionDefinition<{->Any[*]}>[1]| + println('BEFORE: ' + meta::pure::metamodel::serialization::grammar::printFunctionDefinition($z, '')); + + // Init + let initState = meta::relational::relation::testUtils::initState($z->openVariableValues()); + let db = $initState.database; + let schema = $initState.schema; + let runtime = $initState.runtime; + + // Reprocess the function replacing values with Database elements + let reprocessed = $z.expressionSequence->evaluateAndDeactivate()->map(z|$z->reprocess($initState)); + + // Add 'from' + let returnGenericType = $z.expressionSequence->evaluateAndDeactivate()->last().genericType->toOne(); + let returnMultiplicity = $z.expressionSequence->evaluateAndDeactivate()->last().multiplicity->toOne(); + let result = pair( + ^$z + ( + expressionSequence = ^SimpleFunctionExpression + ( + importGroup=system::imports::coreImport, + func = if($reprocessed.mapping->isEmpty(),|from_T_m__Runtime_1__T_m_,|from_T_m__Mapping_1__Runtime_1__T_m_), + functionName = 'from', + genericType = $returnGenericType, + multiplicity = $returnMultiplicity, + parametersValues = + $reprocessed.current->toOne()->cast(@ValueSpecification) + ->concatenate(if ($reprocessed.mapping->isEmpty(), + |[], + |^InstanceValue + ( + genericType = ^GenericType(rawType=Mapping), + multiplicity = PureOne, + values = $reprocessed.mapping + ) + )) + ->concatenate(^InstanceValue + ( + genericType = ^GenericType(rawType=Runtime), + multiplicity = PureOne, + values = $runtime + ) + ) + , + resolvedMultiplicityParameters = $returnMultiplicity, + resolvedTypeParameters = $returnGenericType + ) + ), + list($reprocessed.replaced) + ); + + println('AFTER: ' + meta::pure::metamodel::serialization::grammar::printFunctionDefinition($result.first, '') + '\n'); + + // Update the database + let setUpSQLs = $reprocessed.csvs->joinStrings('\n-\n')->meta::alloy::service::execution::setUpDataSQLs($reprocessed.database->toOne()); +// println($setUpSQLs); + $setUpSQLs->map(sql | executeInDb($sql, $reprocessed.runtime.connectionStores.connection->toOne()->cast(@TestDatabaseConnection))); + + $result; + ] + ); +} + +Class meta::relational::relation::testUtils::ProcessingState +{ + database : Database[1]; + schema : Schema[1]; + tables : Table[*]; + runtime : Runtime[1]; + mapping : Mapping[0..1]; + current : Any[0..1]; + replaced : Pair, RelationStoreAccessor>[*]; + openVars : Map[0..1]; + csvs : String[*]; +} + +function meta::relational::relation::testUtils::merge(s1:ProcessingState[1], s2:ProcessingState[1]):ProcessingState[1] +{ + ^$s1 + ( + tables += $s2.tables, + mapping += $s2.mapping, + replaced += $s2.replaced, + csvs += $s2.csvs, + openVars = if($s1.openVars->isEmpty(),|$s1.openVars,|$s2.openVars) + ); +} + +function meta::relational::relation::testUtils::initState(openVars:Map[0..1]):ProcessingState[1] +{ + let db = ^Database + ( + name = 'MyDatabase', + package = meta::relational::relation::testUtils + ); + + let schema = ^Schema + ( + name='default', + database = $db + ); + + $db->mutateAdd('schemas', $schema); + + ^ProcessingState + ( + database = $db, + schema = $schema, + openVars = $openVars, + runtime = ^Runtime + ( + connectionStores=^ConnectionStore + ( + connection=^TestDatabaseConnection + ( + type = DatabaseType.H2, + timeZone = 'GMT' + ), + element = $db + ) + ) + ); +} + + +###Pure +import meta::relational::metamodel::execute::*; +import meta::relational::functions::database::*; +import meta::external::store::relational::runtime::*; +import meta::pure::mapping::*; +import meta::core::runtime::*; +import meta::relational::metamodel::relation::*; +import meta::relational::metamodel::*; +import meta::pure::metamodel::relation::*; +import meta::relational::relation::testUtils::*; + +function meta::relational::relation::testUtils::reprocess(a:Any[1], state:ProcessingState[1]):ProcessingState[1] +{ + $a->match( + [ + z:FunctionExpression[1]| if($z.func == new_Class_1__String_1__KeyExpression_MANY__T_1_, + | meta::relational::relation::testUtils::reprocessNew($z->reactivate()->evaluateAndDeactivate(), $z.genericType.rawType->toOne()->cast(@Class), $state);, + | let repro = $z.parametersValues->evaluateAndDeactivate()->map(x|$x->reprocess($state)); + ^$state + ( + current = ^$z(parametersValues = $repro.current->cast(@ValueSpecification))->evaluateAndDeactivate(), + mapping = $repro.mapping->first(), + replaced = $repro.replaced, + tables = $repro.tables, + csvs = $repro.csvs + ); + );, + ix:InstanceValue[1]| + let i = $ix->evaluateAndDeactivate(); + let type = $i.genericType.rawType->toOne(); + if ($type->instanceOf(Class) && $type != LambdaFunction && $type != TDS && $type != Enumeration && $type != SortInfo, + | + let values = $i.values->map( + x|$x->match([ + v:ValueSpecification[1]|$v->reactivate()->evaluateAndDeactivate(), + a:Any[1]|$a + ] + ) + ); + meta::relational::relation::testUtils::reprocessNew($values, $type->cast(@Class), $state);, + | + let repro = $i.values->map(x|$x->reprocess($state)); + ^$state + ( + current = ^$i + ( + genericType = if($repro.current.classifierGenericType->isEmpty(),|$i.genericType, |$repro.current.classifierGenericType->first()->toOne()), + values = $repro.current + ), + mapping = $repro.mapping->first(), + replaced = $repro.replaced, + tables = $repro.tables, + csvs = $repro.csvs + ); + );, + z:LambdaFunction[1] | let repro = $z.expressionSequence->evaluateAndDeactivate()->map(z|$z->reprocess($state)); + ^$state + ( + current=^$z(expressionSequence = $repro.current->cast(@ValueSpecification)->toOneMany()), + mapping = $repro.mapping->first(), + replaced=$repro.replaced, + tables = $repro.tables, + csvs = $repro.csvs + );, + v:VariableExpression[1] | let openVar = $state.openVars->toOne()->get($v.name); + if ($openVar->isEmpty(), + |^$state + ( + current = $v + ), + |reprocess(^InstanceValue + ( + genericType = $openVar->toOne()->cast(@List).values->at(0).classifierGenericType->toOne(), + multiplicity = PureOne, + values = $openVar->toOne()->cast(@List).values + ), $state) + );, + x:TDS[1] | processTDS($x, $state), + e:Enumeration[1] | ^$state + ( + current = $e + );, + r:Integer[1] | ^$state + ( + current = $r + );, + s:String[1] | ^$state + ( + current = $s + ); + ] + ); +} + +function meta::relational::relation::testUtils::reprocessNew(values:Any[*], type:Class[1], state:ProcessingState[1]):ProcessingState[1] +{ + let newState = $state->merge(classesToDatabase($values, $state)); + ^$newState + ( + current = ^SimpleFunctionExpression + ( + importGroup=system::imports::coreImport, + func = getAll_Class_1__T_MANY_, + functionName = 'getAll', + genericType = ^GenericType(rawType=$type), + multiplicity = ZeroMany, + parametersValues = [ + ^InstanceValue + ( + genericType = ^GenericType(rawType=$type), + multiplicity = PureOne, + values = [] + ) + ] + )->evaluateAndDeactivate() + ); +} + +function meta::relational::relation::testUtils::processTDS(tds:TDS[1], state:ProcessingState[1]):ProcessingState[1] +{ + let map = meta::relational::transform::fromPure::pureTypeToDataTypeMap(); + let table = ^Table + ( + name = 'tb' + now()->toEpochValue(DurationUnit.MILLISECONDS)->toString(), + columns = $tds->columns()->map(c| + ^meta::relational::metamodel::Column( + name=$c.name->toOne(), + type=$map->meta::pure::functions::collection::get($c.classifierGenericType.typeArguments->at(1).rawType->toOne())->toOne() + ) + ), + schema = $state.schema + ); + + $state.schema->mutateAdd('tables', $table); + + let relAccessor = ^RelationDatabaseAccessor + ( + store = $state.database, + database = $state.database, + relation = $table + ); + + // Create CSV out of TDS data + let cols = $tds->columns(); + let csv = $state.schema.name+'\n' + + $relAccessor.relation.name + '\n' + + $cols->map(x|$x.name)->joinStrings(',' ) + '\n' + + $tds->map(x|$cols->map(c|$c->eval($x)->toOne()->toString())->joinStrings(',')) + ->joinStrings('\n'); + + ^$state + ( + current = $relAccessor, + replaced = pair($tds, $relAccessor), + tables += $table, + csvs += $csv + ); +} + + + + +function meta::relational::relation::testUtils::testTDSDatabaseRun(f:Function<{->Any[*]}>[1]):Any[*] +{ + // //For debug + // meta::pure::executionPlan::executionPlan($f->meta::relational::relation::testUtils::reprocess().first, ^meta::pure::runtime::ExecutionContext(), meta::relational::extension::relationalExtensions(), debug()); + // []; + + let x = meta::legend::executeLegendQuery($f->meta::relational::relation::testUtils::reprocess().first, [], ^meta::pure::runtime::ExecutionContext(), meta::relational::extension::relationalExtensions()); + let res = $x->meta::json::fromJSON(meta::protocols::pure::vX_X_X::metamodel::invocation::execution::execute::RelationalTDSResult, ^meta::json::ExtendedJSONDeserializationConfig(typeKeyName='__TYPE', failOnUnknownProperties=true, nullReplacementInArray=TDSNull)); + let tdsString = '#TDS\n'+ $res.result.columns->joinStrings(',') + '\n' + + $res.result.rows->map(x| + range($x.values->size())->map(z | if($x.values->at($z) == TDSNull, + |let type = $res.builder->cast(@meta::protocols::pure::vX_X_X::metamodel::invocation::execution::execute::TDSBuilder).columns->at($z).type; + if ([ + pair(|$type == 'Integer', |-2147483648), + pair(|$type == 'String', |'null') + ], + |fail();0; + );, + |$x.values->at($z) + ) + )->makeString(',') + )->joinStrings('\n') + + '#'; +// println($tdsString); + let comp = compileValueSpecification($tdsString); + $comp.result->toOne()->reactivate(); +} + + + + + + + + + + + +###Pure +import meta::relational::metamodel::execute::*; +import meta::relational::functions::database::*; +import meta::external::store::relational::runtime::*; +import meta::relational::relation::testUtils::tests::*; +import meta::relational::relation::testUtils::*; +import meta::relational::metamodel::*; +import meta::relational::metamodel::relation::*; +import meta::relational::metamodel::join::*; +import meta::relational::mapping::*; +import meta::pure::mapping::*; + + + +function meta::relational::relation::testUtils::classesToDatabase(values:Any[*], givenState:ProcessingState[0..1]):ProcessingState[1] +{ + let _state = if ($givenState->isEmpty(),|initState([]),|$givenState)->toOne(); + let state = ^$_state( + mapping = ^Mapping + ( + name = 'myMapping' + ) + ); + + if (!$values->isEmpty(), + | // Scan types + let rootType = $values->genericType().rawType->first()->toOne()->cast(@Class); + let allClasses = scanClass($rootType); + + // Build schema + let tables = $allClasses->map(c|$c->classToTable($state.schema, $state.mapping->toOne())); + let joins = $allClasses->map(c|$c->buildJoins($tables, $state.database)); + $state.schema->mutateAdd('tables', $tables.table); + $state.database->mutateAdd('joins', $joins.join); + + buildCSV($values, $rootType, [], 1, $tables); + let csvs = $tables->map(k|$k.csv->joinStrings('\n')); + $state.mapping->toOne()->mutateAdd('classMappings', $tables.classMapping); + + let runtime = $state.runtime; + let mapping = $state.mapping->toOne(); + + ^$state + ( + csvs += $csvs + );, + | $state + ); + +} + +function meta::relational::relation::testUtils::buildCSV(values:Any[*], class:Class[1], property:Property[0..1], parentId:Integer[1], maps:ClassTableMapping[*]):ClassTableMapping[*] +{ + let info = $maps->filter(c|$c.class == $class)->toOne(); + let header = $info.table.schema.name->toOne()+'\n'+ + $info.table.name+'\n'+ + $info.table.columns->cast(@Column).name->joinStrings(','); + let rows = $values->map + ( + v | let id = $values->indexOf($v) + $parentId*10; + + let r = $id + ->concatenate($info.properties->map(p | $p->eval($v))) + ->concatenate($info.parentProperties->map(p | if($p == $property,|$parentId,|'-1'))) + ->makeString(','); + + let props = $class.properties->filter(p|!$p->isPrimitiveValueProperty()); + $props->map(p| + let vals = $p->eval($v); + buildCSV($vals, $p->functionReturnType().rawType->toOne()->cast(@Class), $p, $id, $maps); + ); + + $r; + + )->joinStrings('\n'); + + $info->mutateAdd('csv', if($info.csv->isEmpty(), + |$header+'\n'+$rows, + |$rows + )); + + $maps; +} + +Class meta::relational::relation::testUtils::ClassTableMapping +{ + class : Class[1]; + table : Table[1]; + properties : Property[*]; + parentProperties : Property[*]; + classMapping: RootRelationalInstanceSetImplementation[1]; + csv : String[*]; +} + +Class meta::relational::relation::testUtils::PropertyColumnMapping +{ + property : Property[1]; + column : Column[1]; +} + +function meta::relational::relation::testUtils::classToTable(class:Class[1], schema:Schema[1], mapping:Mapping[1]):ClassTableMapping[1] +{ + let map = meta::relational::transform::fromPure::pureTypeToDataTypeMap(); + let properties = $class.properties->filter(p|$p->isPrimitiveValueProperty()); + let cols = $properties->map(p|^PropertyColumnMapping(property=$p, column=^Column(name=$p.name->toOne(), type=$map->get($p->functionReturnType().rawType->toOne())->toOne()))); + let idCol = ^Column(name='_pureId', type=^meta::relational::metamodel::datatype::Integer()); + let table = ^Table(name=$class.name->toOne(), schema=$schema, primaryKey=$idCol, columns=$idCol->concatenate($cols.column)); + let tableAlias = ^TableAlias(name=$table.name, relationalElement = $table); + + + let set = ^RootRelationalInstanceSetImplementation + ( + id = $class.name->toOne(), + root = true, + userDefinedPrimaryKey = true, + primaryKey = ^TableAliasColumn(alias=$tableAlias, column=$idCol), + parent = $mapping, + class = $class, + mainTableAlias = $tableAlias + ); + + let pmappings = $cols->map(c | + ^RelationalPropertyMapping + ( + property = $c.property, + sourceSetImplementationId = $class.name->toOne(), + targetSetImplementationId = '', + owner = $set, + relationalOperationElement = ^TableAliasColumn + ( + columnName = $c.column.name, + alias = $tableAlias, + column = $c.column + ) + ) + + ); + + $set->mutateAdd('propertyMappings', $pmappings); + + ^ClassTableMapping + ( + class = $class, + table = $table, + properties = $properties, + classMapping = $set + ); +} + +Class meta::relational::relation::testUtils::JoinRes +{ + join : Join[1]; + property : Property[1]; + fk : Column[1]; + propertyMapping : RelationalPropertyMapping[1]; +} + +function meta::relational::relation::testUtils::buildJoins(class:Class[1], classTableMappings:ClassTableMapping[*], db:Database[1]):meta::relational::relation::testUtils::JoinRes[*] +{ + let src = $classTableMappings->filter(ctm|$ctm.class == $class)->toOne(); + let cols = $class.properties + ->filter(p|!$p->isPrimitiveValueProperty()) + ->map(p| + let targetType = $p->functionReturnType().rawType->toOne(); + let target = $classTableMappings->filter(ctm|$ctm.class == $targetType)->toOne(); + let srcColumn = $src.table.columns->cast(@Column)->filter(c|$c.name == '_pureId')->toOne(); + let fkColumn = ^Column(name='_'+$class.name->toOne()+'_'+$p.name->toOne(), type=^meta::relational::metamodel::datatype::Integer()); + let targetTable = $target.table; + $targetTable->mutateAdd('columns', $fkColumn); + let srcAlias = ^TableAlias(name='src', relationalElement=$src.table); + let targetAlias = ^TableAlias(name=$targetTable.name, relationalElement=$targetTable); + let join = ^Join + ( + name = $class.name->toOne() + '_' + $p.name->toOne(), + aliases = [pair($srcAlias,$targetAlias),pair($targetAlias,$srcAlias)], + operation = ^DynaFunction + ( + name = 'equal', + parameters = [ + ^TableAliasColumn(alias=$srcAlias, column=$srcColumn), + ^TableAliasColumn(alias=$targetAlias, column=$fkColumn) + ] + ) + ); + $target->mutateAdd('parentProperties', $p); + let res = ^JoinRes + ( + join = $join, + property = $p, + fk = $fkColumn, + propertyMapping = ^RelationalPropertyMapping + ( + property = $p, + sourceSetImplementationId = $class.name->toOne(), + targetSetImplementationId = $targetType.name->toOne(), + relationalOperationElement = ^RelationalOperationElementWithJoin + ( + joinTreeNode = ^JoinTreeNode + ( + joinName = $join.name, + database = $db, + alias = $srcAlias, + join = $join + ) + ) + ) + ); + $res.propertyMapping->mutateAdd('owner', $src.classMapping); + $res; + ); + $src.classMapping->mutateAdd('propertyMappings', $cols.propertyMapping); + $cols; +} + + + +function meta::relational::relation::testUtils::scanClass(a:Class[1]):Class[*] +{ + $a->scanClass([])->removeDuplicates(); +} + +function meta::relational::relation::testUtils::scanClass(a:Class[1], visited:Class[*]):Class[*] +{ + let newVisited = $visited->concatenate($a); + if ($a->in($visited), + |[], + | $a + ->concatenate( + $a.properties->map(p|$p.genericType.rawType)->filter(c|$c->instanceOf(Class))->cast(@Class)->map(x|$x->scanClass($newVisited)) + )->concatenate( + $a.generalizations.general.rawType->filter(x|$x != Any && $x->instanceOf(Class))->cast(@Class)->map(x|$x->scanClass($newVisited)) + ) + ); +} + + + + + + + + + + + + + +Class meta::relational::relation::testUtils::tests::Firm +{ + legalName : String[1]; + employees : Person[*]; + address : Address[1]; +} + +Class meta::relational::relation::testUtils::tests::Person +{ + firstName : String[0..1]; + lastName : String[1]; + addresses : Address[*]; +} + +Class meta::relational::relation::testUtils::tests::Address +{ + zip : Integer[1]; +} + +function <> meta::relational::relation::testUtils::tests::testClassToDB():Boolean[1] +{ + let res = meta::relational::relation::testUtils::classesToDatabase( + ^Firm + ( + legalName = 'Goldman', + employees = [ + ^Person + ( + firstName = 'john', + lastName = 'doe', + addresses = [^Address(zip=1), ^Address(zip=2)] + ), + ^Person + ( + firstName = 'billy', + lastName = 'bob', + addresses = [^Address(zip=3), ^Address(zip=4)] + ) + ], + address = ^Address + ( + zip = 1999 + ) + ),[] + ); + + assertEquals([ + 'Firm', + 'Person', + 'Address' + ], $res.schema.tables.name); + + assertEquals([ + 'Firm_employees', + 'Firm_address', + 'Person_addresses' + ], $res.database.joins.name); + + assertEquals([ + 'Firm', + 'Person', + 'Address' + ], $res.mapping.classMappings.class.name); + + assertEquals([ + 'legalName', + 'employees', + 'address', + 'firstName', + 'lastName', + 'addresses', + 'zip' + ], $res.mapping.classMappings->cast(@RootRelationalInstanceSetImplementation).propertyMappings.property.name); +} + + + +function meta::relational::relation::executeDatabaseTests():Boolean[1] +{ + meta::pure::functions::relation::tests::executeTests(meta::relational::relation::testUtils::testTDSDatabaseRun_Function_1__Any_MANY_); +} + +function meta::relational::relation::executeSingleTest():Boolean[1] +{ + meta::pure::functions::relation::tests::filter::testSimpleFilterShared(meta::relational::relation::testUtils::testTDSDatabaseRun_Function_1__Any_MANY_); +} \ No newline at end of file diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relationalMappingExecution.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relationalMappingExecution.pure index e43f4eca2c7..a8021e2e409 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relationalMappingExecution.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/relationalMappingExecution.pure @@ -42,12 +42,12 @@ import meta::relational::milestoning::*; import meta::pure::router::routing::*; import meta::pure::router::store::metamodel::*; -function meta::relational::mapping::generateExecutionNodeForPostProcessedResult(postProcessorResult:PostProcessorResult[1], sq:meta::pure::mapping::StoreQuery[1], store:Database[1], ext:RoutedValueSpecification[0..1], m:Mapping[1], runtime:Runtime[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], extensions:Extension[*]):ExecutionNode[1] +function meta::relational::mapping::generateExecutionNodeForPostProcessedResult(postProcessorResult:PostProcessorResult[1], sq:meta::pure::mapping::StoreQuery[1], store:Database[1], ext:RoutedValueSpecification[0..1], m:Mapping[0..1], runtime:Runtime[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], extensions:Extension[*]):ExecutionNode[1] { generateExecutionNodeForPostProcessedResult($postProcessorResult, $sq, $store, $ext, $m, $runtime, $exeCtx, $debug, true, $extensions) } -function meta::relational::mapping::generateExecutionNodeForPostProcessedResult(postProcessorResult:PostProcessorResult[1], sq:meta::pure::mapping::StoreQuery[1], store:Database[1], ext:RoutedValueSpecification[0..1], m:Mapping[1], runtime:Runtime[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], wrapInInstantiationNode: Boolean[1], extensions:Extension[*]):ExecutionNode[1] +function meta::relational::mapping::generateExecutionNodeForPostProcessedResult(postProcessorResult:PostProcessorResult[1], sq:meta::pure::mapping::StoreQuery[1], store:Database[1], ext:RoutedValueSpecification[0..1], m:Mapping[0..1], runtime:Runtime[1], exeCtx:ExecutionContext[1], debug:DebugContext[1], wrapInInstantiationNode: Boolean[1], extensions:Extension[*]):ExecutionNode[1] { let sqlNode = generateSQLExecutionNode($postProcessorResult.query, $runtime->toOne()->connectionByElement($store)->cast(@DatabaseConnection), addEnumMapSupportFunctions($sq, $m), $extensions); let relationalNode = if($wrapInInstantiationNode, | generateInstantiationExecutionNode($sq, $ext, $postProcessorResult.query, $sqlNode, $m), | $sqlNode); @@ -60,45 +60,65 @@ function meta::relational::mapping::generateExecutionNodeForPostProcessedResult( ); } -function meta::relational::mapping::generateInstantiationExecutionNode(sq:meta::pure::mapping::StoreQuery[1], ext:RoutedValueSpecification[0..1], query:SQLQuery[1], node:ExecutionNode[1], m:Mapping[1]):ExecutionNode[1] +function meta::relational::mapping::generateInstantiationExecutionNode(sq:meta::pure::mapping::StoreQuery[1], ext:RoutedValueSpecification[0..1], query:SQLQuery[1], node:ExecutionNode[1], m:Mapping[0..1]):ExecutionNode[1] { let possibleClass = $sq.fe.genericType.rawType->toOne(); let class = if ($possibleClass == Any, | let getAllClass = findMainClassInGetAllExpression($sq.fe); if($getAllClass->isEmpty(), | $possibleClass, | $getAllClass);, | $possibleClass ); - let resultType = if($class->_subTypeOf(TabularDataSet), - |let paths = $query->cast(@TdsSelectSqlQuery).paths; - ^TDSResultType - ( - type = $class, - tdsColumns = $paths->map(p| - ^TDSColumn - ( - name = $p.first, - type = $p.second.type->cast(@meta::pure::metamodel::type::DataType), - documentation = $p.second.documentation, - enumMappingId = $p.second.propertyMapping->match([r:RelationalPropertyMapping[0..1] | $r.transformer->cast(@EnumerationMapping).name, p:PropertyMapping[0..1] | []]), - offset = $paths->indexOf($p), - sourceDataType = if($p.second.relationalType->isNotEmpty(), - | $p.second.relationalType, - | $p.second.propertyMapping->match([ - rpm: RelationalPropertyMapping[0..1] | $rpm->getRelationalTypeFromRelationalPropertyMapping($p.first), - cpm: meta::pure::router::clustering::CrossSetImplementationPrimtivePropertyMapping[0..1] | $cpm.sourcePropertyMapping->match([rpm: RelationalPropertyMapping[0..1] | $rpm->getRelationalTypeFromRelationalPropertyMapping($p.first), pm: PropertyMapping[0..1] | []]), - pm: PropertyMapping[0..1] | [] - ])) - ); - ) - );, - | if($class->_subTypeOf(RelationData), - | let relationDataQuery = $query->cast(@RelationDataSelectSqlQuery); - ^RelationResultType + let resultType = if([ + pair( + |$class->_subTypeOf(TabularDataSet), + |let paths = $query->cast(@TdsSelectSqlQuery).paths; + ^TDSResultType ( - relationName = $relationDataQuery.relation.name, - relationType = $relationDataQuery.relation->instanceOf(View)->if(|RelationType.VIEW,|RelationType.TABLE), - schemaName = $relationDataQuery.relation->match([t:Table[1]|$t.schema,v:View[1]|$v.schema])->cast(@Schema).name, - database = $relationDataQuery.relation->match([t:Table[1]|$t.schema,v:View[1]|$v.schema])->cast(@Schema).database->elementToPath(), - columns = $relationDataQuery.columns->cast(@Alias)->map(x | ^Column(name = $x.name, type=$x.relationalElement->cast(@TableAliasColumn).column.type)), - type = $class - );, - | $class->match([ + type = $class, + tdsColumns = $paths->map(p| + ^TDSColumn + ( + name = $p.first, + type = $p.second.type->cast(@meta::pure::metamodel::type::DataType), + documentation = $p.second.documentation, + enumMappingId = $p.second.propertyMapping->match([r:RelationalPropertyMapping[0..1] | $r.transformer->cast(@EnumerationMapping).name, p:PropertyMapping[0..1] | []]), + offset = $paths->indexOf($p), + sourceDataType = if($p.second.relationalType->isNotEmpty(), + | $p.second.relationalType, + | $p.second.propertyMapping->match([ + rpm: RelationalPropertyMapping[0..1] | $rpm->getRelationalTypeFromRelationalPropertyMapping($p.first), + cpm: meta::pure::router::clustering::CrossSetImplementationPrimtivePropertyMapping[0..1] | $cpm.sourcePropertyMapping->match([rpm: RelationalPropertyMapping[0..1] | $rpm->getRelationalTypeFromRelationalPropertyMapping($p.first), pm: PropertyMapping[0..1] | []]), + pm: PropertyMapping[0..1] | [] + ])) + ); + ) + ); + ), + pair( + |$class->_subTypeOf(meta::pure::metamodel::relation::Relation), + |^TDSResultType + ( + type = $class, + tdsColumns = $sq.fe.genericType.typeArguments->at(0).rawType->cast(@meta::pure::metamodel::relation::RelationType).columns->map(p| + ^TDSColumn + ( + name = $p.name->toOne(), + type = $p.classifierGenericType.typeArguments->at(1).rawType->cast(@meta::pure::metamodel::type::DataType) + ); + ) + ); + ), + pair( + |$class->_subTypeOf(RelationData), + | let relationDataQuery = $query->cast(@RelationDataSelectSqlQuery); + ^RelationResultType + ( + relationName = $relationDataQuery.relation.name, + relationType = $relationDataQuery.relation->instanceOf(View)->if(|RelationType.VIEW,|RelationType.TABLE), + schemaName = $relationDataQuery.relation->match([t:Table[1]|$t.schema,v:View[1]|$v.schema])->cast(@Schema).name, + database = $relationDataQuery.relation->match([t:Table[1]|$t.schema,v:View[1]|$v.schema])->cast(@Schema).database->elementToPath(), + columns = $relationDataQuery.columns->cast(@Alias)->map(x | ^Column(name = $x.name, type=$x.relationalElement->cast(@TableAliasColumn).column.type)), + type = $class + ); + ) + ], + |$class->match([ e : Enumeration[1] | ^DataTypeResultType(type=$class), p : PrimitiveType[1] | ^DataTypeResultType(type=$class), c : Class[1] | ^ClassResultType @@ -109,8 +129,12 @@ function meta::relational::mapping::generateInstantiationExecutionNode(sq:meta:: | $ext->cast(@StoreMappingRoutedValueSpecification).sets->at(0) )->resolveOperation($m->toOne()) ) - ]); - ) + ]) + + + + + ); $resultType->match([ @@ -174,11 +198,11 @@ function <> meta::relational::mapping::getRelationalTypeFromRela ])->cast(@meta::relational::metamodel::datatype::DataType); } -function meta::relational::mapping::addEnumMapSupportFunctions(sq:meta::pure::mapping::StoreQuery[1], m:Mapping[1]):String[*] +function meta::relational::mapping::addEnumMapSupportFunctions(sq:meta::pure::mapping::StoreQuery[1], m:Mapping[0..1]):String[*] { let enumParam = $sq.inScopeVars->keyValues().second->map(p | $p.values)->filter(e | $e->instanceOf(PlanVarPlaceHolder))->map(p | $p->cast(@PlanVarPlaceHolder).type)->filter(e | $e->instanceOf(Enumeration)); let enumMapTemplateFunctions = if($enumParam->isNotEmpty(), - |$m->allEnumerationMappings()->filter(e | $e.enumeration->in($enumParam))->map(enum | let concatStr = if($enum.enumValueMappings->at(0).sourceValues->type() == String, |'\'', |''); + |$m->toOne()->allEnumerationMappings()->filter(e | $e.enumeration->in($enumParam))->map(enum | let concatStr = if($enum.enumValueMappings->at(0).sourceValues->type() == String, |'\'', |''); let enumHashMap = $enum.enumValueMappings->map(e | '"'+ $e.enum->cast(@Enum).name +'":"'+ $concatStr + $e.sourceValues->makeString('\', \'') + $concatStr + '"')->makeString(', '); '<#function enumMap_' + fetchEnumFullPath($enum) + ' inputVal> <#assign enumMap = {'->concatenate($enumHashMap)->concatenate('}> <#if inputVal?has_content> <#return enumMap[inputVal]> <#else> <#return ""> ')->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/advanced/testContractMoneyScenario.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/advanced/testContractMoneyScenario.pure index 0919bc98857..3b473e2c34b 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/advanced/testContractMoneyScenario.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/tests/advanced/testContractMoneyScenario.pure @@ -45,7 +45,7 @@ function <> meta::relational::tests::advanced::contractmoneyscenario: ), ContractMoney, testRuntime(), meta::relational::extension::relationalExtensions()); assertEqualsH2Compatible( - 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1))', + 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1))', 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1))', $result->sqlRemoveFormatting() ); @@ -69,8 +69,8 @@ function <> meta::relational::tests::advanced::contractmoneyscenario: ), ContractMoney, testRuntime(), meta::relational::extension::relationalExtensions()); assertEqualsH2Compatible( - 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1))', - 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1))', + 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = \'2003-10-10\' and "fx_0".tenor = 1))', + 'select "root".id as "id", "root".price as "amount", "fx_0".rate as "rate", case when "currency_0".value = \'USD\' then "root".price else ("root".price * "fx_0".rate) end as "value" from Contract as "root" left outer join Currency as "currency_0" on ("root".id = "currency_0".contractId) left outer join FX as "fx_0" on ("root".currency = "fx_0".currency and ("fx_0".date = DATE\'2003-10-10\' and "fx_0".tenor = 1))', $result->sqlRemoveFormatting() ); } diff --git a/pom.xml b/pom.xml index b6e40ef94f7..664402cc86a 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ - 4.10.2 + 4.10.3-SNAPSHOT 0.24.1 @@ -818,6 +818,11 @@ legend-engine-pure-runtime-execution ${project.version} + + org.finos.legend.engine + legend-engine-pure-platform-functions-relation-java + ${project.version} + org.finos.legend.engine legend-engine-xt-relationalStore-executionPlan-connection @@ -1912,6 +1917,11 @@ legend-engine-pure-platform-dsl-path-java ${project.version} + + org.finos.legend.engine + legend-engine-pure-platform-dsl-tds-java + ${project.version} + org.finos.legend.engine legend-engine-pure-platform-dsl-mapping-java @@ -2279,6 +2289,26 @@ legend-pure-m2-dsl-diagram-grammar ${legend.pure.version} + + org.finos.legend.pure + legend-pure-m2-dsl-tds-pure + ${legend.pure.version} + + + org.finos.legend.pure + legend-pure-m2-dsl-tds-grammar + ${legend.pure.version} + + + org.finos.legend.pure + legend-pure-m2-functions-relation-pure + ${legend.pure.version} + + + org.finos.legend.pure + legend-pure-runtime-java-extension-functions-relation + ${legend.pure.version} + org.finos.legend.pure legend-pure-m2-dsl-mapping-grammar