Skip to content

Commit

Permalink
Rewrite Middleware Compiler with Source Generators (#6896)
Browse files Browse the repository at this point in the history
michaelstaib authored Feb 17, 2024
1 parent 554fdc0 commit 8397331
Showing 64 changed files with 1,229 additions and 238 deletions.
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ public static class QueryCacheRequestExecutorBuilderExtensions
/// </param>
public static IRequestExecutorBuilder UseQueryCache(
this IRequestExecutorBuilder builder)
=> builder.UseRequest<QueryCacheMiddleware>();
=> builder.UseRequest(QueryCacheMiddleware.Create());

/// <summary>
/// Uses the default request pipeline including the
17 changes: 13 additions & 4 deletions src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using System.Threading.Tasks;
using HotChocolate.Execution;
using Microsoft.Extensions.DependencyInjection;
using static HotChocolate.WellKnownContextData;

namespace HotChocolate.Caching;

internal sealed class QueryCacheMiddleware
{
private readonly RequestDelegate _next;
private readonly ICacheControlOptions _options;

public QueryCacheMiddleware(
private readonly RequestDelegate _next;

private QueryCacheMiddleware(
RequestDelegate next,
[SchemaService] ICacheControlOptionsAccessor optionsAccessor)
{
@@ -58,4 +59,12 @@ queryResult.ContextData is not null
queryResult.HasNext);
}
}
}

internal static RequestCoreMiddleware Create()
=> (core, next) =>
{
var options = core.SchemaServices.GetRequiredService<ICacheControlOptionsAccessor>();
var middleware = new QueryCacheMiddleware(next, options);
return context => middleware.InvokeAsync(context);
};
}
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using CookieCrumble;
using HotChocolate.Types;
using Microsoft.Extensions.DependencyInjection;
using Snapshooter.Xunit;
using Xunit;

namespace HotChocolate.Caching.Http.Tests;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Headers": [],
"ContentHeaders": [
{
@@ -9,4 +9,4 @@
}
],
"Body": "{\"data\":{\"field\":\"\"}}"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Headers": [
{
"Key": "Cache-Control",
@@ -16,4 +16,4 @@
}
],
"Body": "{}"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Headers": [
{
"Key": "Cache-Control",
@@ -16,4 +16,4 @@
}
],
"Body": "{}"
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Headers": [
{
"Key": "Cache-Control",
@@ -16,4 +16,4 @@
}
],
"Body": "{}"
}
}
11 changes: 11 additions & 0 deletions src/HotChocolate/Core/src/Abstractions/MutationAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace HotChocolate;

/// <summary>
/// Marks a public/internal static method or property as a mutation root field.
/// The Hot Chocolate source generator will collect these and merge them into
/// the mutation type.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public sealed class MutationAttribute : Attribute;

This file was deleted.

11 changes: 11 additions & 0 deletions src/HotChocolate/Core/src/Abstractions/QueryAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace HotChocolate;

/// <summary>
/// Marks a public/internal static method or property as a query root field.
/// The Hot Chocolate source generator will collect these and merge them into
/// the query type.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public sealed class QueryAttribute : Attribute;
6 changes: 0 additions & 6 deletions src/HotChocolate/Core/src/Abstractions/QueryFieldAttribute.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -3,6 +3,4 @@
namespace HotChocolate;

[AttributeUsage(AttributeTargets.Parameter)]
public sealed class SchemaServiceAttribute : Attribute
{
}
public sealed class SchemaServiceAttribute : Attribute;
11 changes: 11 additions & 0 deletions src/HotChocolate/Core/src/Abstractions/SubscriptionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace HotChocolate;

/// <summary>
/// Marks a public/internal static method or property as a subscription root field.
/// The Hot Chocolate source generator will collect these and merge them into
/// the subscription type.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public sealed class SubscriptionAttribute : Attribute;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -4,14 +4,9 @@

namespace HotChocolate.Execution.Caching;

internal sealed class DefaultPreparedOperationCache : IPreparedOperationCache
internal sealed class DefaultPreparedOperationCache(int capacity = 100) : IPreparedOperationCache
{
private readonly Cache<IOperation> _cache;

public DefaultPreparedOperationCache(int capacity = 100)
{
_cache = new Cache<IOperation>(capacity);
}
private readonly Cache<IOperation> _cache = new(capacity);

public int Capacity => _cache.Capacity;

Original file line number Diff line number Diff line change
@@ -84,85 +84,86 @@ public static IRequestExecutorBuilder UseRequest<TMiddleware>(

public static IRequestExecutorBuilder UseDocumentCache(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<DocumentCacheMiddleware>();
builder.UseRequest(DocumentCacheMiddleware.Create());

public static IRequestExecutorBuilder UseDocumentParser(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<DocumentParserMiddleware>();
builder.UseRequest(DocumentParserMiddleware.Create());

public static IRequestExecutorBuilder UseDocumentValidation(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<DocumentValidationMiddleware>();
builder.UseRequest(DocumentValidationMiddleware.Create());

public static IRequestExecutorBuilder UseExceptions(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<ExceptionMiddleware>();
builder.UseRequest(ExceptionMiddleware.Create());

public static IRequestExecutorBuilder UseTimeout(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<TimeoutMiddleware>();
builder.UseRequest(DocumentParserMiddleware.Create());

public static IRequestExecutorBuilder UseInstrumentation(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<InstrumentationMiddleware>();
builder.UseRequest(InstrumentationMiddleware.Create());

public static IRequestExecutorBuilder UseOperationCache(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OperationCacheMiddleware>();
builder.UseRequest(OperationCacheMiddleware.Create());

public static IRequestExecutorBuilder UseOperationComplexityAnalyzer(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OperationComplexityMiddleware>();
builder.UseRequest(OperationComplexityMiddleware.Create());

public static IRequestExecutorBuilder UseOperationExecution(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OperationExecutionMiddleware>();
builder.UseRequest(OperationExecutionMiddleware.Create());

public static IRequestExecutorBuilder UseOperationResolver(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OperationResolverMiddleware>();
builder.UseRequest(OperationResolverMiddleware.Create());

public static IRequestExecutorBuilder UseOperationVariableCoercion(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OperationVariableCoercionMiddleware>();
builder.UseRequest(OperationVariableCoercionMiddleware.Create());

public static IRequestExecutorBuilder UseReadPersistedQuery(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<ReadPersistedQueryMiddleware>();
builder.UseRequest(ReadPersistedQueryMiddleware.Create());

public static IRequestExecutorBuilder UseAutomaticPersistedQueryNotFound(
this IRequestExecutorBuilder builder)
=> builder.UseRequest(next => context =>
{
if (context.Document is null && context.Request.Query is null)
if (context.Document is not null || context.Request.Query is not null)
{
var error = ReadPersistedQueryMiddleware_PersistedQueryNotFound();
var result = QueryResultBuilder.CreateError(
error,
new Dictionary<string, object?>
{
{ WellKnownContextData.HttpStatusCode, HttpStatusCode.BadRequest },
});

context.DiagnosticEvents.RequestError(context, new GraphQLException(error));
context.Result = result;
return default;
return next(context);
}

var error = ReadPersistedQueryMiddleware_PersistedQueryNotFound();
var result = QueryResultBuilder.CreateError(
error,
new Dictionary<string, object?>
{
{ WellKnownContextData.HttpStatusCode, HttpStatusCode.BadRequest },
});

context.DiagnosticEvents.RequestError(context, new GraphQLException(error));
context.Result = result;
return default;

return next(context);
});

public static IRequestExecutorBuilder UseWritePersistedQuery(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<WritePersistedQueryMiddleware>();
builder.UseRequest(WritePersistedQueryMiddleware.Create());

public static IRequestExecutorBuilder UsePersistedQueryNotFound(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<PersistedQueryNotFoundMiddleware>();
builder.UseRequest(PersistedQueryNotFoundMiddleware.Create());

public static IRequestExecutorBuilder UseOnlyPersistedQueriesAllowed(
this IRequestExecutorBuilder builder) =>
builder.UseRequest<OnlyPersistedQueriesAllowedMiddleware>();
builder.UseRequest(OnlyPersistedQueriesAllowedMiddleware.Create());

public static IRequestExecutorBuilder UseDefaultPipeline(
this IRequestExecutorBuilder builder)
@@ -229,16 +230,16 @@ public static IRequestExecutorBuilder UseAutomaticPersistedQueryPipeline(

internal static void AddDefaultPipeline(this IList<RequestCoreMiddleware> pipeline)
{
pipeline.Add(RequestClassMiddlewareFactory.Create<InstrumentationMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<ExceptionMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<TimeoutMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<DocumentCacheMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<DocumentParserMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<DocumentValidationMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<OperationCacheMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<OperationComplexityMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<OperationResolverMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<OperationVariableCoercionMiddleware>());
pipeline.Add(RequestClassMiddlewareFactory.Create<OperationExecutionMiddleware>());
pipeline.Add(InstrumentationMiddleware.Create());
pipeline.Add(ExceptionMiddleware.Create());
pipeline.Add(TimeoutMiddleware.Create());
pipeline.Add(DocumentCacheMiddleware.Create());
pipeline.Add(DocumentParserMiddleware.Create());
pipeline.Add(DocumentValidationMiddleware.Create());
pipeline.Add(OperationCacheMiddleware.Create());
pipeline.Add(OperationComplexityMiddleware.Create());
pipeline.Add(OperationResolverMiddleware.Create());
pipeline.Add(OperationVariableCoercionMiddleware.Create());
pipeline.Add(OperationExecutionMiddleware.Create());
}
}
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
using HotChocolate.Execution.Instrumentation;
using HotChocolate.Language;
using HotChocolate.Validation;
using Microsoft.Extensions.DependencyInjection;

namespace HotChocolate.Execution.Pipeline;

@@ -13,9 +14,8 @@ internal sealed class DocumentCacheMiddleware
private readonly IDocumentCache _documentCache;
private readonly IDocumentHashProvider _documentHashProvider;

public DocumentCacheMiddleware(
RequestDelegate next,
IExecutionDiagnosticEvents diagnosticEvents,
private DocumentCacheMiddleware(RequestDelegate next,
[SchemaService] IExecutionDiagnosticEvents diagnosticEvents,
IDocumentCache documentCache,
IDocumentHashProvider documentHashProvider)
{
@@ -84,4 +84,21 @@ public async ValueTask InvokeAsync(IRequestContext context)
_diagnosticEvents.AddedDocumentToCache(context);
}
}

public static RequestCoreMiddleware Create()
=> (core, next) =>
{
var diagnosticEvents = core.SchemaServices.GetRequiredService<IExecutionDiagnosticEvents>();
var documentCache = core.Services.GetRequiredService<IDocumentCache>();
var documentHashProvider = core.Services.GetRequiredService<IDocumentHashProvider>();
var middleware = Create(next, diagnosticEvents, documentCache, documentHashProvider);
return context => middleware.InvokeAsync(context);
};

internal static DocumentCacheMiddleware Create(
RequestDelegate next,
IExecutionDiagnosticEvents diagnosticEvents,
IDocumentCache documentCache,
IDocumentHashProvider documentHashProvider)
=> new(next, diagnosticEvents, documentCache, documentHashProvider);
}
Loading

0 comments on commit 8397331

Please sign in to comment.