Description
openedon Jul 4, 2024
Product
Hot Chocolate
Version
13.9.6
Link to minimal reproduction
https://github.com/wietlol-org/HotChocolateIssues/tree/main/HotChocolateIssues.AnyTypeDataOmission
Steps to reproduce
Run the unit tests in the HotChocolateIssues.AnyTypeDataOmission project.
The test GetBooks will fail.
After running the tests, the output is written to the TestFiles folder where the erroneous response is presented.
What is expected?
When creating a query/mutation with output of type AnyType.
The data should all be present in the output.
What is actually happening?
Data that was already written to the output is omitted.
Given the following query definitions:
[GraphQLType<AnyType>]
public List<Book> GetBooksAny() =>
GetBooks();
public List<Book> GetBooks() =>
[
new Book(
Title: "C# for dummies",
Author: new Author(
Name: "Jon Skeet"
)
),
new Book(
Title: "Hot Chocolate: A .NET GraphQl server",
Author: new Author(
Name: "Michael Staib"
)
),
new Book(
Title: "C# in depth.",
Author: new Author(
Name: "Jon Skeet"
)
),
];
Running the following query:
query {
books {
title
author {
name
}
}
booksAny
}
Gives the following output:
{
"data": {
"books": [
{
"title": "C# for dummies",
"author": {
"name": "Jon Skeet"
}
},
{
"title": "Hot Chocolate: A .NET GraphQl server",
"author": {
"name": "Michael Staib"
}
},
{
"title": "C# in depth.",
"author": {
"name": "Jon Skeet"
}
}
],
"booksAny": [
{
"title": "C# for dummies",
"author": {
"name": "Jon Skeet"
}
},
{
"title": "Hot Chocolate: A .NET GraphQl server",
"author": {
"name": "Michael Staib"
}
},
{
"title": "C# in depth."
}
]
}
}
As you can see, the author
is omitted in the booksAny
output because the value is already present in the same output.
The equality is based on the class' implementation of Equals and HashCode, which for records is value-equality by default.
But this would be the same effect for any class/struct that has an implementation of Equals and HashCode that would consider it equal to another value that is in the output.
Looking at HotChocolate.Types.AnyType.cs
line 151, the AnyType deliberately skips values that are already processed.
if (set.Add(value))
uses a HashSet<object>
to check if the value was already processed.
This is probably added to prevent some form of recursive tree structure of generating an infinite recursion.
But this breaks the usage in the above example, where data is just not present and it becomes impossible to know what data should be there.
The output of books
and booksAny
should be the same.
Relevant log output
No response
Additional context
No response