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

Fix issue with Query Planner ExecutionStep Requirements #6504

Merged
merged 3 commits into from
Sep 4, 2023
Merged
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 @@ -64,7 +64,9 @@ currentStep.ParentSelection is { } parent &&
roots.Add(siblingExecutionStep.SubgraphName);
}

schemas.TryAdd(siblingExecutionStep.SubgraphName, siblingExecutionStep);
// Tracks the most recent execution step (by query plan step order) targeting a given subgraph
// Replacing a previous execution step if necessary.
schemas[siblingExecutionStep.SubgraphName] = siblingExecutionStep;
}

// clean and fill requires set
Expand Down Expand Up @@ -94,7 +96,7 @@ currentStep.ParentSelection is { } parent &&
// already depends on.
var variables = OrderByUsage(step.SelectionSetTypeMetadata.Variables, currentStep);

// if we have root steps as siblings we will prfer to fulfill the requirements
// if we have root steps as siblings we will prefer to fulfill the requirements
// from these steps.
if (roots.Count > 0 && requires.Count > 0)
{
Expand Down
40 changes: 40 additions & 0 deletions src/HotChocolate/Fusion/test/Core.Tests/RequestPlannerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,46 @@ query TopProducts {
await snapshot.MatchAsync();
}

[Fact]
public async Task Query_Plan_27_Multiple_Require_Steps_From_Same_Subgraph()
{
// arrange
using var demoProject = await DemoProject.CreateAsync();

var fusionGraph = await FusionGraphComposer.ComposeAsync(
new[]
{
demoProject.Authors.ToConfiguration(),
demoProject.Books.ToConfiguration()
});

// act
var result = await CreateQueryPlanAsync(
fusionGraph,
"""
query Query {
authorById(id: "1") {
id,
name,
bio,
books {
id
author {
books {
id
}
}
}
}
}
""");

var snapshot = new Snapshot();
snapshot.Add(result.UserRequest, nameof(result.UserRequest));
snapshot.Add(result.QueryPlan, nameof(result.QueryPlan));
await snapshot.MatchAsync();
}

private static async Task<(DocumentNode UserRequest, Execution.Nodes.QueryPlan QueryPlan)> CreateQueryPlanAsync(
Skimmed.Schema fusionGraph,
[StringSyntax("graphql")] string query)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ QueryPlan
"node": {
"type": "Resolve",
"subgraph": "Reviews2",
"document": "query FetchNode_2($id: ID!) { node(id: $id) { ... on User { reviews { body } __typename } } }",
"document": "query FetchNode_2($id: ID!) { node(id: $id) { ... on User { reviews { body } __fusion_exports__2: id __typename } } }",
"selectionSetId": 0,
"forwardedVariables": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
UserRequest
---------------
query Query {
authorById(id: "1") {
id
name
bio
books {
id
author {
books {
id
}
}
}
}
}
---------------

QueryPlan
---------------
{
"document": "query Query { authorById(id: \u00221\u0022) { id name bio books { id author { books { id } } } } }",
"operation": "Query",
"rootNode": {
"type": "Sequence",
"nodes": [
{
"type": "Resolve",
"subgraph": "Authors",
"document": "query Query_1 { authorById(id: \u00221\u0022) { id name bio __fusion_exports__1: id } }",
"selectionSetId": 0,
"provides": [
{
"variable": "__fusion_exports__1"
},
{
"variable": "__fusion_exports__2"
}
]
},
{
"type": "Compose",
"selectionSetIds": [
0
]
},
{
"type": "Parallel",
"nodes": [
{
"type": "Resolve",
"subgraph": "Books",
"document": "query Query_2($__fusion_exports__1: String!) { authorById(id: $__fusion_exports__1) { books { id } } }",
"selectionSetId": 1,
"path": [
"authorById"
],
"requires": [
{
"variable": "__fusion_exports__1"
}
]
},
{
"type": "Resolve",
"subgraph": "Authors",
"document": "query Query_3($__fusion_exports__2: String!) { bookByAuthorId(authorId: $__fusion_exports__2) { author { __fusion_exports__3: id } } }",
"selectionSetId": 2,
"path": [
"bookByAuthorId"
],
"requires": [
{
"variable": "__fusion_exports__2"
}
],
"provides": [
{
"variable": "__fusion_exports__3"
}
]
}
]
},
{
"type": "Compose",
"selectionSetIds": [
1,
2
]
},
{
"type": "Resolve",
"subgraph": "Books",
"document": "query Query_4($__fusion_exports__3: String!) { authorById(id: $__fusion_exports__3) { books { id } } }",
"selectionSetId": 3,
"path": [
"authorById"
],
"requires": [
{
"variable": "__fusion_exports__3"
}
]
},
{
"type": "Compose",
"selectionSetIds": [
3
]
}
]
},
"state": {
"__fusion_exports__1": "Author_id",
"__fusion_exports__2": "Book_authorId",
"__fusion_exports__3": "Author_id"
}
}
---------------
16 changes: 16 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Authors/Author.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace HotChocolate.Fusion.Shared.Authors;

public class Author
{
public string Id { get; set;}

public string Name { get; set; }

public string Bio { get; set;}

public Author(string id, string name, string bio) {
this.Id = id;
this.Name = name;
this.Bio = bio;
}
}
20 changes: 20 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Authors/AuthorQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace HotChocolate.Fusion.Shared.Authors;

[GraphQLName("Query")]
public sealed class AuthorQuery
{
public Author? AuthorById(
string id,
[Service] AuthorRepository repository)
=> repository.GetAuthorById(id);

public IEnumerable<Author> Authors(int limit, [Service] AuthorRepository repository)
=> repository.GetAuthors(limit);

public Book BookByAuthorId(
string authorId,
[Service] AuthorRepository repository) {
Author author = repository.GetAuthorById(authorId);
return new Book(authorId, author);
}
}
22 changes: 22 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Authors/AuthorRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace HotChocolate.Fusion.Shared.Authors;

public sealed class AuthorRepository
{
private readonly Dictionary<string, Author> _authors;

public AuthorRepository()
{
_authors = new[]
{
new Author("1", "First author", "The first author")
}.ToDictionary(t => t.Id);
}

public IEnumerable<Author> GetAuthors(int limit)
=> _authors.Values.OrderBy(t => t.Id).Take(limit);

public Author? GetAuthorById(string id)
=> _authors.TryGetValue(id, out var author)
? author
: null;
}
15 changes: 15 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Authors/Book.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

namespace HotChocolate.Fusion.Shared.Authors;

public class Book
{

michaelstaib marked this conversation as resolved.
Show resolved Hide resolved
public string AuthorId { get; set;}

public Author Author {get; set; }

public Book(string authorId, Author author) {
this.AuthorId = authorId;
this.Author = author;
}
}
14 changes: 14 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Books/Author.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace HotChocolate.Fusion.Shared.Books;


public class Author
{
public string Id { get; set;}

public IEnumerable<Book> Books { get; set; }

public Author(string id, IEnumerable<Book> books) {
this.Id = id;
this.Books = books;
}
}
17 changes: 17 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Books/Book.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace HotChocolate.Fusion.Shared.Books;

public class Book
{
public string Id { get; set;}

public string AuthorId { get; set;}

public string Title {get; set; }


public Book(string id, string authorId, string title) {
this.Id = id;
this.AuthorId = authorId;
this.Title = title;
}
}
18 changes: 18 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Books/BookQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace HotChocolate.Fusion.Shared.Books;

[GraphQLName("Query")]
public sealed class BookQuery
{
public Book? BookById(
string id,
[Service] BookRepository repository)
=> repository.GetBookById(id);

public IEnumerable<Book> Books(int limit, [Service] BookRepository repository)
=> repository.GetBooks(limit);

public Author authorById(
string id,
[Service] BookRepository repository)
=> new Author(id, repository.GetBooksByAuthorId(id));
}
25 changes: 25 additions & 0 deletions src/HotChocolate/Fusion/test/Shared/Books/BookRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace HotChocolate.Fusion.Shared.Books;

public sealed class BookRepository
{
private readonly Dictionary<string, Book> _books;

public BookRepository()
{
_books = new[]
{
new Book("1", "1", "The first book")
}.ToDictionary(t => t.Id);
}

public IEnumerable<Book> GetBooks(int limit)
=> _books.Values.OrderBy(t => t.Id).Take(limit);

public Book? GetBookById(string id)
=> _books.TryGetValue(id, out var book)
? book
: null;

public IEnumerable<Book> GetBooksByAuthorId(string authorId)
=> _books.Values.Where(b => b.AuthorId.Equals(authorId));
}
Loading
Loading