core_servicestore.executionPlan.executionPlan_generation.pure Maven / Gradle / Ivy
The newest version!
// Copyright 2021 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::executionPlan::*;
import meta::pure::functions::collection::*;
import meta::pure::graphFetch::*;
import meta::pure::graphFetch::execution::*;
import meta::pure::graphFetch::executionPlan::*;
import meta::pure::graphFetch::routing::*;
import meta::pure::metamodel::path::*;
import meta::pure::mapping::*;
import meta::external::store::model::*;
import meta::pure::mapping::modelToModel::executionContext::*;
import meta::pure::mapping::modelToModel::graphFetch::executionPlan::*;
import meta::pure::mapping::xStore::*;
import meta::pure::extension::*;
import meta::core::runtime::*;
import meta::pure::router::store::metamodel::*;
import meta::pure::router::store::metamodel::clustering::*;
import meta::pure::router::utils::*;
import meta::pure::store::*;
import meta::external::format::shared::binding::*;
import meta::external::format::shared::binding::validation::*;
import meta::external::format::shared::executionPlan::*;
import meta::external::format::shared::router::extension::*;
import meta::external::format::shared::utils::*;
import meta::external::store::service::executionPlan::nodes::*;
import meta::external::store::service::executionPlan::generation::*;
import meta::external::store::service::metamodel::*;
import meta::external::store::service::metamodel::runtime::*;
import meta::external::store::service::metamodel::mapping::*;
import meta::external::store::service::functions::pureToServiceStoreQuery::*;
import meta::external::store::service::router::systemMapping::*;
import meta::external::store::service::utils::helperFunction::*;
function meta::external::store::service::executionPlan::generation::planRootGraphFetchExecutionServiceStore(sq: StoreQuery[1], ext: RoutedValueSpecification[0..1], clusteredTree: StoreMappingClusteredGraphFetchTree[1], orderedPaths: String[*], mapping: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], enableConstraints: Boolean[1], checked: Boolean[1], extensions: meta::pure::extension::Extension[*], debug: DebugContext[1]): InMemoryRootGraphFetchExecutionNode[1]
{
let store = $sq.store;
assert($store->instanceOf(ServiceStore), | 'Expected a ServiceStore. Found - ' + $store->cast(@Store)->elementToPath());
let fe = $sq.fe->evaluateAndDeactivate();
let rootTree = $clusteredTree->byPassClusteringInfo()->cast(@RoutedRootGraphFetchTree);
let batchSize = if($fe.func == graphFetch_T_MANY__RootGraphFetchTree_1__Integer_1__T_MANY_ || $fe.func == meta::pure::graphFetch::execution::graphFetchChecked_T_MANY__RootGraphFetchTree_1__Integer_1__Checked_MANY_,
| $fe->instanceValuesAtParameter(2, $sq.inScopeVars)->toOne()->cast(@Integer),
| 1);
let connection = $runtime->connectionByElement($store);
let sourceTree = calculateSourceTree($rootTree, $mapping, $extensions);
let sourceTreeExtended = if($enableConstraints, | $sourceTree->ensureConstraintsRequirements(), | $sourceTree);
let serviceSetImpl = $rootTree.sets->toOne()->cast(@RootServiceInstanceSetImplementation);
let setsProcessed = if($ext->isNotEmpty() && $ext->toOne()->instanceOf(StoreMappingRoutedValueSpecification), | $ext->cast(@StoreMappingRoutedValueSpecification).processedChainSets, |[]);
let map = resolveParamMapForChainProcessing($setsProcessed, $sq.inScopeVars, $debug);
let serviceStoreQueryProcessedState = $sq->processServiceStoreQuery($map, $debug);
let sourceNode = $connection->meta::external::store::service::executionPlan::generation::nodeFromServiceStoreConnection($sourceTreeExtended, $serviceSetImpl, $serviceStoreQueryProcessedState, $enableConstraints, $checked, $extensions);
let sourceNodeDecorator = {sourceNode:ExecutionNode[1] | if($serviceStoreQueryProcessedState.recordsToBeRead->isEmpty(),
|$sourceNode,
|assert($setsProcessed->cast(@PureInstanceSetImplementation).filter->isEmpty(), | 'Service Store does not support ->take when filters added in chained M2m mapping');
let fromCluster = ^StoreMappingClusteredValueSpecification(
val = $fe,
store = $store,
s = meta::external::store::service::contract::serviceStoreStoreContract(),
mapping = $mapping,
executable=true,
multiplicity = $fe.multiplicity,
genericType = $fe.genericType,
openVars = $sq.inScopeVars
);
^LimitExecutionNode(limit = $serviceStoreQueryProcessedState.recordsToBeRead->toOne(),
resultType = $sourceNode.resultType,
executionNodes = ^$sourceNode(fromCluster = $fromCluster));)};
^InMemoryRootGraphFetchExecutionNode
(
resultType = $rootTree->resultTypeFromGraphFetchTree(),
nodeIndex = 0,
graphFetchTree = $rootTree,
batchSize = $batchSize,
checked = $checked,
children = $rootTree->generateInMemoryChildGraphNodes($rootTree->nodePathName(), $orderedPaths, $debug),
executionNodes = $sourceNodeDecorator->eval($sourceNode)
);
}
function meta::external::store::service::executionPlan::generation::planCrossStoreGraphFetchExecutionServiceStore(clusteredTree: StoreMappingClusteredGraphFetchTree[1], orderedPaths: String[*], parentPath: String[1], inScopeVars: Map>[1], mapping: Mapping[1], runtime: Runtime[1], exeCtx: meta::pure::runtime::ExecutionContext[1], enableConstraints: Boolean[1], checked: Boolean[1], extensions: Extension[*], debug: DebugContext[1]): InMemoryCrossStoreGraphFetchExecutionNode[1]
{
let store = $clusteredTree.store;
assert($store->instanceOf(ServiceStore), | 'Expected a ServiceStore. Found - ' + $store->cast(@Store)->elementToPath());
let rootTree = $clusteredTree->byPassClusteringInfo()->cast(@RoutedPropertyGraphFetchTree);
let updatedRootTree = ^RoutedRootGraphFetchTree
(
subTrees = $rootTree.subTrees,
class = $rootTree->typeFromGraphFetchTree()->cast(@Class),
sets = $rootTree.sets,
requiredQualifiedProperties = $rootTree.requiredQualifiedProperties
);
let rootPath = $parentPath + '.' + $rootTree->nodePathName();
/* Assertions */
assert($parentPath->in($orderedPaths), | 'Unknown path ' + $parentPath + '; known are: ' + $orderedPaths->joinStrings('[', '; ', ']'));
assert($rootPath->in($orderedPaths), | 'Unknown path ' + $rootPath + '; known are: ' + $orderedPaths->joinStrings('[', '; ', ']'));
assertFalse($checked, | 'graphFetchChecked is not supported with Service Store');
let parentIdx = $orderedPaths->indexOf($parentPath);
let currentIdx = $orderedPaths->indexOf($rootPath);
let xStorePropertyMapping = $rootTree.propertyMapping->toOne()->cast(@XStorePropertyMapping);
let connection = $runtime->connectionByElement($store);
let sourceTree = calculateSourceTree($updatedRootTree, $mapping, $extensions);
let sourceTreeExtended = if($enableConstraints, | $sourceTree->ensureConstraintsRequirements(), | $sourceTree);
let xStorePropInScope = $xStorePropertyMapping->getPopulatedXStorePropertiesInScope($rootTree->typeFromGraphFetchTree()->cast(@Class));
assert($xStorePropInScope->forAll(prop | $prop.multiplicity->hasToOneUpperBound()), 'All properties in XStore relationship should have 1 as multiplicty upper bound for service store.');
let paramMap = $xStorePropInScope->getParamMapFromXStoreProperties($rootTree->typeFromGraphFetchTree()->cast(@Class));
let serviceSetImpl = $rootTree.sets->toOne()->cast(@RootServiceInstanceSetImplementation);
^InMemoryCrossStoreGraphFetchExecutionNode
(
resultType = $rootTree->resultTypeFromGraphFetchTree(),
parentIndex = $parentIdx,
nodeIndex = $currentIdx,
graphFetchTree = $rootTree,
checked = $checked,
xStorePropertyMapping = $xStorePropertyMapping,
supportsBatching = $xStorePropInScope->querySupportsBatching($paramMap, $serviceSetImpl),
children = $rootTree->generateInMemoryChildGraphNodes($rootPath, $orderedPaths, $debug),
executionNodes = $connection->meta::external::store::service::executionPlan::generation::nodeFromServiceStoreConnection($sourceTreeExtended, $serviceSetImpl, ^ServiceStoreQueryProcessedState(paramMap = $paramMap), $enableConstraints, $checked, $extensions)
);
}
// Helper functions to parse query and generate required allocationNodes & param map
function meta::external::store::service::executionPlan::generation::getParamMapFromXStoreProperties(properties: AbstractProperty[*], rootClass:Class[1]):Map[1]
{
$properties->map(p | pathAsString(^Path(path=^PropertyPathElement(property=$p), start = ^GenericType(rawType = $rootClass))))
->map(p | pair($p, $p))->newMap();
}
Class <> meta::external::store::service::executionPlan::generation::ServiceStoreQueryProcessedState
{
executionNodes : ExecutionNode[*];
paramMap : Map[1];
recordsToBeRead : Integer[0..1];
}
function meta::external::store::service::executionPlan::generation::processServiceStoreQuery(sq:StoreQuery[1], initialMap:Map[1], debug: DebugContext[1]):ServiceStoreQueryProcessedState[1]
{
let serviceStoreQuery = $sq.fe->toServiceStoreQuery($sq.inScopeVars, $debug);
let paramValues = $serviceStoreQuery.processedParamValueMap->keyValues();
let literalParams = $paramValues->filter(p | $p.second->instanceOf(LiteralValue));
let varParams = $paramValues->filter(p | $p.second->instanceOf(VariableValue));
let allocationNodes = $literalParams->map(param | ^AllocationExecutionNode(varName = $param.first,
executionNodes = ^ConstantExecutionNode(
//TODO: This is valid now because we don't support in for service store but would need to be fixed when in is supported.
//When value is a list it get translated to CList with CString values which cause issues in parsing at execution time.
values = $param.second->cast(@LiteralValue).value->toOne(),
resultType = ^ResultType(type = Any)
),
resultType = ^ResultType(type = Any)
));
let paramMap = $paramValues->map(p | let varName = $p.second->match([
v:VariableValue[1] | $v.var.name,
l:LiteralValue[1] | $p.first
]);
pair($p.first, $varName);)->newMap();
^ServiceStoreQueryProcessedState(executionNodes = $allocationNodes,
paramMap = $initialMap->putAll($paramMap),
recordsToBeRead = $serviceStoreQuery.recordsToBeRead);
}
// Helper Functions to analyze query supports batching
function meta::external::store::service::executionPlan::generation::querySupportsBatching(xStorePropInScope:AbstractProperty[*], paramMap:Map[1], serviceSetImpl:RootServiceInstanceSetImplementation[1]):Boolean[1]
{
let xStorePropertyIsLocal = $xStorePropInScope->exists(prop | $prop.owner->instanceOf(MappingClass));
let serviceMappingInScope = $serviceSetImpl->getServiceMappingForParameters($paramMap->keys());
let serParamForXStoreProp = $serviceMappingInScope.requestBuildInfo.requestParametersBuildInfo.parameterBuildInfoList->filter(pm | $pm.transform.expressionSequence->evaluateAndDeactivate()->toOne()->findPropertiesInValueSpecification()->exists(p | $p->in($xStorePropInScope))).serviceParameter;
!$xStorePropertyIsLocal && $serParamForXStoreProp.type->forAll(t | $t.list);
}
// Helper Functions to generate node for connection with query context
function meta::external::store::service::executionPlan::generation::nodeFromServiceStoreConnection(c:Connection[1], tree:RootGraphFetchTree[1], serviceSetImpl:RootServiceInstanceSetImplementation[1], serviceStoreQueryProcessedState:ServiceStoreQueryProcessedState[1], enableConstraints:Boolean[1], checked:Boolean[1], extensions:meta::pure::extension::Extension[*]):ExecutionNode[1]
{
let serviceMapping = $serviceSetImpl->getServiceMappingForParameters($serviceStoreQueryProcessedState.paramMap->keys());
let s = $c->cast(@ServiceStoreConnection);
let serviceParamResolutionNode = getServiceParametersResolutionExecutionNode($serviceMapping.requestBuildInfo.requestParametersBuildInfo, $serviceStoreQueryProcessedState.paramMap);
assert($serviceMapping.service.requestBody->isEmpty() || $serviceMapping.service.requestBody->toOne()->instanceOf(ComplexTypeReference), | 'Request Body with primitive type not supported yet!!');
let serviceBodyResolutionNode = getServiceRequestBodyResolutionExecutionNode($serviceMapping, $serviceStoreQueryProcessedState.paramMap, $extensions);
let requestBodyDescription = if($serviceBodyResolutionNode->isEmpty(),
| [],
|^RequestBodyDescription(mimeType = $serviceMapping.service.requestBody->cast(@ComplexTypeReference).binding.contentType->toOne(),
resultKey = $serviceBodyResolutionNode->toOne()->cast(@AllocationExecutionNode).varName));
let mappedParameters = $serviceMapping.requestBuildInfo.requestParametersBuildInfo.parameterBuildInfoList.serviceParameter;
let serviceStoreNode = ^RestServiceExecutionNode(url = $s.baseUrl + $serviceMapping.service.resolveFullPathRecursively(),
method = $serviceMapping.service.method,
mimeType = $serviceMapping.service.response.binding.contentType,
params = $serviceMapping.service.parameters,
// Combining Security schemes(with logical AND) is not supported yet.
authenticationSchemes = $serviceMapping.service.security->map(a | ^SingleAuthenticationSchemeRequirement(securityScheme = $a->cast(@SingleSecuritySchemeRequirement).securityScheme, authenticationSpecification = $s.authenticationSpecifications->get($a->cast(@SingleSecuritySchemeRequirement).id))),
requestBodyDescription = $requestBodyDescription,
requiredVariableInputs = $mappedParameters.name->concatenate($requestBodyDescription.resultKey)->map(v | ^VariableInput(name = $v, type = Any, multiplicity = ZeroMany)),
resultType = ^DataTypeResultType(type = String));
let allNodes = $serviceStoreQueryProcessedState.executionNodes->concatenate($serviceParamResolutionNode)
->concatenate($serviceBodyResolutionNode)
->concatenate($serviceStoreNode);
let node = if($allNodes->size() > 1,
| ^SequenceExecutionNode(executionNodes = $allNodes, resultType = $serviceStoreNode.resultType),
| $allNodes)->toOne();
let config = if($serviceMapping.pathOffset->isNotEmpty(),
|assert($serviceMapping.service.response.binding.contentType->in(meta::external::format::json::contract::jsonSchemaFormatContract().contentTypes), 'PathOffset is supported with json only!');
meta::external::format::json::metamodel::internalize::generateJsonSchemaInternalizeConfig($serviceMapping.pathOffset->toOne());,
|[]);
^ExternalFormatInternalizeExecutionNode
(
resultType = ^PartialClassResultType(
type = $tree.class,
propertiesWithParameters = $tree.subTrees->cast(@PropertyGraphFetchTree)->map(x | $x->map(x | ^PropertyWithParameters(property = $x.property, parameters = $x.parameters)))
),
resultSizeRange = ZeroMany,
tree = $tree,
binding = $serviceMapping.service.response.binding,
executionNodes = $node,
config = $config,
enableConstraints = $enableConstraints,
checked = $checked
);
}
function meta::external::store::service::executionPlan::generation::getServiceMappingForParameters(serviceSetImpl:RootServiceInstanceSetImplementation[1], availablePropPaths:String[*]):ServiceMapping[1]
{
let propToServiceMappingMap = $serviceSetImpl.servicesMapping->map(sm | let reqPropPaths = $sm.requestBuildInfo.requestParametersBuildInfo.parameterBuildInfoList
->map(pb | $pb.transform.expressionSequence->toOne()->findAndReplacePropertyPathsInValueSpecification([]).second.values)
->concatenate($sm.requestBuildInfo.requestBodyBuildInfo.transform.expressionSequence->map(x | $x->findAndReplacePropertyPathsInValueSpecification([]).second.values));
let propPaths = if($reqPropPaths->isEmpty(), |'', |$reqPropPaths)->removeDuplicates();
pair($propPaths->sort()->joinStrings(','), $sm);)->newMap();
let reqServiceMapping = $propToServiceMappingMap->get($availablePropPaths->sort()->joinStrings(','));
assert($reqServiceMapping->isNotEmpty(), |'No service mapping found for available parameters. Available params - ' + $availablePropPaths->sort()->joinStrings('[', ', ', ']') + '. Available paths - ' + $propToServiceMappingMap->keys()->joinStrings('[', ', ', ']'));
$reqServiceMapping->toOne();
}
function meta::external::store::service::executionPlan::generation::getServiceParametersResolutionExecutionNode(parametersBuildInfo:ServiceRequestParametersBuildInfo[0..1], paramMap:Map[1]):ServiceParametersResolutionExecutionNode[0..1]
{
let parameterBuildInfoList = $parametersBuildInfo.parameterBuildInfoList;
if($parameterBuildInfoList->isEmpty(),
|[],
|let updatedMappingAndSources = $parameterBuildInfoList->map(pb | let transform = $pb.transform;
let updatedTransformAndPaths = $transform.expressionSequence->toOne()->findAndReplacePropertyPathsInValueSpecification([], $paramMap)->toOne();
let requiredVariableInputs = $updatedTransformAndPaths.second.values->map(path | ^VariableInput(name = $paramMap->get(pathAsString($path))->toOne(),
type = $path.path->at(0)->cast(@PropertyPathElement).property->functionReturnType().rawType->toOne(),
multiplicity = $path.path->at(0)->cast(@PropertyPathElement).property->functionReturnMultiplicity()));
pair(^$pb(transform = ^$transform(expressionSequence = $updatedTransformAndPaths.first->cast(@ValueSpecification))), ^List(values = $requiredVariableInputs)););
^ServiceParametersResolutionExecutionNode(requiredVariableInputs = $updatedMappingAndSources.second.values,
requestParametersBuildInfo = ^ServiceRequestParametersBuildInfo(parameterBuildInfoList = $updatedMappingAndSources.first),
resultType = ^DataTypeResultType(type = Map)););
}
function meta::external::store::service::executionPlan::generation::getServiceRequestBodyResolutionExecutionNode(serviceMapping:ServiceMapping[1], paramMap:Map[1], extensions:meta::pure::extension::Extension[*]):ExecutionNode[0..1]
{
let requestBodyBuildInfo = $serviceMapping.requestBuildInfo.requestBodyBuildInfo;
let requestBodyType = $serviceMapping.service.requestBody;
if($requestBodyBuildInfo->isEmpty(),
|[],
|let requestBodyBuildInfoOne = $requestBodyBuildInfo->toOne();
let updatedTransformAndPropPath = $requestBodyBuildInfoOne.transform.expressionSequence->toOne()->findAndReplacePropertyPathsInValueSpecification([], $paramMap)->toOne();
let resultType = if($requestBodyType->toOne()->instanceOf(ComplexTypeReference),
|^ClassResultType(setImplementations = [], type = $requestBodyType->cast(@ComplexTypeReference).type->toOne()),
|^DataTypeResultType(type = String));
let requiredVariableInputs = $updatedTransformAndPropPath.second.values->map(path | ^VariableInput(name = $paramMap->get(pathAsString($path))->toOne(),
type = $path.path->at(0)->cast(@PropertyPathElement).property->functionReturnType().rawType->toOne(),
multiplicity = $path.path->at(0)->cast(@PropertyPathElement).property->functionReturnMultiplicity()));
let requestBodyResolutionNode = ^PureExpressionPlatformExecutionNode(expression = $updatedTransformAndPropPath.first->cast(@ValueSpecification),
requiredVariableInputs = $requiredVariableInputs,
resultType = $resultType);
let serializedRequestBody = ^ExternalFormatExternalizeExecutionNode
(
resultType = ^ResultType(type=String),
resultSizeRange = PureOne,
checked = false,
binding = $requestBodyType->toOne()->cast(@ComplexTypeReference).binding,
tree = generateRootTreeFromBinding($requestBodyType->toOne()->cast(@ComplexTypeReference).type, $requestBodyType->toOne()->cast(@ComplexTypeReference).binding, $extensions),
executionNodes = $requestBodyResolutionNode
);
^AllocationExecutionNode(varName = $serviceMapping.service.owner->elementToPath('_') + '_' + $serviceMapping.service.resolveFullPathRecursively()->replace('/', '_') + '_requestBody',
executionNodes = $serializedRequestBody,
resultType = ^VoidResultType(type = meta::pure::router::store::routing::Void));
);
}
function <> meta::external::store::service::executionPlan::generation::generateRootTreeFromBinding(classIn:meta::pure::metamodel::type::Class[1], binding:Binding[1], extensions:Extension[*]): RootGraphFetchTree[1]
{
let externalFormatContract = $extensions.availableExternalFormats->getExternalFormatContractForContentType($binding.contentType);
let bindingDetail = $externalFormatContract.validateBinding($binding);
assert($bindingDetail->instanceOf(SuccessfulBindingDetail), | 'Binding validation failed.\n' + $bindingDetail->cast(@FailedBindingDetail).errorMessages->joinStrings('\n'));
let propertiesInScope = $bindingDetail->cast(@SuccessfulBindingDetail).mappedPropertiesForClass($classIn);
let subTrees = $propertiesInScope->map(p | $p->generatePropertyTreeForProperty($bindingDetail->cast(@SuccessfulBindingDetail)));
^RootGraphFetchTree(class=$classIn, subTrees = $subTrees);
}
function <> meta::external::store::service::executionPlan::generation::generatePropertyTreeForProperty(property:AbstractProperty[1], detail:SuccessfulBindingDetail[1]): PropertyGraphFetchTree[1]
{
let returnType = $property->functionReturnType().rawType->toOne();
let isPropertyPrimitive = $returnType->instanceOf(meta::pure::metamodel::type::PrimitiveType) || $returnType->instanceOf(meta::pure::metamodel::type::Enumeration) ;
let subPropertiesInScope = if($isPropertyPrimitive, | [], | $detail.mappedPropertiesForClass($returnType->cast(@meta::pure::metamodel::type::Class)));
let subTrees = $subPropertiesInScope->map(p | $p->generatePropertyTreeForProperty($detail));
^PropertyGraphFetchTree(property=$property, subTrees = $subTrees);
}
function meta::external::store::service::executionPlan::generation::findAndReplacePropertyPathsInValueSpecification(vs:ValueSpecification[1], propertiesInCurrentPath:AbstractProperty[*]):Pair>[0..1]
{
findAndReplacePropertyPathsInValueSpecification($vs, $propertiesInCurrentPath, newMap([])->cast(@Map))
->map(p | pair($p.first, ^List(values = $p.second.values->map(p | pathAsString($p)))));
}
function meta::external::store::service::executionPlan::generation::findAndReplacePropertyPathsInValueSpecification(vs:ValueSpecification[1], propertiesInCurrentPath:AbstractProperty[*], paramMap:Map[1]):Pair>>[0..1]
{
$vs->deepByPassRouterInfo()
->match([fe:FunctionExpression[1] | let newPropertiesInCurrentPath = if ($fe.func->instanceOf(AbstractProperty),
| $fe.func->cast(@AbstractProperty)->concatenate($propertiesInCurrentPath);,
| [];);
let res = $fe.parametersValues->map(v | $v->findAndReplacePropertyPathsInValueSpecification($newPropertiesInCurrentPath, $paramMap));
let propPaths = $newPropertiesInCurrentPath->map(p | ^PropertyPathElement(property=$p));
let newPath = if($newPropertiesInCurrentPath->isNotEmpty(),
| ^Path(path=$propPaths->toOneMany(), start=$fe.parametersValues->toOne().genericType),
| []);
let updatedFe = if ($fe.func->instanceOf(AbstractProperty),
|let newPathString = pathAsString($newPath->toOne());
^VariableExpression(name = if($paramMap->get($newPathString)->isEmpty(), |$newPathString, | $paramMap->get($newPathString)->toOne()),
genericType = ^GenericType(rawType = Any),
multiplicity = $fe.func->functionReturnMultiplicity())->wrapVariableExpressionInCast($fe.func->cast(@AbstractProperty));,
|^$fe(parametersValues = $res.first->cast(@ValueSpecification)));
let updatedPathList = if($newPropertiesInCurrentPath->isEmpty() || (($fe.parametersValues->size() == 1) && ($fe.parametersValues->at(0)->instanceOf(SimpleFunctionExpression)) && ($fe.parametersValues->at(0)->cast(@SimpleFunctionExpression).func->instanceOf(AbstractProperty))),
| ^List>(values = $res.second.values),
| ^List>(values = $res.second.values->concatenate($newPath)));
pair($updatedFe, $updatedPathList);,
i:InstanceValue[1] | let updatedValues = $i.values->map( v |
$v->match([ a : ValueSpecification[1] | $a->findAndReplacePropertyPathsInValueSpecification($propertiesInCurrentPath, $paramMap),
k : KeyExpression[1] | let keyExpressionPair = $k.expression->findAndReplacePropertyPathsInValueSpecification($propertiesInCurrentPath, $paramMap)->toOne();
pair(^KeyExpression(key = $k.key, expression = $keyExpressionPair.first->cast(@ValueSpecification)), $keyExpressionPair.second);,
l : LambdaFunction[1] | let results = $l.expressionSequence->map(e | $e->findAndReplacePropertyPathsInValueSpecification($propertiesInCurrentPath, $paramMap));
pair(^$l(expressionSequence = $results.first->cast(@ValueSpecification)->toOneMany()), ^List>(values = $results.second.values));,
a : Any[1] | pair($a, ^List>(values = []))]));
pair(^$i(values = $updatedValues.first), ^List>(values = $updatedValues.second.values));,
ve:VariableExpression[1] | let updatedName = if($paramMap->get($ve.name)->isEmpty(),
| $ve.name,
| $paramMap->get($ve.name)->toOne());
pair(^$ve(name = $updatedName), ^List>(values = []));
]
);
}
function meta::external::store::service::executionPlan::generation::wrapVariableExpressionInCast(v:VariableExpression[1], prop:AbstractProperty[1]):SimpleFunctionExpression[1]
{
^SimpleFunctionExpression
(
func = cast_Any_m__T_1__T_m_,
functionName = 'cast',
multiplicity = $prop->functionReturnMultiplicity(),
genericType = $prop->functionReturnType(),
importGroup = system::imports::coreImport,
parametersValues =
[
$v,
^InstanceValue
(
multiplicity = $prop->functionReturnMultiplicity(),
genericType = $prop->functionReturnType()
)
]
);
}
function meta::external::store::service::executionPlan::generation::pathAsString(p:Path[1]):String[1]
{
if($p.start.rawType->toOne()->instanceOf(MappingClass),
|$p.start.rawType->cast(@MappingClass).generalizations.general.rawType.name->toOne(),
|$p.start.rawType.name->toOne()) + '_' + $p.path->map(prop|$prop->cast(@PropertyPathElement).property.name)->joinStrings('_');
}