Skip to content

Commit

Permalink
Fixed node field projections when nothing is selected. (#7554)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Oct 3, 2024
1 parent f2a93cb commit b7b3910
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public Expression<Func<TRoot, TRoot>> BuildNodeExpression<TRoot>(ISelection sele

if (typeNode.Nodes.Count == 0)
{
TryAddAnyLeafField(selection, typeNode);
TryAddAnyLeafField(typeNode, entityType);
}

CollectTypes(context, selection, root);
Expand Down Expand Up @@ -90,7 +90,7 @@ private void CollectTypes(Context context, ISelection selection, TypeContainer p

if (possibleTypeNode.Nodes.Count == 0)
{
TryAddAnyLeafField(selection, possibleTypeNode);
TryAddAnyLeafField(possibleTypeNode, possibleType);
}
}

Expand All @@ -105,7 +105,7 @@ private void CollectTypes(Context context, ISelection selection, TypeContainer p

if (typeNode.Nodes.Count == 0)
{
TryAddAnyLeafField(selection, typeNode);
TryAddAnyLeafField(typeNode, objectType);
}
}

Expand Down Expand Up @@ -201,22 +201,21 @@ private void CollectSelection(
}

private static void TryAddAnyLeafField(
ISelection selection,
TypeNode parent)
TypeNode parent,
IObjectType selectionType)
{
// if we could not collect anything it means that either all fields
// are skipped or that __typename is the only field that is selected.
// in this case we will try to select the id field or if that does
// not exist we will look for a leaf field that we can select.
var type = (ObjectType)selection.Type.NamedType();
if (type.Fields.TryGetField("id", out var idField)
if (selectionType.Fields.TryGetField("id", out var idField)
&& idField.Member is PropertyInfo idProperty)
{
parent.AddOrGetNode(idProperty);
}
else
{
var anyProperty = type.Fields.FirstOrDefault(t => t.Type.IsLeafType() && t.Member is PropertyInfo);
var anyProperty = selectionType.Fields.FirstOrDefault(t => t.Type.IsLeafType() && t.Member is PropertyInfo);
if (anyProperty?.Member is PropertyInfo anyPropertyInfo)
{
parent.AddOrGetNode(anyPropertyInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using HotChocolate.Execution.Processing;
using HotChocolate.Execution.TestContext;
using HotChocolate.Types;
using HotChocolate.Types.Relay;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Squadron;
Expand Down Expand Up @@ -664,6 +665,108 @@ public async Task Brand_Only_TypeName()
.MatchMarkdownSnapshot();
}


[Fact]
public async Task Brand_With_Id_And_Name_Over_Node()
{
// Arrange
var queries = new List<string>();
var connectionString = CreateConnectionString();
await CatalogContext.SeedAsync(connectionString);

// Act
var result = await new ServiceCollection()
.AddScoped(_ => queries)
.AddTransient(_ => new CatalogContext(connectionString))
.AddGraphQL()
.AddQueryType<NodeQuery>()
.AddGlobalObjectIdentification()
.AddPagingArguments()
.ModifyRequestOptions(o => o.IncludeExceptionDetails = true)
.ExecuteRequestAsync(
"""
{
node(id: "QnJhbmQ6MQ==") {
id
... on Brand {
name
}
}
}
""");

Snapshot.Create()
.AddSql(queries)
.AddResult(result)
.MatchMarkdownSnapshot();
}

[Fact]
public async Task Brand_With_Name_Over_Node()
{
// Arrange
var queries = new List<string>();
var connectionString = CreateConnectionString();
await CatalogContext.SeedAsync(connectionString);

// Act
var result = await new ServiceCollection()
.AddScoped(_ => queries)
.AddTransient(_ => new CatalogContext(connectionString))
.AddGraphQL()
.AddQueryType<NodeQuery>()
.AddGlobalObjectIdentification()
.AddPagingArguments()
.ModifyRequestOptions(o => o.IncludeExceptionDetails = true)
.ExecuteRequestAsync(
"""
{
node(id: "QnJhbmQ6MQ==") {
... on Brand {
name
}
}
}
""");

Snapshot.Create()
.AddSql(queries)
.AddResult(result)
.MatchMarkdownSnapshot();
}

[Fact]
public async Task Brand_With_Default_Field_Over_Node()
{
// Arrange
var queries = new List<string>();
var connectionString = CreateConnectionString();
await CatalogContext.SeedAsync(connectionString);

// Act
var result = await new ServiceCollection()
.AddScoped(_ => queries)
.AddTransient(_ => new CatalogContext(connectionString))
.AddGraphQL()
.AddQueryType<NodeQuery>()
.AddGlobalObjectIdentification()
.AddPagingArguments()
.ModifyRequestOptions(o => o.IncludeExceptionDetails = true)
.ExecuteRequestAsync(
"""
{
node(id: "QnJhbmQ6MQ==") {
__typename
}
}
""");

Snapshot.Create()
.AddSql(queries)
.AddResult(result)
.MatchMarkdownSnapshot();
}

public class Query
{
public async Task<Brand?> GetBrandByIdAsync(
Expand Down Expand Up @@ -708,6 +811,17 @@ public class Query
=> await brandById.Select(default(Expression<Func<Brand, Brand>>)).LoadAsync(id, cancellationToken);
}

public class NodeQuery
{
[NodeResolver]
public async Task<Brand?> GetBrandByIdAsync(
int id,
ISelection selection,
BrandByIdDataLoader brandById,
CancellationToken cancellationToken)
=> await brandById.Select(selection).LoadAsync(id, cancellationToken);
}

[ExtendObjectType<Brand>]
public class BrandExtensions
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Brand_With_Default_Field_Over_Node

## SQL

```text
-- @__keys_0={ '1' } (DbType = Object)
SELECT b."Id"
FROM "Brands" AS b
WHERE b."Id" = ANY (@__keys_0)
```

## Result

```json
{
"data": {
"node": {
"__typename": "Brand"
}
}
}
```

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Brand_With_Id_And_Name_Over_Node

## SQL

```text
-- @__keys_0={ '1' } (DbType = Object)
SELECT b."Id", b."Name"
FROM "Brands" AS b
WHERE b."Id" = ANY (@__keys_0)
```

## Result

```json
{
"data": {
"node": {
"id": "QnJhbmQ6MQ==",
"name": "Brand0"
}
}
}
```

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

```text
-- @__keys_0={ '1' } (DbType = Object)
SELECT b."Id", b."Name"
SELECT b."Name", b."Id"
FROM "Brands" AS b
WHERE b."Id" = ANY (@__keys_0)
```
Expand All @@ -15,7 +15,6 @@ WHERE b."Id" = ANY (@__keys_0)
{
"data": {
"node": {
"id": "QnJhbmQ6MQ==",
"name": "Brand0"
}
}
Expand Down

0 comments on commit b7b3910

Please sign in to comment.