diff --git a/legend-engine-config/legend-engine-server/src/test/java/org/finos/legend/engine/server/test/pureClient/stores/Test_Relational_UsingPureClientTestSuite.java b/legend-engine-config/legend-engine-server/src/test/java/org/finos/legend/engine/server/test/pureClient/stores/Test_Relational_UsingPureClientTestSuite.java index 0330801d70d..8937363f18e 100644 --- a/legend-engine-config/legend-engine-server/src/test/java/org/finos/legend/engine/server/test/pureClient/stores/Test_Relational_UsingPureClientTestSuite.java +++ b/legend-engine-config/legend-engine-server/src/test/java/org/finos/legend/engine/server/test/pureClient/stores/Test_Relational_UsingPureClientTestSuite.java @@ -77,8 +77,6 @@ public static Test suite() throws Exception suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::graphFetch::tests::crossDatabase", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::graphFetch::tests::subType", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::graphFetch::tests::union::propertyLevel", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); - suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::graphFetch::tests::union::rootLevel", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); - suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWithMilestoning", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::tests::aggregationAware", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); suite.addTest(buildSuite(TestCollection.collectTests("meta::relational::tests::advanced::resultSourcing", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); suite.addTest(buildSuite(TestCollection.collectTests("meta::pure::graphFetch::tests::XStore::inMemoryAndRelational", executionSupport.getProcessorSupport(), ci -> satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport)); diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphFetch_routing.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphFetch_routing.pure index 3d259e468e4..7ccf2535377 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphFetch_routing.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/graphFetch/graphFetch_routing.pure @@ -245,83 +245,61 @@ function meta::pure::graphFetch::routing::routeRootGraphFetchTree(root: RootGrap function meta::pure::graphFetch::splitPropertyTrees(tree:RoutedGraphFetchTree[1], mapping: Mapping[1], extensions:meta::pure::extension::Extension[*], exeCtx: ExecutionContext[1]):RoutedGraphFetchTree[1] { let updatedSubTrees = $tree.subTrees->map(st | let propertyTree = $st->cast(@RoutedPropertyGraphFetchTree); + let splitPropertyTreeWhenMultipleSetImpls = ($propertyTree.sets->size() > 1) && ($propertyTree.sets->forAll(set | $set->storeContractForSetImplementation($mapping, $extensions).first.splitGraphFetchTreeForPropertyUnion)); let splitPropertyTreeWhenMultiplePropertyMappings = ($propertyTree.propertyMapping->size() > 1) && $propertyTree.propertyMapping->forAll(pm | $pm.owner->isNotEmpty() && $pm.owner->toOne()->instanceOf(InstanceSetImplementation) && $extensions->storeContractForSetImplementation($pm.owner->cast(@InstanceSetImplementation)->toOne()).splitGraphFetchTreeForPropertyUnion); - - if($propertyTree.property->instanceOf(QualifiedProperty) && $tree.sets->forAll(set | $set->storeContractForSetImplementation($mapping, $extensions).first.splitGraphFetchTreeForPropertyUnion), - | splitBasedOnQualifiedProperty($propertyTree, $tree.sets->toOne(), $mapping, $exeCtx, $extensions), - |if($splitPropertyTreeWhenMultiplePropertyMappings, - | - let sourceSetImplementationIds = $mapping->allSuperSetImplementationIds($tree.sets->toOne().id); - $propertyTree.propertyMapping->filter(x | $x.sourceSetImplementationId->in($sourceSetImplementationIds))->map(pm | ^$propertyTree(propertyMapping = $pm, sets = $propertyTree.sets->filter(s | $s.id == $pm.targetSetImplementationId)));, - | $propertyTree - ) - ); + + if( $splitPropertyTreeWhenMultipleSetImpls, + | if($propertyTree.property->instanceOf(QualifiedProperty), + | let property = $propertyTree.property->cast(@QualifiedProperty); + let sourceSetImplementation = $tree.sets->toOne(); + let multipleExpressionForUnion = meta::pure::graphFetch::getMultiValueSpecBasedOnSetImplPermutation($property.expressionSequence->evaluateAndDeactivate()->toOne()->cast(@StoreMappingRoutedValueSpecification), $sourceSetImplementation, $exeCtx, $extensions); + $multipleExpressionForUnion->map(x | ^$propertyTree(property = ^$property(expressionSequence = $x), sets = $x.sets););, + | let sourceSetImplementationIds = $mapping->allSuperSetImplementationIds($tree.sets->toOne().id); + $propertyTree.propertyMapping->filter(x | $x.sourceSetImplementationId->in($sourceSetImplementationIds))->map(pm | ^$propertyTree(propertyMapping = $pm, sets = $propertyTree.sets->filter(s | $s.id == $pm.targetSetImplementationId))); + );, + | if($splitPropertyTreeWhenMultiplePropertyMappings, + | let sourceSetImplementationIds = $mapping->allSuperSetImplementationIds($tree.sets->toOne().id); + ^$propertyTree(propertyMapping = $propertyTree.propertyMapping->filter(pm | $pm.sourceSetImplementationId->in($sourceSetImplementationIds)));, + | $propertyTree + ); + ); ); ^$tree(subTrees = $updatedSubTrees->map(s | $s->cast(@RoutedGraphFetchTree)->splitPropertyTrees($mapping, $extensions, $exeCtx))); } -function meta::pure::graphFetch::getPermutationSetList(vs: ValueSpecification[1]): PermutationSet[*] +function meta::pure::graphFetch::getMultiValueSpecBasedOnSetImplPermutation(routedVs: StoreMappingRoutedValueSpecification[1], sourceSetImplementation:SetImplementation[1], exeCtx: ExecutionContext[1], extensions:meta::pure::extension::Extension[*]): StoreMappingRoutedValueSpecification[*] { - $vs->match([ - f:FunctionExpression[1]| $f->evaluateAndDeactivate().parametersValues->evaluateAndDeactivate()->map(x | $x->meta::pure::graphFetch::getPermutationSetList());, - routedVs:StoreMappingRoutedValueSpecification[1]| $routedVs->evaluateAndDeactivate().routingStrategy->cast(@StoreMappingRoutingStrategy).sets->cast(@PermutationSet);, - f:FunctionRoutedValueSpecification[1]| $f->evaluateAndDeactivate().value->getPermutationSetList();, - a: Any[1] | []; - ]); -} + let debug = noDebug(); + let permutationSetList = $routedVs.routingStrategy->cast(@StoreMappingRoutingStrategy).sets->cast(@PermutationSet); + let uniqueClassesInPermutationSet = $permutationSetList->map(permSet | $permSet.sets->at(0).class)->removeDuplicates(); -function meta::pure::graphFetch::splitBasedOnQualifiedProperty(propertyTree: RoutedPropertyGraphFetchTree[1], sourceSetImplementation:SetImplementation[1], mapping: Mapping[1], exeCtx: ExecutionContext[1], extensions:meta::pure::extension::Extension[*]): RoutedPropertyGraphFetchTree[*] -{ - let debug = noDebug(); - let qualifiedProperty = $propertyTree.property->cast(@QualifiedProperty); - let expr = $qualifiedProperty.expressionSequence->toOne(); + assert($permutationSetList->size() == $uniqueClassesInPermutationSet->size(), 'Multiple permutationSetImplementation for same class is not suppported for qualified/milestoned property union in GraphFetch'); - let permutationSetList = $expr->getPermutationSetList(); + let setsInScope = $permutationSetList->map(x | ^$x(sets = $x.sets->map(s | $s->resolveOperation($routedVs.mapping)))); + let mapping = $routedVs.mapping; print(if($debug.debug,|'\n'+$debug.space+'Sets found:\n', |'')); - print(if($debug.debug,|$permutationSetList->map(s|$debug.space+' ['+$s.id->toString()+'|'+$s.sets->map(si|$si.id)->joinStrings(',')+']')->joinStrings('\n')+'\n',|'')); - - if($permutationSetList->isEmpty(), - | $propertyTree, - | let filteredSets = $permutationSetList->map(permSet | if($permSet.sets->at(0).class == $sourceSetImplementation.class, - | ^$permSet(sets = $permSet.sets->map(s | $s->resolveOperation($mapping))->filter(s | $s.id == $sourceSetImplementation.id)), - | $permSet - ); - ); - - print(if($debug.debug,|'\n'+$debug.space+'filtered sets found:\n', |'')); - print(if($debug.debug,|$filteredSets->map(s|$debug.space+' ['+$s.id->toString()+'|'+$s.sets->map(si|$si.id)->joinStrings(',')+']')->joinStrings('\n')+'\n',|'')); - - let returnType = $qualifiedProperty.genericType.rawType->toOne(); - let propertyTreeWithRequiredPermutationSet = if($returnType->instanceOf(Class), - | let permutationSetOfReturnType = $filteredSets->filter(permSet | $permSet.sets->at(0).class == $returnType)->at(0); - $permutationSetOfReturnType.sets->map(s | $s->resolveOperation($mapping))->map(s | pair(^$propertyTree(sets = $s), ^List(values = $filteredSets->map(permSet | if($permSet.sets->at(0).class == $returnType, - | ^$permSet(sets = $permSet.sets->map(s | $s->resolveOperation($mapping))->filter(set | $set.id == $s.id)), - | $permSet - ) - ) - ) - ) - );, - | pair(^$propertyTree(sets = []), ^List(values=$filteredSets)) - ); - - print(if($debug.debug,|'\n'+$debug.space+ 'RequiredPermutationSet found:\n', |'')); - print(if($debug.debug,|$propertyTreeWithRequiredPermutationSet->map(l|$l.second.values->map(p|$debug.space + ' ['+$p.id->toString()+'|'+$p.sets.id->map(x | $x->toString())->makeString(', ') +']')->makeString(', '))->makeString('\n')+'\n', |'')); - - print(if($debug.debug,|'\n'+$debug.space+'Building new queries\n', |'')); - let built = $propertyTreeWithRequiredPermutationSet->map(p | print(if($debug.debug,|' Query '+$propertyTreeWithRequiredPermutationSet->indexOf($p)->toString()+'\n', |'')); - pair($p.first, $expr->evaluateAndDeactivate()->meta::pure::router::store::routing::build($p.second, [], $mapping, $exeCtx, $extensions, $debug)); - ); - - print(if($debug.debug,|'\n'+$debug.space+'Built queries:'+$built->size()->toString()+'\n', |'')); - print(if($debug.debug,|$built->map(b|$debug.space+' - '+$b.second->asString())->makeString('\n')+'\n',|'')); - - $built->filter(x|!$x.second->instanceOf(Void))->map(p | let pt = $p.first; - ^$pt(property = ^$qualifiedProperty(expressionSequence = $p.second)); - ); - ); + print(if($debug.debug,|$setsInScope->map(s|$debug.space+' ['+$s.id->toString()+'|'+$s.sets->map(si|$si.id)->joinStrings(',')+']')->joinStrings('\n')+'\n',|'')); + + print(if($debug.debug,|'\n'+$debug.space+'Process Permutations ('+$setsInScope.id->size()->toString()+')\n', |'')); + let permutations = $setsInScope->meta::pure::router::store::routing::permute(); + print(if($debug.debug,|$permutations->map(l|$l.values->map(p|$debug.space + ' ['+$p.id->toString()+'|'+$p.sets->toOne().id->toString()+']')->makeString(', '))->makeString('\n')+'\n', |'')); + + print(if($debug.debug,|'\n'+$debug.space+'Filtered Permutations ('+$setsInScope.id->size()->toString()+')\n', |'')); + let filteredPermutationSet = $permutations->filter(permSet | $permSet.values.sets->forAll(s | ($s.class == $sourceSetImplementation.class && $s.id == $sourceSetImplementation.id) || $s.class != $sourceSetImplementation.class)); + + print(if($debug.debug,|$filteredPermutationSet->map(l|$l.values->map(p|$debug.space + ' ['+$p.id->toString()+'|'+$p.sets->toOne().id->toString()+']')->makeString(', '))->makeString('\n')+'\n', |'')); + + print(if($debug.debug,|'\n'+$debug.space+'Building new queries\n', |'')); + let built = $filteredPermutationSet->map(p | print(if($debug.debug,|' Query '+$permutations->indexOf($p)->toString()+'\n', |'')); + $routedVs->evaluateAndDeactivate()->meta::pure::router::store::routing::build($p, [], $mapping, $exeCtx, $extensions, $debug);); + + print(if($debug.debug,|'\n'+$debug.space+'Built queries:'+$built->size()->toString()+'\n', |'')); + print(if($debug.debug,|$built->map(b|$debug.space+' - '+$b->asString())->makeString('\n')+'\n',|'')); + + $built->filter(x|!$x->instanceOf(Void))->cast(@StoreMappingRoutedValueSpecification); } + function <> meta::pure::graphFetch::routing::ensureXStoreRequirementsAtCurrentLevel(currentTree: RoutedGraphFetchTree[1], currentExpression: ValueSpecification[1], processedXStoreMappings: XStorePropertyMapping[*], processedQualifiers: QualifiedProperty[*], mapping: Mapping[1], extensions: Extension[*]): RoutedGraphFetchTree[1] { // Add XStore requirements diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/builder.pure b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/builder.pure index d6642fe47c6..ed44652f0bb 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/builder.pure +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/store/builder.pure @@ -107,10 +107,7 @@ function meta::pure::router::store::routing::build(v:ValueSpecification[1], l:Li p:Property[1]|pair($p, $p.classifierGenericType.typeArguments->at(1).rawType->toOne()), qp:QualifiedProperty[1]|pair($qp, $qp.genericType.rawType->toOne()) ])->toOne(); - let propertyName = if($propReturnTypePair.first->instanceOf(QualifiedProperty) && $propReturnTypePair.first->meta::pure::milestoning::hasGeneratedMilestoningPropertyStereotype(), - |$propReturnTypePair.first->edgePointPropertyName()->toOne(); , - |$propReturnTypePair.first.name->toOne(); - ); + let propertyName = $propReturnTypePair.first.name->toOne(); let setImplementation = $params->at(0)->cast(@StoreMappingRoutedValueSpecification).sets->toOne(); let newParams = $setImplementation->match([ o:OtherwiseEmbeddedSetImplementation[1]| let pMapping = $o->propertyMappingsByPropertyName($propertyName); diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/graphFetch/tests/union/relationalGraphFetchUnionWithMilestoning.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/graphFetch/tests/union/relationalGraphFetchUnionWithMilestoning.pure index b084c48e838..b6f2ebfabaf 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/graphFetch/tests/union/relationalGraphFetchUnionWithMilestoning.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/src/main/resources/core_relational/relational/graphFetch/tests/union/relationalGraphFetchUnionWithMilestoning.pure @@ -172,33 +172,6 @@ function <> {serverVersion.start='v1_32_0'} meta::rel ); } -function <> {serverVersion.start='v1_32_0'} meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWithMilestoning::testMilestoningWithMultiLevelUnionMapping2(): Boolean[1] -{ - let tree = #{ - Order { - id, - product(%2015-8-20) { - name, - synonyms(%2015-8-20){ //Single Set Implementation but multiple property mapping - type, - synonym - } - } - } - }#; - - let query = {|Order.all()->graphFetch($tree)->serialize($tree)}; - let mapping = meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWithMilestoning::MilestoningUnionMap2; - let runtime = meta::external::store::relational::tests::testRuntime(); - - let queryresult = execute($query, $mapping, $runtime, meta::relational::extension::relationalExtensions()).values; - assertJsonStringsEqual( - '[{"id":1,"product(2015-08-20)":[{"synonyms(2015-08-20)":[{"synonym":"GS-Mod-S1","type":"STOCK"},{"synonym":"GS-Mod-S2","type":"STOCK"}],"name":"ProductName1"},{"synonyms(2015-08-20)":[],"name":"ProductName3"}]},' + - '{"id":2,"product(2015-08-20)":[{"synonyms(2015-08-20)":[{"synonym":"GS-Mod-S0","type":"CUSIP"},{"synonym":"GS-Mod-S1","type":"CUSIP"}],"name":"ProductName2"},{"synonyms(2015-08-20)":[],"name":"ProductName4"}]}]', - $queryresult - ); -} - ###Mapping import meta::relational::tests::milestoning::*; Mapping meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWithMilestoning::MilestoningUnionMap @@ -289,46 +262,3 @@ Mapping meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWit name : [db]ProductExchangeTableNoMilestoning.name } ) - - -Mapping meta::relational::graphFetch::tests::union::relationalGraphFetchUnionWithMilestoning::MilestoningUnionMap2 -( - *Order : Operation - { - meta::pure::router::operations::union_OperationSetImplementation_1__SetImplementation_MANY_(o1, o2) - } - - *Product : Operation - { - meta::pure::router::operations::union_OperationSetImplementation_1__SetImplementation_MANY_(p1, p2) - } - - meta::relational::tests::milestoning::Order[o1] : Relational{ - id : [db]OrderTable.id, - product[p1] : [db]@Order_Product, - product[p2] : [db]@Order_MilestonedProductTable2 - } - - meta::relational::tests::milestoning::Order[o2] : Relational{ - id : [db]OrderTable2.id, - product[p1] : [db]@Order2_Product, - product[p2] : [db]@Order2_MilestonedProductTable2 - } - - meta::relational::tests::milestoning::Product[p1] : Relational{ - id : [db]ProductTable.id, - name : [db]ProductTable.name, - synonyms : [db]@Product_SynonymNoMilestoning - } - - meta::relational::tests::milestoning::Product[p2] : Relational{ - id : [db]MilestonedProductTable2.id, - name : [db]MilestonedProductTable2.name, - synonyms : [db]@MilestonedProductTable2_SynonymNoMilestoning - } - - meta::relational::tests::milestoning::ProductSynonym : Relational{ - type : [db]ProductSynonymTableNoMilestoning.type, - synonym : [db]ProductSynonymTableNoMilestoning.synonym - } -)