Skip to content

Commit

Permalink
[Fusion] Enrich Operation Plan Snapshots (#7816)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib authored Dec 10, 2024
1 parent c443c83 commit 45d8625
Show file tree
Hide file tree
Showing 13 changed files with 261 additions and 177 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
using HotChocolate.Language;

namespace HotChocolate.Fusion.Planning.Nodes;

public sealed class RootPlanNode : PlanNode
public sealed class RequestPlanNode : PlanNode
{
private readonly List<OperationPlanNode> _operations = [];

public RequestPlanNode(DocumentNode document, string? operationName = null)
{
Document = document;
OperationName = operationName;
}

public DocumentNode Document { get; }

public string? OperationName { get; }

public IReadOnlyList<OperationPlanNode> Operations => _operations;

public void AddOperation(OperationPlanNode node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ public sealed class OperationPlanner(CompositeSchema schema)
{
private int _lastRequirementId;

public RootPlanNode CreatePlan(DocumentNode document, string? operationName)
public RequestPlanNode CreatePlan(DocumentNode document, string? operationName)
{
ArgumentNullException.ThrowIfNull(document);

var operationDefinition = document.GetOperation(operationName);
var schemasWeighted = GetSchemasWeighted(schema.QueryType, operationDefinition.SelectionSet);
var operationPlan = new RootPlanNode();
var operationPlan = new RequestPlanNode(document, operationName);

// this need to be rewritten to check if everything is planned for.
foreach (var schemaName in schemasWeighted.OrderByDescending(t => t.Value).Select(t => t.Key))
Expand Down Expand Up @@ -709,11 +709,6 @@ public record UnresolvedType(
InlineFragmentNode InlineFragment,
CompositeComplexType TypeCondition);

public class RequestPlanNode
{
public ICollection<OperationPlanNode> Operations { get; } = new List<OperationPlanNode>();
}

private record struct LookupOperation(
OperationPlanNode Operation,
FieldPlanNode Field);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal static class OperationVariableBinder
{
public static void BindOperationVariables(
OperationDefinitionNode operationDefinition,
RootPlanNode operationPlan)
RequestPlanNode operationPlan)
{
var operationBacklog = new Stack<OperationPlanNode>(operationPlan.Operations.OfType<OperationPlanNode>());
var selectionBacklog = new Stack<SelectionPlanNode>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ namespace HotChocolate.Fusion.Planning;

public static class PlanNodeJsonFormatter
{
public static string ToJson(this RootPlanNode root)
public static string ToJson(this RequestPlanNode request)
{
var buffer = new ArrayBufferWriter<byte>();
var writer = new Utf8JsonWriter(buffer, new JsonWriterOptions { Indented = true });
writer.Write(root);
writer.Write(request);
writer.Flush();
return Encoding.UTF8.GetString(buffer.WrittenSpan);
}

public static void Write(this Utf8JsonWriter writer, RootPlanNode root)
public static void Write(this Utf8JsonWriter writer, RequestPlanNode request)
{
var nodeIdLookup = CollectNodeIds(root);
var nodeIdLookup = CollectNodeIds(request);

writer.WriteStartObject();

Expand Down Expand Up @@ -105,7 +105,7 @@ private static Dictionary<OperationPlanNode, int> CollectNodeIds(PlanNode root)

while (backlog.TryDequeue(out var node))
{
if (node is RootPlanNode rootPlanNode)
if (node is RequestPlanNode rootPlanNode)
{
foreach (var child in rootPlanNode.Operations)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,38 @@ namespace HotChocolate.Fusion.Planning;

public static class PlanNodeYamlFormatter
{
public static string ToYaml(this RootPlanNode root)
public static string ToYaml(this RequestPlanNode request)
{
var sb = new StringBuilder();
var writer = new StringWriter(sb);
Write(writer, root);
Write(writer, request);
writer.Flush();
return sb.ToString();
}

public static void Write(this StringWriter writer, RootPlanNode root)
public static void Write(this StringWriter writer, RequestPlanNode request)
{
var nodeIdLookup = CollectNodeIds(root);
var nodeIdLookup = CollectNodeIds(request);

writer.WriteLine("request:");
writer.WriteLine(" - document: >-");

var reader = new StringReader(request.Document.ToString());
while (true)
{
var line = reader.ReadLine();
if (line is null)
{
break;
}

writer.WriteLine(" {0}", line);
}

if (!string.IsNullOrEmpty(request.OperationName))
{
writer.WriteLine(" - operationName: \"{0}\"", request.OperationName);
}

writer.WriteLine("nodes:");

Expand Down Expand Up @@ -84,7 +104,7 @@ private static Dictionary<OperationPlanNode, int> CollectNodeIds(PlanNode root)

while (backlog.TryDequeue(out var node))
{
if (node is RootPlanNode rootPlanNode)
if (node is RequestPlanNode rootPlanNode)
{
foreach (var child in rootPlanNode.Operations)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using HotChocolate.Fusion.Planning;
using HotChocolate.Fusion.Planning.Nodes;

namespace HotChocolate.Fusion;

public static class TestSnapshotExtensions
{
public static void MatchSnapshot(this RequestPlanNode plan)
{
plan.ToYaml().MatchSnapshot(extension: ".yaml");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ protected static CompositeSchema CreateCompositeSchema()
return CompositeSchemaBuilder.Create(compositeSchemaDoc);
}

protected static RootPlanNode PlanOperationAsync(CompositeSchema compositeSchema, string operation)
protected static RequestPlanNode PlanOperationAsync(CompositeSchema compositeSchema, string operation)
{
var doc = Utf8GraphQLParser.Parse(operation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,7 @@ fragment Product on Product {
""");

// assert
plan.ToYaml().MatchInlineSnapshot(
"""
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
{
productById(id: 1) {
id
name
}
}
""");
plan.MatchSnapshot();
}

[Test]
Expand All @@ -69,35 +56,7 @@ fragment Product on Product {
""");

// assert
plan.ToYaml().MatchInlineSnapshot(
"""
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
{
productById(id: 1) {
id
name
id
}
}
- id: 2
schema: "SHIPPING"
operation: >-
query($__fusion_requirement_1: ID!) {
productById(id: $__fusion_requirement_1) {
estimatedDelivery(postCode: "12345")
}
}
requirements:
- name: "__fusion_requirement_1"
dependsOn: "1"
selectionSet: "productById"
field: "id"
type: "ID!"
""");
plan.MatchSnapshot();
}

[Test]
Expand Down Expand Up @@ -139,56 +98,7 @@ fragment AuthorCard on UserProfile {
""");

// assert
plan.ToYaml().MatchInlineSnapshot(
"""
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
{
productById(id: 1) {
name
id
}
}
- id: 2
schema: "REVIEWS"
operation: >-
query($__fusion_requirement_2: ID!) {
productById(id: $__fusion_requirement_2) {
reviews(first: 10) {
nodes {
body
stars
author {
id
}
}
}
}
}
requirements:
- name: "__fusion_requirement_2"
dependsOn: "1"
selectionSet: "productById"
field: "id"
type: "ID!"
- id: 3
schema: "ACCOUNTS"
operation: >-
query($__fusion_requirement_1: ID!) {
userById(id: $__fusion_requirement_1) {
displayName
}
}
requirements:
- name: "__fusion_requirement_1"
dependsOn: "2"
selectionSet: "productById.reviews.nodes.author"
field: "id"
type: "ID!"
""");
plan.MatchSnapshot();
}

[Test]
Expand Down Expand Up @@ -230,56 +140,7 @@ fragment AuthorCard on UserProfile {
""");

// assert
plan.ToYaml().MatchInlineSnapshot(
"""
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
query($id: ID!) {
productById(id: $id) {
name
id
}
}
- id: 2
schema: "REVIEWS"
operation: >-
query($__fusion_requirement_2: ID!, $first: Int! = 10) {
productById(id: $__fusion_requirement_2) {
reviews(first: $first) {
nodes {
body
stars
author {
id
}
}
}
}
}
requirements:
- name: "__fusion_requirement_2"
dependsOn: "1"
selectionSet: "productById"
field: "id"
type: "ID!"
- id: 3
schema: "ACCOUNTS"
operation: >-
query($__fusion_requirement_1: ID!) {
userById(id: $__fusion_requirement_1) {
displayName
}
}
requirements:
- name: "__fusion_requirement_1"
dependsOn: "2"
selectionSet: "productById.reviews.nodes.author"
field: "id"
type: "ID!"
""");
plan.MatchSnapshot();
}

[Test]
Expand Down Expand Up @@ -313,19 +174,6 @@ ... @include(if: true) {
var plan = planner.CreatePlan(rewritten, null);

// assert
plan.ToYaml().MatchInlineSnapshot(
"""
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
{
productById(id: 1) {
id
name
}
}
""");
plan.MatchSnapshot();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
request:
- document: >-
{
productById(id: 1) {
id
name
}
}
nodes:
- id: 1
schema: "PRODUCTS"
operation: >-
{
productById(id: 1) {
id
name
}
}
Loading

0 comments on commit 45d8625

Please sign in to comment.