All Downloads are FREE. Search and download functionalities are using the official Maven repository.

core.pure.graphFetch.graphFetchExecutionPlan.pure Maven / Gradle / Ivy

There is a newer version: 4.57.1
Show newest version
// Copyright 2020 Goldman Sachs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import meta::pure::router::store::metamodel::*;
import meta::pure::dataQuality::*;
import meta::pure::graphFetch::*;
import meta::pure::store::*;
import meta::pure::extension::*;
import meta::pure::graphFetch::routing::*;
import meta::pure::graphFetch::execution::*;
import meta::pure::graphFetch::executionPlan::*;
import meta::pure::executionPlan::*;
import meta::pure::executionPlan::toString::*;
import meta::pure::mapping::*;
import meta::external::store::model::*;
import meta::pure::mapping::modelToModel::graphFetch::executionPlan::*;
import meta::pure::mapping::xStore::*;
import meta::core::runtime::*;
import meta::pure::router::metamodel::*;
import meta::pure::router::utils::*;

Class <> meta::pure::graphFetch::executionPlan::GlobalGraphFetchExecutionNode extends ExecutionNode
{
   graphFetchTree               : ClusteredGraphFetchTree[1];
   children                     : GlobalGraphFetchExecutionNode[*];
   localGraphFetchExecutionNode : LocalGraphFetchExecutionNode[1];
   parentIndex                  : Integer[0..1];
   enableConstraints            : Boolean[0..1];
   checked                      : Boolean[0..1];
   localTreeIndices             : Integer[*];
   dependencyIndices            : Integer[*];
}

Class meta::pure::graphFetch::executionPlan::StoreMappingGlobalGraphFetchExecutionNode extends GlobalGraphFetchExecutionNode
{
   store                        : meta::pure::store::Store[1];
   xStorePropertyMapping        : meta::pure::mapping::xStore::XStorePropertyMapping[0..1];
   xStorePropertyFetchDetails   : XStorePropertyFetchDetails[0..1];
}

Class meta::pure::graphFetch::executionPlan::XStorePropertyFetchDetails
{
   supportsCaching         : Boolean[1];
   propertyPath            : String[1];
   sourceMappingId         : String[1];
   sourceSetId             : String[1];
   targetMappingId         : String[1];
   targetSetId             : String[1];
   targetPropertiesOrdered : String[*];
   subTree                 : String[1];
}

Class meta::pure::graphFetch::executionPlan::PlatformGlobalGraphFetchExecutionNode extends GlobalGraphFetchExecutionNode
{
}

Class meta::pure::graphFetch::executionPlan::LocalGraphFetchExecutionNode extends ExecutionNode
{
   nodeIndex      : Integer[1];
   parentIndex    : Integer[0..1];
   graphFetchTree : RoutedGraphFetchTree[1];
}

Class meta::pure::graphFetch::executionPlan::PlatformPrimitiveQualifierLocalGraphFetchExecutionNode extends LocalGraphFetchExecutionNode
{
}

Class meta::pure::graphFetch::executionPlan::StoreMappingLocalGraphFetchExecutionNodeGenerationInput
{
  clusteredTree:     StoreMappingClusteredGraphFetchTree[1];
  orderedPaths:      String[*];
  enableConstraints: Boolean[1];
  checked:           Boolean[1];
  storeQuery:        StoreQuery[1];
  ext:               RoutedValueSpecification[0..1];
  mapping:           Mapping[1];
  runtime:           Runtime[1];
  exeCtx:            meta::pure::runtime::ExecutionContext[1];
  extensions:        Extension[*];
  debug:             DebugContext[1];
}

Class meta::pure::graphFetch::executionPlan::StoreMappingCrossLocalGraphFetchExecutionNodeGenerationInput
{
  clusteredTree:     StoreMappingClusteredGraphFetchTree[1];
  orderedPaths:      String[*];
  parentPath:        String[1];
  enableConstraints: Boolean[1];
  checked:           Boolean[1];
  inScopeVars:       Map>[1];
  mapping:           Mapping[1];
  runtime:           Runtime[1];
  exeCtx:            meta::pure::runtime::ExecutionContext[1];
  extensions:        Extension[*];
  debug:             DebugContext[1];
}

function meta::pure::graphFetch::executionPlan::nodeIsMerged(node:LocalGraphFetchExecutionNode[1]): Boolean[1]
{
   let set = $node.graphFetchTree.sets;
   let mergeOp = $set->filter(m|$m->instanceOf(OperationSetImplementation))->cast(@OperationSetImplementation)->filter(o|$o.operation==meta::pure::router::operations::merge_OperationSetImplementation_1__SetImplementation_MANY_);
   $mergeOp->map(m | assert($m->instanceOf(MergeOperationSetImplementation),'Please specify a merge function for merge operation on class '+ $m.class->elementToPath()));
   $mergeOp->isNotEmpty();
}
function meta::pure::graphFetch::executionPlan::planGraphFetchExecution(sq: StoreQuery[1], ext: RoutedValueSpecification[0..1], mapping: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], extensions: Extension[*], debug: DebugContext[1]): ExecutionNode[1]
{
   print(if($debug.debug,|$debug.space+'>Generating Graph Fetch Execution Plan:\n',|''));
   let fe = $sq.fe->evaluateAndDeactivate();
   let resultSize = $fe.parametersValues->evaluateAndDeactivate()->at(0)->match([rvs:ExtendedRoutedValueSpecification[1] | $rvs.value.multiplicity->toOne(),
                                                                                 vs: ValueSpecification[1] | $fe.multiplicity->toOne()]);
   assert($fe.func->in(graphFetchFunctions()) || $fe->isUnionOnGraphFetch(true));
   let clusteredTreePreFilter  = $fe.parametersValues->evaluateAndDeactivate()->at(1)->cast(@InstanceValue).values->at(0)->cast(@ClusteredGraphFetchTree);

   let chainConnection = if ($sq.store->instanceOf(ModelStore),
                             | $runtime.connectionStores->filter(c|$c.element->instanceOf(ModelStore) && $c.connection->instanceOf(ModelChainConnection)).connection;,
                             | []
                         );

   let possibleFilter =  $fe->graphFetchFilter()->evaluateAndDeactivate();
   let clusteredTree = if($possibleFilter->isNotEmpty()  && $sq.store-> instanceOf(ModelStore) && $chainConnection->isEmpty(),
                              |meta::pure::graphFetch::executionPlan::enrichTargetTreeForFilterProperties($clusteredTreePreFilter,$possibleFilter->toOne(),$mapping, $exeCtx,$runtime,$extensions,$debug);,
                              |$clusteredTreePreFilter
                          );

    print(if($debug.debug,|$debug.space+'   Clustered Tree: '+$clusteredTree->asString(false)+'\n',|''));

   let orderedPaths             = $clusteredTree->getPathsOrdered();
   let clusterTreesWithParents  = $clusteredTree->findAllClusterTreesWithParents([]);
   print(if($debug.debug,|$debug.space+'   Found '+$clusterTreesWithParents->size()->toString()+' store-mapping/platform cluster tree(s) in main clustered tree\n',|''));

   let rootTree                 = $clusterTreesWithParents->filter(x | $x.second.values->isEmpty()).first->toOne()->cast(@StoreMappingClusteredGraphFetchTree);
   let rootTreeOneCluster       = $rootTree->recursivelyRemoveClusterTrees();

   print(if($debug.debug,|$debug.space+'      >Generating store local node for root tree\n',|''));
   print(if($debug.debug,|$debug.space+'         Store local tree: '+$rootTreeOneCluster->asString(false)+'\n',|''));

   let enableConstraints        = $exeCtx.enableConstraints->isEmpty() || $exeCtx.enableConstraints->toOne();
   let checked                  = $fe.genericType.rawType == Checked;


   let localNodeGenerationInput = ^StoreMappingLocalGraphFetchExecutionNodeGenerationInput
                                  (
                                    clusteredTree     = $rootTreeOneCluster->cast(@StoreMappingClusteredGraphFetchTree),
                                    orderedPaths      = $orderedPaths,
                                    enableConstraints = $enableConstraints,
                                    checked           = $checked,
                                    storeQuery        = $sq,
                                    ext               = $ext,
                                    mapping           = $mapping,
                                    runtime           = $runtime,
                                    exeCtx            = $exeCtx,
                                    extensions        = $extensions,
                                    debug             = $debug->indent(3)
                                  );

   let localRoot = $rootTree.s.planGraphFetchExecution->toOne()->eval($localNodeGenerationInput);

   let rootGlobalNode = ^StoreMappingGlobalGraphFetchExecutionNode
                        (
                           resultType                   = $clusteredTree->resultTypeFromGraphFetchTree(),
                           resultSizeRange              = $resultSize,
                           graphFetchTree               = $clusteredTree,
                           store                        = $rootTree.store,
                           localGraphFetchExecutionNode = $localRoot,
                           enableConstraints            = $enableConstraints,
                           checked                      = $checked,
                           localTreeIndices             = $rootTreeOneCluster->getPathsOrdered()->map(p | let idx = $orderedPaths->indexOf($p); assert($idx >= 0, | 'Path ' + $p + ' not found in orderedPaths: ' + $orderedPaths->makeString('[', ', ', ']')); $idx;)
                        );

   print(if($debug.debug,|$debug.space+'      >Generated store local node for root tree\n',|''));
   $rootGlobalNode->addCrossStoreChildren([], $rootTree, $orderedPaths, $clusterTreesWithParents, $sq.inScopeVars, $mapping, $runtime, $exeCtx, $enableConstraints, $checked, $extensions, $debug->indent(2));
}

function meta::pure::graphFetch::executionPlan::enrichTargetTreeForFilterProperties(originalTree: ClusteredGraphFetchTree[1], fe: SimpleFunctionExpression[1], mapping: Mapping[1], context:meta::pure::runtime::ExecutionContext[1] ,runtime: Runtime[1], extensions: meta::pure::extension::Extension[*], debug: DebugContext[1]): ClusteredGraphFetchTree[1]
{

   let class = $originalTree.tree->cast(@RoutedRootGraphFetchTree).class;
   let tree = $originalTree.tree->meta::pure::graphFetch::ensureFunctionRequirementsFromLambda($class,$fe->toOne().parametersValues->at(1)->cast(@FunctionRoutedValueSpecification).originalFunction,[],true)->cast(@RootGraphFetchTree);
   let routedTrees = $tree->deepByPassRouterInfo()->cast(@RootGraphFetchTree)->routeRootGraphFetchTree($originalTree.tree.sets->at(0),$mapping,$context,$extensions);
  ^$originalTree(tree=$routedTrees);

}

function meta::pure::graphFetch::executionPlan::planStoreUnionGraphFetchExecution(sq: StoreQuery[1], ext: RoutedValueSpecification[0..1], sets: InstanceSetImplementation[*], mapping: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], extensions: meta::pure::extension::Extension[*], debug: DebugContext[1]): ExecutionNode[1]
{
   let fe     = $sq.fe->evaluateAndDeactivate();
   let params = $fe.parametersValues->evaluateAndDeactivate();
   let p1     = $params->at(0);
   let p2     = $params->at(1)->cast(@InstanceValue);
   let tree   = $p2.values->at(0)->cast(@ClusteredGraphFetchTree);
   let rf     = {set: InstanceSetImplementation[1] | ^$fe(parametersValues = [$p1, ^$p2(values = ^$tree(tree = $tree->byPassClusteringInfoDeep()->cast(@RootGraphFetchTree)->routeRootGraphFetchTree($set, $mapping, $exeCtx, $extensions)))]->evaluateAndDeactivate())->evaluateAndDeactivate()};

   let newFe  = $sets->tail()->fold({set, agg |
      ^SimpleFunctionExpression
      (
         func = union_T_MANY__T_MANY__T_MANY_,
         functionName = 'union',
         genericType = $fe.genericType,
         multiplicity = ZeroMany,
         importGroup = system::imports::coreImport,
         resolvedTypeParameters = ^GenericType(rawType=Any),
         parametersValues = [$agg, $rf->eval($set)]->evaluateAndDeactivate()
      )->evaluateAndDeactivate()
   }, $rf->eval($sets->at(0)));

   planRouterUnionGraphFetchExecution(^$sq(fe = $newFe), $ext, $mapping, $runtime, $exeCtx, $extensions, $debug);
}

function meta::pure::graphFetch::executionPlan::planRouterUnionGraphFetchExecution(sq: StoreQuery[1], ext: RoutedValueSpecification[0..1], mapping: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], extensions: Extension[*], debug: DebugContext[1]): ExecutionNode[1]
{
   let fe = $sq.fe->evaluateAndDeactivate();
   assert($fe->isUnionOnGraphFetch(true), | 'Non union graphFetch function encountered');

   let subClusters  = $fe.parametersValues->evaluateAndDeactivate()->map({p | $p->meta::pure::router::clustering::cluster($mapping, $runtime, $sq.inScopeVars, $exeCtx, $extensions, $debug).cluster->evaluateAndDeactivate()})->cast(@meta::pure::router::metamodel::clustering::ClusteredValueSpecification);
   let firstCluster = $subClusters->at(0);
   let childNodes   = $subClusters->map(cls | $cls->plan($sq.inScopeVars, $exeCtx, $extensions, $debug));

   ^PlatformUnionExecutionNode
   (
      fromCluster    = ^$firstCluster(val = $fe),
      resultType     = $childNodes->at(0).resultType,
      isChildrenExecutionParallelizable = true,
      executionNodes = $childNodes
   );
}

function <> meta::pure::graphFetch::executionPlan::addCrossStoreChildren(currentNode: GlobalGraphFetchExecutionNode[1], parentPath: String[0..1], currentTree: ClusteredGraphFetchTree[1], orderedPaths: String[*], clusterNodesWithParents: Pair>[*], inScopeVars: Map>[1], m: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], enableConstraints: Boolean[1], checked: Boolean[1], extensions:Extension[*], debug: DebugContext[1]):GlobalGraphFetchExecutionNode[1]
{
   let currentNonClusterTrees = $currentTree->recursivelyFindNonClusterTrees();
   let childrenClusterNodes   = $clusterNodesWithParents->filter(x | $x.second.values->isNotEmpty() && $x.second.values->toOne()->in($currentNonClusterTrees));
   if($childrenClusterNodes->isEmpty(),
      | $currentNode,
      | print(if($debug.debug,|$debug.space+'>Generating cross-store global child nodes\n',|''));
        let children = $childrenClusterNodes->map({ch |
           let childTreeOneCluster = $ch.first->recursivelyRemoveClusterTrees();
           let routedTree          = $childTreeOneCluster.tree->cast(@RoutedPropertyGraphFetchTree);
           let newParentPath       = if($parentPath->isEmpty(),
                                        |$currentTree->toOne()->getPathTo($ch.first)->toOne(),
                                        |$parentPath->toOne()+'.'+$currentTree->getPathTo($ch.first)->toOne()
                                     );
           $ch.first->match([

              {smct: StoreMappingClusteredGraphFetchTree[1] |

                  print(if($debug.debug,|$debug.space+'   >Generating store local node for cross-store property tree: '+$routedTree.property.name->toOne()+'\n',|''));
                  print(if($debug.debug,|$debug.space+'      Store local tree: '+$childTreeOneCluster->asString(false)+'\n',|''));

                  let crossLocalNodeGenerationInput = ^StoreMappingCrossLocalGraphFetchExecutionNodeGenerationInput
                                                      (
                                                          clusteredTree      = $childTreeOneCluster->cast(@StoreMappingClusteredGraphFetchTree),
                                                          orderedPaths       = $orderedPaths,
                                                          parentPath         = $newParentPath,
                                                          enableConstraints  = $enableConstraints,
                                                          checked            = $checked,
                                                          inScopeVars        = $inScopeVars,
                                                          mapping            = $m,
                                                          runtime            = $runtime,
                                                          exeCtx             = $exeCtx,
                                                          extensions         = $extensions,
                                                          debug              = $debug->indent(2)
                                                      );

                  let crossLocalNode      = $smct.s.planCrossGraphFetchExecution->toOne()->eval($crossLocalNodeGenerationInput);

                  let propertyMapping     = $routedTree.propertyMapping->toOne()->cast(@XStorePropertyMapping);
                  let crossExpr           = $propertyMapping.crossExpression.expressionSequence->evaluateAndDeactivate()->toOne();
                  let sourceCls           = $m->classMappingById($propertyMapping.sourceSetImplementationId)->toOne()->cast(@InstanceSetImplementation)->map(i | if($i.mappingClass->isNotEmpty(), | $i.mappingClass->toOne(), | $i.class));
                  let crossExprTree       = $crossExpr->fetchTreeInExpression($sourceCls);
                  let routedDependencyTree = getRoutedDependencyTree($ch.second.values->toOne(), $crossExprTree);

                  let newCrossNode        = ^StoreMappingGlobalGraphFetchExecutionNode
                                            (
                                                resultType                   = $routedTree->resultTypeFromGraphFetchTree(),
                                                graphFetchTree               = $ch.first,
                                                parentIndex                  = $orderedPaths->indexOf($newParentPath),
                                                xStorePropertyMapping        = $propertyMapping,
                                                store                        = $smct.store,
                                                localGraphFetchExecutionNode = $crossLocalNode,
                                                xStorePropertyFetchDetails   = $propertyMapping->buildXStorePropertyFetchDetails($ch.first, $newParentPath, $m),
                                                localTreeIndices             = $routedTree->getPathsOrdered()->map(p | $newParentPath + '.' + $p)->map(p | let idx = $orderedPaths->indexOf($p); assert($idx >= 0, | 'Path ' + $p + ' not found in orderedPaths: ' + $orderedPaths->makeString('[', ', ', ']')); $idx;),
                                                dependencyIndices            = $routedDependencyTree.subTrees->map(st | $st->getPathsOrdered())->map(p | $newParentPath + '.' + $p)->map(p | let idx = $orderedPaths->indexOf($p); assert($idx >= 0, | 'Path ' + $p + ' not found in orderedPaths: ' + $orderedPaths->makeString('[', ', ', ']')); $idx;)
                                            );
                  print(if($debug.debug,|$debug.space+'   >Generated store local node for cross property tree\n',|''));
                  $newCrossNode->addCrossStoreChildren($newParentPath, $ch.first, $orderedPaths, $clusterNodesWithParents, $inScopeVars, $m, $runtime, $exeCtx, $enableConstraints, $checked, $extensions, $debug->indent(2));

              },


              {p: PlatformClusteredGraphFetchTree[1] |

                  print(if($debug.debug,|$debug.space+'   >Generating local node for platform property tree: '+$routedTree.property.name->toOne()+'\n',|''));
                  assert($routedTree.property->instanceOf(QualifiedProperty) && $routedTree.property->isPrimitiveValueProperty(), | 'Expected primitive qualifier in a platform clustered graph fetch tree');

                  let qp = $routedTree.property->cast(@QualifiedProperty);
                  let qualifierTree = $qp.expressionSequence->evaluateAndDeactivate()->toOne()->fetchTreeInExpression($qp->functionType().parameters->evaluateAndDeactivate()->at(0).genericType.rawType->toOne()->cast(@Class));
                  let routedDependencyTree = getRoutedDependencyTree($ch.second.values->toOne(), $qualifierTree);
                  let resultType = ^ResultType(type = $qp->functionReturnType().rawType->toOne());
                  let currentPath = $newParentPath + '.' + $routedTree->nodePathName();
                  let platformNode = ^PlatformGlobalGraphFetchExecutionNode
                  (
                      resultType                   = $resultType,
                      graphFetchTree               = $ch.first,
                      parentIndex                  = $orderedPaths->indexOf($newParentPath),
                      localGraphFetchExecutionNode = ^PlatformPrimitiveQualifierLocalGraphFetchExecutionNode
                                                      (
                                                        resultType     = $resultType,
                                                        nodeIndex      = $orderedPaths->indexOf($currentPath),
                                                        parentIndex    = $orderedPaths->indexOf($newParentPath),
                                                        graphFetchTree = $routedTree
                                                      ),
                      localTreeIndices             = $routedTree->getPathsOrdered()->map(p | $newParentPath + '.' + $p)->map(p | let idx = $orderedPaths->indexOf($p); assert($idx >= 0, | 'Path ' + $p + ' not found in orderedPaths: ' + $orderedPaths->makeString('[', ', ', ']')); $idx;),
                      dependencyIndices            = $routedDependencyTree.subTrees->map(st | $st->getPathsOrdered())->map(p | $newParentPath + '.' + $p)->map(p | let idx = $orderedPaths->indexOf($p); assert($idx >= 0, | 'Path ' + $p + ' not found in orderedPaths: ' + $orderedPaths->makeString('[', ', ', ']')); $idx;)
                  );

                  print(if($debug.debug,|$debug.space+'   >Generated local node for platform property tree\n',|''));
                  $platformNode;
              }

           ]);
        });

        ^$currentNode(children = $children);
   );
}

function <> meta::pure::graphFetch::executionPlan::getRoutedDependencyTree(routedParentTree :GraphFetchTree[1], UnRoutedParentTree :GraphFetchTree[1]):GraphFetchTree[1]
{
  ^$routedParentTree(subTrees = $routedParentTree.subTrees->map(s | let routedChildTree = if($s->instanceOf(ClusteredGraphFetchTree),| $s->cast(@ClusteredGraphFetchTree).tree, | $s);
                                                            let unRoutedChildTree = $UnRoutedParentTree.subTrees->filter(x | $x->cast(@PropertyGraphFetchTree).property.name == $routedChildTree->cast(@PropertyGraphFetchTree).property.name);
                                                            if($unRoutedChildTree->isEmpty(),
                                                            | [],
                                                            | getRoutedDependencyTree($routedChildTree, $unRoutedChildTree->toOne()));
                                                       )
              );

}

function <> meta::pure::graphFetch::executionPlan::buildXStorePropertyFetchDetails(xStorePropertyMapping: XStorePropertyMapping[1], subTree: ClusteredGraphFetchTree[1], parentPath: String[1], mapping: Mapping[1]): XStorePropertyFetchDetails[1]
{
   let propertyTree = $subTree->byPassClusteringInfo()->cast(@RoutedPropertyGraphFetchTree);
   let subTreeString   = '{' + $propertyTree.subTrees->map(st | $st->meta::pure::graphFetch::routing::asString(false))->joinStrings(',') + '}';
   let propertyPath = $parentPath + '.' + $propertyTree->nodePathName();

   let xStoreExpressionSequence  = $xStorePropertyMapping.crossExpression.expressionSequence->evaluateAndDeactivate();
   let isXStoreMappingMultiEqual = $xStoreExpressionSequence->size() == 1 && $xStoreExpressionSequence->toOne()->isExpressionMultiEqual();

   let supportsCaching = $isXStoreMappingMultiEqual && !($subTreeString->contains('$'));

   ^XStorePropertyFetchDetails
   (
      supportsCaching          = $supportsCaching,
      propertyPath             = $propertyPath,
      sourceMappingId          = $mapping->classMappingById($xStorePropertyMapping.sourceSetImplementationId)->toOne().parent->elementToPath(),
      sourceSetId              = $xStorePropertyMapping.sourceSetImplementationId,
      targetMappingId          = $mapping->classMappingById($xStorePropertyMapping.targetSetImplementationId)->toOne().parent->elementToPath(),
      targetSetId              = $xStorePropertyMapping.targetSetImplementationId,
      targetPropertiesOrdered  = if($supportsCaching, | $xStoreExpressionSequence->toOne()->propertyOrNoArgQualifierPairsInMultiEqual().second.name->sort(), | []),
      subTree                  = $subTreeString
   );
}

function <> meta::pure::graphFetch::executionPlan::isPropertyOrNoArgQualifier(f: Function[1]): Boolean[1]
{
   $f->instanceOf(Property) || ($f->instanceOf(QualifiedProperty) && $f->functionType().parameters->evaluateAndDeactivate()->size() == 1)
}

function meta::pure::graphFetch::executionPlan::isExpressionMultiEqual(v: ValueSpecification[1]):Boolean[1]
{
   $v->evaluateAndDeactivate()->match([
      f: FunctionExpression[1] | let params = $f.parametersValues->evaluateAndDeactivate()->map(x| $x->byPassRouterInfo());
                                 if($f.func->in([meta::pure::functions::boolean::equal_Any_MANY__Any_MANY__Boolean_1_, meta::pure::functions::boolean::eq_Any_1__Any_1__Boolean_1_]),
                                    | $params->match([
                                       sfes: SimpleFunctionExpression[*] | $sfes->at(0).func->isPropertyOrNoArgQualifier() && $sfes->at(1).func->isPropertyOrNoArgQualifier(),
                                       a: Any[*] | false
                                      ]),
                                    | if($f.functionName == 'and',
                                         | $params->at(0)->isExpressionMultiEqual() && $params->at(1)->isExpressionMultiEqual(),
                                         | false
                                      );
                                 );
   ])
}

function meta::pure::graphFetch::executionPlan::propertyOrNoArgQualifierPairsInMultiEqual(v: ValueSpecification[1]):Pair, AbstractProperty>[*]
{
   $v->evaluateAndDeactivate()->match([
      f: FunctionExpression[1] | let params = $f.parametersValues->evaluateAndDeactivate()->map(x| $x->byPassRouterInfo());
                                 if($f.func->in([meta::pure::functions::boolean::equal_Any_MANY__Any_MANY__Boolean_1_, meta::pure::functions::boolean::eq_Any_1__Any_1__Boolean_1_]),
                                    | $params->match([
                                       sfes: SimpleFunctionExpression[*] | assert($sfes->at(0).func->isPropertyOrNoArgQualifier() && $sfes->at(1).func->isPropertyOrNoArgQualifier());
                                                                           if($sfes->at(0).parametersValues->evaluateAndDeactivate()->cast(@VariableExpression).name == 'this' &&
                                                                              $sfes->at(1).parametersValues->evaluateAndDeactivate()->cast(@VariableExpression).name == 'that',
                                                                              | pair($sfes->at(0).func->cast(@AbstractProperty), $sfes->at(1).func->cast(@AbstractProperty)),
                                                                              | if($sfes->at(0).parametersValues->evaluateAndDeactivate()->cast(@VariableExpression).name == 'that' &&
                                                                                   $sfes->at(1).parametersValues->evaluateAndDeactivate()->cast(@VariableExpression).name == 'this',
                                                                                   | pair($sfes->at(1).func->cast(@AbstractProperty), $sfes->at(0).func->cast(@AbstractProperty)),
                                                                                   | assert(false, 'Complex cross expressions not supported yet!'); [];
                                                                                )
                                                                           );,
                                       a: Any[*] | assert(false, 'Complex cross expressions not supported yet!'); [];
                                      ]),
                                    | if($f.functionName == 'and',
                                         | $params->at(0)->propertyOrNoArgQualifierPairsInMultiEqual()->concatenate($params->at(1)->propertyOrNoArgQualifierPairsInMultiEqual()),
                                         | assert(false, 'Complex cross expressions not supported yet!'); [];
                                      );
                                 );
   ])
}

function meta::pure::graphFetch::executionPlan::globalGraphFetchExecutionNodeToString(g: GlobalGraphFetchExecutionNode[1], space: String[1], extensions:meta::pure::extension::Extension[*]):String[1]
{
   $g->match([
      s: StoreMappingGlobalGraphFetchExecutionNode[1] | $s->storeMappingGlobalGraphFetchExecutionNodeToString($space, $extensions),
      p: PlatformGlobalGraphFetchExecutionNode[1] | $p->platformGlobalGraphFetchExecutionNodeToString($space, $extensions)
   ])
}

function meta::pure::graphFetch::executionPlan::storeMappingGlobalGraphFetchExecutionNodeToString(g: StoreMappingGlobalGraphFetchExecutionNode[1], space: String[1], extensions:meta::pure::extension::Extension[*]):String[1]
{
   'StoreMappingGlobalGraphFetch\n' +
      $space + '(' + header($g, $space, $extensions) + '\n'+
      $space + '  store = ' + $g.store->elementToPath() + '\n'+
      $space + '  localGraphFetchExecutionNode = \n' + $g.localGraphFetchExecutionNode->meta::pure::executionPlan::toString::planNodeToString($space+ '     ', $extensions) +
      $space + '  children = ' + $g.children->map(x | globalGraphFetchExecutionNodeToString($x, $space + '     ', $extensions))->joinStrings('[\n'+ $space + '     ', '\n' + $space + '     ', '\n' + $space + '  ]\n') +
      if($g.parentIndex->isEmpty(), | '', | $space + '  parentIndex = ' + $g.parentIndex->toOne()->toString() + '\n') +
      if($g.xStorePropertyMapping->isEmpty(), | '', | $space + '  xStorePropertyMapping = ' + $g.xStorePropertyMapping.property.name->toOne() + '[' + $g.xStorePropertyMapping.sourceSetImplementationId->toOne() + ' -> ' + $g.xStorePropertyMapping.targetSetImplementationId->toOne() + ']' + '\n') +
      $space + '  localTreeIndices = ' + $g.localTreeIndices->makeString('[', ', ', ']') + '\n'+
      $space + '  dependencyIndices = ' + $g.dependencyIndices->makeString('[', ', ', ']') + '\n'+
      $g.implementation->printImplementation('implementation', $space+'  ', $extensions)+
      $space + ')\n';
}

function meta::pure::graphFetch::executionPlan::platformGlobalGraphFetchExecutionNodeToString(g: PlatformGlobalGraphFetchExecutionNode[1], space: String[1], extensions:meta::pure::extension::Extension[*]):String[1]
{
   'PlatformGlobalGraphFetch\n' +
      $space + '(' + header($g, $space, $extensions) + '\n'+
      $space + '  localGraphFetchExecutionNode = \n' + $g.localGraphFetchExecutionNode->meta::pure::executionPlan::toString::planNodeToString($space+ '     ', $extensions) +
      $space + '  children = ' + $g.children->map(x | globalGraphFetchExecutionNodeToString($x, $space + '     ', $extensions))->joinStrings('[\n'+ $space + '     ', '\n' + $space + '     ', '\n' + $space + '  ]\n') +
      if($g.parentIndex->isEmpty(), | '', | $space + '  parentIndex = ' + $g.parentIndex->toOne()->toString() + '\n') +
      $space + '  localTreeIndices = ' + $g.localTreeIndices->makeString('[', ', ', ']') + '\n'+
      $space + '  dependencyIndices = ' + $g.dependencyIndices->makeString('[', ', ', ']') + '\n'+
      $g.implementation->printImplementation('implementation', $space+'  ', $extensions)+
      $space + ')\n';
}

function meta::pure::graphFetch::executionPlan::platformPrimitiveQualifierLocalGraphFetchExecutionNodeToString(g: PlatformPrimitiveQualifierLocalGraphFetchExecutionNode[1], space: String[1], extensions:meta::pure::extension::Extension[*]):String[1]
{
   'PlatformPrimitiveQualifierLocalGraphFetch\n' +
      $space + '(' + header($g, $space, $extensions) + '\n'+
      $space + '  nodeIndex = ' + $g.nodeIndex->toString() + '\n'+
      $space + '  qualfifier = ' + $g.graphFetchTree->cast(@PropertyGraphFetchTree).property.name->toOne() + '\n' +
      $g.implementation->printImplementation('implementation', $space+'  ', $extensions)+
      $space + ')\n';
}

function meta::pure::graphFetch::executionPlan::resultTypeFromGraphFetchTree(g: GraphFetchTree[1]):PartialClassResultType[1]
{
   ^PartialClassResultType
    (
       type = $g->byPassClusteringInfo()->typeFromGraphFetchTree(),
       setImplementations = $g->byPassClusteringInfo()->cast(@RoutedGraphFetchTree).sets,
       propertiesWithParameters = $g->byPassClusteringInfo().subTrees->map(x | $x->byPassClusteringInfo()->cast(@PropertyGraphFetchTree)->map(x | ^PropertyWithParameters(property = $x.property, parameters = $x.parameters)))
    )
}

function <> meta::pure::graphFetch::executionPlan::findAllClusterTreesWithParents(g : GraphFetchTree[1], parent : RoutedGraphFetchTree[0..1]):Pair>[*]
{
   let thisLevel = $g->match([
      c : ClusteredGraphFetchTree[1] | pair($c, list($parent)),
      r : RoutedGraphFetchTree[1] | [],
      s: SystemGeneratedPropertyGraphFetchTree[1] | []
   ]);
   let subClusterTrees = $g->byPassClusteringInfo().subTrees->map(k | $k->findAllClusterTreesWithParents($g->byPassClusteringInfo()->cast(@RoutedGraphFetchTree)));
   $thisLevel->concatenate($subClusterTrees);
}

function <> meta::pure::graphFetch::executionPlan::recursivelyFindNonClusterTrees(cls : ClusteredGraphFetchTree[1]):RoutedGraphFetchTree[*]
{
   $cls.tree->cast(@RoutedGraphFetchTree)->recursivelyFindNonClusterTrees()
}

function <> meta::pure::graphFetch::executionPlan::recursivelyFindNonClusterTrees(routed : RoutedGraphFetchTree[1]):RoutedGraphFetchTree[*]
{
   $routed->concatenate($routed.subTrees->filter(x | !$x->instanceOf(ClusteredGraphFetchTree))->cast(@RoutedGraphFetchTree)->map(x | $x->recursivelyFindNonClusterTrees()))
}

function <> meta::pure::graphFetch::executionPlan::recursivelyRemoveClusterTrees(cls : ClusteredGraphFetchTree[1]):ClusteredGraphFetchTree[1]
{
   ^$cls(tree  = $cls.tree->cast(@RoutedGraphFetchTree)->recursivelyRemoveClusterTrees())
}

function <> meta::pure::graphFetch::executionPlan::recursivelyRemoveClusterTrees(routed : RoutedGraphFetchTree[1]):RoutedGraphFetchTree[1]
{
   ^$routed(subTrees = $routed.subTrees->filter(x | !$x->instanceOf(ClusteredGraphFetchTree))->cast(@RoutedGraphFetchTree)->map(x | $x->recursivelyRemoveClusterTrees()))
}

function meta::pure::graphFetch::executionPlan::indent(d: DebugContext[1], count: Integer[1]): DebugContext[1]
{
   range($count)->fold({x,a | $a->indent()}, $d)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy