From f623ebad295b10cebaf80ac1bcc35a624888ee74 Mon Sep 17 00:00:00 2001 From: Glen Date: Mon, 12 Aug 2024 16:47:57 +0200 Subject: [PATCH 1/3] Added ResolveWith overload that takes a Delegate --- .../Contracts/IObjectFieldDescriptor.cs | 31 +++++++++++ .../Descriptors/ObjectFieldDescriptor.cs | 11 ++++ .../test/Types.Tests/Types/ObjectTypeTests.cs | 53 +++++++++++++++++++ .../ObjectTypeTests.ResolveWithStatic.snap | 6 +++ ...bjectTypeTests.ResolveWithStaticAsync.snap | 7 +++ 5 files changed, 108 insertions(+) create mode 100644 src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStatic.snap create mode 100644 src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStaticAsync.snap diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IObjectFieldDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IObjectFieldDescriptor.cs index fe66947b2b7..6d6a0f4e1d6 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IObjectFieldDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Contracts/IObjectFieldDescriptor.cs @@ -233,6 +233,37 @@ IObjectFieldDescriptor ResolveWith( /// IObjectFieldDescriptor ResolveWith(MemberInfo propertyOrMethod); + /// + /// Adds a resolver based on a delegate to the field. + /// A resolver is a method that resolves the value for a + /// field. The resolver can access parent object, arguments, services and more through the + /// . + /// + /// The resolver of the field + /// + /// Given the following resolvers class + /// + /// GetFoo( + /// [Service] IFooService service, + /// CancellationToken cancellationToken) => + /// service.GetFooAsync(cancellationToken); + /// } + /// ]]> + /// + /// The GetFoo method can be mapped like: + /// + /// x.Foo) + /// .ResolveWith(Resolvers.GetFoo); + /// ]]> + /// + /// + IObjectFieldDescriptor ResolveWith(Delegate @delegate); + /// /// Adds a subscription resolver to to the field /// diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs index bb8ae45a0b3..360d1e620d0 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -371,6 +371,17 @@ public IObjectFieldDescriptor ResolveWith(MemberInfo propertyOrMethod) return ResolveWithInternal(propertyOrMethod, propertyOrMethod.DeclaringType); } + /// + public IObjectFieldDescriptor ResolveWith(Delegate @delegate) + { + if (@delegate is null) + { + throw new ArgumentNullException(nameof(@delegate)); + } + + return ResolveWithInternal(@delegate.Method, resolverType: null); + } + private IObjectFieldDescriptor ResolveWithInternal( MemberInfo propertyOrMethod, Type? resolverType) diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs index 1cf580e0bf9..242489bd35a 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs @@ -1735,6 +1735,30 @@ public void ResolveWithAsync() .MatchSnapshot(); } + [Fact] + public void ResolveWithStatic() + { + SchemaBuilder.New() + .AddQueryType() + .Create() + .MakeExecutable() + .Execute("{ foo baz }") + .ToJson() + .MatchSnapshot(); + } + + [Fact] + public void ResolveWithStaticAsync() + { + SchemaBuilder.New() + .AddQueryType() + .Create() + .MakeExecutable() + .Execute("{ foo baz qux }") + .ToJson() + .MatchSnapshot(); + } + [Fact] public void ResolveWith_NonGeneric() { @@ -2334,6 +2358,16 @@ public Task BarAsync(IResolverContext context) => Task.FromResult(context is not null); } + public static class ResolveWithStaticQueryResolver + { + public static string Bar() => "Bar"; + + public static Task FooAsync() => Task.FromResult("Foo"); + + public static Task BarAsync(IResolverContext context) + => Task.FromResult(context is not null); + } + public class ResolveWithQueryType : ObjectType { protected override void Configure(IObjectTypeDescriptor descriptor) @@ -2359,6 +2393,25 @@ protected override void Configure(IObjectTypeDescriptor descri } } + public class ResolveWithStaticQueryType : ObjectType + { + protected override void Configure(IObjectTypeDescriptor descriptor) + { + descriptor.Field(t => t.Foo).ResolveWith(ResolveWithStaticQueryResolver.Bar); + descriptor.Field("baz").ResolveWith(ResolveWithStaticQueryResolver.Bar); + } + } + + public class ResolveWithStaticQueryTypeAsync : ObjectType + { + protected override void Configure(IObjectTypeDescriptor descriptor) + { + descriptor.Field(t => t.Foo).ResolveWith(ResolveWithStaticQueryResolver.FooAsync); + descriptor.Field("baz").ResolveWith(ResolveWithStaticQueryResolver.FooAsync); + descriptor.Field("qux").ResolveWith(ResolveWithStaticQueryResolver.BarAsync); + } + } + public class ResolveWithNonGenericObjectType : ObjectType { protected override void Configure(IObjectTypeDescriptor descriptor) diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStatic.snap b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStatic.snap new file mode 100644 index 00000000000..0f7762c7429 --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStatic.snap @@ -0,0 +1,6 @@ +{ + "data": { + "foo": "Bar", + "baz": "Bar" + } +} diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStaticAsync.snap b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStaticAsync.snap new file mode 100644 index 00000000000..49f1a810e3f --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithStaticAsync.snap @@ -0,0 +1,7 @@ +{ + "data": { + "foo": "Foo", + "baz": "Foo", + "qux": true + } +} From cbfb9a4adf7d947d727576ebb047d7ce1f01c7dd Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 10 Mar 2026 10:55:13 +0000 Subject: [PATCH 2/3] fix analyzer issue --- .../src/Types/Types/Descriptors/ObjectFieldDescriptor.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs index 0629b19f235..092184183ba 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -403,10 +403,7 @@ public IObjectFieldDescriptor ResolveWith(MemberInfo propertyOrMethod) /// public IObjectFieldDescriptor ResolveWith(Delegate @delegate) { - if (@delegate is null) - { - throw new ArgumentNullException(nameof(@delegate)); - } + ArgumentNullException.ThrowIfNull(@delegate); return ResolveWithInternal(@delegate.Method, resolverType: null); } From 5197c2aa84c05269f1ac9f20e7cd53036a93ff2a Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 11 Mar 2026 13:12:19 +0000 Subject: [PATCH 3/3] polish --- .../Descriptors/ObjectFieldDescriptor.cs | 3 +- .../test/Types.Tests/Types/ObjectTypeTests.cs | 40 +++++++++++++++++++ ...TypeTests.ResolveWithInstanceDelegate.snap | 6 +++ ...ctTypeTests.ResolveWithLambdaDelegate.snap | 6 +++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithInstanceDelegate.snap create mode 100644 src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithLambdaDelegate.snap diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs index 092184183ba..e40555dc051 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -405,7 +405,8 @@ public IObjectFieldDescriptor ResolveWith(Delegate @delegate) { ArgumentNullException.ThrowIfNull(@delegate); - return ResolveWithInternal(@delegate.Method, resolverType: null); + var method = @delegate.Method; + return ResolveWithInternal(method, method.IsStatic ? null : method.DeclaringType); } private IObjectFieldDescriptor ResolveWithInternal( diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs index 7d09d1303fc..62b3701c80c 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs @@ -1757,6 +1757,36 @@ public void ResolveWithStaticAsync() .MatchSnapshot(); } + [Fact] + public void ResolveWithInstanceDelegate() + { + SchemaBuilder.New() + .AddQueryType() + .Create() + .MakeExecutable() + .Execute("{ foo baz }") + .ToJson() + .MatchSnapshot(); + } + + [Fact] + public void ResolveWithLambdaDelegate() + { + Func lambda = () => "Lambda"; + + SchemaBuilder.New() + .AddQueryType(new ObjectType(d => + { + d.Field(t => t.Foo).ResolveWith(lambda); + d.Field("baz").ResolveWith(lambda); + })) + .Create() + .MakeExecutable() + .Execute("{ foo baz }") + .ToJson() + .MatchSnapshot(); + } + [Fact] public void ResolveWith_NonGeneric() { @@ -2431,6 +2461,16 @@ protected override void Configure(IObjectTypeDescriptor descri } } + public class ResolveWithInstanceDelegateQueryType : ObjectType + { + protected override void Configure(IObjectTypeDescriptor descriptor) + { + var resolver = new ResolveWithQueryResolver(); + descriptor.Field(t => t.Foo).ResolveWith(resolver.FooAsync); + descriptor.Field("baz").ResolveWith(resolver.BarAsync); + } + } + public class ResolveWithNonGenericObjectType : ObjectType { protected override void Configure(IObjectTypeDescriptor descriptor) diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithInstanceDelegate.snap b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithInstanceDelegate.snap new file mode 100644 index 00000000000..c102fc3d841 --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithInstanceDelegate.snap @@ -0,0 +1,6 @@ +{ + "data": { + "foo": "Foo", + "baz": true + } +} diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithLambdaDelegate.snap b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithLambdaDelegate.snap new file mode 100644 index 00000000000..cc0f0890478 --- /dev/null +++ b/src/HotChocolate/Core/test/Types.Tests/Types/__snapshots__/ObjectTypeTests.ResolveWithLambdaDelegate.snap @@ -0,0 +1,6 @@ +{ + "data": { + "foo": "Lambda", + "baz": "Lambda" + } +}