Skip to content

Commit

Permalink
Adds Variable Batching (#6981)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelstaib committed May 22, 2024
1 parent 9d1e3ce commit a162880
Show file tree
Hide file tree
Showing 653 changed files with 15,331 additions and 19,577 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public static ValueTask<IRequestExecutor> CreateExceptionExecutor(
if (context.ContextData.TryGetValue("ex", out var queryString))
{
context.Result =
QueryResultBuilder
OperationResultBuilder
.FromResult(context.Result!.ExpectQueryResult())
.SetContextData("ex", queryString)
.Create();
.Build();
}
})
.UseDefaultPipeline()
Expand Down
11 changes: 11 additions & 0 deletions src/CookieCrumble/src/CookieCrumble/Extensions/WriterExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ public static void AppendLine(this IBufferWriter<byte> snapshot)
snapshot.GetSpan(1)[0] = (byte)'\n';
snapshot.Advance(1);
}

public static void AppendLine(this IBufferWriter<byte> snapshot, bool appendWhenTrue)
{
if (!appendWhenTrue)
{
return;
}

snapshot.GetSpan(1)[0] = (byte)'\n';
snapshot.Advance(1);
}

public static void AppendSeparator(this IBufferWriter<byte> snapshot)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,43 @@ internal sealed class OperationResultSnapshotValueFormatter : SnapshotValueForma
{
protected override void Format(IBufferWriter<byte> snapshot, OperationResult value)
{
var next = false;

if(value.RequestIndex.HasValue)
{
snapshot.Append("RequestIndex: ");
snapshot.Append(value.RequestIndex.Value.ToString());
next = true;
}

if(value.VariableIndex.HasValue)
{
snapshot.AppendLine(appendWhenTrue: next);
snapshot.Append("VariableIndex: ");
snapshot.Append(value.VariableIndex.Value.ToString());
next = true;
}

if (value.Data.ValueKind is JsonValueKind.Object)
{
snapshot.Append("Data:");
snapshot.AppendLine();
snapshot.AppendLine(appendWhenTrue: next);
snapshot.Append("Data: ");
snapshot.Append(value.Data.ToString());
next = true;
}

if (value.Errors.ValueKind is JsonValueKind.Array)
{
snapshot.Append("Errors:");
snapshot.AppendLine();
snapshot.AppendLine(appendWhenTrue: next);
snapshot.Append("Errors: ");
snapshot.Append(value.Errors.ToString());
next = true;
}

if (value.Extensions.ValueKind is JsonValueKind.Object)
{
snapshot.Append("Extensions:");
snapshot.AppendLine();
snapshot.AppendLine(appendWhenTrue: next);
snapshot.Append("Extensions: ");
snapshot.Append(value.Extensions.ToString());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task Subgraph_SDL()
// assert
Assert.IsType<ObjectResult>(
Assert.IsType<ObjectResult>(
Assert.IsType<QueryResult>(result).Data)
Assert.IsType<OperationResult>(result).Data)
.GetValueOrDefault("_service"))
.GetValueOrDefault("sdl")
.MatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task Subgraph_SDL()
""");

// assert
var queryResult = Assert.IsType<QueryResult>(result);
var queryResult = Assert.IsType<OperationResult>(result);
var data = Assert.IsType<ObjectResult>(queryResult.Data);
var service = Assert.IsType<ObjectResult>(data.GetValueOrDefault("_service"));
service.GetValueOrDefault("sdl").MatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class DefaultHttpRequestInterceptor : IHttpRequestInterceptor
public virtual ValueTask OnCreateAsync(
HttpContext context,
IRequestExecutor requestExecutor,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken)
{
var userState = new UserState(context.User);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ public virtual ValueTask<ConnectionStatus> OnConnectAsync(
public virtual ValueTask OnRequestAsync(
ISocketSession session,
string operationSessionId,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken = default)
{
var context = session.Connection.HttpContext;
var userState = new UserState(context.User);
var serviceScopeFactory = session.Connection.RequestServices.GetService<IServiceScopeFactory>();

requestBuilder.TryAddGlobalState(nameof(IServiceScopeFactory), serviceScopeFactory);
requestBuilder.TryAddGlobalState(nameof(CancellationToken), session.Connection.RequestAborted);
requestBuilder.TryAddGlobalState(nameof(HttpContext), context);
Expand All @@ -47,10 +47,10 @@ public virtual ValueTask OnRequestAsync(
return default;
}

public virtual ValueTask<IQueryResult> OnResultAsync(
public virtual ValueTask<IOperationResult> OnResultAsync(
ISocketSession session,
string operationSessionId,
IQueryResult result,
IOperationResult result,
CancellationToken cancellationToken = default)
=> new(result);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public DelegateHttpRequestInterceptor(HttpRequestInterceptorDelegate interceptor
public override async ValueTask OnCreateAsync(
HttpContext context,
IRequestExecutor requestExecutor,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken)
{
await _interceptor(context, requestExecutor, requestBuilder, cancellationToken);
Expand Down
20 changes: 10 additions & 10 deletions src/HotChocolate/AspNetCore/src/AspNetCore/ErrorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public static IError NoSupportedAcceptMediaType()
.SetCode(ErrorCodes.Server.NoSupportedAcceptMediaType)
.Build();

public static IQueryResult TypeNameIsEmpty()
=> QueryResultBuilder.CreateError(
public static IOperationResult TypeNameIsEmpty()
=> OperationResultBuilder.CreateError(
new Error(
ErrorHelper_TypeNameIsEmpty,
code: ErrorCodes.Server.TypeParameterIsEmpty));

public static IQueryResult InvalidTypeName(string typeName)
=> QueryResultBuilder.CreateError(
public static IOperationResult InvalidTypeName(string typeName)
=> OperationResultBuilder.CreateError(
new Error(
ErrorHelper_InvalidTypeName,
code: ErrorCodes.Server.InvalidTypeName,
Expand All @@ -41,8 +41,8 @@ public static IQueryResult InvalidTypeName(string typeName)
{ nameof(typeName), typeName },
}));

public static IQueryResult TypeNotFound(string typeName)
=> QueryResultBuilder.CreateError(
public static IOperationResult TypeNotFound(string typeName)
=> OperationResultBuilder.CreateError(
new Error(
string.Format(ErrorHelper_TypeNotFound, typeName),
code: ErrorCodes.Server.TypeDoesNotExist,
Expand All @@ -51,8 +51,8 @@ public static IQueryResult TypeNotFound(string typeName)
{ nameof(typeName), typeName },
}));

public static IQueryResult InvalidAcceptMediaType(string headerValue)
=> QueryResultBuilder.CreateError(
public static IOperationResult InvalidAcceptMediaType(string headerValue)
=> OperationResultBuilder.CreateError(
new Error(
string.Format(ErrorHelper_InvalidAcceptMediaType, headerValue),
code: ErrorCodes.Server.InvalidAcceptHeaderValue,
Expand All @@ -61,8 +61,8 @@ public static IQueryResult InvalidAcceptMediaType(string headerValue)
{ nameof(headerValue), headerValue },
}));

public static IQueryResult MultiPartRequestPreflightRequired()
=> QueryResultBuilder.CreateError(
public static IOperationResult MultiPartRequestPreflightRequired()
=> OperationResultBuilder.CreateError(
new Error(
ErrorHelper_MultiPartRequestPreflightRequired,
code: ErrorCodes.Server.MultiPartPreflightRequired));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public AcceptHeaderResult(string headerValue)

public AcceptMediaType[] AcceptMediaTypes { get; }

public IQueryResult? ErrorResult { get; }
public IOperationResult? ErrorResult { get; }

[MemberNotNullWhen(true, nameof(ErrorResult))]
public bool HasError { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public sealed class HttpMultipartMiddleware : HttpPostMiddlewareBase
private const string _operations = "operations";
private const string _map = "map";
private readonly FormOptions _formOptions;
private readonly IQueryResult _multipartRequestError = MultiPartRequestPreflightRequired();
private readonly IOperationResult _multipartRequestError = MultiPartRequestPreflightRequired();

public HttpMultipartMiddleware(
HttpRequestDelegate next,
Expand Down Expand Up @@ -185,7 +185,7 @@ private static void InsertFilesIntoRequest(
GraphQLRequest request,
IDictionary<string, IFile> fileMap)
{
if (!(request.Variables is Dictionary<string, object?> mutableVariables))
if (request.Variables is not [Dictionary<string, object?> mutableVariables,])
{
throw new InvalidOperationException(
HttpMultipartMiddleware_InsertFilesIntoRequest_VariablesImmutable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ protected async Task HandleRequestAsync(HttpContext context)
statusCode = HttpStatusCode.NotAcceptable;

var error = ErrorHelper.NoSupportedAcceptMediaType();
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
goto HANDLE_RESULT;
}
Expand All @@ -120,15 +120,15 @@ protected async Task HandleRequestAsync(HttpContext context)
// GraphQL error result.
statusCode = HttpStatusCode.BadRequest;
var errors = errorHandler.Handle(ex.Errors);
result = QueryResultBuilder.CreateError(errors);
result = OperationResultBuilder.CreateError(errors);
DiagnosticEvents.ParserErrors(context, errors);
goto HANDLE_RESULT;
}
catch (Exception ex)
{
statusCode = HttpStatusCode.InternalServerError;
var error = errorHandler.CreateUnexpectedError(ex).Build();
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
goto HANDLE_RESULT;
}
Expand All @@ -145,7 +145,7 @@ protected async Task HandleRequestAsync(HttpContext context)
{
statusCode = HttpStatusCode.BadRequest;
var error = errorHandler.Handle(ErrorHelper.RequestHasNoElements());
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
break;
}
Expand Down Expand Up @@ -178,7 +178,7 @@ protected async Task HandleRequestAsync(HttpContext context)
{
var error = errorHandler.Handle(ErrorHelper.InvalidRequest());
statusCode = HttpStatusCode.BadRequest;
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
}

Expand Down Expand Up @@ -221,7 +221,7 @@ protected async Task HandleRequestAsync(HttpContext context)
{
var error = errorHandler.Handle(ErrorHelper.InvalidRequest());
statusCode = HttpStatusCode.BadRequest;
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
}
break;
Expand All @@ -231,7 +231,7 @@ protected async Task HandleRequestAsync(HttpContext context)
{
// This allows extensions to throw GraphQL exceptions in the GraphQL interceptor.
statusCode = null; // we let the serializer determine the status code.
result = QueryResultBuilder.CreateError(ex.Errors);
result = OperationResultBuilder.CreateError(ex.Errors);

foreach (var error in ex.Errors)
{
Expand All @@ -242,7 +242,7 @@ protected async Task HandleRequestAsync(HttpContext context)
{
statusCode = HttpStatusCode.InternalServerError;
var error = errorHandler.CreateUnexpectedError(ex).Build();
result = QueryResultBuilder.CreateError(error);
result = OperationResultBuilder.CreateError(error);
DiagnosticEvents.HttpRequestError(context, error);
}

Expand All @@ -262,7 +262,7 @@ protected async Task HandleRequestAsync(HttpContext context)
// to the HTTP response stream.
Debug.Assert(result is not null, "No GraphQL result was created.");

if (result is IQueryResult queryResult)
if (result is IOperationResult queryResult)
{
formatScope = DiagnosticEvents.FormatHttpResponse(context, queryResult);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace HotChocolate.AspNetCore;
public delegate ValueTask HttpRequestInterceptorDelegate(
HttpContext context,
IRequestExecutor requestExecutor,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken);
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ public interface IHttpRequestInterceptor
ValueTask OnCreateAsync(
HttpContext context,
IRequestExecutor requestExecutor,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ ValueTask<ConnectionStatus> OnConnectAsync(
ValueTask OnRequestAsync(
ISocketSession session,
string operationSessionId,
IQueryRequestBuilder requestBuilder,
OperationRequestBuilder requestBuilder,
CancellationToken cancellationToken = default);

/// <summary>
Expand All @@ -69,10 +69,10 @@ ValueTask OnRequestAsync(
/// <returns>
/// Returns the result that shall be send to the client.
/// </returns>
ValueTask<IQueryResult> OnResultAsync(
ValueTask<IOperationResult> OnResultAsync(
ISocketSession session,
string operationSessionId,
IQueryResult result,
IOperationResult result,
CancellationToken cancellationToken = default);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void ParserErrors(HttpContext context, IReadOnlyList<IError> errors)
}
}

public IDisposable FormatHttpResponse(HttpContext context, IQueryResult result)
public IDisposable FormatHttpResponse(HttpContext context, IOperationResult result)
{
var scopes = new IDisposable[_listeners.Length];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void StartOperationBatchRequest(
/// <returns>
/// A scope that will be disposed when GraphQL query result is written to the response stream.
/// </returns>
IDisposable FormatHttpResponse(HttpContext context, IQueryResult result);
IDisposable FormatHttpResponse(HttpContext context, IOperationResult result);

/// <summary>
/// Called when starting to establish a GraphQL WebSocket session.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void ParserErrors(HttpContext context, IReadOnlyList<IError> errors)
{
}

public IDisposable FormatHttpResponse(HttpContext context, IQueryResult result) => EmptyScope;
public IDisposable FormatHttpResponse(HttpContext context, IOperationResult result) => EmptyScope;

public IDisposable WebSocketSession(HttpContext context) => EmptyScope;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public virtual void ParserErrors(HttpContext context, IReadOnlyList<IError> erro
}

/// <inheritdoc />
public virtual IDisposable FormatHttpResponse(HttpContext context, IQueryResult result)
public virtual IDisposable FormatHttpResponse(HttpContext context, IOperationResult result)
=> EmptyScope;

/// <inheritdoc />
Expand Down
Loading

0 comments on commit a162880

Please sign in to comment.