Skip to content

Commit 884a0e9

Browse files
[Fusion] Rewrite conditionals in document (#8734)
1 parent 75975d6 commit 884a0e9

File tree

44 files changed

+10065
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+10065
-57
lines changed

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationCompiler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace HotChocolate.Fusion.Execution.Nodes;
1010
public sealed class OperationCompiler
1111
{
1212
private readonly ISchemaDefinition _schema;
13-
private readonly InlineFragmentOperationRewriter _inlineRewriter;
13+
private readonly DocumentRewriter _documentRewriter;
1414
private readonly ObjectPool<OrderedDictionary<string, List<FieldSelectionNode>>> _fieldsPool;
1515
private readonly TypeNameField _typeNameField;
1616
private static readonly ArrayPool<object> s_objectArrayPool = ArrayPool<object>.Shared;
@@ -24,7 +24,7 @@ public OperationCompiler(
2424

2525
_schema = schema;
2626
_fieldsPool = fieldsPool;
27-
_inlineRewriter = new InlineFragmentOperationRewriter(schema, removeStaticallyExcludedSelections: true);
27+
_documentRewriter = new(schema, removeStaticallyExcludedSelections: true);
2828
var nonNullStringType = new NonNullType(_schema.Types.GetType<IScalarTypeDefinition>(SpecScalarNames.String));
2929
_typeNameField = new TypeNameField(nonNullStringType);
3030
}
@@ -35,7 +35,7 @@ public Operation Compile(string id, string hash, OperationDefinitionNode operati
3535
ArgumentNullException.ThrowIfNull(operationDefinition);
3636

3737
var document = new DocumentNode(new IDefinitionNode[] { operationDefinition });
38-
document = _inlineRewriter.RewriteDocument(document);
38+
document = _documentRewriter.RewriteDocument(document);
3939
operationDefinition = (OperationDefinitionNode)document.Definitions[0];
4040

4141
var includeConditions = new IncludeConditionCollection();

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationPlanMiddleware.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace HotChocolate.Fusion.Execution.Pipeline;
1111
internal sealed class OperationPlanMiddleware
1212
{
1313
private readonly OperationPlanner _planner;
14-
private readonly InlineFragmentOperationRewriter _rewriter;
14+
private readonly DocumentRewriter _documentRewriter;
1515
private readonly IOperationPlannerInterceptor[] _interceptors;
1616
private readonly IFusionExecutionDiagnosticEvents _diagnosticsEvents;
1717

@@ -21,7 +21,7 @@ private OperationPlanMiddleware(
2121
IEnumerable<IOperationPlannerInterceptor>? interceptors,
2222
IFusionExecutionDiagnosticEvents diagnosticsEvents)
2323
{
24-
_rewriter = new InlineFragmentOperationRewriter(schema);
24+
_documentRewriter = new(schema, removeStaticallyExcludedSelections: true);
2525
_planner = planner;
2626
_interceptors = interceptors?.ToArray() ?? [];
2727
_diagnosticsEvents = diagnosticsEvents;
@@ -60,8 +60,8 @@ private void PlanOperation(
6060

6161
try
6262
{
63-
// Before we can plan an operation, we must defragmentize it and remove statical include conditions.
64-
var rewritten = _rewriter.RewriteDocument(operationDocument, context.Request.OperationName);
63+
// Before we can plan an operation, we must de-fragmentize it and remove static include conditions.
64+
var rewritten = _documentRewriter.RewriteDocument(operationDocument, context.Request.OperationName);
6565
var operation = rewritten.GetOperation(context.Request.OperationName);
6666

6767
// After optimizing the query structure we can begin the planning process.

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Planning/OperationPlanner.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,7 @@ private OperationDefinitionNode InlineSelections(
12761276
bool inlineInternal = false)
12771277
{
12781278
List<SelectionSetNode>? backlog = null;
1279+
var didInline = false;
12791280

12801281
var rewriter = SyntaxRewriter.Create<List<ISyntaxNode>>(
12811282
rewrite: (node, path) =>
@@ -1337,6 +1338,8 @@ private OperationDefinitionNode InlineSelections(
13371338
index);
13381339
}
13391340

1341+
didInline = true;
1342+
13401343
index.Register(originalSelectionSet, newSelectionSet);
13411344
return newSelectionSet;
13421345
},
@@ -1347,7 +1350,16 @@ private OperationDefinitionNode InlineSelections(
13471350
},
13481351
leave: (_, path) => path.Pop());
13491352

1350-
return (OperationDefinitionNode)rewriter.Rewrite(operation, [])!;
1353+
var rewrittenOperation = (OperationDefinitionNode)rewriter.Rewrite(operation, [])!;
1354+
1355+
if (!didInline)
1356+
{
1357+
throw new InvalidOperationException(
1358+
$"Selections `{selectionsToInline}` could not be inlined into selection set of type "
1359+
+ $"'{selectionSetType.Name}', as no selection set with the id {targetSelectionSetId} was found.");
1360+
}
1361+
1362+
return rewrittenOperation;
13511363

13521364
static IReadOnlyList<DirectiveNode> AddInternalDirective(IHasDirectives selection)
13531365
{

src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Planning/Partitioners/NodeFieldSelectionSetPartitioner.cs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,40 +49,32 @@ public RootSelectionSetPartitionerResult Partition(RootSelectionSetPartitionerIn
4949
{
5050
switch (selection)
5151
{
52-
case FieldNode fieldNode when schema.QueryType.Fields.TryGetField(fieldNode.Name.Value, out var field)
53-
&& field is { Name: "node", Type: IInterfaceTypeDefinition { Name: "Node" } }:
54-
var directives = new List<DirectiveNode>(fieldNode.Directives);
55-
foreach (var fragment in context.FragmentPath)
52+
case FieldNode fieldNode:
53+
var field = schema.QueryType.Fields[fieldNode.Name.Value];
54+
55+
if (field.IsIntrospectionField)
5656
{
57-
directives.AddRange(fragment.Directives);
57+
continue;
5858
}
5959

60-
context.NodeFields ??= [];
61-
context.NodeFields.Add(fieldNode.WithDirectives(directives));
62-
break;
60+
if (field is { Name: "node", Type: IInterfaceTypeDefinition { Name: "Node" } })
61+
{
62+
context.NodeFields ??= [];
63+
context.NodeFields.Add(fieldNode);
64+
}
65+
else
66+
{
67+
selections ??= [];
68+
selections.Add(selection);
69+
}
6370

64-
case FieldNode:
65-
selections ??= [];
66-
selections.Add(selection);
6771
break;
6872

6973
case InlineFragmentNode inlineFragmentNode:
70-
var hasDirectives = inlineFragmentNode.Directives.Any();
71-
72-
if (hasDirectives)
73-
{
74-
context.FragmentPath.Push(inlineFragmentNode);
75-
}
76-
7774
var fragmentSelectionSet = RewriteSelectionSet(
7875
inlineFragmentNode.SelectionSet,
7976
context);
8077

81-
if (hasDirectives)
82-
{
83-
context.FragmentPath.Pop();
84-
}
85-
8678
if (fragmentSelectionSet is not null)
8779
{
8880
selections ??= [];
@@ -103,13 +95,6 @@ public RootSelectionSetPartitionerResult Partition(RootSelectionSetPartitionerIn
10395

10496
private class Context
10597
{
106-
/// <summary>
107-
/// Gets the fragment path.
108-
/// This is pushed to whenever we enter an inline fragment with directives,
109-
/// in order to preserve those.
110-
/// </summary>
111-
public List<InlineFragmentNode> FragmentPath { get; } = [];
112-
11398
public List<FieldNode>? NodeFields { get; set; }
11499
}
115100
}

0 commit comments

Comments
 (0)