From d51b71a6239d73a820deba591067327dca3bc306 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 23 Oct 2018 23:36:13 +0200 Subject: [PATCH] Diagnostics (#302) --- README.md | 25 ++- src/Core.Tests/Core.Tests.csproj | 2 + src/Core.Tests/Execution/DiagnosticTests.cs | 140 ++++++++++++ src/Core/Core.csproj | 1 + .../ExecutionStrategyBase.Helpers.cs | 199 ------------------ .../ExecutionStrategyBase.Resolver.cs | 117 ++++++++++ src/Core/Execution/ExecutionStrategyBase.cs | 38 ++-- .../Execution/MutationExecutionStrategy.cs | 49 +++-- src/Core/Execution/QueryExecuter.cs | 55 ++++- .../Execution/Utilities/DirectiveCollector.cs | 1 - .../Execution/Utilities/DirectiveLookup.cs | 5 +- .../Execution/Utilities/ExecutionHelper.cs | 66 ++++++ .../Utilities/QueryDiagnosticEvents.cs | 103 +++++++++ .../Utilities/ResolverDiagnosticEvents.cs | 72 +++++++ src/Core/Execution/Utilities/ResolverTask.cs | 24 +++ .../FieldValueCompletionContext.cs | 6 +- .../Configuration/SchemaConfigurationTests.cs | 16 +- .../Resolvers/FieldResolverBuilderTests.cs | 21 +- .../Resolvers/FieldResolverTests.cs | 31 +-- .../Types/Descriptors/FieldDescriptorTests.cs | 2 +- src/Types.Tests/Types/InputObjectTypeTests.cs | 3 +- src/Types.Tests/Types/TypeFactoryTests.cs | 5 +- ...enerator_GenerateWithCancellationToken.txt | 6 +- ...verMethodGenerator_GenerateWithContext.txt | 6 +- ...olverMethodGenerator_GenerateWithField.txt | 6 +- ...odGenerator_GenerateWithFieldSelection.txt | 6 +- ...MethodGenerator_GenerateWithObjectType.txt | 6 +- ...erator_GenerateWithOperationDefinition.txt | 6 +- ...hodGenerator_GenerateWithQueryDocument.txt | 6 +- ...ethodGenerator_GenerateWithQuerySchema.txt | 6 +- ...thodGenerator_GenerateWithQueryService.txt | 6 +- ...odGenerator_GenerateWithSourceArgument.txt | 6 +- ..._GenerateWithSourceArgumentAndArgument.txt | 6 +- ...erateWithSourceArgumentAndTwoArguments.txt | 6 +- ...thodGenerator_GenerateWithoutArguments.txt | 6 +- ...ethodGenerator_GenerateWithOneArgument.txt | 6 +- ...ethodGenerator_GenerateWithTwoArgument.txt | 6 +- ...thodGenerator_GenerateWithoutArguments.txt | 6 +- .../ResolverPropertyGenerator_Generate.txt | 6 +- .../SourcePropertyGenerator_Generate.txt | 6 +- ...odGenerator_GenerateWithSourceArgument.txt | 6 +- ..._GenerateWithSourceArgumentAndArgument.txt | 6 +- ...erateWithSourceArgumentAndTwoArguments.txt | 6 +- ...thodGenerator_GenerateWithoutArguments.txt | 6 +- ...ethodGenerator_GenerateWithOneArgument.txt | 6 +- ...ethodGenerator_GenerateWithTwoArgument.txt | 6 +- ...thodGenerator_GenerateWithoutArguments.txt | 6 +- .../Bindings/ResolverDelegateBindingInfo.cs | 15 +- src/Types/Configuration/IResolverRegistry.cs | 2 +- src/Types/Configuration/ResolverRegistry.cs | 14 +- .../MiddlewareSourceCodeGenerator.cs | 2 +- .../CodeGeneration/ResolverBuilder.cs | 4 +- .../AsyncResolverMethodGenerator.cs | 6 +- .../AsyncSourceMethodGenerator.cs | 6 +- .../ResolverPropertyGenerator.cs | 6 +- .../ResolverSourceCodeGenerator.cs | 26 ++- .../SourcePropertyGenerator.cs | 6 +- .../SyncResolverMethodGenerator.cs | 8 +- .../SyncSourceMethodGenerator.cs | 8 +- .../Resolvers/DirectiveMiddlewareDelegates.cs | 2 +- .../Resolvers/DirectiveResolverMiddleware.cs | 4 +- src/Types/Resolvers/FieldReference.cs | 2 +- src/Types/Resolvers/FieldResolver.cs | 8 +- .../Descriptors/DirectiveTypeDescriptor.cs | 6 +- .../Descriptors/IDirectiveTypeDescriptor.cs | 4 +- .../Descriptors/IObjectFieldDescriptor.cs | 29 ++- .../Descriptors/ObjectFieldDescription.cs | 2 +- .../Descriptors/ObjectFieldDescriptor.cs | 32 ++- src/Types/Types/Directive.cs | 2 +- src/Types/Types/DirectiveType.cs | 2 +- src/Types/Types/IDirective.cs | 2 +- src/Types/Types/ITypeInitializationContext.cs | 2 +- src/Types/Types/ObjectField.cs | 2 +- src/Types/Types/TypeInitializationContext.cs | 2 +- 74 files changed, 873 insertions(+), 462 deletions(-) create mode 100644 src/Core.Tests/Execution/DiagnosticTests.cs delete mode 100644 src/Core/Execution/ExecutionStrategyBase.Helpers.cs create mode 100644 src/Core/Execution/ExecutionStrategyBase.Resolver.cs create mode 100644 src/Core/Execution/Utilities/ExecutionHelper.cs create mode 100644 src/Core/Execution/Utilities/QueryDiagnosticEvents.cs create mode 100644 src/Core/Execution/Utilities/ResolverDiagnosticEvents.cs diff --git a/README.md b/README.md index b3a8f397553..164ddd848c0 100644 --- a/README.md +++ b/README.md @@ -254,16 +254,15 @@ Moreover, we are working on the following parts that are not defined in the spec We are currently working on the following features that are proposed for the next GraphQL specification. -- [ ] [Limit directive uniqueness to explicitly marked directives](https://github.com/facebook/graphql/pull/472) (#291 in development - 0.5.3) -- [ ] [Add rules for how circular references in Input Objects are handled](https://github.com/facebook/graphql/pull/445) -- [ ] [Add description to Schema](https://github.com/facebook/graphql/pull/466) -- [ ] ["Directive order is significant" section](https://github.com/facebook/graphql/pull/470) +- [ ] [Limit directive uniqueness to explicitly marked directives](https://github.com/facebook/graphql/pull/472) (#291 in development - 0.7.0) +- [ ] [Add rules for how circular references in Input Objects are handled](https://github.com/facebook/graphql/pull/445) (in development - 0.10.0) +- [ ] [Add description to Schema](https://github.com/facebook/graphql/pull/466) (in development - 0.9.0) +- [ ] ["Directive order is significant" section](https://github.com/facebook/graphql/pull/470) (in development - 0.7.0) ### Additional Scalar Types - [x] DateTime - [x] Date -- [x] Time - [x] URL - [x] UUID - [x] Decimal @@ -273,9 +272,8 @@ We are currently working on the following features that are proposed for the nex ### Additional Directives -- [ ] Export -- [ ] Defer -- [ ] Stream +- [ ] Schema Stitching (in development - 0.8.0) +- [ ] HTTP Directives (in development - 0.8.0) - [x] Custom Schema Directives - [x] Custom Query Directives @@ -292,15 +290,16 @@ We are currently working on the following features that are proposed for the nex ## Supported Frameworks - [ ] ASP.NET Classic - - - [ ] _Get_ (in development - 0.5.3) - - [ ] _Post_ (in development - 0.5.3) - - [ ] _WebSockets_ (in development - 0.5.5) + - [ ] _Get_ (in development - 0.7.0) + - [ ] _Post_ (in development - 0.7.0) + - [ ] _WebSockets_ (in development - 0.8.0) + - [ ] Schema Builder (in development - 1.0.0) - [x] ASP.NET Core - [x] Get - [x] Post - - [ ] _WebSockets_ (in development - 0.5.4) + - [x] WebSockets + - [ ] Schema Builder (in development - 0.11.0) ## Documentation diff --git a/src/Core.Tests/Core.Tests.csproj b/src/Core.Tests/Core.Tests.csproj index 919f718837b..bf0f59fa4cb 100644 --- a/src/Core.Tests/Core.Tests.csproj +++ b/src/Core.Tests/Core.Tests.csproj @@ -21,6 +21,8 @@ + + diff --git a/src/Core.Tests/Execution/DiagnosticTests.cs b/src/Core.Tests/Execution/DiagnosticTests.cs new file mode 100644 index 00000000000..32759cb71ec --- /dev/null +++ b/src/Core.Tests/Execution/DiagnosticTests.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using Microsoft.Extensions.DiagnosticAdapter; +using Xunit; + +namespace HotChocolate.Execution +{ + public class DiagnosticTests + { + [Fact] + public async Task ResolverEvents() + { + // arrange + var listener = new TestDiagnosticListener(); + using (DiagnosticListener.AllListeners.Subscribe( + new DiagnosticObserver(listener))) + { + ISchema schema = CreateSchema(); + + // act + await schema.ExecuteAsync("{ foo }"); + + // assert + Assert.True(listener.ResolveFieldStart); + Assert.True(listener.ResolveFieldStop); + Assert.Equal("foo", listener.FieldSelection.Name.Value); + Assert.InRange(listener.Duration, + TimeSpan.FromMilliseconds(50), + TimeSpan.FromMilliseconds(2000)); + } + } + + [Fact] + public async Task QueryEvents() + { + // arrange + var listener = new TestDiagnosticListener(); + using (DiagnosticListener.AllListeners.Subscribe( + new DiagnosticObserver(listener))) + { + ISchema schema = CreateSchema(); + + // act + await schema.ExecuteAsync("{ foo }"); + + // assert + Assert.True(listener.QueryStart); + Assert.True(listener.QueryStop); + } + } + + private ISchema CreateSchema() + { + return Schema.Create( + "type Query { foo: String }", + c => c.BindResolver(() => + { + Thread.Sleep(50); + return "bar"; + }).To("Query", "foo")); + } + + private class TestDiagnosticListener + { + public bool ResolveFieldStart { get; private set; } + + public bool ResolveFieldStop { get; private set; } + + public TimeSpan Duration { get; private set; } + + public FieldNode FieldSelection { get; private set; } + + public bool QueryStart { get; private set; } + + public bool QueryStop { get; private set; } + + + [DiagnosticName("HotChocolate.Execution.Resolver.Start")] + public virtual void OnResolveFieldStart() + { + ResolveFieldStart = true; + } + + [DiagnosticName("HotChocolate.Execution.Resolver.Stop")] + public virtual void OnResolveFieldStop(IResolverContext context) + { + ResolveFieldStop = true; + FieldSelection = context.FieldSelection; + Duration = Activity.Current.Duration; + } + + [DiagnosticName("HotChocolate.Execution.Query.Start")] + public virtual void OnQueryStart() + { + QueryStart = true; + } + + [DiagnosticName("HotChocolate.Execution.Query.Stop")] + public virtual void OnQueryStop(IResolverContext context) + { + QueryStop = true; + } + } + + private class DiagnosticObserver + : IObserver + { + private readonly TestDiagnosticListener _listener; + + public DiagnosticObserver(TestDiagnosticListener listener) + { + _listener = listener; + } + + public void OnCompleted() + { + } + + public void OnError(Exception error) + { + } + + public void OnNext(DiagnosticListener value) + { + if (value.Name == "HotChocolate.Execution") + { + value.SubscribeWithAdapter(_listener, s => + { + return true; + }); + } + } + } + } +} diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 47cc2d30a0c..bea14fc64ed 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -24,6 +24,7 @@ + diff --git a/src/Core/Execution/ExecutionStrategyBase.Helpers.cs b/src/Core/Execution/ExecutionStrategyBase.Helpers.cs deleted file mode 100644 index 2a1e8dc08ea..00000000000 --- a/src/Core/Execution/ExecutionStrategyBase.Helpers.cs +++ /dev/null @@ -1,199 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using HotChocolate.Language; -using HotChocolate.Resolvers; -using HotChocolate.Types; - -namespace HotChocolate.Execution -{ - internal abstract partial class ExecutionStrategyBase - { - private static readonly FieldValueCompleter _fieldValueCompleter = - new FieldValueCompleter(); - - protected static object ExecuteResolver( - ResolverTask resolverTask, - bool isDeveloperMode, - CancellationToken cancellationToken) - { - if (resolverTask.HasMiddleware) - { - return ExecuteResolverMiddlewareAsync( - resolverTask, isDeveloperMode, - cancellationToken); - } - else - { - return ExecuteFieldResolver( - resolverTask, isDeveloperMode, - cancellationToken); - } - } - - private static object ExecuteFieldResolver( - ResolverTask resolverTask, - bool isDeveloperMode, - CancellationToken cancellationToken) - { - try - { - if (resolverTask.FieldSelection.Field.Resolver == null) - { - return null; - } - - return resolverTask.FieldSelection.Field.Resolver( - resolverTask.ResolverContext, - cancellationToken); - } - catch (QueryException ex) - { - return ex.Errors; - } - catch (Exception ex) - { - return CreateErrorFromException(ex, - resolverTask.FieldSelection.Selection, - isDeveloperMode); - } - } - - private static async Task ExecuteResolverMiddlewareAsync( - ResolverTask resolverTask, - bool isDeveloperMode, - CancellationToken cancellationToken) - { - try - { - return await resolverTask.ExecuteMiddleware.Invoke( - resolverTask.ResolverContext, ExecuteResolver); - } - catch (QueryException ex) - { - return ex.Errors; - } - catch (Exception ex) - { - return CreateErrorFromException(ex, - resolverTask.FieldSelection.Selection, - isDeveloperMode); - } - - async Task ExecuteResolver() - { - object result = ExecuteFieldResolver( - resolverTask, - isDeveloperMode, - cancellationToken); - - return await FinalizeResolverResultAsync( - resolverTask.FieldSelection.Selection, - result, - isDeveloperMode); - }; - } - - protected static Task FinalizeResolverResultAsync( - FieldNode fieldSelection, - object resolverResult, - bool isDeveloperMode) - { - switch (resolverResult) - { - case Task task: - return FinalizeResolverResultTaskAsync( - fieldSelection, task, isDeveloperMode); - - case IResolverResult result: - return Task.FromResult( - CompleteResolverResult(fieldSelection, result)); - - default: - return Task.FromResult(resolverResult); - } - } - - private static async Task FinalizeResolverResultTaskAsync( - FieldNode fieldSelection, - Task task, - bool isDeveloperMode) - { - try - { - object resolverResult = task.IsCompleted - ? task.Result - : await task; - - if (resolverResult is IResolverResult r) - { - return CompleteResolverResult(fieldSelection, r); - } - return resolverResult; - } - catch (QueryException ex) - { - return ex.Errors; - } - catch (Exception ex) - { - return CreateErrorFromException(ex, - fieldSelection, isDeveloperMode); - } - } - - private static IQueryError CreateErrorFromException( - Exception exception, - FieldNode fieldSelection, - bool isDeveloperMode) - { - if (isDeveloperMode) - { - return new FieldError( - $"{exception.Message}\r\n\r\n{exception.StackTrace}", - fieldSelection); - } - else - { - return new FieldError( - "Unexpected execution error.", - fieldSelection); - } - } - - protected void CompleteValue( - FieldValueCompletionContext completionContext) - { - _fieldValueCompleter.CompleteValue(completionContext); - } - - private static object CompleteResolverResult( - FieldNode fieldSelection, - IResolverResult resolverResult) - { - if (resolverResult.IsError) - { - return new FieldError( - resolverResult.ErrorMessage, - fieldSelection); - } - return resolverResult.Value; - } - - private static bool IsMaxExecutionDepthReached( - IExecutionContext executionContext, - ResolverTask resolverTask) - { - bool isLeafField = - resolverTask.FieldSelection.Field.Type.IsLeafType(); - - int maxExecutionDepth = isLeafField - ? executionContext.Options.MaxExecutionDepth - : executionContext.Options.MaxExecutionDepth - 1; - - return resolverTask.Path.Depth > maxExecutionDepth; - } - } -} diff --git a/src/Core/Execution/ExecutionStrategyBase.Resolver.cs b/src/Core/Execution/ExecutionStrategyBase.Resolver.cs new file mode 100644 index 00000000000..69acb2700e0 --- /dev/null +++ b/src/Core/Execution/ExecutionStrategyBase.Resolver.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types; + +namespace HotChocolate.Execution +{ + internal abstract partial class ExecutionStrategyBase + { + private static readonly FieldValueCompleter _fieldValueCompleter = + new FieldValueCompleter(); + + protected static async Task ExecuteResolverAsync( + ResolverTask resolverTask, + CancellationToken cancellationToken) + { + Activity activity = ResolverDiagnosticEvents.BeginResolveField( + resolverTask.ResolverContext); + + object result = await ExecuteMiddlewareAsync( + resolverTask, + cancellationToken); + + if (result is IQueryError error) + { + activity?.AddTag("error", "true"); + } + + ResolverDiagnosticEvents.EndResolveField( + activity, + resolverTask.ResolverContext, + result); + + return result; + } + + private static async Task ExecuteMiddlewareAsync( + ResolverTask resolverTask, + CancellationToken cancellationToken) + { + object result = null; + + try + { + if (!resolverTask.FieldSelection.Field.IsIntrospectionField + && resolverTask.HasMiddleware) + { + result = await ExecuteDirectiveMiddlewareAsync( + resolverTask, + cancellationToken); + } + else + { + result = await ExecuteFieldMiddlewareAsync( + resolverTask, + cancellationToken); + } + } + catch (QueryException ex) + { + result = ex.Errors; + } + catch (Exception ex) + { + ResolverDiagnosticEvents.ResolverError( + resolverTask.ResolverContext, + ex); + + result = resolverTask.CreateError(ex); + } + + return result; + } + + private static async Task ExecuteFieldMiddlewareAsync( + ResolverTask resolverTask, + CancellationToken cancellationToken) + { + if (resolverTask.FieldSelection.Field.Resolver == null) + { + return null; + } + + object result = await resolverTask.FieldSelection.Field.Resolver( + resolverTask.ResolverContext, + cancellationToken); + + return resolverTask.CompleteResolverResult(result); + } + + private static async Task ExecuteDirectiveMiddlewareAsync( + ResolverTask resolverTask, + CancellationToken cancellationToken) + { + return await resolverTask.ExecuteMiddleware.Invoke( + resolverTask.ResolverContext, ExecuteResolver); + + Task ExecuteResolver() + { + return ExecuteFieldMiddlewareAsync( + resolverTask, + cancellationToken); + }; + } + + protected void CompleteValue( + FieldValueCompletionContext completionContext) + { + _fieldValueCompleter.CompleteValue(completionContext); + } + } +} diff --git a/src/Core/Execution/ExecutionStrategyBase.cs b/src/Core/Execution/ExecutionStrategyBase.cs index 1b11e1ec8af..59d60713042 100644 --- a/src/Core/Execution/ExecutionStrategyBase.cs +++ b/src/Core/Execution/ExecutionStrategyBase.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -63,7 +64,9 @@ private async Task ExecuteResolverBatchAsync( { // start field resolvers BeginExecuteResolverBatch( - executionContext, currentBatch, cancellationToken); + executionContext, + currentBatch, + cancellationToken); // execute batch data loaders await CompleteDataLoadersAsync( @@ -72,7 +75,10 @@ await CompleteDataLoadersAsync( // await field resolver results await EndExecuteResolverBatchAsync( - executionContext, currentBatch, nextBatch, cancellationToken); + executionContext, + currentBatch, + nextBatch.Add, + cancellationToken); } private void BeginExecuteResolverBatch( @@ -85,18 +91,18 @@ private void BeginExecuteResolverBatch( bool isLeafField = resolverTask.FieldSelection.Field.Type.IsLeafType(); - if (IsMaxExecutionDepthReached(executionContext, resolverTask)) + if (resolverTask.IsMaxExecutionDepthReached()) { - executionContext.ReportError(resolverTask.CreateError( + resolverTask.ReportError( "The field has a depth of " + $"{resolverTask.Path.Depth}, " + "which exceeds max allowed depth of " + - $"{executionContext.Options.MaxExecutionDepth}")); + $"{resolverTask.Options.MaxExecutionDepth}"); } else { - resolverTask.ResolverResult = ExecuteResolver( - resolverTask, executionContext.Options.DeveloperMode, + resolverTask.Task = ExecuteResolverAsync( + resolverTask, cancellationToken); } @@ -119,21 +125,25 @@ await Task.WhenAll(dataLoaders.Touched private async Task EndExecuteResolverBatchAsync( IExecutionContext executionContext, IEnumerable currentBatch, - List nextBatch, + Action enqueueTask, CancellationToken cancellationToken) { foreach (ResolverTask resolverTask in currentBatch) { - // await async results - resolverTask.ResolverResult = await FinalizeResolverResultAsync( - resolverTask.FieldSelection.Selection, - resolverTask.ResolverResult, - executionContext.Options.DeveloperMode); + // complete resolver tasks + if (resolverTask.Task.IsCompleted) + { + resolverTask.ResolverResult = resolverTask.Task.Result; + } + else + { + resolverTask.ResolverResult = await resolverTask.Task; + } // serialize and integrate result into final query result var completionContext = new FieldValueCompletionContext( executionContext, resolverTask.ResolverContext, - resolverTask, t => nextBatch.Add(t)); + resolverTask, enqueueTask); CompleteValue(completionContext); diff --git a/src/Core/Execution/MutationExecutionStrategy.cs b/src/Core/Execution/MutationExecutionStrategy.cs index 2bf424fd5a7..fc08b3b55d7 100644 --- a/src/Core/Execution/MutationExecutionStrategy.cs +++ b/src/Core/Execution/MutationExecutionStrategy.cs @@ -17,10 +17,10 @@ public override Task ExecuteAsync( throw new ArgumentNullException(nameof(executionContext)); } - return ExecuteInternalAsync(executionContext, cancellationToken); + return ExecuteMutationAsync(executionContext, cancellationToken); } - private async Task ExecuteInternalAsync( + private async Task ExecuteMutationAsync( IExecutionContext executionContext, CancellationToken cancellationToken) { @@ -41,28 +41,32 @@ private async Task ExecuteResolverBatchSeriallyAsync( IEnumerable currentBatch, CancellationToken cancellationToken) { + var nextBatch = new List(); + foreach (ResolverTask resolverTask in currentBatch) { - var nextBatch = new List(); - - if (resolverTask.Path.Depth <= executionContext.Options.MaxExecutionDepth) + if (resolverTask.IsMaxExecutionDepthReached()) { - await ExecuteResolverSeriallyAsync( - executionContext, resolverTask, - nextBatch, cancellationToken); + resolverTask.ReportError( + $"The field has a depth of {resolverTask.Path.Depth}," + + " which exceeds max allowed depth of " + + $"{executionContext.Options.MaxExecutionDepth}"); } else { - executionContext.ReportError(resolverTask.CreateError( - $"The field has a depth of {resolverTask.Path.Depth}, " + - "which exceeds max allowed depth of " + - $"{executionContext.Options.MaxExecutionDepth}")); + await ExecuteResolverSeriallyAsync( + executionContext, + resolverTask, + nextBatch.Add, + cancellationToken); } // execute child fields with the default parallel flow logic await ExecuteResolversAsync( executionContext, nextBatch, cancellationToken); + nextBatch.Clear(); + cancellationToken.ThrowIfCancellationRequested(); } } @@ -70,27 +74,30 @@ await ExecuteResolversAsync( private async Task ExecuteResolverSeriallyAsync( IExecutionContext executionContext, ResolverTask resolverTask, - List nextBatch, + Action enqueueTask, CancellationToken cancellationToken) { - resolverTask.ResolverResult = ExecuteResolver( - resolverTask, executionContext.Options.DeveloperMode, + resolverTask.Task = ExecuteResolverAsync( + resolverTask, cancellationToken); await CompleteDataLoadersAsync( executionContext.DataLoaders, cancellationToken); - // await async results - resolverTask.ResolverResult = await FinalizeResolverResultAsync( - resolverTask.FieldSelection.Selection, - resolverTask.ResolverResult, - executionContext.Options.DeveloperMode); + if (resolverTask.Task.IsCompleted) + { + resolverTask.ResolverResult = resolverTask.Task.Result; + } + else + { + resolverTask.ResolverResult = await resolverTask.Task; + } // serialize and integrate result into final query result var completionContext = new FieldValueCompletionContext( executionContext, resolverTask.ResolverContext, - resolverTask, t => nextBatch.Add(t)); + resolverTask, enqueueTask); CompleteValue(completionContext); } diff --git a/src/Core/Execution/QueryExecuter.cs b/src/Core/Execution/QueryExecuter.cs index f05576aec90..26ddddf73d2 100644 --- a/src/Core/Execution/QueryExecuter.cs +++ b/src/Core/Execution/QueryExecuter.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using HotChocolate.Validation; using HotChocolate.Runtime; +using System.Diagnostics; namespace HotChocolate.Execution { @@ -37,23 +38,45 @@ public QueryExecuter(ISchema schema, int cacheSize) public int CachedOperations => _queryCache.Usage; public Task ExecuteAsync( - QueryRequest queryRequest, + QueryRequest request, CancellationToken cancellationToken = default) { - if (queryRequest == null) + if (request == null) { - throw new ArgumentNullException(nameof(queryRequest)); + throw new ArgumentNullException(nameof(request)); } - QueryInfo queryInfo = GetOrCreateQuery(queryRequest.Query); - if (queryInfo.ValidationResult.HasErrors) + QueryInfo queryInfo = null; + Activity activity = QueryDiagnosticEvents.BeginExecute( + Schema, + request); + + try { - return Task.FromResult( - new QueryResult(queryInfo.ValidationResult.Errors)); + queryInfo = GetOrCreateQuery(request.Query); + if (queryInfo.ValidationResult.HasErrors) + { + QueryDiagnosticEvents.ValidationError( + Schema, + request, + queryInfo.QueryDocument, + queryInfo.ValidationResult.Errors); + + return Task.FromResult( + new QueryResult(queryInfo.ValidationResult.Errors)); + } + + return ExecuteInternalAsync( + request, queryInfo, cancellationToken); + } + finally + { + QueryDiagnosticEvents.EndExecute( + activity, + Schema, + request, + queryInfo?.QueryDocument); } - - return ExecuteInternalAsync( - queryRequest, queryInfo, cancellationToken); } private async Task ExecuteInternalAsync( @@ -76,10 +99,22 @@ private async Task ExecuteInternalAsync( } catch (QueryException ex) { + QueryDiagnosticEvents.QueryError( + Schema, + queryRequest, + queryInfo.QueryDocument, + ex); + return new QueryResult(ex.Errors); } catch (Exception ex) { + QueryDiagnosticEvents.QueryError( + Schema, + queryRequest, + queryInfo.QueryDocument, + ex); + return new QueryResult(CreateErrorFromException(ex)); } finally diff --git a/src/Core/Execution/Utilities/DirectiveCollector.cs b/src/Core/Execution/Utilities/DirectiveCollector.cs index 865eb6bc205..f975371496c 100644 --- a/src/Core/Execution/Utilities/DirectiveCollector.cs +++ b/src/Core/Execution/Utilities/DirectiveCollector.cs @@ -122,7 +122,6 @@ private IEnumerable GetFieldSelectionDirectives( } } - private void CollectInheritedDirectives( HashSet processed, List directives, diff --git a/src/Core/Execution/Utilities/DirectiveLookup.cs b/src/Core/Execution/Utilities/DirectiveLookup.cs index d920e35161a..4bc630b18a5 100644 --- a/src/Core/Execution/Utilities/DirectiveLookup.cs +++ b/src/Core/Execution/Utilities/DirectiveLookup.cs @@ -108,6 +108,8 @@ private DirectiveDelegate BuildComponent( return context => { + context.Result = context.CompleteResolverResult(context.Result); + if (HasErrors(context.Result)) { return Task.CompletedTask; @@ -121,8 +123,7 @@ private DirectiveDelegate BuildComponent( private bool HasErrors(object result) { if (result is IQueryError error - || result is IEnumerable errors - || result is IResolverResult rr && rr.IsError) + || result is IEnumerable errors) { return true; } diff --git a/src/Core/Execution/Utilities/ExecutionHelper.cs b/src/Core/Execution/Utilities/ExecutionHelper.cs new file mode 100644 index 00000000000..d21fa408e32 --- /dev/null +++ b/src/Core/Execution/Utilities/ExecutionHelper.cs @@ -0,0 +1,66 @@ +using System; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types; + +namespace HotChocolate.Execution +{ + internal static class ExecutionHelper + { + public static object CompleteResolverResult( + this ResolverTask resolverTask, + object resolverResult) + { + return CompleteResolverResult( + resolverTask.ResolverContext, + resolverResult); + } + + public static object CompleteResolverResult( + this IResolverContext resolverContext, + object resolverResult) + { + if (resolverResult is IResolverResult r) + { + if (r.IsError) + { + return new FieldError( + r.ErrorMessage, + resolverContext.FieldSelection); + } + return r.Value; + } + + return resolverResult; + } + + public static bool IsMaxExecutionDepthReached( + this ResolverTask resolverTask) + { + bool isLeafField = + resolverTask.FieldSelection.Field.Type.IsLeafType(); + + int maxExecutionDepth = isLeafField + ? resolverTask.Options.MaxExecutionDepth + : resolverTask.Options.MaxExecutionDepth - 1; + + return resolverTask.Path.Depth > maxExecutionDepth; + } + + public static FieldError CreateError( + this ResolverTask resolverTask, + Exception exception) + { + if (resolverTask.Options.DeveloperMode) + { + return resolverTask.CreateError( + $"{exception.Message}\r\n\r\n{exception.StackTrace}"); + } + else + { + return resolverTask.CreateError("Unexpected execution error."); + } + } + } + +} diff --git a/src/Core/Execution/Utilities/QueryDiagnosticEvents.cs b/src/Core/Execution/Utilities/QueryDiagnosticEvents.cs new file mode 100644 index 00000000000..feeb2554a43 --- /dev/null +++ b/src/Core/Execution/Utilities/QueryDiagnosticEvents.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using HotChocolate.Language; +using HotChocolate.Resolvers; + +namespace HotChocolate.Execution +{ + internal static class QueryDiagnosticEvents + { + private const string _diagnosticListenerName = "HotChocolate.Execution"; + private const string _queryActivityName = + _diagnosticListenerName + ".Query"; + private const string _queryActivityStartName = + _queryActivityName + ".Start"; + private const string _queryActivityStopName = + _queryActivityName + ".Stop"; + private const string _queryErrorEventName = + _queryActivityName + ".QueryError"; + + private const string _validationErrorEventName = + _queryActivityName + ".ValidationError"; + + private static readonly DiagnosticSource _src = + new DiagnosticListener(_diagnosticListenerName); + + public static Activity BeginExecute( + ISchema schema, + QueryRequest request) + { + if (_src.IsEnabled(_queryActivityStartName, schema, request) + || _src.IsEnabled(_queryActivityStopName, schema, request)) + { + var activity = new Activity(_queryActivityName); + + _src.StartActivity(activity, new + { + Schema = schema, + Request = request, + Timestamp = Stopwatch.GetTimestamp() + }); + + return activity; + } + + return null; + } + + public static void EndExecute( + Activity activity, + ISchema schema, + QueryRequest request, + DocumentNode query) + { + if (activity != null) + { + _src.StopActivity(activity, new + { + Schema = schema, + Request = request, + Query = query, + Timestamp = Stopwatch.GetTimestamp() + }); + } + } + + public static void QueryError( + ISchema schema, + QueryRequest request, + DocumentNode query, + Exception exception) + { + if (_src.IsEnabled(_queryErrorEventName)) + { + _src.Write(_queryErrorEventName, new + { + Schema = schema, + Request = request, + Query = query, + Exception = exception + }); + } + } + + public static void ValidationError( + ISchema schema, + QueryRequest request, + DocumentNode query, + IReadOnlyCollection errors) + { + if (_src.IsEnabled(_queryErrorEventName)) + { + _src.Write(_queryErrorEventName, new + { + Schema = schema, + Request = request, + Query = query, + Errors = errors + }); + } + } + } +} diff --git a/src/Core/Execution/Utilities/ResolverDiagnosticEvents.cs b/src/Core/Execution/Utilities/ResolverDiagnosticEvents.cs new file mode 100644 index 00000000000..b58b8a482f2 --- /dev/null +++ b/src/Core/Execution/Utilities/ResolverDiagnosticEvents.cs @@ -0,0 +1,72 @@ +using System; +using System.Diagnostics; +using HotChocolate.Resolvers; + +namespace HotChocolate.Execution +{ + internal static class ResolverDiagnosticEvents + { + private const string _diagnosticListenerName = "HotChocolate.Execution"; + private const string _resolverActivityName = + _diagnosticListenerName + ".Resolver"; + private const string _resolverActivityStartName = + _resolverActivityName + ".Start"; + private const string _resolverActivityStopName = + _resolverActivityName + ".Stop"; + private const string _exceptionEventName = + _resolverActivityName + ".Error"; + + private static readonly DiagnosticSource _src = + new DiagnosticListener(_diagnosticListenerName); + + public static Activity BeginResolveField( + IResolverContext resolverContext) + { + if (_src.IsEnabled(_resolverActivityStartName, resolverContext) + || _src.IsEnabled(_resolverActivityStopName, resolverContext)) + { + var activity = new Activity(_resolverActivityName); + + _src.StartActivity(activity, new + { + Context = resolverContext, + Timestamp = Stopwatch.GetTimestamp() + }); + + return activity; + } + + return null; + } + + public static void EndResolveField( + Activity activity, + IResolverContext resolverContext, + object resolvedValue) + { + if (activity != null) + { + _src.StopActivity(activity, new + { + Context = resolverContext, + Result = resolvedValue, + Timestamp = Stopwatch.GetTimestamp() + }); + } + } + + public static void ResolverError( + IResolverContext resolverContext, + Exception exception) + { + if (_src.IsEnabled(_exceptionEventName)) + { + _src.Write(_exceptionEventName, new + { + Context = resolverContext, + Exception = exception + }); + } + } + } +} diff --git a/src/Core/Execution/Utilities/ResolverTask.cs b/src/Core/Execution/Utilities/ResolverTask.cs index 506f2cfb5fa..752b4e0a8ce 100644 --- a/src/Core/Execution/Utilities/ResolverTask.cs +++ b/src/Core/Execution/Utilities/ResolverTask.cs @@ -3,6 +3,8 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; +using System.Threading.Tasks; +using HotChocolate.Configuration; using HotChocolate.Resolvers; using HotChocolate.Types; @@ -10,6 +12,8 @@ namespace HotChocolate.Execution { internal sealed class ResolverTask { + private IExecutionContext _executionContext; + public ResolverTask( IExecutionContext executionContext, ObjectType objectType, @@ -18,6 +22,8 @@ public ResolverTask( ImmutableStack source, OrderedDictionary result) { + _executionContext = executionContext; + Source = source; ObjectType = objectType; FieldSelection = fieldSelection; @@ -29,11 +35,15 @@ public ResolverTask( executionContext, this, executionContext.CancellationToken); + Options = executionContext.Options; + ExecuteMiddleware = executionContext.GetMiddleware( objectType, fieldSelection.Selection); HasMiddleware = ExecuteMiddleware != null; } + public IReadOnlySchemaOptions Options { get; } + public ImmutableStack Source { get; } public ObjectType ObjectType { get; } @@ -48,6 +58,8 @@ public ResolverTask( public IResolverContext ResolverContext { get; } + public Task Task { get; set; } + public object ResolverResult { get; set; } public ExecuteMiddleware ExecuteMiddleware { get; } @@ -59,6 +71,18 @@ public void IntegrateResult(object value) Result[FieldSelection.ResponseName] = value; } + + + public void ReportError(string message) + { + ReportError(CreateError(message)); + } + + public void ReportError(IQueryError error) + { + _executionContext.ReportError(error); + } + public FieldError CreateError(string message) { if (string.IsNullOrEmpty(message)) diff --git a/src/Core/Execution/ValueCompletion/FieldValueCompletionContext.cs b/src/Core/Execution/ValueCompletion/FieldValueCompletionContext.cs index 9d9533d018d..78900cad045 100644 --- a/src/Core/Execution/ValueCompletion/FieldValueCompletionContext.cs +++ b/src/Core/Execution/ValueCompletion/FieldValueCompletionContext.cs @@ -17,7 +17,7 @@ public FieldValueCompletionContext( IExecutionContext executionContext, IResolverContext resolverContext, ResolverTask resolverTask, - Action enqueueResolverTask) + Action enqueueTask) { if (resolverTask == null) { @@ -25,8 +25,8 @@ public FieldValueCompletionContext( } _integrateResult = resolverTask.IntegrateResult; - _enqueueResolverTask = enqueueResolverTask - ?? throw new ArgumentNullException(nameof(enqueueResolverTask)); + _enqueueResolverTask = enqueueTask + ?? throw new ArgumentNullException(nameof(enqueueTask)); ExecutionContext = executionContext ?? throw new ArgumentNullException(nameof(executionContext)); diff --git a/src/Types.Tests/Configuration/SchemaConfigurationTests.cs b/src/Types.Tests/Configuration/SchemaConfigurationTests.cs index ada728e25bf..89c8c762bba 100644 --- a/src/Types.Tests/Configuration/SchemaConfigurationTests.cs +++ b/src/Types.Tests/Configuration/SchemaConfigurationTests.cs @@ -81,9 +81,9 @@ public void BindResolverCollectionToObjectTypeExplicitly() // assert Assert.True(hasErrors); - FieldResolverDelegate resolver = schemaContext.Resolvers.GetResolver("TestObjectA", "a"); + AsyncFieldResolverDelegate resolver = schemaContext.Resolvers.GetResolver("TestObjectA", "a"); Assert.NotNull(resolver); - Assert.Equal("a_dummy_a", resolver(resolverContext.Object, CancellationToken.None)); + Assert.Equal("a_dummy_a", resolver(resolverContext.Object, CancellationToken.None).Result); Assert.Null(schemaContext.Resolvers.GetResolver("TestObjectA", "b")); } @@ -124,8 +124,8 @@ public void BindResolverCollectionToObjectTypeViaName() // assert Assert.False(hasErrors); - FieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar"); - object result = fieldResolver(resolverContext.Object, CancellationToken.None); + AsyncFieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar"); + object result = fieldResolver(resolverContext.Object, CancellationToken.None).Result; Assert.Equal(dummyObjectType.Bar, result); } @@ -162,8 +162,8 @@ public void DeriveResolverFromObjectTypeProperty() // assert Assert.False(hasErrors); - FieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar"); - object result = fieldResolver(resolverContext.Object, CancellationToken.None); + AsyncFieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar"); + object result = fieldResolver(resolverContext.Object, CancellationToken.None).Result; Assert.Equal(dummyObjectType.Bar, result); } @@ -200,8 +200,8 @@ public void DeriveResolverFromObjectTypeMethod() // assert Assert.False(hasErrors); - FieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar2"); - object result = fieldResolver(resolverContext.Object, CancellationToken.None); + AsyncFieldResolverDelegate fieldResolver = schemaContext.Resolvers.GetResolver("Dummy", "bar2"); + object result = fieldResolver(resolverContext.Object, CancellationToken.None).Result; Assert.Equal(dummyObjectType.GetBar2(), result); } } diff --git a/src/Types.Tests/Resolvers/FieldResolverBuilderTests.cs b/src/Types.Tests/Resolvers/FieldResolverBuilderTests.cs index 4f35a84b2b6..c8921567faf 100644 --- a/src/Types.Tests/Resolvers/FieldResolverBuilderTests.cs +++ b/src/Types.Tests/Resolvers/FieldResolverBuilderTests.cs @@ -36,8 +36,9 @@ public void CreateSyncSourceMethodResolver() Assert.Equal("field", r.FieldName); Assert.NotNull(r.Resolver); - object resolvedValue = - r.Resolver(context.Object, CancellationToken.None); + object resolvedValue = r.Resolver( + context.Object, + CancellationToken.None).Result; Assert.Equal("Hello World", resolvedValue); }); } @@ -79,8 +80,9 @@ public void CreateSyncCollectionMethodResolver() Assert.Equal("field", r.FieldName); Assert.NotNull(r.Resolver); - object resolvedValue = - r.Resolver(context.Object, CancellationToken.None); + object resolvedValue = r.Resolver( + context.Object, + CancellationToken.None).Result; Assert.Equal("Hello World_123", resolvedValue); }); } @@ -122,8 +124,10 @@ public void CreateAsyncCollectionMethodResolver() Assert.Equal("field", r.FieldName); Assert.NotNull(r.Resolver); - object resolvedValue = ((Task)r.Resolver( - context.Object, CancellationToken.None)).Result; + object resolvedValue = r.Resolver( + context.Object, + CancellationToken.None) + .Result; Assert.Equal("Hello World_123", resolvedValue); }); } @@ -153,8 +157,9 @@ public void CreateSourcePropertyResolver() Assert.Equal("field", r.FieldName); Assert.NotNull(r.Resolver); - object resolvedResult = - r.Resolver(context.Object, CancellationToken.None); + object resolvedResult = r.Resolver( + context.Object, + CancellationToken.None).Result; Assert.Equal("Hello World Property", resolvedResult); }); } diff --git a/src/Types.Tests/Resolvers/FieldResolverTests.cs b/src/Types.Tests/Resolvers/FieldResolverTests.cs index fdb982bb4db..e4c06f67670 100644 --- a/src/Types.Tests/Resolvers/FieldResolverTests.cs +++ b/src/Types.Tests/Resolvers/FieldResolverTests.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using System.Threading.Tasks; using Xunit; namespace HotChocolate.Resolvers @@ -12,7 +13,7 @@ public void Create() // arrange var typeName = Guid.NewGuid().ToString(); var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); // act var fieldMember = new FieldResolver( @@ -29,7 +30,7 @@ public void CreateTypeNull() { // arrange var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); // act Action action = () => new FieldResolver(null, fieldName, resolver); @@ -43,7 +44,7 @@ public void CreateFieldNull() { // arrange var typeName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); // act Action action = () => new FieldResolver(typeName, null, resolver); @@ -73,7 +74,7 @@ public void WithTypeName() var originalTypeName = Guid.NewGuid().ToString(); var newTypeName = Guid.NewGuid().ToString(); var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); var fieldMember = new FieldResolver( originalTypeName, fieldName, resolver); @@ -91,7 +92,7 @@ public void WithTypeNameNull() // arrange var originalTypeName = Guid.NewGuid().ToString(); var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); var fieldMember = new FieldResolver( originalTypeName, fieldName, resolver); @@ -110,7 +111,7 @@ public void WithFieldName() var typeName = Guid.NewGuid().ToString(); var originalFieldName = Guid.NewGuid().ToString(); var newFieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); var fieldMember = new FieldResolver( typeName, originalFieldName, resolver); @@ -128,7 +129,7 @@ public void WithFieldNameNull() // arrange var typeName = Guid.NewGuid().ToString(); var originalFieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate resolver = GetResolverA(); + AsyncFieldResolverDelegate resolver = GetResolverA(); var fieldMember = new FieldResolver( typeName, originalFieldName, resolver); @@ -146,8 +147,8 @@ public void WithResolver() // arrange var typeName = Guid.NewGuid().ToString(); var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate originalResolver = GetResolverA(); - FieldResolverDelegate newResolver = GetResolverB(); + AsyncFieldResolverDelegate originalResolver = GetResolverA(); + AsyncFieldResolverDelegate newResolver = GetResolverB(); var fieldMember = new FieldResolver( typeName, fieldName, originalResolver); @@ -165,7 +166,7 @@ public void WithResolverNull() // arrange var typeName = Guid.NewGuid().ToString(); var fieldName = Guid.NewGuid().ToString(); - FieldResolverDelegate originalResolver = GetResolverA(); + AsyncFieldResolverDelegate originalResolver = GetResolverA(); var fieldMember = new FieldResolver( typeName, fieldName, originalResolver); @@ -309,14 +310,16 @@ public void EqualsObjectMemberNotEqual() Assert.False(result); } - private FieldResolverDelegate GetResolverA() + private AsyncFieldResolverDelegate GetResolverA() { - return new FieldResolverDelegate((a, b) => null); + return new AsyncFieldResolverDelegate( + (a, b) => Task.FromResult(null)); } - private FieldResolverDelegate GetResolverB() + private AsyncFieldResolverDelegate GetResolverB() { - return new FieldResolverDelegate((a, b) => null); + return new AsyncFieldResolverDelegate( + (a, b) => Task.FromResult(null)); } private class Foo diff --git a/src/Types.Tests/Types/Descriptors/FieldDescriptorTests.cs b/src/Types.Tests/Types/Descriptors/FieldDescriptorTests.cs index 694b6b5d550..76ff5409c37 100644 --- a/src/Types.Tests/Types/Descriptors/FieldDescriptorTests.cs +++ b/src/Types.Tests/Types/Descriptors/FieldDescriptorTests.cs @@ -121,7 +121,7 @@ public void SetResolverAndInferTypeFromResolver() Assert.NotNull(description.Resolver); Mock context = new Mock(MockBehavior.Strict); - Assert.Equal("ThisIsAString", description.Resolver(context.Object, default)); + Assert.Equal("ThisIsAString", description.Resolver(context.Object, default).Result); } [Fact] diff --git a/src/Types.Tests/Types/InputObjectTypeTests.cs b/src/Types.Tests/Types/InputObjectTypeTests.cs index a3b0e617e30..2ae48460847 100644 --- a/src/Types.Tests/Types/InputObjectTypeTests.cs +++ b/src/Types.Tests/Types/InputObjectTypeTests.cs @@ -12,7 +12,8 @@ public void ParseLiteral() { // arrange Schema schema = Create(); - InputObjectType object1Type = schema.GetType("Object1"); + InputObjectType object1Type = + schema.GetType("Object1"); ObjectValueNode literal = CreateObjectLiteral(); // act diff --git a/src/Types.Tests/Types/TypeFactoryTests.cs b/src/Types.Tests/Types/TypeFactoryTests.cs index 36cd1dafe79..be7bc4da15b 100644 --- a/src/Types.Tests/Types/TypeFactoryTests.cs +++ b/src/Types.Tests/Types/TypeFactoryTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading; +using System.Threading.Tasks; using HotChocolate.Configuration; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -20,7 +21,7 @@ public void CreateObjectType() type Simple { a: String b: [String] }"); var resolverBinding = new FieldResolver( - "Simple", "a", (c, r) => "hello"); + "Simple", "a", (c, r) => Task.FromResult("hello")); // act var factory = new ObjectTypeFactory(); @@ -45,7 +46,7 @@ public void CreateObjectType() Assert.Equal("String", type.Fields["b"].Type.TypeName()); Assert.Equal("hello", (type.Fields["a"] - .Resolver(null, CancellationToken.None))); + .Resolver(null, CancellationToken.None).Result)); } [Fact] diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithCancellationToken.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithCancellationToken.txt index 768a9586721..d69b1afeb55 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithCancellationToken.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithCancellationToken.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ct; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithContext.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithContext.txt index ae3158fa3ae..73db1197a74 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithContext.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithContext.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithField.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithField.txt index 6dfb903b085..7d3093edf96 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithField.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithField.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.Field; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithFieldSelection.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithFieldSelection.txt index 17d00c8ed47..dbbf7607e81 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithFieldSelection.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithFieldSelection.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.FieldSelection; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithObjectType.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithObjectType.txt index c9d5ef0cfa3..e85eadefec4 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithObjectType.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithObjectType.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.ObjectType; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithOperationDefinition.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithOperationDefinition.txt index ca07ee0b2b3..dd34ddb9cc2 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithOperationDefinition.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithOperationDefinition.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.Operation; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryDocument.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryDocument.txt index ad0a35137b9..c33d09cf70c 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryDocument.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryDocument.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.QueryDocument; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQuerySchema.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQuerySchema.txt index 978781a135e..162f90544a5 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQuerySchema.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQuerySchema.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.Schema; var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryService.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryService.txt index 809675d47d0..12cf37ed9d0 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryService.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithQueryService.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var b = ctx.Service(); var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(b); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgument.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgument.txt index f80a77fa826..16ad22defc7 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgument.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgument.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var v0_a = ctx.Parent(); var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(v0_a); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt index f59ec98bc9d..22a27720962 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt @@ -1,9 +1,8 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var v0_a = ctx.Parent(); var v1_b = ctx.Argument("b"); var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(v0_a, v1_b); @@ -12,6 +11,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt index 2ccddd5c951..305e080bd4c 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt @@ -1,10 +1,9 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var v0_a = ctx.Parent(); var v1_b = ctx.Argument("b"); var v2_c = ctx.Argument("c"); var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(v0_a, v1_b, v2_c); @@ -13,6 +12,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithoutArguments.txt b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithoutArguments.txt index 361e5e7304b..2bfb79b184b 100644 --- a/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithoutArguments.txt +++ b/src/Types.Tests/__snapshots__/AsyncResolverMethodGenerator_GenerateWithoutArguments.txt @@ -1,7 +1,6 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var resolver = ctx.Resolver(); -Func> f = async () => { try { return await resolver.GetFooAsync(); @@ -10,6 +9,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithOneArgument.txt b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithOneArgument.txt index 501cc3d539a..5f3a0b43f4b 100644 --- a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithOneArgument.txt +++ b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithOneArgument.txt @@ -1,8 +1,7 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var v0_a = ctx.Argument("a"); var source = ctx.Parent(); -Func> f = async () => { try { return await source.GetFooAsync(v0_a); @@ -12,6 +11,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithTwoArgument.txt b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithTwoArgument.txt index f2019748705..6c12aa8ac53 100644 --- a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithTwoArgument.txt +++ b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithTwoArgument.txt @@ -1,9 +1,8 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var v0_a = ctx.Argument("a"); var v1_b = ctx.Argument("b"); var source = ctx.Parent(); -Func> f = async () => { try { return await source.GetFooAsync(v0_a, v1_b); @@ -13,6 +12,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithoutArguments.txt b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithoutArguments.txt index 1dd999e5bc1..15fca7273fd 100644 --- a/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithoutArguments.txt +++ b/src/Types.Tests/__snapshots__/AsyncSourceMethodGenerator_GenerateWithoutArguments.txt @@ -1,7 +1,6 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = async (ctx, ct) => { var source = ctx.Parent(); -Func> f = async () => { try { return await source.GetFooAsync(); @@ -11,6 +10,5 @@ catch(HotChocolate.Execution.QueryException ex) { return ex.Errors; } -}; -return f(); + }; diff --git a/src/Types.Tests/__snapshots__/ResolverPropertyGenerator_Generate.txt b/src/Types.Tests/__snapshots__/ResolverPropertyGenerator_Generate.txt index 99e3ed14d52..88a87b77440 100644 --- a/src/Types.Tests/__snapshots__/ResolverPropertyGenerator_Generate.txt +++ b/src/Types.Tests/__snapshots__/ResolverPropertyGenerator_Generate.txt @@ -1,13 +1,13 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var resolver = ctx.Resolver(); try { -return resolver.Bar; +return Task.FromResult(resolver.Bar); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SourcePropertyGenerator_Generate.txt b/src/Types.Tests/__snapshots__/SourcePropertyGenerator_Generate.txt index d66068e6044..9ca2c6bcf7f 100644 --- a/src/Types.Tests/__snapshots__/SourcePropertyGenerator_Generate.txt +++ b/src/Types.Tests/__snapshots__/SourcePropertyGenerator_Generate.txt @@ -1,13 +1,13 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var source = ctx.Parent(); try { -return source.Bar; +return Task.FromResult(source.Bar); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgument.txt b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgument.txt index b2cedf49324..958f9dffae2 100644 --- a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgument.txt +++ b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgument.txt @@ -1,14 +1,14 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var v0_a = ctx.Parent(); var resolver = ctx.Resolver(); try { -return resolver.GetFoo(v0_a); +return Task.FromResult(resolver.GetFoo(v0_a)); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt index 58c9d2de7e2..2d4290567ca 100644 --- a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt +++ b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndArgument.txt @@ -1,15 +1,15 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var v0_a = ctx.Parent(); var v1_b = ctx.Argument("b"); var resolver = ctx.Resolver(); try { -return resolver.GetFoo(v0_a, v1_b); +return Task.FromResult(resolver.GetFoo(v0_a, v1_b)); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt index 0a1885a266b..66d5ab6e088 100644 --- a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt +++ b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithSourceArgumentAndTwoArguments.txt @@ -1,16 +1,16 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var v0_a = ctx.Parent(); var v1_b = ctx.Argument("b"); var v2_c = ctx.Argument("c"); var resolver = ctx.Resolver(); try { -return resolver.GetFoo(v0_a, v1_b, v2_c); +return Task.FromResult(resolver.GetFoo(v0_a, v1_b, v2_c)); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithoutArguments.txt b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithoutArguments.txt index 74bcbec877d..7fa267ec3de 100644 --- a/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithoutArguments.txt +++ b/src/Types.Tests/__snapshots__/SyncResolverMethodGenerator_GenerateWithoutArguments.txt @@ -1,13 +1,13 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var resolver = ctx.Resolver(); try { -return resolver.GetFoo(); +return Task.FromResult(resolver.GetFoo()); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithOneArgument.txt b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithOneArgument.txt index c6fe16d9aad..fe8424bf443 100644 --- a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithOneArgument.txt +++ b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithOneArgument.txt @@ -1,14 +1,14 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var v0_a = ctx.Argument("a"); var source = ctx.Parent(); try { -return source.GetFoo(v0_a); +return Task.FromResult(source.GetFoo(v0_a)); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithTwoArgument.txt b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithTwoArgument.txt index 2c5e9910153..20a28bdd572 100644 --- a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithTwoArgument.txt +++ b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithTwoArgument.txt @@ -1,15 +1,15 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var v0_a = ctx.Argument("a"); var v1_b = ctx.Argument("b"); var source = ctx.Parent(); try { -return source.GetFoo(v0_a, v1_b); +return Task.FromResult(source.GetFoo(v0_a, v1_b)); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithoutArguments.txt b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithoutArguments.txt index 3b24ef950b4..efcff38b186 100644 --- a/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithoutArguments.txt +++ b/src/Types.Tests/__snapshots__/SyncSourceMethodGenerator_GenerateWithoutArguments.txt @@ -1,13 +1,13 @@ /* Foo.bar */ -public static FieldResolverDelegate abc = (ctx, ct) => { +public static AsyncFieldResolverDelegate abc = (ctx, ct) => { var source = ctx.Parent(); try { -return source.GetFoo(); +return Task.FromResult(source.GetFoo()); } catch(HotChocolate.Execution.QueryException ex) { -return ex.Errors; +return Task.FromResult(ex.Errors); } }; diff --git a/src/Types/Configuration/Bindings/ResolverDelegateBindingInfo.cs b/src/Types/Configuration/Bindings/ResolverDelegateBindingInfo.cs index 6a6de8252bc..7e91e9938e1 100644 --- a/src/Types/Configuration/Bindings/ResolverDelegateBindingInfo.cs +++ b/src/Types/Configuration/Bindings/ResolverDelegateBindingInfo.cs @@ -1,4 +1,5 @@ using System.Reflection; +using System.Threading.Tasks; using HotChocolate.Resolvers; namespace HotChocolate.Configuration @@ -13,10 +14,16 @@ internal class ResolverDelegateBindingInfo public FieldResolver CreateFieldResolver() { - return AsyncFieldResolver == null - ? new FieldResolver(ObjectTypeName, FieldName, FieldResolver) - : new FieldResolver(ObjectTypeName, FieldName, - (ctx, ct) => AsyncFieldResolver(ctx, ct)); + return FieldResolver == null + ? new FieldResolver( + ObjectTypeName, + FieldName, + AsyncFieldResolver) + : new FieldResolver( + ObjectTypeName, + FieldName, + (ctx, ct) => Task.FromResult( + FieldResolver(ctx, ct))); } } } diff --git a/src/Types/Configuration/IResolverRegistry.cs b/src/Types/Configuration/IResolverRegistry.cs index 9125f440aa0..81e892af454 100644 --- a/src/Types/Configuration/IResolverRegistry.cs +++ b/src/Types/Configuration/IResolverRegistry.cs @@ -13,7 +13,7 @@ internal interface IResolverRegistry bool ContainsResolver(FieldReference fieldReference); - FieldResolverDelegate GetResolver(string typeName, string fieldName); + AsyncFieldResolverDelegate GetResolver(string typeName, string fieldName); IDirectiveMiddleware GetMiddleware(string directiveName); } diff --git a/src/Types/Configuration/ResolverRegistry.cs b/src/Types/Configuration/ResolverRegistry.cs index a12c9d48983..d92685ea5a3 100644 --- a/src/Types/Configuration/ResolverRegistry.cs +++ b/src/Types/Configuration/ResolverRegistry.cs @@ -11,8 +11,8 @@ namespace HotChocolate.Configuration internal class ResolverRegistry : IResolverRegistry { - private readonly Dictionary _resolvers = - new Dictionary(); + private readonly Dictionary _resolvers = + new Dictionary(); private readonly Dictionary _resolverBindings = new Dictionary(); private readonly Dictionary _resolverDescriptors = @@ -65,10 +65,13 @@ public bool ContainsResolver(FieldReference fieldReference) || _resolverBindings.ContainsKey(fieldReference); } - public FieldResolverDelegate GetResolver(string typeName, string fieldName) + public AsyncFieldResolverDelegate GetResolver( + string typeName, + string fieldName) { var fieldReference = new FieldReference(typeName, fieldName); - if (_resolvers.TryGetValue(fieldReference, out FieldResolverDelegate resolver)) + if (_resolvers.TryGetValue(fieldReference, + out AsyncFieldResolverDelegate resolver)) { return resolver; } @@ -145,7 +148,8 @@ private IEnumerable CreateMiddlewareDescriptors() foreach (DirectiveMethodMiddleware methodMiddleware in _middlewares.Values.OfType()) { - yield return new DirectiveMiddlewareDescriptor(methodMiddleware); + yield return new DirectiveMiddlewareDescriptor( + methodMiddleware); } } } diff --git a/src/Types/Resolvers/CodeGeneration/DirectiveResolverGenerator/MiddlewareSourceCodeGenerator.cs b/src/Types/Resolvers/CodeGeneration/DirectiveResolverGenerator/MiddlewareSourceCodeGenerator.cs index 3d640ffdeb3..bb6bc825754 100644 --- a/src/Types/Resolvers/CodeGeneration/DirectiveResolverGenerator/MiddlewareSourceCodeGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/DirectiveResolverGenerator/MiddlewareSourceCodeGenerator.cs @@ -19,7 +19,7 @@ protected override void GenerateDelegateHeader( string delegateName, T descriptor, StringBuilder source) { source.AppendLine($"/* @{descriptor.DirectiveName} */"); - source.Append($"public static {nameof(Middleware)}"); + source.Append($"public static {nameof(DirectiveMiddleware)}"); source.Append(" "); source.Append(delegateName); source.Append(" "); diff --git a/src/Types/Resolvers/CodeGeneration/ResolverBuilder.cs b/src/Types/Resolvers/CodeGeneration/ResolverBuilder.cs index 49ed6dfe5cc..89c68e39b69 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverBuilder.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverBuilder.cs @@ -89,7 +89,7 @@ private IEnumerable ExtractResolvers( yield return new FieldResolver( resolverDescriptors[i].Field.TypeName, resolverDescriptors[i].Field.FieldName, - (FieldResolverDelegate)field.GetValue(field)); + (AsyncFieldResolverDelegate)field.GetValue(field)); } } @@ -108,7 +108,7 @@ private IEnumerable ExtractMiddlewares( yield return new DirectiveDelegateMiddleware( middlewareDescriptors[i].DirectiveName, - (Middleware)field.GetValue(field)); + (DirectiveMiddleware)field.GetValue(field)); } } diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncResolverMethodGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncResolverMethodGenerator.cs index 80f81117796..d77238dbbc5 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncResolverMethodGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncResolverMethodGenerator.cs @@ -7,12 +7,13 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class AsyncResolverMethodGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => true; + protected override void GenerateResolverInvocation( ResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var resolver = ctx.{nameof(IResolverContext.Resolver)}<{resolverDescriptor.ResolverType.GetTypeName()}>();"); - source.AppendLine("Func> f = async () => {"); HandleExceptions(source, s => { @@ -26,9 +27,6 @@ protected override void GenerateResolverInvocation( } s.Append(");"); }); - - source.AppendLine("};"); - source.Append("return f();"); } protected override bool CanHandle(ResolverDescriptor descriptor) diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncSourceMethodGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncSourceMethodGenerator.cs index 8574f5b14b7..4954a60aedf 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncSourceMethodGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/AsyncSourceMethodGenerator.cs @@ -7,12 +7,13 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class AsyncSourceMethodGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => true; + protected override void GenerateResolverInvocation( SourceResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var source = ctx.{nameof(IResolverContext.Parent)}<{resolverDescriptor.SourceType.GetTypeName()}>();"); - source.AppendLine("Func> f = async () => {"); HandleExceptions(source, s => { @@ -26,9 +27,6 @@ protected override void GenerateResolverInvocation( } s.AppendLine(");"); }); - - source.AppendLine("};"); - source.Append("return f();"); } protected override bool CanHandle(SourceResolverDescriptor descriptor) diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverPropertyGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverPropertyGenerator.cs index 4f26b4050f6..369cbd93e91 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverPropertyGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverPropertyGenerator.cs @@ -6,14 +6,16 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class ResolverPropertyGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => false; + protected override void GenerateResolverInvocation( ResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var resolver = ctx.{nameof(IResolverContext.Resolver)}<{resolverDescriptor.ResolverType.GetTypeName()}>();"); - HandleExceptions(source, s => + HandleExceptionsSync(source, s => { - s.Append($"return resolver.{resolverDescriptor.Field.Member.Name};"); + s.Append($"return Task.FromResult(resolver.{resolverDescriptor.Field.Member.Name});"); }); } diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverSourceCodeGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverSourceCodeGenerator.cs index 1502e4e68a7..37ce3edb026 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverSourceCodeGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/ResolverSourceCodeGenerator.cs @@ -13,16 +13,25 @@ internal abstract class ResolverSourceCodeGenerator protected override IReadOnlyCollection ArgumentGenerators => ArgumentGeneratorCollections.ResolverArguments; + protected abstract bool IsAsync { get; } + protected override void GenerateDelegateHeader( string delegateName, T descriptor, StringBuilder source) { source.AppendLine($"/* {descriptor.Field.TypeName}.{descriptor.Field.FieldName} */"); - source.Append($"public static {nameof(FieldResolverDelegate)}"); + source.Append($"public static {nameof(AsyncFieldResolverDelegate)}"); source.Append(" "); source.Append(delegateName); source.Append(" "); source.Append(" = "); - source.Append("(ctx, ct) => {"); + if (IsAsync) + { + source.Append("async (ctx, ct) => {"); + } + else + { + source.Append("(ctx, ct) => {"); + } source.AppendLine(); } @@ -38,5 +47,18 @@ protected override IEnumerable GetArguments( { return descriptor.Arguments; } + + protected virtual void HandleExceptionsSync(StringBuilder source, Action code) + { + source.AppendLine("try"); + source.AppendLine("{"); + code(source); + source.AppendLine(); + source.AppendLine("}"); + source.AppendLine($"catch(HotChocolate.Execution.QueryException ex)"); + source.AppendLine("{"); + source.AppendLine($"return Task.FromResult(ex.Errors);"); + source.AppendLine("}"); + } } } diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SourcePropertyGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SourcePropertyGenerator.cs index c03b50ccfb8..35f2f5b870b 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SourcePropertyGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SourcePropertyGenerator.cs @@ -6,14 +6,16 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class SourcePropertyGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => false; + protected override void GenerateResolverInvocation( SourceResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var source = ctx.{nameof(IResolverContext.Parent)}<{resolverDescriptor.SourceType.GetTypeName()}>();"); - HandleExceptions(source, s => + HandleExceptionsSync(source, s => { - s.Append($"return source.{resolverDescriptor.Field.Member.Name};"); + s.Append($"return Task.FromResult(source.{resolverDescriptor.Field.Member.Name});"); }); } diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncResolverMethodGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncResolverMethodGenerator.cs index bdf18815f36..b421a7b6f59 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncResolverMethodGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncResolverMethodGenerator.cs @@ -7,14 +7,16 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class SyncResolverMethodGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => false; + protected override void GenerateResolverInvocation( ResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var resolver = ctx.{nameof(IResolverContext.Resolver)}<{resolverDescriptor.ResolverType.GetTypeName()}>();"); - HandleExceptions(source, s => + HandleExceptionsSync(source, s => { - s.Append($"return resolver.{resolverDescriptor.Field.Member.Name}("); + s.Append($"return Task.FromResult(resolver.{resolverDescriptor.Field.Member.Name}("); if (resolverDescriptor.Arguments.Count > 0) { string arguments = string.Join(", ", @@ -22,7 +24,7 @@ protected override void GenerateResolverInvocation( .Select(t => t.VariableName)); s.Append(arguments); } - s.Append(");"); + s.Append("));"); }); } diff --git a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncSourceMethodGenerator.cs b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncSourceMethodGenerator.cs index 115aa59ca4a..e2caad33740 100644 --- a/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncSourceMethodGenerator.cs +++ b/src/Types/Resolvers/CodeGeneration/ResolverGenerators/SyncSourceMethodGenerator.cs @@ -7,14 +7,16 @@ namespace HotChocolate.Resolvers.CodeGeneration internal sealed class SyncSourceMethodGenerator : ResolverSourceCodeGenerator { + protected override bool IsAsync => false; + protected override void GenerateResolverInvocation( SourceResolverDescriptor resolverDescriptor, StringBuilder source) { source.AppendLine($"var source = ctx.{nameof(IResolverContext.Parent)}<{resolverDescriptor.SourceType.GetTypeName()}>();"); - HandleExceptions(source, s => + HandleExceptionsSync(source, s => { - s.Append($"return source.{resolverDescriptor.Field.Member.Name}("); + s.Append($"return Task.FromResult(source.{resolverDescriptor.Field.Member.Name}("); if (resolverDescriptor.Arguments.Count > 0) { string arguments = string.Join(", ", @@ -22,7 +24,7 @@ protected override void GenerateResolverInvocation( .Select(t => t.VariableName)); s.Append(arguments); } - s.Append(");"); + s.Append("));"); }); } diff --git a/src/Types/Resolvers/DirectiveMiddlewareDelegates.cs b/src/Types/Resolvers/DirectiveMiddlewareDelegates.cs index 59c751a04cd..28943e5b89f 100644 --- a/src/Types/Resolvers/DirectiveMiddlewareDelegates.cs +++ b/src/Types/Resolvers/DirectiveMiddlewareDelegates.cs @@ -2,7 +2,7 @@ namespace HotChocolate.Resolvers { - public delegate DirectiveDelegate Middleware( + public delegate DirectiveDelegate DirectiveMiddleware( DirectiveDelegate next); public delegate Task DirectiveDelegate( diff --git a/src/Types/Resolvers/DirectiveResolverMiddleware.cs b/src/Types/Resolvers/DirectiveResolverMiddleware.cs index a6b213a2140..2c574b02b33 100644 --- a/src/Types/Resolvers/DirectiveResolverMiddleware.cs +++ b/src/Types/Resolvers/DirectiveResolverMiddleware.cs @@ -7,7 +7,7 @@ internal sealed class DirectiveDelegateMiddleware { public DirectiveDelegateMiddleware( string directiveName, - Middleware middleware) + DirectiveMiddleware middleware) { if (string.IsNullOrEmpty(directiveName)) { @@ -25,6 +25,6 @@ public DirectiveDelegateMiddleware( public string DirectiveName { get; } - public Middleware Middleware { get; } + public DirectiveMiddleware Middleware { get; } } } diff --git a/src/Types/Resolvers/FieldReference.cs b/src/Types/Resolvers/FieldReference.cs index 710aa9641c8..e2fafb7b63e 100644 --- a/src/Types/Resolvers/FieldReference.cs +++ b/src/Types/Resolvers/FieldReference.cs @@ -37,7 +37,7 @@ public FieldMember WithMember(MemberInfo member) return new FieldMember(TypeName, FieldName, member); } - public FieldResolver WithResolver(FieldResolverDelegate resolver) + public FieldResolver WithResolver(AsyncFieldResolverDelegate resolver) { return new FieldResolver(TypeName, FieldName, resolver); } diff --git a/src/Types/Resolvers/FieldResolver.cs b/src/Types/Resolvers/FieldResolver.cs index 3ec0e8caf18..36bd073a095 100644 --- a/src/Types/Resolvers/FieldResolver.cs +++ b/src/Types/Resolvers/FieldResolver.cs @@ -10,7 +10,7 @@ public sealed class FieldResolver public FieldResolver( string typeName, string fieldName, - FieldResolverDelegate resolver) + AsyncFieldResolverDelegate resolver) : base(typeName, fieldName) { Resolver = resolver @@ -19,7 +19,7 @@ public FieldResolver( public FieldResolver( FieldReference fieldReference, - FieldResolverDelegate resolver) + AsyncFieldResolverDelegate resolver) : base(fieldReference) { _fieldReference = fieldReference; @@ -27,7 +27,7 @@ public FieldResolver( ?? throw new ArgumentNullException(nameof(resolver)); } - public FieldResolverDelegate Resolver { get; } + public AsyncFieldResolverDelegate Resolver { get; } public FieldResolver WithTypeName(string typeName) { @@ -49,7 +49,7 @@ public FieldResolver WithFieldName(string fieldName) return new FieldResolver(TypeName, fieldName, Resolver); } - public FieldResolver WithResolver(FieldResolverDelegate resolver) + public FieldResolver WithResolver(AsyncFieldResolverDelegate resolver) { if (Equals(Resolver, resolver)) { diff --git a/src/Types/Types/Descriptors/DirectiveTypeDescriptor.cs b/src/Types/Types/Descriptors/DirectiveTypeDescriptor.cs index 151740c615d..936667a6d37 100644 --- a/src/Types/Types/Descriptors/DirectiveTypeDescriptor.cs +++ b/src/Types/Types/Descriptors/DirectiveTypeDescriptor.cs @@ -122,7 +122,7 @@ protected void Location(DirectiveLocation location) } } - protected void Middleware(Middleware middleware) + protected void Middleware(DirectiveMiddleware middleware) { if (middleware == null) { @@ -221,7 +221,7 @@ IDirectiveTypeDescriptor IDirectiveTypeDescriptor.Location( } IDirectiveTypeDescriptor IDirectiveTypeDescriptor.Middleware( - Middleware middleware) + DirectiveMiddleware middleware) { Middleware(middleware); return this; @@ -412,7 +412,7 @@ IDirectiveTypeDescriptor IDirectiveTypeDescriptor.Location( } IDirectiveTypeDescriptor IDirectiveTypeDescriptor.Middleware( - Middleware middleware) + DirectiveMiddleware middleware) { Middleware(middleware); return this; diff --git a/src/Types/Types/Descriptors/IDirectiveTypeDescriptor.cs b/src/Types/Types/Descriptors/IDirectiveTypeDescriptor.cs index 75fe79f0dfd..0e2f2b2a5a8 100644 --- a/src/Types/Types/Descriptors/IDirectiveTypeDescriptor.cs +++ b/src/Types/Types/Descriptors/IDirectiveTypeDescriptor.cs @@ -49,7 +49,7 @@ public interface IDirectiveTypeDescriptor // TODO : DOCU IDirectiveTypeDescriptor Middleware( - Middleware middleware); + DirectiveMiddleware middleware); // TODO : DOCU IDirectiveTypeDescriptor Middleware( @@ -128,7 +128,7 @@ IDirectiveArgumentDescriptor Argument( // TODO : DOCU new IDirectiveTypeDescriptor Middleware( - Middleware middleware); + DirectiveMiddleware middleware); // TODO : DOCU new IDirectiveTypeDescriptor Middleware( diff --git a/src/Types/Types/Descriptors/IObjectFieldDescriptor.cs b/src/Types/Types/Descriptors/IObjectFieldDescriptor.cs index d1c95447c09..a0eda7fa369 100644 --- a/src/Types/Types/Descriptors/IObjectFieldDescriptor.cs +++ b/src/Types/Types/Descriptors/IObjectFieldDescriptor.cs @@ -27,9 +27,11 @@ IObjectFieldDescriptor Argument(string name, IObjectFieldDescriptor Ignore(); - IObjectFieldDescriptor Resolver(FieldResolverDelegate fieldResolver); + IObjectFieldDescriptor Resolver( + AsyncFieldResolverDelegate fieldResolver); - IObjectFieldDescriptor Resolver(FieldResolverDelegate fieldResolver, + IObjectFieldDescriptor Resolver( + AsyncFieldResolverDelegate fieldResolver, Type resultType); IObjectFieldDescriptor Directive(T directive) @@ -49,7 +51,8 @@ public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, Func fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver(ctx)); + return descriptor.Resolver((ctx, ct) => + Task.FromResult(fieldResolver(ctx))); } public static IObjectFieldDescriptor Resolver( @@ -58,7 +61,8 @@ public static IObjectFieldDescriptor Resolver( { return descriptor .Type>() - .Resolver((ctx, ct) => fieldResolver(ctx), + .Resolver((ctx, ct) => + Task.FromResult(fieldResolver(ctx)), typeof(NativeType)); } @@ -66,22 +70,24 @@ public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, Func fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver()); + return descriptor.Resolver((ctx, ct) => + Task.FromResult(fieldResolver())); } public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, Func fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver(), - typeof(NativeType)); + return descriptor.Resolver((ctx, ct) => + Task.FromResult(fieldResolver()), + typeof(NativeType)); } public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, AsyncFieldResolverDelegate fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver(ctx, ct)); + return descriptor.Resolver(fieldResolver); } public static IObjectFieldDescriptor Resolver( @@ -95,8 +101,9 @@ public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, Func> fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver(ctx), - typeof(NativeType)); + return descriptor.Resolver( + async (ctx, ct) => await fieldResolver(ctx), + typeof(NativeType)); } public static IObjectFieldDescriptor Resolver( @@ -110,7 +117,7 @@ public static IObjectFieldDescriptor Resolver( this IObjectFieldDescriptor descriptor, Func> fieldResolver) { - return descriptor.Resolver((ctx, ct) => fieldResolver(), + return descriptor.Resolver(async (ctx, ct) => await fieldResolver(), typeof(NativeType)); } } diff --git a/src/Types/Types/Descriptors/ObjectFieldDescription.cs b/src/Types/Types/Descriptors/ObjectFieldDescription.cs index 79d9c94d996..9e0cc1b62ac 100644 --- a/src/Types/Types/Descriptors/ObjectFieldDescription.cs +++ b/src/Types/Types/Descriptors/ObjectFieldDescription.cs @@ -13,6 +13,6 @@ internal class ObjectFieldDescription public MemberInfo Member { get; set; } - public FieldResolverDelegate Resolver { get; set; } + public AsyncFieldResolverDelegate Resolver { get; set; } } } diff --git a/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs b/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs index 3ded8df863c..223f7d81a76 100644 --- a/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs +++ b/src/Types/Types/Descriptors/ObjectFieldDescriptor.cs @@ -69,12 +69,14 @@ protected void Ignore() FieldDescription.Ignored = true; } - protected void Resolver(FieldResolverDelegate fieldResolver) + protected void Resolver(AsyncFieldResolverDelegate fieldResolver) { FieldDescription.Resolver = fieldResolver; } - protected void Resolver(FieldResolverDelegate fieldResolver, Type resultType) + protected void Resolver( + AsyncFieldResolverDelegate fieldResolver, + Type resultType) { FieldDescription.Resolver = fieldResolver; FieldDescription.TypeReference = FieldDescription.TypeReference @@ -94,12 +96,14 @@ private IEnumerable CreateArguments() { var descriptions = new Dictionary(); - foreach (ArgumentDescription descriptor in FieldDescription.Arguments) + foreach (ArgumentDescription descriptor in + FieldDescription.Arguments) { descriptions[descriptor.Name] = descriptor; } - if (FieldDescription.Member != null && FieldDescription.Member is MethodInfo m) + if (FieldDescription.Member != null + && FieldDescription.Member is MethodInfo m) { foreach (ParameterInfo parameter in m.GetParameters()) { @@ -128,7 +132,8 @@ private bool IsArgumentType(ParameterInfo parameter) #region IObjectFieldDescriptor - IObjectFieldDescriptor IObjectFieldDescriptor.SyntaxNode(FieldDefinitionNode syntaxNode) + IObjectFieldDescriptor IObjectFieldDescriptor.SyntaxNode( + FieldDefinitionNode syntaxNode) { SyntaxNode(syntaxNode); return this; @@ -140,13 +145,15 @@ IObjectFieldDescriptor IObjectFieldDescriptor.Name(string name) return this; } - IObjectFieldDescriptor IObjectFieldDescriptor.Description(string description) + IObjectFieldDescriptor IObjectFieldDescriptor.Description( + string description) { Description(description); return this; } - IObjectFieldDescriptor IObjectFieldDescriptor.DeprecationReason(string deprecationReason) + IObjectFieldDescriptor IObjectFieldDescriptor.DeprecationReason( + string deprecationReason) { DeprecationReason(deprecationReason); return this; @@ -164,7 +171,9 @@ IObjectFieldDescriptor IObjectFieldDescriptor.Type(ITypeNode type) return this; } - IObjectFieldDescriptor IObjectFieldDescriptor.Argument(string name, Action argument) + IObjectFieldDescriptor IObjectFieldDescriptor.Argument( + string name, + Action argument) { Argument(name, argument); return this; @@ -176,13 +185,16 @@ IObjectFieldDescriptor IObjectFieldDescriptor.Ignore() return this; } - IObjectFieldDescriptor IObjectFieldDescriptor.Resolver(FieldResolverDelegate fieldResolver) + IObjectFieldDescriptor IObjectFieldDescriptor.Resolver( + AsyncFieldResolverDelegate fieldResolver) { Resolver(fieldResolver); return this; } - IObjectFieldDescriptor IObjectFieldDescriptor.Resolver(FieldResolverDelegate fieldResolver, Type resultType) + IObjectFieldDescriptor IObjectFieldDescriptor.Resolver( + AsyncFieldResolverDelegate fieldResolver, + Type resultType) { Resolver(fieldResolver, resultType); return this; diff --git a/src/Types/Types/Directive.cs b/src/Types/Types/Directive.cs index ade8315678c..1d8384e1fc6 100644 --- a/src/Types/Types/Directive.cs +++ b/src/Types/Types/Directive.cs @@ -49,7 +49,7 @@ internal Directive( public object Source { get; } - public Middleware Middleware => Type.Middleware; + public DirectiveMiddleware Middleware => Type.Middleware; public bool IsExecutable => Type.IsExecutable; diff --git a/src/Types/Types/DirectiveType.cs b/src/Types/Types/DirectiveType.cs index fc892a9198a..1e98ad914f3 100644 --- a/src/Types/Types/DirectiveType.cs +++ b/src/Types/Types/DirectiveType.cs @@ -35,7 +35,7 @@ public DirectiveType(Action configure) public FieldCollection Arguments { get; private set; } - public Middleware Middleware { get; private set; } + public DirectiveMiddleware Middleware { get; private set; } public bool IsExecutable { get; private set; } diff --git a/src/Types/Types/IDirective.cs b/src/Types/Types/IDirective.cs index c75d9dd8a27..4f985635966 100644 --- a/src/Types/Types/IDirective.cs +++ b/src/Types/Types/IDirective.cs @@ -11,7 +11,7 @@ public interface IDirective object Source { get; } - Middleware Middleware { get; } + DirectiveMiddleware Middleware { get; } bool IsExecutable { get; } diff --git a/src/Types/Types/ITypeInitializationContext.cs b/src/Types/Types/ITypeInitializationContext.cs index 87c95bb674a..f9e19d89852 100644 --- a/src/Types/Types/ITypeInitializationContext.cs +++ b/src/Types/Types/ITypeInitializationContext.cs @@ -28,7 +28,7 @@ void RegisterResolver( void RegisterMiddleware(IDirectiveMiddleware middleware); - FieldResolverDelegate GetResolver(string fieldName); + AsyncFieldResolverDelegate GetResolver(string fieldName); IDirectiveMiddleware GetMiddleware(string directiveName); diff --git a/src/Types/Types/ObjectField.cs b/src/Types/Types/ObjectField.cs index 8bed1e6ac46..ddc6b21ffe1 100644 --- a/src/Types/Types/ObjectField.cs +++ b/src/Types/Types/ObjectField.cs @@ -58,7 +58,7 @@ private static ObjectFieldDescription ExecuteConfigure( /// Gets the field resolver. /// /// - public FieldResolverDelegate Resolver { get; private set; } + public AsyncFieldResolverDelegate Resolver { get; private set; } /// /// Gets the interface fields that are implemented by this object field. diff --git a/src/Types/Types/TypeInitializationContext.cs b/src/Types/Types/TypeInitializationContext.cs index 9dcf6e45c92..a160a22aa8c 100644 --- a/src/Types/Types/TypeInitializationContext.cs +++ b/src/Types/Types/TypeInitializationContext.cs @@ -78,7 +78,7 @@ private IEnumerable GetPossibleInterfaceTypes( } } - public FieldResolverDelegate GetResolver(string fieldName) + public AsyncFieldResolverDelegate GetResolver(string fieldName) { if (string.IsNullOrEmpty(fieldName)) {