Skip to content

Commit 8607cec

Browse files
authored
[Fusion] Add support for result from different subgraph on interfaces (#8293)
1 parent 9262b2e commit 8607cec

File tree

3 files changed

+169
-7
lines changed

3 files changed

+169
-7
lines changed

src/HotChocolate/Fusion/src/Core/Planning/Pipeline/ExecutionStepDiscoveryMiddleware.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,14 +435,44 @@ private void CollectNestedSelections(
435435
subgraph.Add(executionStep.SubgraphName);
436436
}
437437

438-
backlog.Enqueue(
439-
new BacklogItem(
440-
parentSelection,
441-
selectionSetPath,
442-
declaringType,
443-
leftovers,
444-
preferBatching));
438+
TryEnqueueBacklogItem(
439+
backlog,
440+
parentSelection,
441+
selectionSetPath,
442+
declaringType,
443+
leftovers,
444+
preferBatching
445+
);
446+
}
447+
}
448+
449+
private static void TryEnqueueBacklogItem(
450+
Queue<BacklogItem> backlog,
451+
ISelection parentSelection,
452+
SelectionPath? selectionSetPath,
453+
ObjectTypeMetadata declaringType,
454+
List<ISelection> leftovers,
455+
bool preferBatching)
456+
{
457+
foreach (var item in backlog)
458+
{
459+
if ((item.SelectionPath?.Equals(selectionSetPath) ?? selectionSetPath is null) &&
460+
item.DeclaringTypeMetadata == declaringType &&
461+
item.PreferBatching == preferBatching &&
462+
item.Selections.Count == leftovers.Count &&
463+
item.Selections.SequenceEqual(leftovers))
464+
{
465+
return;
466+
}
445467
}
468+
469+
backlog.Enqueue(
470+
new BacklogItem(
471+
parentSelection,
472+
selectionSetPath,
473+
declaringType,
474+
leftovers,
475+
preferBatching));
446476
}
447477

448478
private static SelectionPath? CreateSelectionPath(SelectionPath? rootPath, List<ISelection> pathSegments)

src/HotChocolate/Fusion/test/Core.Tests/RequestPlannerTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,71 @@ type Query {
27942794
await snapshot.MatchMarkdownAsync();
27952795
}
27962796

2797+
[Fact]
2798+
public async Task Subgraph_Requested_On_Interface_Called_Only_Once()
2799+
{
2800+
// arrange
2801+
var subgraphA = await TestSubgraph.CreateAsync(
2802+
"""
2803+
schema {
2804+
query: Query
2805+
}
2806+
2807+
type Query {
2808+
books: [Book!]!
2809+
}
2810+
2811+
interface Book {
2812+
author: Author!
2813+
}
2814+
2815+
type FunnyBook implements Book {
2816+
author: Author!
2817+
}
2818+
2819+
type ScaryBook implements Book {
2820+
author: Author!
2821+
}
2822+
2823+
type Author {
2824+
id: Int!
2825+
}
2826+
"""
2827+
);
2828+
2829+
var subgraphB = await TestSubgraph.CreateAsync(
2830+
"""
2831+
schema {
2832+
query: Query
2833+
}
2834+
2835+
type Query {
2836+
authorById(id: [Int!]!): [Author!]!
2837+
}
2838+
2839+
type Author {
2840+
id: Int!
2841+
name: String!
2842+
}
2843+
"""
2844+
);
2845+
2846+
using var subgraphs = new TestSubgraphCollection(output, [subgraphA, subgraphB]);
2847+
var fusionGraph = await subgraphs.GetFusionGraphAsync();
2848+
2849+
// act
2850+
var result = await CreateQueryPlanAsync(
2851+
fusionGraph,
2852+
//"query { subgraph2Foo { name } }");
2853+
"query { books { author { name } } }");
2854+
2855+
// assert
2856+
var snapshot = new Snapshot();
2857+
snapshot.Add(result.UserRequest, nameof(result.UserRequest));
2858+
snapshot.Add(result.QueryPlan, nameof(result.QueryPlan));
2859+
await snapshot.MatchMarkdownAsync();
2860+
}
2861+
27972862
private static async Task<(DocumentNode UserRequest, Execution.Nodes.QueryPlan QueryPlan)> CreateQueryPlanAsync(
27982863
Skimmed.SchemaDefinition fusionGraph,
27992864
[StringSyntax("graphql")] string query)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Subgraph_Requested_On_Interface_Called_Only_Once
2+
3+
## UserRequest
4+
5+
```graphql
6+
{
7+
books {
8+
author {
9+
name
10+
}
11+
}
12+
}
13+
```
14+
15+
## QueryPlan
16+
17+
```json
18+
{
19+
"document": "{ books { author { name } } }",
20+
"rootNode": {
21+
"type": "Sequence",
22+
"nodes": [
23+
{
24+
"type": "Resolve",
25+
"subgraph": "Subgraph_1",
26+
"document": "query fetch_books_1 { books { __typename ... on ScaryBook { author { __fusion_exports__1: id } } ... on FunnyBook { author { __fusion_exports__1: id } } } }",
27+
"selectionSetId": 0,
28+
"provides": [
29+
{
30+
"variable": "__fusion_exports__1"
31+
}
32+
]
33+
},
34+
{
35+
"type": "Compose",
36+
"selectionSetIds": [
37+
0
38+
]
39+
},
40+
{
41+
"type": "ResolveByKeyBatch",
42+
"subgraph": "Subgraph_2",
43+
"document": "query fetch_books_2($__fusion_exports__1: [Int!]!) { authorById(id: $__fusion_exports__1) { name __fusion_exports__1: id } }",
44+
"selectionSetId": 3,
45+
"path": [
46+
"authorById"
47+
],
48+
"requires": [
49+
{
50+
"variable": "__fusion_exports__1"
51+
}
52+
]
53+
},
54+
{
55+
"type": "Compose",
56+
"selectionSetIds": [
57+
3
58+
]
59+
}
60+
]
61+
},
62+
"state": {
63+
"__fusion_exports__1": "Author_id"
64+
}
65+
}
66+
```
67+

0 commit comments

Comments
 (0)