Skip to content

Commit

Permalink
Added more execution abstractions
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed Apr 20, 2020
1 parent c668be4 commit a7fa8a0
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/HotChocolate/Core/src/Core/Execution/ExecutionContext.cs
Expand Up @@ -13,14 +13,14 @@ internal class ExecutionContext
: IExecutionContext
{
private readonly object _syncRoot = new object();
private readonly IRequestContext _requestContext;
private readonly IRawRequestContext _requestContext;
private readonly FieldCollector _fieldCollector;
private readonly ICachedQuery _cachedQuery;

public ExecutionContext(
ISchema schema,
IOperation operation,
IRequestContext requestContext,
IRawRequestContext requestContext,
CancellationToken requestAborted)
{
Schema = schema ??
Expand Down
4 changes: 2 additions & 2 deletions src/HotChocolate/Core/src/Core/Execution/IRequestContext.cs
Expand Up @@ -6,7 +6,7 @@

namespace HotChocolate.Execution
{
public interface IRequestContext
public interface IRawRequestContext
{
IRequestServiceScope ServiceScope { get; }

Expand All @@ -18,6 +18,6 @@ public interface IRequestContext

QueryExecutionDiagnostics Diagnostics { get; }

IRequestContext Clone();
IRawRequestContext Clone();
}
}
Expand Up @@ -3,7 +3,7 @@

namespace HotChocolate.Execution
{
public static class ClassMiddlewareFactory
internal static class ClassMiddlewareFactory
{
internal static QueryMiddleware Create<TMiddleware>()
where TMiddleware : class
Expand Down
4 changes: 2 additions & 2 deletions src/HotChocolate/Core/src/Core/Execution/RequestContext.cs
Expand Up @@ -10,7 +10,7 @@
namespace HotChocolate.Execution
{
internal class RequestContext
: IRequestContext
: IRawRequestContext
{
private readonly Func<ObjectField, FieldNode, FieldDelegate> _factory;

Expand Down Expand Up @@ -48,7 +48,7 @@ internal class RequestContext
return _factory(field, selection);
}

public IRequestContext Clone()
public IRawRequestContext Clone()
{
IServiceScope serviceScope = ServiceScope.ServiceProvider.CreateScope();

Expand Down
Expand Up @@ -8,7 +8,7 @@ namespace HotChocolate.Execution
/// This executor processes GraphQL query, mutation and subscription requests for the
/// <see cref="Schema" /> to which it is bound to.
/// </summary>
public interface IQueryExecutor
public interface IRequestExecutor
: IDisposable
{
/// <summary>
Expand All @@ -28,15 +28,16 @@ public interface IQueryExecutor
/// </param>
/// <returns>
/// Returns the execution result of the given GraphQL <paramref name="request" />.
///
/// If the request operation is a simple query or mutation the result is a
/// <see cref="IReadOnlyQueryResult" />.
///
/// If the request operation is a query or mutation where data is deferred, streamed or
/// includes live data the result is a <see cref="IResponseStream" /> where reach result
/// includes live data the result is a <see cref="IResponseStream" /> where each result
/// that the <see cref="IResponseStream" /> yields is a <see cref="IReadOnlyQueryResult" />.
///
/// If the request operation is a subscription the result is a
/// <see cref="IResponseStream" /> where reach result that the
/// <see cref="IResponseStream" /> where each result that the
/// <see cref="IResponseStream" /> yields is a
/// <see cref="IReadOnlyQueryResult" />.
/// </returns>
Expand Down
18 changes: 18 additions & 0 deletions src/HotChocolate/Core/src/Execution/IRequestMiddleware.cs
@@ -0,0 +1,18 @@
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
/// <summary>
/// Defines request middleware that can be added to the GraphQL request pipeline.
/// </summary>
public interface IRequestMiddleware
{
/// <summary>
/// Request handling method.
/// </summary>
/// <param name="context">The <see cref="IRequestContext"/> for the request.</param>
/// <param name="next">The delegate representing the remaining middleware in the request pipeline.</param>
/// <returns>A <see cref="Task"/> that represents the execution of this middleware.</returns>
Task InvokeAsync(IRequestContext context, RequestDelegate next);
}
}
16 changes: 16 additions & 0 deletions src/HotChocolate/Core/src/Execution/MutationExecutor.cs
@@ -0,0 +1,16 @@
using System.Threading;
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
internal sealed class MutationExecutor
: IOperationExecutor
{
public Task<IExecutionResult> ExecuteAsync(
IOperationContext executionContext,
CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
}
@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("HotChocolate.Execution.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
16 changes: 16 additions & 0 deletions src/HotChocolate/Core/src/Execution/QueryExecutor.cs
@@ -0,0 +1,16 @@
using System.Threading;
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
internal sealed class QueryExecutor
: IOperationExecutor
{
public Task<IExecutionResult> ExecuteAsync(
IOperationContext executionContext,
CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
}
11 changes: 11 additions & 0 deletions src/HotChocolate/Core/src/Execution/RequestDelegate.cs
@@ -0,0 +1,11 @@
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
/// <summary>
/// A function that can process a GraphQL request.
/// </summary>
/// <param name="context">The <see cref="IRequestContext"/> for the request.</param>
/// <returns>A task that represents the completion of request processing.</returns>
public delegate Task RequestDelegate(IRequestContext context);
}
7 changes: 3 additions & 4 deletions src/HotChocolate/Core/src/Execution/RequestMiddleware.cs
@@ -1,8 +1,7 @@
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
/// <summary>
/// Defines request middleware that can be added to the GraphQL request pipeline.
/// </summary>
public delegate RequestDelegate RequestMiddleware(RequestDelegate next);

public delegate Task RequestDelegate(IRequestContext context);
}
16 changes: 16 additions & 0 deletions src/HotChocolate/Core/src/Execution/SubscriptionExecutor.cs
@@ -0,0 +1,16 @@
using System.Threading;
using System.Threading.Tasks;

namespace HotChocolate.Execution
{
internal sealed class SubscriptionExecutor
: IOperationExecutor
{
public Task<IExecutionResult> ExecuteAsync(
IOperationContext executionContext,
CancellationToken cancellationToken)
{
throw new System.NotImplementedException();
}
}
}
@@ -0,0 +1,55 @@
using System;
using HotChocolate.Utilities;

namespace HotChocolate.Execution.Utilities
{
internal static class ClassMiddlewareFactory
{
internal static RequestMiddleware Create<TMiddleware>()
where TMiddleware : class
{
return next =>
{
MiddlewareFactory<TMiddleware, RequestDelegate> factory =
MiddlewareActivator.CompileFactory<TMiddleware, RequestDelegate>();
return CreateDelegate((s, n) => factory(s, n), next);
};
}

internal static RequestMiddleware Create<TMiddleware>(
Func<IServiceProvider, RequestDelegate, TMiddleware> factory)
where TMiddleware : class
{
return next => CreateDelegate(factory, next);
}

internal static RequestDelegate CreateDelegate<TMiddleware>(
Func<IServiceProvider, RequestDelegate, TMiddleware> factory,
RequestDelegate next)
where TMiddleware : class
{
object sync = new object();
TMiddleware? middleware = null;

ClassQueryDelegate<TMiddleware, IRequestContext> compiled =
MiddlewareActivator.CompileMiddleware<TMiddleware, IRequestContext>();

return context =>
{
if (middleware == null)
{
lock (sync)
{
if (middleware == null)
{
middleware = factory(context.Services, next);
}
}
}
return compiled(context, context.Services, middleware);
};
}
}
}
Expand Up @@ -43,7 +43,7 @@ public void ContextDataArePassedOn()
{ "abc", "123" }
};

var requestContext = new Mock<IRequestContext>();
var requestContext = new Mock<IRawRequestContext>();
requestContext.Setup(t => t.ContextData).Returns(contextData);
requestContext.Setup(t => t.ServiceScope).Returns(serviceScope);

Expand Down
@@ -0,0 +1,26 @@
using System.Threading.Tasks;
using Moq;
using Xunit;

namespace HotChocolate.Execution.Utilities
{
public class ClassMiddlewareFactoryTests
{
[Fact]
public void Create_Middleware_From_Class_That_Implements_IRequestMiddleware()
{
RequestMiddleware middleware =
ClassMiddlewareFactory.Create<CustomMiddlewareThatImplementsInterface>();
var contextMock = new Mock<IRequestContext>();
middleware.Invoke(c => Task.CompletedTask).Invoke(contextMock.Object);
}

public class CustomMiddlewareThatImplementsInterface : IRequestMiddleware
{
public Task InvokeAsync(IRequestContext context, RequestDelegate next)
{
return Task.CompletedTask;
}
}
}
}

0 comments on commit a7fa8a0

Please sign in to comment.