Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fusion] Add support for viewer convention #8000

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ internal FusionGraphComposer(
.Use<MergeSchemaDefinitionMiddleware>()
.Use<MergeSubscriptionTypeMiddleware>()
.Use<NodeMiddleware>()
.Use<ViewerMiddleware>()
.Use<ApplyTagDirectiveMiddleware>()
.Use<ApplyExcludeTagMiddleware>()
.Use<RemoveFusionTypesMiddleware>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ public async ValueTask InvokeAsync(CompositionContext context, MergeDelegate nex

if (fusionGraph.QueryType is not null &&
context.Features.IsNodeFieldSupported() &&
fusionGraph.QueryType.Fields.TryGetField("node", out var nodeField))
fusionGraph.QueryType.Fields.ContainsName("node"))
{
fusionGraph.QueryType.Fields.TryGetField("nodes", out var nodesField);

var nodes = new HashSet<ObjectTypeDefinition>();

foreach (var schema in context.Subgraphs)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using HotChocolate.Language;
using HotChocolate.Skimmed;

namespace HotChocolate.Fusion.Composition.Pipeline;

internal sealed class ViewerMiddleware : IMergeMiddleware
{
public async ValueTask InvokeAsync(CompositionContext context, MergeDelegate next)
{
var fusionGraph = context.FusionGraph;
var fusionTypes = context.FusionTypes;

if (fusionGraph.QueryType is not null &&
fusionGraph.QueryType.Fields.TryGetField("viewer", out var viewerField) &&
viewerField.Type.NamedType() is ObjectTypeDefinition { Name: "Viewer" } viewerType)
{
var viewerSelectionNode = new SelectionSetNode([new FieldNode("viewer")]);

foreach (var subgraphSchema in context.Subgraphs)
{
if (subgraphSchema.QueryType is not null &&
subgraphSchema.QueryType.Fields.TryGetField("viewer", out var subgraphViewerField) &&
subgraphViewerField.Type.NamedType() is ObjectTypeDefinition { Name: "Viewer" })
{
viewerType.Directives.Add(fusionTypes.CreateResolverDirective(subgraphSchema.Name, viewerSelectionNode));
}
}
}

if (!context.Log.HasErrors)
{
await next(context).ConfigureAwait(false);
}
}
}
64 changes: 64 additions & 0 deletions src/HotChocolate/Fusion/test/Core.Tests/DemoIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,70 @@ type ResaleSurveyFeedback {
await snapshot.MatchMarkdownAsync();
}

[Fact]
public async Task Viewer_Returned_From_Mutation_With_Selection_On_Another_Subgraph()
{
// arrange
var subgraphA = await TestSubgraph.CreateAsync(
"""
type Query {
viewer: Viewer
}

type Mutation {
doSomething: DoSomethingPayload
}

type DoSomethingPayload {
something: Int
viewer: Viewer
}

type Viewer {
subgraphA: String
}
""");
var subgraphB = await TestSubgraph.CreateAsync(
"""
type Query {
viewer: Viewer
}

type Viewer {
subgraphB: String
}
""");

using var subgraphs = new TestSubgraphCollection(output, [subgraphA, subgraphB]);
var executor = await subgraphs.GetExecutorAsync();

var request = Parse(
"""
mutation {
doSomething {
something
viewer {
subgraphA
subgraphB
}
}
}

""");

// act
await using var result = await executor.ExecuteAsync(
OperationRequestBuilder
.New()
.SetDocument(request)
.Build());

// assert
var snapshot = new Snapshot();
CollectSnapshotData(snapshot, request, result);
await snapshot.MatchMarkdownAsync();
}

public sealed class HotReloadConfiguration : IObservable<GatewayConfiguration>
{
private GatewayConfiguration _configuration;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Viewer_Returned_From_Mutation_With_Selection_On_Another_Subgraph

## Result

```json
{
"data": {
"doSomething": {
"something": 123,
"viewer": {
"subgraphA": "string",
"subgraphB": "string"
}
}
}
}
```

## Request

```graphql
mutation {
doSomething {
something
viewer {
subgraphA
subgraphB
}
}
}
```

## QueryPlan Hash

```text
3BAD760CBB742706BF2DEDB9CA40F8DA880B22CC
```

## QueryPlan

```json
{
"document": "mutation { doSomething { something viewer { subgraphA subgraphB } } }",
"rootNode": {
"type": "Sequence",
"nodes": [
{
"type": "Resolve",
"subgraph": "Subgraph_1",
"document": "mutation fetch_doSomething_1 { doSomething { something viewer { subgraphA } } }",
"selectionSetId": 0
},
{
"type": "Compose",
"selectionSetIds": [
0
]
},
{
"type": "Resolve",
"subgraph": "Subgraph_2",
"document": "query fetch_doSomething_2 { viewer { subgraphB } }",
"selectionSetId": 2,
"path": [
"viewer"
]
},
{
"type": "Compose",
"selectionSetIds": [
2
]
}
]
}
}
```

Loading