Skip to content

Commit

Permalink
Fixed infer arguments when using lookup. (#7552)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Oct 3, 2024
1 parent f72f117 commit f2a93cb
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public FusionGraphComposer(
Func<ICompositionLog>? logFactory = null)
: this(
[
new LookupEntityEnricher(),
new RefResolverEntityEnricher(),
new PatternEntityEnricher(),
new RequireEnricher(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Runtime.CompilerServices;
using HotChocolate.Language;
using HotChocolate.Skimmed;
using HotChocolate.Types;

namespace HotChocolate.Fusion.Composition.Pipeline;

/// <summary>
/// A pipeline enricher that processes entity groups and adds entity resolvers to
/// metadata for all arguments that contain the @ref directive.
/// </summary>
internal sealed class LookupEntityEnricher : IEntityEnricher
{
/// <inheritdoc />
public ValueTask EnrichAsync(
CompositionContext context,
EntityGroup entity,
CancellationToken cancellationToken = default)
{
foreach (var (type, schema) in entity.Parts)
{
// Check if the schema has a query type
if (schema.QueryType is null)
{
continue;
}

if (!schema.DirectiveDefinitions.TryGetDirective("is", out var isDirective))
{
if(!schema.Types.TryGetType(BuiltIns.String.Name, out var stringType))
{
stringType = BuiltIns.String.Create();
schema.Types.Add(stringType);
}

isDirective = new DirectiveDefinition("is");
isDirective.Arguments.Add(new InputFieldDefinition("field", stringType));
schema.DirectiveDefinitions.Add(isDirective);
}

// Loop through each query field
foreach (var entityResolverField in schema.QueryType.Fields)
{
if (entityResolverField.Directives.ContainsName("lookup"))
{
foreach (var argument in entityResolverField.Arguments)
{
if (!argument.ContainsIsDirective())
{
argument.Directives.Add(
new Directive(
isDirective,
new ArgumentAssignment("field", argument.Name)));
}
}
}
}
}

return default;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public async Task Accounts_And_Reviews()
var fusionConfig = await composer.ComposeAsync(
[
demoProject.Accounts.ToConfiguration(AccountsExtensionSdl),
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl)
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl)
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
Expand All @@ -37,7 +37,7 @@ public async Task Accounts_And_Reviews_Infer_Patterns()
var fusionConfig = await composer.ComposeAsync(
[
demoProject.Accounts.ToConfiguration(),
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl)
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl)
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
Expand All @@ -54,8 +54,8 @@ public async Task Accounts_And_Reviews_Products()
var fusionConfig = await composer.ComposeAsync(
[
demoProject.Accounts.ToConfiguration(AccountsExtensionSdl),
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl),
demoProject.Products.ToConfiguration(ProductsExtensionSdl)
demoProject.Reviews.ToConfiguration(ReviewsExtensionSdl),
demoProject.Products.ToConfiguration(ProductsExtensionSdl)
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
Expand Down Expand Up @@ -110,8 +110,8 @@ public async Task Accounts_And_Reviews_Products_AutoCompose_With_Node()
var fusionConfig = await composer.ComposeAsync(
[
demoProject.Accounts.ToConfiguration(),
demoProject.Reviews.ToConfiguration(),
demoProject.Products.ToConfiguration()
demoProject.Reviews.ToConfiguration(),
demoProject.Products.ToConfiguration()
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
Expand All @@ -135,4 +135,86 @@ public async Task Compose_With_SourceSchema_Lib()

fusionConfig.MatchSnapshot(extension: ".graphql");
}

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

var composer = new FusionGraphComposer(logFactory: _logFactory);

var fusionConfig = await composer.ComposeAsync(
[
new SubgraphConfiguration(
"Schema1",
"""
schema {
query: Query
}
type Query {
user(id: Int! @is(field: "id")): User @lookup
}
type User {
id: Int!
name: String!
email: String!
password: String!
}
""",
Array.Empty<string>(),
[
new HttpClientConfiguration(
new Uri("http://localhost:5000/graphql"),
"Schema1")
],
default)
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
}

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

var composer = new FusionGraphComposer(logFactory: _logFactory);

var fusionConfig = await composer.ComposeAsync(
[
new SubgraphConfiguration(
"Schema1",
"""
schema {
query: Query
}
type Query {
user(id: Int!): User @lookup
}
type User {
id: Int!
name: String!
email: String!
password: String!
}
""",
Array.Empty<string>(),
[
new HttpClientConfiguration(
new Uri("http://localhost:5000/graphql"),
"Schema1")
],
default)
]);

fusionConfig.MatchSnapshot(extension: ".graphql");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
schema
@fusion(version: 1)
@transport(subgraph: "Schema1", group: "Schema1", location: "http:\/\/localhost:5000\/graphql", kind: "HTTP") {
query: Query
}

type Query {
user(id: Int!): User
@variable(subgraph: "Schema1", name: "id", argument: "id")
@resolver(subgraph: "Schema1", select: "{ user(id: $id) }", arguments: [ { name: "id", type: "Int!" } ])
}

type User
@variable(subgraph: "Schema1", name: "User_id", select: "id")
@resolver(subgraph: "Schema1", select: "{ user(id: $User_id) }", arguments: [ { name: "User_id", type: "Int!" } ]) {
email: String!
@source(subgraph: "Schema1")
id: Int!
@source(subgraph: "Schema1")
name: String!
@source(subgraph: "Schema1")
password: String!
@source(subgraph: "Schema1")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
schema
@fusion(version: 1)
@transport(subgraph: "Schema1", group: "Schema1", location: "http:\/\/localhost:5000\/graphql", kind: "HTTP") {
query: Query
}

type Query {
user(id: Int!): User
@variable(subgraph: "Schema1", name: "id", argument: "id")
@resolver(subgraph: "Schema1", select: "{ user(id: $id) }", arguments: [ { name: "id", type: "Int!" } ])
}

type User
@variable(subgraph: "Schema1", name: "User_id", select: "id")
@resolver(subgraph: "Schema1", select: "{ user(id: $User_id) }", arguments: [ { name: "User_id", type: "Int!" } ]) {
email: String!
@source(subgraph: "Schema1")
id: Int!
@source(subgraph: "Schema1")
name: String!
@source(subgraph: "Schema1")
password: String!
@source(subgraph: "Schema1")
}
16 changes: 7 additions & 9 deletions src/HotChocolate/Fusion/test/Core.Tests/RequestPlannerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1450,9 +1450,8 @@ public async Task Query_Plan_31_Argument_No_Value_Specified_With_Selection_Set()
{
// arrange
var fusionGraph = await FusionGraphComposer.ComposeAsync(
new[]
{
new SubgraphConfiguration(
[
new SubgraphConfiguration(
"Test",
"""
type Query {
Expand All @@ -1469,12 +1468,11 @@ enum TestEnum {
}
""",
"",
new []
{
new HttpClientConfiguration(new Uri("http://client"), "Test"),
},
null),
});
[
new HttpClientConfiguration(new Uri("http://client"), "Test")
],
null)
]);

// act
var result = await CreateQueryPlanAsync(
Expand Down

0 comments on commit f2a93cb

Please sign in to comment.