diff --git a/src/All.slnx b/src/All.slnx index a4dad5e1730..63155413f31 100644 --- a/src/All.slnx +++ b/src/All.slnx @@ -263,6 +263,7 @@ + diff --git a/src/Build.Pack.slnx b/src/Build.Pack.slnx index 933faef9bc6..56ce0407e96 100644 --- a/src/Build.Pack.slnx +++ b/src/Build.Pack.slnx @@ -97,6 +97,7 @@ + diff --git a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/IOperationRequest.cs b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/IOperationRequest.cs index a3686a197f5..1d79b1871af 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/IOperationRequest.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/IOperationRequest.cs @@ -13,10 +13,17 @@ public interface IOperationRequest : IRequestBody /// string? Id { get; } +#if FUSION + /// + /// Gets the UTF-8 encoded query document containing the operation to execute. + /// + ReadOnlyMemory Query { get; } +#else /// /// Gets the query string or document containing the operation to execute. /// string? Query { get; } +#endif /// /// Gets the name of the operation to execute. diff --git a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/OperationRequest.cs b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/OperationRequest.cs index 38da00dc000..4df46c39993 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/OperationRequest.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/OperationRequest.cs @@ -25,7 +25,7 @@ public sealed class OperationRequest : IEquatable, IOperationR /// Initializes a new instance of the struct. /// /// - /// The query document containing the operation to execute. + /// The UTF-8 encoded query document containing the operation to execute. /// /// /// The ID of a previously persisted operation that should be executed. @@ -46,7 +46,7 @@ public sealed class OperationRequest : IEquatable, IOperationR /// The file map entries for multipart file uploads. Default is empty. /// public OperationRequest( - string? query, + ReadOnlyMemory query, string? id, string? operationName, ErrorHandlingMode? onError, @@ -149,10 +149,17 @@ public OperationRequest( /// public string? Id { get; } +#if FUSION + /// + /// Gets the UTF-8 encoded query document containing the operation to execute. + /// + public ReadOnlyMemory Query { get; } +#else /// /// Gets the query string or document containing the operation to execute. /// public string? Query { get; } +#endif /// /// Gets the name of the operation to execute. @@ -241,7 +248,7 @@ public bool Equals(OperationRequest? other) } return Id == other.Id - && Query == other.Query + && Query.Span.SequenceEqual(other.Query.Span) && Variables.Equals(other.Variables) && Extensions.Equals(other.Extensions); } @@ -252,7 +259,7 @@ public override bool Equals(object? obj) /// public override int GetHashCode() - => HashCode.Combine(Id, Query, Variables, Extensions); + => HashCode.Combine(Id, Query.Length, Variables, Extensions); #else public bool Equals(OperationRequest? other) { diff --git a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs index 8ebf19d9d79..137716def58 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/Serialization/Utf8JsonWriterHelper.cs @@ -42,10 +42,10 @@ public static void WriteOperationRequest(JsonWriter writer, OperationRequest req writer.WriteStringValue(request.Id); } - if (!string.IsNullOrWhiteSpace(request.Query)) + if (!request.Query.IsEmpty) { writer.WritePropertyName(Utf8GraphQLRequestProperties.QueryProp); - writer.WriteStringValue(request.Query); + writer.WriteStringValue(request.Query.Span); } if (!string.IsNullOrWhiteSpace(request.OperationName)) @@ -85,10 +85,10 @@ public static void WriteVariableBatchRequest(JsonWriter writer, VariableBatchReq writer.WriteStringValue(request.Id); } - if (!string.IsNullOrWhiteSpace(request.Query)) + if (!request.Query.IsEmpty) { writer.WritePropertyName(Utf8GraphQLRequestProperties.QueryProp); - writer.WriteStringValue(request.Query); + writer.WriteStringValue(request.Query.Span); } if (!string.IsNullOrWhiteSpace(request.OperationName)) diff --git a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/VariableBatchRequest.cs b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/VariableBatchRequest.cs index 7d13f293e0e..ab8ce021081 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Abstractions/VariableBatchRequest.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Abstractions/VariableBatchRequest.cs @@ -24,7 +24,7 @@ public sealed class VariableBatchRequest : IOperationRequest, IEquatable struct. /// /// - /// The query document containing the operation to execute. + /// The UTF-8 encoded query document containing the operation to execute. /// /// /// The ID of a previously persisted operation that should be executed. @@ -45,7 +45,7 @@ public sealed class VariableBatchRequest : IOperationRequest, IEquatable public VariableBatchRequest( - string? query, + ReadOnlyMemory query, string? id, string? operationName, ErrorHandlingMode? onError, @@ -146,10 +146,17 @@ public VariableBatchRequest( /// public string? Id { get; } +#if FUSION + /// + /// Gets the UTF-8 encoded query document containing the operation to execute. + /// + public ReadOnlyMemory Query { get; } +#else /// /// Gets the query string or document containing the operation to execute. /// public string? Query { get; } +#endif /// /// Gets the name of the operation to execute. @@ -230,7 +237,7 @@ public bool Equals(VariableBatchRequest? other) } return Id == other.Id - && Query == other.Query + && Query.Span.SequenceEqual(other.Query.Span) && Variables.Equals(other.Variables) && Extensions.Equals(other.Extensions); } @@ -241,7 +248,7 @@ public override bool Equals(object? obj) /// public override int GetHashCode() - => HashCode.Combine(Id, Query, Variables, Extensions); + => HashCode.Combine(Id, Query.Length, Variables, Extensions); #else public bool Equals(VariableBatchRequest? other) { diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs index 412aab8a6f2..632573fef61 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/DefaultGraphQLHttpClient.cs @@ -443,11 +443,11 @@ private static Uri CreateGetRequestUri( sb.Append(Uri.EscapeDataString(or.Id)); } - if (!string.IsNullOrWhiteSpace(or.Query)) + if (!or.Query.IsEmpty) { AppendAmpersand(sb, ref appendAmpersand); sb.Append("query="); - sb.Append(Uri.EscapeDataString(or.Query)); + sb.Append(Uri.EscapeDataString(Encoding.UTF8.GetString(or.Query.Span))); } if (!string.IsNullOrWhiteSpace(or.OperationName)) diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpClientExtensions.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpClientExtensions.cs index f23222c3a5c..0ee6b079000 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpClientExtensions.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpClientExtensions.cs @@ -1,4 +1,5 @@ #if FUSION +using System.Text; using HotChocolate.Fusion.Execution; #endif @@ -35,7 +36,7 @@ public static Task GetAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -171,7 +172,7 @@ public static Task GetAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -211,7 +212,7 @@ public static Task GetAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -347,7 +348,7 @@ public static Task PostAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -415,7 +416,7 @@ public static Task PostAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -455,7 +456,7 @@ public static Task PostAsync( { #if FUSION var operation = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpRequest.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpRequest.cs index 5f679acb6d0..32bee766c1c 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpRequest.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpRequest.cs @@ -2,6 +2,7 @@ using System.Net.Http.Headers; using HotChocolate.Language; #if FUSION +using System.Text; using HotChocolate.Fusion.Execution; using HotChocolate.Fusion.Execution.Clients; using HotChocolate.Transport.Http; @@ -41,7 +42,7 @@ public GraphQLHttpRequest(string query, Uri? requestUri = null) #if FUSION Body = new OperationRequest( - query, + Encoding.UTF8.GetBytes(query), id: null, operationName: null, onError: null, @@ -70,7 +71,7 @@ public GraphQLHttpRequest(OperationRequest body, Uri? requestUri = null) { #if FUSION if (string.IsNullOrEmpty(body.Id) - && string.IsNullOrEmpty(body.Query) + && body.Query.IsEmpty && body.Extensions.IsEmpty) { throw new ArgumentException( @@ -110,7 +111,7 @@ public GraphQLHttpRequest(VariableBatchRequest body, Uri? requestUri = null) { #if FUSION if (string.IsNullOrEmpty(body.Id) - && string.IsNullOrEmpty(body.Query) + && body.Query.IsEmpty && body.Extensions.IsEmpty) { throw new ArgumentException( @@ -158,7 +159,7 @@ public GraphQLHttpRequest(OperationBatchRequest body, Uri? requestUri = null) { #if FUSION if (string.IsNullOrEmpty(request.Id) - && string.IsNullOrEmpty(request.Query) + && request.Query.IsEmpty && request.Extensions.IsEmpty) #else if (string.IsNullOrEmpty(request.Id) diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSchemaToFile_When_OutputOptionIsSpecified.md b/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSchemaToFile_When_OutputOptionIsSpecified.md index 0b654140e70..8a879639dd2 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSchemaToFile_When_OutputOptionIsSpecified.md +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSchemaToFile_When_OutputOptionIsSpecified.md @@ -20,7 +20,15 @@ type Query { "name": "_Default", "transports": { "http": { - "url": "http://localhost:5000/graphql" + "url": "http://localhost:5000/graphql", + "capabilities": { + "batching": { + "variableBatching": true, + "requestBatching": true, + "aliasBatching": true + }, + "onError": "propagate" + } } } } diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSemanticNonNullSchemaToFile_When_SemanticNonNullOptionIsSpecified.md b/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSemanticNonNullSchemaToFile_When_SemanticNonNullOptionIsSpecified.md index 703798decb3..b9b1bbc172d 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSemanticNonNullSchemaToFile_When_SemanticNonNullOptionIsSpecified.md +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.CommandLine.Tests/__snapshots__/SchemaExportCommandTests.App_Should_WriteSemanticNonNullSchemaToFile_When_SemanticNonNullOptionIsSpecified.md @@ -22,7 +22,15 @@ directive @semanticNonNull(levels: [Int!] = [0]) on FIELD_DEFINITION "name": "_Default", "transports": { "http": { - "url": "http://localhost:5000/graphql" + "url": "http://localhost:5000/graphql", + "capabilities": { + "batching": { + "variableBatching": true, + "requestBatching": true, + "aliasBatching": true + }, + "onError": "propagate" + } } } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs index 7114094239a..9f9d9d0ba53 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs @@ -124,6 +124,20 @@ private static async Task CreateNewSettingsFile( jsonWriter.WriteString("url", "http://localhost:5000/graphql"); + // A Hot Chocolate source schema knows which transport extensions it implements, so the + // exported template declares them instead of leaving the gateway on the defaults. + jsonWriter.WriteStartObject("capabilities"); + + jsonWriter.WriteStartObject("batching"); + jsonWriter.WriteBoolean("variableBatching", true); + jsonWriter.WriteBoolean("requestBatching", true); + jsonWriter.WriteBoolean("aliasBatching", true); + jsonWriter.WriteEndObject(); + + jsonWriter.WriteString("onError", "propagate"); + + jsonWriter.WriteEndObject(); + jsonWriter.WriteEndObject(); jsonWriter.WriteEndObject(); diff --git a/src/HotChocolate/Fusion/src/Fusion.Connectors.InMemory/InMemorySourceSchemaClient.cs b/src/HotChocolate/Fusion/src/Fusion.Connectors.InMemory/InMemorySourceSchemaClient.cs index 51f90479e75..0e29d4bdc97 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Connectors.InMemory/InMemorySourceSchemaClient.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Connectors.InMemory/InMemorySourceSchemaClient.cs @@ -386,12 +386,13 @@ private static IOperationRequest BuildOperationRequest( features.Set(fileLookup); } + // The operation executes in-process, so the source text is parsed here directly + // instead of routing the request through a source-text document that would parse again. + var document = new OperationDocument(Utf8GraphQLParser.Parse(request.OperationSourceText.Span)); + if (request.Variables.Length == 0) { - return OperationRequest.FromSourceText( - request.OperationSourceText, - errorHandlingMode: onError, - features: features); + return CreateOperationRequest(document, onError, features: features); } if (request.Variables.Length == 1) @@ -400,17 +401,17 @@ private static IOperationRequest BuildOperationRequest( if (!request.RequiresFileUpload) { - return OperationRequest.FromSourceText( - request.OperationSourceText, - errorHandlingMode: onError, + return CreateOperationRequest( + document, + onError, variableValues: JsonDocument.Parse(sequence)); } buffer ??= new ChunkedArrayWriter(); var cleanedJson = StripFileMarkers(buffer, sequence); - return OperationRequest.FromSourceText( - request.OperationSourceText, - errorHandlingMode: onError, + return CreateOperationRequest( + document, + onError, variableValues: JsonDocument.Parse(cleanedJson.AsSequence()), features: features); } @@ -433,13 +434,38 @@ private static IOperationRequest BuildOperationRequest( ? StripFileMarkers(buffer, variables.AsSequence()).AsSequence() : variables.AsSequence(); - return VariableBatchRequest.FromSourceText( - request.OperationSourceText, - variableValues: JsonDocument.Parse(variableSequence), + return new VariableBatchRequest( + document, + documentId: null, + documentHash: null, + operationName: null, errorHandlingMode: onError, - features: features); + variableValues: new JsonDocumentOwner(JsonDocument.Parse(variableSequence)), + extensions: null, + contextData: null, + features: features, + services: null, + flags: RequestFlags.AllowAll); } + private static OperationRequest CreateOperationRequest( + IOperationDocument document, + ErrorHandlingMode? onError, + JsonDocument? variableValues = null, + IFeatureCollection? features = null) + => new( + document, + documentId: null, + documentHash: null, + operationName: null, + errorHandlingMode: onError, + variableValues: variableValues is null ? null : new JsonDocumentOwner(variableValues), + extensions: null, + contextData: null, + features: features, + services: null, + flags: RequestFlags.AllowAll); + /// /// Scans JSON for $.file(key) string markers and replaces them with just key. /// diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Configuration/Parsers/DefaultGraphQLClientConfigurationParser.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Configuration/Parsers/DefaultGraphQLClientConfigurationParser.cs index 315b121d1a9..03453114a95 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Configuration/Parsers/DefaultGraphQLClientConfigurationParser.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Configuration/Parsers/DefaultGraphQLClientConfigurationParser.cs @@ -4,6 +4,7 @@ using System.Text.Json; using HotChocolate.Fusion.Execution.Clients; using HotChocolate.Fusion.Types; +using HotChocolate.Fusion.Types.Metadata; using HotChocolate.Language; namespace HotChocolate.Fusion.Configuration.Parsers; @@ -29,17 +30,24 @@ public bool TryParse( return false; } - configurations = [CreateHttpClientConfiguration(sourceSchema.Name, http)]; + configurations = [CreateHttpClientConfiguration(schema, sourceSchema.Name, http)]; return true; } private static HttpSourceSchemaClientConfiguration CreateHttpClientConfiguration( + FusionSchemaDefinition schema, string schemaName, JsonElement http) { var clientName = HttpSourceSchemaClientConfiguration.DefaultClientName; - var capabilities = SourceSchemaClientCapabilities.All; + // An Apollo Federation subgraph is only assumed to speak plain GraphQL, so alias batching + // is the only batching capability that is defaulted on for it. Every other source schema + // keeps the protocol-extension defaults. Explicitly declared settings win, per flag. + var capabilities = + schema.GetSourceSchemaConnectorKind(schemaName) == ConnectorKindNames.ApolloFederation + ? SourceSchemaClientCapabilities.AliasBatching + : SourceSchemaClientCapabilities.Default; var supportedOperations = SupportedOperationType.All; ImmutableArray? defaultAcceptHeaderValues = null; ImmutableArray? batchingAcceptHeaderValues = null; @@ -87,6 +95,13 @@ private static HttpSourceSchemaClientConfiguration CreateHttpClientConfiguration : capabilities & ~SourceSchemaClientCapabilities.RequestBatching; } + if (batchingElement.TryGetProperty("aliasBatching", out supported)) + { + capabilities = supported.GetBoolean() + ? capabilities | SourceSchemaClientCapabilities.AliasBatching + : capabilities & ~SourceSchemaClientCapabilities.AliasBatching; + } + if (batchingElement.TryGetProperty("formats", out var formats)) { var builder = ImmutableArray.CreateBuilder(); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/DependencyInjection/CoreFusionGatewayBuilderExtensions.SourceSchemaClients.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/DependencyInjection/CoreFusionGatewayBuilderExtensions.SourceSchemaClients.cs index 4d7b0070c1b..75b655542b7 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/DependencyInjection/CoreFusionGatewayBuilderExtensions.SourceSchemaClients.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/DependencyInjection/CoreFusionGatewayBuilderExtensions.SourceSchemaClients.cs @@ -57,7 +57,7 @@ public static IFusionGatewayBuilder AddHttpClientConfiguration( string name, Uri baseAddress, SupportedOperationType supportedOperations = SupportedOperationType.All, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, @@ -131,7 +131,7 @@ public static IFusionGatewayBuilder AddHttpClientConfiguration( string httpClientName, Uri baseAddress, SupportedOperationType supportedOperations = SupportedOperationType.All, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/ApolloFederation/LookupEntityQueryRewriter.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/ApolloFederation/LookupEntityQueryRewriter.cs index 453584e3344..70e0d14689c 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/ApolloFederation/LookupEntityQueryRewriter.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/ApolloFederation/LookupEntityQueryRewriter.cs @@ -1,3 +1,4 @@ +using System.Text; using HotChocolate.Fusion.Execution.Nodes; using HotChocolate.Fusion.Types; using HotChocolate.Fusion.Types.Metadata; @@ -20,6 +21,9 @@ namespace HotChocolate.Fusion.Execution.ApolloFederation; /// internal static class LookupEntityQueryRewriter { + // The federation union that the '_entities' field returns. + private const string EntityUnionTypeName = "_Entity"; + /// /// Rewrites a lookup operation into an Apollo Federation _entities query. /// @@ -42,7 +46,7 @@ public static RewrittenOperation Rewrite( ArgumentNullException.ThrowIfNull(schema); ArgumentException.ThrowIfNullOrEmpty(schemaName); - var document = Utf8GraphQLParser.Parse(operation.SourceText); + var document = Utf8GraphQLParser.Parse(operation.SourceText.Span); var operationDefinition = GetOperationDefinition(document); var lookupField = GetLookupField(operationDefinition); var lookup = ResolveLookup(schema, schemaName, lookupField); @@ -74,7 +78,12 @@ public static RewrittenOperation Rewrite( operationDefinition.VariableDefinitions); return new RewrittenOperation( - new OperationSourceText(operation.Name, operation.Type, text, operation.Hash), + OperationSourceText.Create( + operation.Name, + operation.Type, + Encoding.UTF8.GetBytes(text), + operation.Hash, + lookupTypeName: EntityUnionTypeName), entityTypeName, lookupField); } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchItem.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchItem.cs new file mode 100644 index 00000000000..1bb10e66998 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchItem.cs @@ -0,0 +1,40 @@ +using HotChocolate.Language; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Represents one logical operation of a batched request: the root selection of a source schema +/// request paired with a single set of variable values. +/// +/// The index of the request this item was flattened from. +/// The root selection of the request's operation. +/// +/// The name of the type that the body of is selected on. +/// +/// The variable values of this item. +internal readonly struct AliasBatchItem( + int requestIndex, + Utf8FieldNode rootField, + string lookupTypeName, + VariableValues variables) +{ + /// + /// Gets the index of the request this item was flattened from. + /// + public int RequestIndex { get; } = requestIndex; + + /// + /// Gets the root selection of the request's operation. + /// + public Utf8FieldNode RootField { get; } = rootField; + + /// + /// Gets the name of the type that the body of is selected on. + /// + public string LookupTypeName { get; } = lookupTypeName; + + /// + /// Gets the variable values of this item. + /// + public VariableValues Variables { get; } = variables; +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchPrefixHelper.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchPrefixHelper.cs new file mode 100644 index 00000000000..4d5b496473e --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchPrefixHelper.cs @@ -0,0 +1,113 @@ +using System.Buffers.Text; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Composes and reads the _{index}_ prefix that identifies the item a root selection, a +/// variable, or an error path of a batched request belongs to. +/// +internal static class AliasBatchPrefixHelper +{ + // An underscore, the decimal digits of a non-negative int and a second underscore. + private const int MaxPrefixLength = 12; + + /// + /// Writes the prefix of the item at into . + /// + /// + /// The buffer that receives the prefix. It must hold at least + /// bytes. + /// + /// The zero-based item index. + /// The written prefix. + public static ReadOnlySpan ComposePrefix(Span buffer, int index) + { + buffer[0] = (byte)'_'; + Utf8Formatter.TryFormat(index, buffer[1..], out var written); + buffer[written + 1] = (byte)'_'; + return buffer[..(written + 2)]; + } + + /// + /// Writes the prefixed name of for the item at + /// into . + /// + /// + /// The buffer that receives the name. It must hold at least + /// bytes more than . + /// + /// The zero-based item index. + /// The name that is prefixed. + /// The written name. + public static ReadOnlySpan ComposeName( + Span buffer, + int index, + ReadOnlySpan name) + { + var prefix = ComposePrefix(buffer, index); + name.CopyTo(buffer[prefix.Length..]); + return buffer[..(prefix.Length + name.Length)]; + } + + /// + /// Returns the buffer length required to compose a prefixed form of a name of + /// bytes. + /// + /// The length of the name that is prefixed. + public static int GetNameBufferLength(int nameLength) => nameLength + MaxPrefixLength; + + /// + /// Reads the item index from a prefixed name. + /// + /// The name to read. + /// The zero-based item index the name belongs to. + /// The name without its prefix. + /// + /// when carries a prefix; otherwise, + /// . + /// + public static bool TryReadIndex( + ReadOnlySpan prefixedName, + out int index, + out ReadOnlySpan name) + { + index = 0; + name = default; + + if (prefixedName.Length < 3 || prefixedName[0] != (byte)'_') + { + return false; + } + + var value = 0; + var position = 1; + + while (position < prefixedName.Length) + { + var digit = prefixedName[position] - (byte)'0'; + + if ((uint)digit > 9) + { + break; + } + + // An index that does not fit into an int names no item of the batch. + if (value > (int.MaxValue - digit) / 10) + { + return false; + } + + value = (value * 10) + digit; + position++; + } + + if (position == 1 || position == prefixedName.Length || prefixedName[position] != (byte)'_') + { + return false; + } + + index = value; + name = prefixedName[(position + 1)..]; + return true; + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchResponseSplitter.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchResponseSplitter.cs new file mode 100644 index 00000000000..997d94c402f --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchResponseSplitter.cs @@ -0,0 +1,146 @@ +using System.Runtime.InteropServices; +using System.Text.Json; +using HotChocolate.Fusion.Text.Json; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Splits the single response of a batched request into one result per item. Fields and error +/// paths are dispatched by their alias, not by their position. +/// +internal static class AliasBatchResponseSplitter +{ + private static ReadOnlySpan DataProperty => "data"u8; + private static ReadOnlySpan ErrorsProperty => "errors"u8; + private static ReadOnlySpan PathProperty => "path"u8; + + /// + /// Splits into one result per item of the batched request. The + /// results share the document, which is freed once the last of them is disposed. + /// + /// The response document of the batched request. + /// The items of the batched request. + /// + /// The buffer that receives one result per item. It must hold at least as many entries as + /// there are items. + /// + /// How the response relates to the items of the request. + public static AliasBatchSplitStatus TrySplit( + SourceResultDocument document, + ReadOnlySpan items, + SourceSchemaResult[] results) + { + document.Root.TryGetProperty(ErrorsProperty, out var errors); + + List?[]? routedErrors = null; + + if (errors.ValueKind is JsonValueKind.Array) + { + var status = RouteErrors(errors, items, ref routedErrors); + + if (status is not AliasBatchSplitStatus.Split) + { + return status; + } + } + + if (!document.Root.TryGetProperty(DataProperty, out var data) + || data.ValueKind is not JsonValueKind.Object) + { + return AliasBatchSplitStatus.Invalid; + } + + var roots = new SourceResultElement[items.Length]; + + foreach (var property in data.EnumerateObject()) + { + if (!TryResolveItem(property.NameSpan, items, out var index)) + { + return AliasBatchSplitStatus.Invalid; + } + + roots[index] = property.Value; + } + + var documentOwner = new SourceResultDocumentOwner(document, items.Length); + + for (var i = 0; i < items.Length; i++) + { + var variables = items[i].Variables; + var root = roots[i]; + var itemErrors = routedErrors?[i]; + + results[i] = new SourceSchemaResult( + variables.Path, + document, + documentOwner: documentOwner, + // An item whose field the response does not carry has no lookup data. + lookupData: root.ValueKind is JsonValueKind.Undefined ? null : root, + errors: itemErrors is null + ? null + : SourceSchemaErrors.Create(CollectionsMarshal.AsSpan(itemErrors)), + additionalPaths: variables.AdditionalPaths); + } + + return AliasBatchSplitStatus.Split; + } + + /// + /// Routes every error to the item its path identifies. An error without a path applies to the + /// whole request, and an error whose path names no item makes the response unusable. + /// + private static AliasBatchSplitStatus RouteErrors( + SourceResultElement errors, + ReadOnlySpan items, + ref List?[]? routedErrors) + { + foreach (var error in errors.EnumerateArray()) + { + if (error.ValueKind is not JsonValueKind.Object + || !error.TryGetProperty(PathProperty, out var path) + || path.ValueKind is not JsonValueKind.Array + || path.GetArrayLength() == 0) + { + return AliasBatchSplitStatus.Broadcast; + } + + var first = path[0]; + + if (first.ValueKind is not JsonValueKind.String + || !TryResolveItem(first.ValueSpan, items, out var index)) + { + return AliasBatchSplitStatus.Invalid; + } + + var routed = SourceSchemaErrors.CreateRoutedError(error, items[index].RootField.Name); + + if (routed is null) + { + return AliasBatchSplitStatus.Invalid; + } + + routedErrors ??= new List?[items.Length]; + (routedErrors[index] ??= []).Add(routed); + } + + return AliasBatchSplitStatus.Split; + } + + /// + /// Resolves the item that an aliased response name belongs to. The alias must carry the item's + /// prefix and the response name of that item's root selection. + /// + private static bool TryResolveItem( + ReadOnlySpan alias, + ReadOnlySpan items, + out int index) + { + if (!AliasBatchPrefixHelper.TryReadIndex(alias, out index, out var name) + || (uint)index >= (uint)items.Length) + { + return false; + } + + return name.SequenceEqual(items[index].RootField.Utf8Name); + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchSplitStatus.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchSplitStatus.cs new file mode 100644 index 00000000000..2d098c48787 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchSplitStatus.cs @@ -0,0 +1,22 @@ +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Describes how a batched response relates to the items of the request it answers. +/// +internal enum AliasBatchSplitStatus +{ + /// + /// The response was split, and every item received its own result. + /// + Split, + + /// + /// The response carries an outcome that applies to every item, so the whole request failed. + /// + Broadcast, + + /// + /// The response does not follow the shape a batched request asks for. + /// + Invalid +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchVariableWriter.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchVariableWriter.cs new file mode 100644 index 00000000000..6b41a37f072 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchVariableWriter.cs @@ -0,0 +1,200 @@ +using System.Buffers; +using System.Text.Json; +using HotChocolate.Language; +using HotChocolate.Text.Json; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Writes the variables object of a batched request. A shared variable keeps its name and +/// is written once; every other variable is written under the prefixed name of its item. +/// +internal static class AliasBatchVariableWriter +{ + private const int StackBufferLength = 256; + + /// + /// Writes the merged variable values of . + /// + /// The writer that receives the variables object. + /// The items of the batched request. + /// The variable definitions that the items share. + public static void Write( + JsonWriter writer, + ReadOnlySpan items, + List sharedVariables) + { + var sharedWritten = sharedVariables.Count == 0 + ? [] + : new bool[sharedVariables.Count]; + + writer.WriteStartObject(); + + for (var i = 0; i < items.Length; i++) + { + var values = items[i].Variables.Values; + + if (values.IsEmpty) + { + continue; + } + + WriteItem(writer, i, values.AsSequence(), sharedVariables, sharedWritten); + } + + writer.WriteEndObject(); + } + + private static void WriteItem( + JsonWriter writer, + int index, + ReadOnlySequence values, + List sharedVariables, + Span sharedWritten) + { + var reader = new Utf8JsonReader(values, isFinalBlock: true, state: default); + + if (!reader.Read() || reader.TokenType is not JsonTokenType.StartObject) + { + return; + } + + // A gathered name is still read while the prefixed name is composed from it, so the two + // buffers must stay separate. + Span prefixedNameStackBuffer = stackalloc byte[StackBufferLength]; + Span gatheredNameStackBuffer = stackalloc byte[StackBufferLength]; + var prefixedNameBuffer = new ScratchBuffer(prefixedNameStackBuffer); + var gatheredNameBuffer = new ScratchBuffer(gatheredNameStackBuffer); + + try + { + while (reader.Read() && reader.TokenType is JsonTokenType.PropertyName) + { + // A name that crosses a chunk boundary is gathered before it is compared and + // written; the value it names never is. + var name = reader.HasValueSequence + ? Gather(reader.ValueSequence, gatheredNameBuffer.GetSpan((int)reader.ValueSequence.Length)) + : reader.ValueSpan; + + var sharedIndex = IndexOfShared(sharedVariables, name); + + reader.Read(); + var valueStart = reader.TokenStartIndex; + reader.Skip(); + var value = values.Slice(valueStart, reader.BytesConsumed - valueStart); + + if (sharedIndex >= 0) + { + if (sharedWritten[sharedIndex]) + { + continue; + } + + sharedWritten[sharedIndex] = true; + writer.WritePropertyName(name); + } + else + { + var buffer = prefixedNameBuffer.GetSpan(AliasBatchPrefixHelper.GetNameBufferLength(name.Length)); + writer.WritePropertyName(AliasBatchPrefixHelper.ComposeName(buffer, index, name)); + } + + WriteValue(writer, value); + } + } + finally + { + prefixedNameBuffer.Dispose(); + gatheredNameBuffer.Dispose(); + } + } + + /// + /// Copies bytes that are stored in several chunks into one buffer. + /// + /// The bytes to gather. + /// The buffer that receives them. + private static ReadOnlySpan Gather(ReadOnlySequence value, Span destination) + { + value.CopyTo(destination); + return destination[..(int)value.Length]; + } + + /// + /// Writes the value of one variable, chunk by chunk when it crosses a chunk boundary. + /// + private static void WriteValue(JsonWriter writer, ReadOnlySequence value) + { + if (value.IsSingleSegment) + { + writer.WriteRawValue(value.FirstSpan); + return; + } + + var isFirst = true; + + foreach (var segment in value) + { + if (isFirst) + { + isFirst = false; + writer.WriteRawValueStart(segment.Span); + continue; + } + + writer.WriteRawValueContinuation(segment.Span); + } + + writer.WriteRawValueEnd(); + } + + private static int IndexOfShared( + List sharedVariables, + ReadOnlySpan name) + { + for (var i = 0; i < sharedVariables.Count; i++) + { + if (sharedVariables[i].Utf8Name.SequenceEqual(name)) + { + return i; + } + } + + return -1; + } + + /// + /// Hands out spans of a requested length, backed by the caller's stack buffer while the + /// length fits into it and by a pooled array beyond it. + /// + private ref struct ScratchBuffer(Span stackBuffer) + { + private readonly Span _stackBuffer = stackBuffer; + private byte[]? _rented; + + public Span GetSpan(int length) + { + if (length <= _stackBuffer.Length) + { + return _stackBuffer[..length]; + } + + if (_rented is not null && _rented.Length < length) + { + ArrayPool.Shared.Return(_rented); + _rented = null; + } + + return (_rented ??= ArrayPool.Shared.Rent(length)).AsSpan(0, length); + } + + public void Dispose() + { + if (_rented is not null) + { + ArrayPool.Shared.Return(_rented); + _rented = null; + } + } + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchedRequestBody.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchedRequestBody.cs new file mode 100644 index 00000000000..7df2adaa59f --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/AliasBatching/AliasBatchedRequestBody.cs @@ -0,0 +1,115 @@ +using System.Buffers; +using System.Buffers.Text; +using System.Text.Json; +using HotChocolate.Fusion.Transport; +using HotChocolate.Fusion.Transport.Serialization; +using HotChocolate.Language; +using HotChocolate.Text.Json; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Represents the body of a batched request. The items of the batch are merged into one +/// spec-conformant GraphQL operation whose root selections are aliased per item. +/// +internal sealed class AliasBatchedRequestBody : IRequestBody +{ + // 'Batch_' plus the 16 hexadecimal digits of the operation hash. + private const int OperationNameLength = 22; + + private readonly AliasBatchItem[] _items; + private readonly int _itemCount; + private readonly List _sharedVariables; + private readonly ulong _operationHash; + private readonly ErrorHandlingMode? _onError; + + /// + /// Initializes a new instance of . + /// + /// The items that are merged into one operation. + /// The number of items in . + /// + /// The variable definitions that the items share. They keep their name and are declared once. + /// + /// The hash the generated operation name is derived from. + /// The requested error handling mode. + public AliasBatchedRequestBody( + AliasBatchItem[] items, + int itemCount, + List sharedVariables, + ulong operationHash, + ErrorHandlingMode? onError) + { + _items = items; + _itemCount = itemCount; + _sharedVariables = sharedVariables; + _operationHash = operationHash; + _onError = onError; + } + + /// + public void WriteTo(JsonWriter writer) + { + ArgumentNullException.ThrowIfNull(writer); + + var items = _items.AsSpan(0, _itemCount); + + writer.WriteStartObject(); + + writer.WritePropertyName(Utf8GraphQLRequestProperties.QueryProp); + WriteQuery(writer, items); + + writer.WritePropertyName(Utf8GraphQLRequestProperties.VariablesProp); + AliasBatchVariableWriter.Write(writer, items, _sharedVariables); + + if (_onError is { } onError) + { + writer.WritePropertyName(Utf8GraphQLRequestProperties.OnErrorProp); + writer.WriteStringValue(GetErrorHandlingMode(onError)); + } + + writer.WriteEndObject(); + } + + /// + /// Writes the merged operation as a JSON string value. + /// + private void WriteQuery(JsonWriter writer, ReadOnlySpan items) + { + writer.WriteRawValueStart([]); + + Span operationName = stackalloc byte[OperationNameLength]; + var builder = Utf8OperationDocumentBuilder + .New(writer.InnerWriter, formatAsJsonStringValue: true) + .SetName(ComposeOperationName(operationName, _operationHash)); + + foreach (var sharedVariable in _sharedVariables) + { + builder = builder.AddSharedVariable(sharedVariable); + } + + foreach (var item in items) + { + builder = builder.AddRootSelection(item.RootField, item.LookupTypeName); + } + + builder.Complete(); + + writer.WriteRawValueEnd(JsonTokenType.String); + } + + private static ReadOnlySpan ComposeOperationName(Span buffer, ulong operationHash) + { + "Batch_"u8.CopyTo(buffer); + Utf8Formatter.TryFormat(operationHash, buffer[6..], out var written, new StandardFormat('x', 16)); + return buffer[..(6 + written)]; + } + + private static string GetErrorHandlingMode(ErrorHandlingMode mode) + => mode switch + { + ErrorHandlingMode.Propagate => "PROPAGATE", + ErrorHandlingMode.Null => "NULL", + _ => throw new ArgumentOutOfRangeException(nameof(mode)) + }; +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.AliasBatching.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.AliasBatching.cs new file mode 100644 index 00000000000..bc642a92abe --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.AliasBatching.cs @@ -0,0 +1,454 @@ +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +using HotChocolate.Fusion.Execution.Clients.AliasBatching; +using HotChocolate.Fusion.Text.Json; +using HotChocolate.Fusion.Transport.Http; +using HotChocolate.Language; + +namespace HotChocolate.Fusion.Execution.Clients; + +public sealed partial class HttpSourceSchemaClient +{ + private static ReadOnlySpan ErrorsProperty => "errors"u8; + + /// + /// Sends the variable sets of one request as a single batched request and streams the result + /// of every set back in request order. + /// + private async IAsyncEnumerable ExecuteAliasBatchAsync( + OperationPlanContext context, + SourceSchemaClientRequest request, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + var requests = ImmutableArray.Create(request); + var items = new AliasBatchItem[request.Variables.Length]; + var sharedVariables = new List(); + var itemCount = CollectItems(requests, items, sharedVariables); + + await foreach (var result in ExecuteAliasBatchStreamAsync( + context, requests, items, itemCount, sharedVariables, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false)) + { + yield return result.Result; + } + } + + /// + /// Sends every batchable request of the batch as a single batched request and streams the + /// results of the requests that peel off individually alongside it. + /// + private async IAsyncEnumerable ExecuteAliasBatchAsync( + OperationPlanContext context, + ImmutableArray requests, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + var items = new AliasBatchItem[CountVariableSets(requests)]; + var sharedVariables = new List(); + var itemCount = CollectItems(requests, items, sharedVariables); + + // A batch that merges fewer than two items gains nothing from the alias protocol, so + // every request stays on the protocol the source schema natively supports. + if (itemCount < 2) + { + await foreach (var result in ExecuteBatchWithNativeProtocolAsync( + context, requests, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false)) + { + yield return result; + } + + yield break; + } + + await foreach (var result in ExecuteAliasBatchStreamAsync( + context, requests, items, itemCount, sharedVariables, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false)) + { + yield return result; + } + + // A request that cannot join the batch, for example because it uploads files, is sent on + // its own so that the remaining requests still share one round-trip. + for (var i = 0; i < requests.Length; i++) + { + if (CanAliasBatch(requests[i], out _, out _)) + { + continue; + } + + await foreach (var result in ExecuteIsolatedAsync(context, requests[i], i, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false)) + { + yield return result; + } + } + } + + private async IAsyncEnumerable ExecuteAliasBatchStreamAsync( + OperationPlanContext context, + ImmutableArray requests, + AliasBatchItem[] items, + int itemCount, + List sharedVariables, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + var node = requests[0].Node; + var body = new AliasBatchedRequestBody( + items, + itemCount, + sharedVariables, + requests[0].OperationHash, + _onError); + + var httpRequest = new GraphQLHttpRequest(body, _configuration.BaseAddress) + { + AcceptHeaderValue = _configuration.BatchingAcceptHeaderValue, + OperationKind = GetOperationKindHint(requests[0].OperationType) + }; + + SourceSchemaCallbackHelper.ConfigureCallbacks(httpRequest, context, node, _configuration); + + GraphQLHttpResponse? httpResponse = null; + SourceSchemaResult[] results; + + try + { + httpResponse = await _client.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); + context.TrackTransport(node, httpRequest.Uri, httpResponse.RawContentType); + + var document = await httpResponse + .ReadAsResultAsync(context.Memory, cancellationToken) + .ConfigureAwait(false); + + try + { + results = SplitResponse(document, items.AsSpan(0, itemCount), requests[0].SchemaName); + } + catch + { + document.Dispose(); + throw; + } + } + finally + { + httpResponse?.Dispose(); + } + + var onSourceSchemaResult = _configuration.OnSourceSchemaResult; + var pending = 0; + + try + { + while (pending < itemCount) + { + var result = results[pending]; + onSourceSchemaResult?.Invoke(context, node, result); + var requestIndex = items[pending].RequestIndex; + + // The caller frees the result it receives, so the result leaves the pending range + // before it is handed out. + pending++; + + yield return new SourceSchemaBatchResult(requestIndex, result); + } + } + finally + { + // A caller that stops before the last item leaves the results it did not receive + // behind, so their hold on the shared response document is released here. + for (var i = pending; i < itemCount; i++) + { + results[i].Dispose(); + } + } + } + + /// + /// Splits the batched response into one result per item. A response that carries an outcome + /// for the whole request is handed to every item, and a response that does not follow the + /// batched shape fails the request. + /// + private static SourceSchemaResult[] SplitResponse( + SourceResultDocument document, + ReadOnlySpan items, + string schemaName) + { + var results = new SourceSchemaResult[items.Length]; + + switch (AliasBatchResponseSplitter.TrySplit(document, items, results)) + { + case AliasBatchSplitStatus.Split: + return results; + + case AliasBatchSplitStatus.Broadcast: + var documentOwner = new SourceResultDocumentOwner(document, items.Length); + + // The outcome applies to the whole request, so every item reports the errors of + // the response. + document.Root.TryGetProperty(ErrorsProperty, out var errorsElement); + var errors = SourceSchemaErrors.From(errorsElement); + + for (var i = 0; i < items.Length; i++) + { + var variables = items[i].Variables; + results[i] = new SourceSchemaResult( + variables.Path, + document, + documentOwner: documentOwner, + errors: errors, + additionalPaths: variables.AdditionalPaths); + } + + return results; + + default: + throw ThrowHelper.InvalidAliasBatchResponse(schemaName); + } + } + + /// + /// Flattens the batchable requests into one item per variable set and collects the variable + /// definitions that the items share. + /// + private static int CollectItems( + ImmutableArray requests, + AliasBatchItem[] items, + List sharedVariables) + { + var itemCount = 0; + + for (var requestIndex = 0; requestIndex < requests.Length; requestIndex++) + { + var request = requests[requestIndex]; + + if (!CanAliasBatch(request, out var operation, out var rootField)) + { + continue; + } + + if (!request.ForwardedVariables.IsEmpty) + { + CollectSharedVariables(request.ForwardedVariables, operation, sharedVariables); + } + + var lookupTypeName = request.LookupTypeName!; + + if (request.Variables.IsDefaultOrEmpty) + { + items[itemCount++] = new AliasBatchItem( + requestIndex, rootField, lookupTypeName, VariableValues.Empty); + continue; + } + + foreach (var variables in request.Variables) + { + items[itemCount++] = new AliasBatchItem( + requestIndex, rootField, lookupTypeName, variables); + } + } + + if (sharedVariables.Count > 0) + { + DemoteConflictingVariables(requests, sharedVariables); + } + + return itemCount; + } + + /// + /// Collects the variable definitions of an operation that the request forwards from the client + /// request, because those carry one value for the whole request and are therefore declared + /// once for the batched operation. Every other variable of that request carries a value per + /// item. + /// + private static void CollectSharedVariables( + ImmutableArray forwardedVariables, + Utf8OperationDefinitionNode operation, + List sharedVariables) + { + foreach (var definition in operation.GetVariableDefinitions()) + { + var name = definition.Utf8Name; + + if (ContainsName(sharedVariables, name) || !ContainsName(forwardedVariables, name)) + { + continue; + } + + sharedVariables.Add(definition); + } + } + + /// + /// Drops every shared variable whose name another request of the batch declares without + /// forwarding it. The batched operation declares each name once, so a name that one request + /// carries a value per item for is prefixed for every item of the batch, including the items + /// of the requests that forward it. + /// + private static void DemoteConflictingVariables( + ImmutableArray requests, + List sharedVariables) + { + foreach (var request in requests) + { + if (!CanAliasBatch(request, out var operation, out _)) + { + continue; + } + + foreach (var definition in operation.GetVariableDefinitions()) + { + var name = definition.Utf8Name; + + if (!ContainsName(request.ForwardedVariables, name)) + { + RemoveName(sharedVariables, name); + } + } + } + } + + private static bool ContainsName( + List sharedVariables, + ReadOnlySpan name) + { + for (var i = 0; i < sharedVariables.Count; i++) + { + if (sharedVariables[i].Utf8Name.SequenceEqual(name)) + { + return true; + } + } + + return false; + } + + private static void RemoveName( + List sharedVariables, + ReadOnlySpan name) + { + for (var i = 0; i < sharedVariables.Count; i++) + { + if (sharedVariables[i].Utf8Name.SequenceEqual(name)) + { + sharedVariables.RemoveAt(i); + return; + } + } + } + + private static bool ContainsName(ImmutableArray names, ReadOnlySpan utf8Name) + { + for (var i = 0; i < names.Length; i++) + { + if (EqualsName(names[i], utf8Name)) + { + return true; + } + } + + return false; + } + + // A GraphQL name holds ASCII characters only, so each character is one UTF-8 byte. + private static bool EqualsName(string name, ReadOnlySpan utf8Name) + { + if (name.Length != utf8Name.Length) + { + return false; + } + + for (var i = 0; i < name.Length; i++) + { + if (name[i] != utf8Name[i]) + { + return false; + } + } + + return true; + } + + private static int CountVariableSets(ImmutableArray requests) + { + var count = 0; + + foreach (var request in requests) + { + count += Math.Max(1, request.Variables.Length); + } + + return count; + } + + /// + /// Determines whether a request can join a batched request and returns the parts of its + /// operation the batch is built from. File uploads keep their multipart encoding, mutations + /// and subscriptions are never batched, and an operation that the plan did not resolve a + /// lookup type for or that does not read its data from a single unaliased root selection + /// cannot be rewritten into an aliased copy of itself. + /// + /// The request to inspect. + /// The single operation of the request's document. + /// The single root selection of . + private static bool CanAliasBatch( + SourceSchemaClientRequest request, + out Utf8OperationDefinitionNode operation, + out Utf8FieldNode rootField) + { + if (request is + { + LookupTypeName: not null, + OperationType: OperationType.Query, + RequiresFileUpload: false + }) + { + return TryGetSingleRootField( + request.OperationDocument, + out operation, + out rootField); + } + + operation = default; + rootField = default; + return false; + } + + /// + /// Returns the document's single operation together with its single unaliased root field. + /// + private static bool TryGetSingleRootField( + Utf8OperationDocument document, + out Utf8OperationDefinitionNode operation, + out Utf8FieldNode rootField) + { + operation = default; + rootField = default; + + var operations = document.GetOperations().GetEnumerator(); + + if (!operations.MoveNext()) + { + return false; + } + + operation = operations.Current; + + if (operations.MoveNext()) + { + return false; + } + + var selections = operation.SelectionSet.GetSelections().GetEnumerator(); + + if (!selections.MoveNext() + || !selections.Current.TryGetField(out rootField) + || rootField.HasAlias) + { + return false; + } + + return !selections.MoveNext(); + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs index 4d1b74a3307..0f19f94b5b3 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClient.cs @@ -18,7 +18,7 @@ namespace HotChocolate.Fusion.Execution.Clients; /// to a downstream service over HTTP. Supports single requests, Apollo-style request batching, /// and variable batching depending on the configured . /// -public sealed class HttpSourceSchemaClient : ISourceSchemaClient +public sealed partial class HttpSourceSchemaClient : ISourceSchemaClient { private static ReadOnlySpan VariableIndex => "variableIndex"u8; private static ReadOnlySpan RequestIndex => "requestIndex"u8; @@ -27,6 +27,8 @@ public sealed class HttpSourceSchemaClient : ISourceSchemaClient private readonly HttpSourceSchemaClientConfiguration _configuration; private readonly ErrorHandlingMode? _onError; private readonly bool _supportsVariableBatching; + private readonly bool _useAliasBatchingForVariableSets; + private readonly bool _useAliasBatchingForOperationBatches; private readonly bool _annotateOperationKind; private bool _disposed; @@ -59,6 +61,17 @@ public HttpSourceSchemaClient( Capabilities = capabilities; _supportsVariableBatching = capabilities.HasFlag(SourceSchemaClientCapabilities.VariableBatching); + + var supportsAliasBatching = capabilities.HasFlag(SourceSchemaClientCapabilities.AliasBatching); + var supportsRequestBatching = capabilities.HasFlag(SourceSchemaClientCapabilities.RequestBatching); + + // The many variable sets of one operation are merged into one aliased operation only when + // the source schema does not support variable batching. + _useAliasBatchingForVariableSets = supportsAliasBatching && !_supportsVariableBatching; + + // The distinct operations of one batch are merged into one aliased operation only when the + // source schema does not support request batching. + _useAliasBatchingForOperationBatches = supportsAliasBatching && !supportsRequestBatching; } /// @@ -80,6 +93,13 @@ public IAsyncEnumerable ExecuteAsync( Debug.WriteLine(request.SchemaName); + if (_useAliasBatchingForVariableSets + && request.Variables.Length > 1 + && CanAliasBatch(request, out _, out _)) + { + return ExecuteAliasBatchAsync(context, request, cancellationToken); + } + return CreateStreamAsync(context, request, cancellationToken); async IAsyncEnumerable CreateStreamAsync( @@ -93,7 +113,11 @@ async IAsyncEnumerable CreateStreamAsync( try { var httpRequest = CreateHttpRequest(context, request, ref buffer); - ConfigureCallbacks(httpRequest, context, request.Node); + SourceSchemaCallbackHelper.ConfigureCallbacks( + httpRequest, + context, + request.Node, + _configuration); httpResponse = await _client.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); context.TrackTransport(request.Node, httpRequest.Uri, httpResponse.RawContentType); @@ -142,6 +166,23 @@ public IAsyncEnumerable ExecuteBatchAsync( FusionExecutionResources.HttpSourceSchemaClient_SubscriptionBatchNotSupported); } + if (_useAliasBatchingForOperationBatches) + { + return ExecuteAliasBatchAsync(context, requests, cancellationToken); + } + + return ExecuteBatchWithNativeProtocolAsync(context, requests, cancellationToken); + } + + /// + /// Sends a batch through the protocol extensions that the source schema supports, which is + /// either an operation batch or one request per operation. + /// + private IAsyncEnumerable ExecuteBatchWithNativeProtocolAsync( + OperationPlanContext context, + ImmutableArray requests, + CancellationToken cancellationToken) + { // A source schema that does not support request batching still accepts // each operation on its own, so we fall back to individual requests and // stream the results back in request order. @@ -160,7 +201,7 @@ public IAsyncEnumerable ExecuteBatchAsync( requests, requiresFileUpload, ref buffer); - ConfigureCallbacks(httpRequest, context, requests[0].Node); + SourceSchemaCallbackHelper.ConfigureCallbacks(httpRequest, context, requests[0].Node, _configuration); var results = ExecuteBatchStreamAsync(context, requests, httpRequest, buffer, cancellationToken); @@ -197,7 +238,7 @@ public async IAsyncEnumerable SubscribeAsync( try { var httpRequest = CreateHttpRequest(context, request, ref buffer); - ConfigureCallbacks(httpRequest, context, request.Node); + SourceSchemaCallbackHelper.ConfigureCallbacks(httpRequest, context, request.Node, _configuration); httpResponse = await _client.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false); context.TrackTransport(request.Node, httpRequest.Uri, httpResponse.RawContentType); @@ -228,41 +269,58 @@ private async IAsyncEnumerable ExecuteBatchAsSingleRequ // leaving results already produced by sibling requests untouched. for (var i = 0; i < requests.Length; i++) { - var request = requests[i]; - var enumerator = ExecuteAsync(context, request, cancellationToken) - .WithCancellation(cancellationToken).ConfigureAwait(false).GetAsyncEnumerator(); + await foreach (var result in ExecuteIsolatedAsync(context, requests[i], i, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false)) + { + yield return result; + } + } + } - try + /// + /// Executes a single request of a batch as its own round-trip. A transport failure of one + /// request must not abort the batch, so its cause is recorded against the request's index and + /// the results already produced by sibling requests stay untouched. + /// + private async IAsyncEnumerable ExecuteIsolatedAsync( + OperationPlanContext context, + SourceSchemaClientRequest request, + int requestIndex, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + var enumerator = ExecuteAsync(context, request, cancellationToken) + .WithCancellation(cancellationToken).ConfigureAwait(false).GetAsyncEnumerator(); + + try + { + while (true) { - while (true) + try { - try + if (!await enumerator.MoveNextAsync()) { - if (!await enumerator.MoveNextAsync()) - { - break; - } - } - catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) - { - // Caller-driven cancellation aborts the whole batch. - throw; - } - catch (Exception exception) - { - // The consuming node attaches the recorded cause to the - // request that produced no result. - context.TrackBatchRequestError(request.Node, i, exception); break; } - - yield return new SourceSchemaBatchResult(i, enumerator.Current); } + catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) + { + // Caller-driven cancellation aborts the whole batch. + throw; + } + catch (Exception exception) + { + // The consuming node attaches the recorded cause to the + // request that produced no result. + context.TrackBatchRequestError(request.Node, requestIndex, exception); + break; + } + + yield return new SourceSchemaBatchResult(requestIndex, enumerator.Current); } - finally - { - await enumerator.DisposeAsync(); - } + } + finally + { + await enumerator.DisposeAsync(); } } @@ -724,7 +782,7 @@ private static OperationBatchRequest CreateOperationBatchRequest( } private static VariableBatchRequest CreateVariableBatchRequest( - string operationSourceText, + ReadOnlyMemory operationSourceText, SourceSchemaClientRequest originalRequest, ErrorHandlingMode? onError) { @@ -853,36 +911,6 @@ public ValueTask DisposeAsync() return ValueTask.CompletedTask; } - /// - /// Attaches and - /// callbacks to - /// the HTTP request. - /// - private void ConfigureCallbacks( - GraphQLHttpRequest request, - OperationPlanContext context, - ExecutionNode node) - { - if (_configuration.OnBeforeSend is null && _configuration.OnAfterReceive is null) - { - return; - } - - request.State = new RequestCallbackState(context, node, _configuration); - - if (_configuration.OnBeforeSend is not null) - { - request.OnMessageCreated += static (_, requestMessage, state) => - state.Configuration.OnBeforeSend!.Invoke(state.Context, state.Node, requestMessage); - } - - if (_configuration.OnAfterReceive is not null) - { - request.OnMessageReceived += static (_, responseMessage, state) => - state.Configuration.OnAfterReceive!.Invoke(state.Context, state.Node, responseMessage); - } - } - private static bool ContainsSubscriptionRequest( IReadOnlyList requests) { diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClientConfiguration.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClientConfiguration.cs index a1a798345e7..e815261a2fb 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClientConfiguration.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/HttpSourceSchemaClientConfiguration.cs @@ -52,7 +52,7 @@ public HttpSourceSchemaClientConfiguration( string name, Uri baseAddress, SupportedOperationType supportedOperations = SupportedOperationType.All, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, @@ -120,7 +120,7 @@ public HttpSourceSchemaClientConfiguration( string httpClientName, Uri baseAddress, SupportedOperationType supportedOperations = SupportedOperationType.All, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceResultDocumentOwner.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceResultDocumentOwner.cs new file mode 100644 index 00000000000..e79b59b7678 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceResultDocumentOwner.cs @@ -0,0 +1,38 @@ +using HotChocolate.Fusion.Text.Json; + +namespace HotChocolate.Fusion.Execution.Clients; + +/// +/// Holds the response document that the results of a split response share. The document is freed +/// once every result has released its reference. +/// +public sealed class SourceResultDocumentOwner : IDisposable +{ + private readonly SourceResultDocument _document; + private int _references; + + /// + /// Initializes a new instance of . + /// + /// The response document that the results share. + /// The number of results that hold . + public SourceResultDocumentOwner(SourceResultDocument document, int references) + { + ArgumentNullException.ThrowIfNull(document); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(references); + + _document = document; + _references = references; + } + + /// + /// Releases one reference to the document and frees the document with the last reference. + /// + public void Dispose() + { + if (Interlocked.Decrement(ref _references) == 0) + { + _document.Dispose(); + } + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaCallbackHelper.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaCallbackHelper.cs new file mode 100644 index 00000000000..71bc4b98808 --- /dev/null +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaCallbackHelper.cs @@ -0,0 +1,48 @@ +using HotChocolate.Fusion.Execution.Nodes; +using HotChocolate.Fusion.Transport.Http; + +namespace HotChocolate.Fusion.Execution.Clients; + +/// +/// Attaches the transport-level request hooks +/// ( and +/// ) to an HTTP request. +/// Shared by the HTTP source schema clients so both observe identical hook behavior. +/// +internal static class SourceSchemaCallbackHelper +{ + /// + /// Attaches and + /// callbacks to + /// the HTTP request. + /// + /// The HTTP request the callbacks are attached to. + /// The current operation plan execution context. + /// The execution node that produced the request. + /// The transport configuration providing the callbacks. + public static void ConfigureCallbacks( + GraphQLHttpRequest request, + OperationPlanContext context, + ExecutionNode node, + HttpSourceSchemaClientConfiguration configuration) + { + if (configuration.OnBeforeSend is null && configuration.OnAfterReceive is null) + { + return; + } + + request.State = new RequestCallbackState(context, node, configuration); + + if (configuration.OnBeforeSend is not null) + { + request.OnMessageCreated += static (_, requestMessage, state) => + state.Configuration.OnBeforeSend!.Invoke(state.Context, state.Node, requestMessage); + } + + if (configuration.OnAfterReceive is not null) + { + request.OnMessageReceived += static (_, responseMessage, state) => + state.Configuration.OnAfterReceive!.Invoke(state.Context, state.Node, responseMessage); + } + } +} diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientCapabilities.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientCapabilities.cs index c734b29bf4e..22a0ea594ac 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientCapabilities.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientCapabilities.cs @@ -22,5 +22,19 @@ public enum SourceSchemaClientCapabilities /// RequestBatching = 1 << 2, - All = VariableBatching | RequestBatching + /// + /// The client supports alias batching, where each row of a batch is rewritten into an + /// aliased copy of the root selections within a single spec-conformant GraphQL request. + /// Unlike and , this mode + /// requires no protocol extension from the downstream service. + /// + AliasBatching = 1 << 3, + + /// + /// Combines the protocol-extension batching capabilities ( + /// and ). is deliberately excluded + /// because it supersedes those modes and is selected through an explicit opt-in rather than + /// advertised as a default capability. + /// + Default = VariableBatching | RequestBatching } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientRequest.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientRequest.cs index d377959b2a1..27bc04f78e5 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientRequest.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaClientRequest.cs @@ -25,13 +25,17 @@ public readonly record struct SourceSchemaClientRequest() public required OperationType OperationType { get; init; } /// - /// Gets the GraphQL operation source text to send. + /// Gets the UTF-8 encoded GraphQL operation source text to send. /// - public required string OperationSourceText { get; init; } + public required ReadOnlyMemory OperationSourceText { get; init; } + + /// + /// Gets the parsed syntax tree of . + /// + public required Utf8OperationDocument OperationDocument { get; init; } /// /// Gets the xxhash64 of the operation source text. - /// Precomputed during planning for use as a cache key by connectors. /// public required ulong OperationHash { get; init; } @@ -46,4 +50,17 @@ public readonly record struct SourceSchemaClientRequest() /// requiring multipart form encoding. /// public bool RequiresFileUpload { get; init; } + + /// + /// Gets the name of the type that the body of the operation's root selection is selected on, + /// or when the operation does not select a single root field that the + /// schema declares. + /// + internal string? LookupTypeName { get; init; } + + /// + /// Gets the names of the variables that this operation takes from the client request. Every + /// other variable of the operation carries a value per variable value set. + /// + internal ImmutableArray ForwardedVariables { get; init; } = []; } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaErrors.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaErrors.cs index a9207215c99..aefc7760d58 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaErrors.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaErrors.cs @@ -49,8 +49,6 @@ public sealed class SourceSchemaErrors foreach (var jsonError in json.EnumerateArray()) { - var currentTrie = root; - var error = CreateError(jsonError); if (error is null) @@ -65,45 +63,92 @@ public sealed class SourceSchemaErrors continue; } - var rented = s_objectPool.Rent(error.Path.Length); - var pathSegments = rented.AsSpan(0, error.Path.Length); - error.Path.CopyTo(pathSegments); - var lastPathIndex = pathSegments.Length - 1; + AddToTrie(root, error); + } + + return new SourceSchemaErrors + { + RootErrors = rootErrors?.ToImmutableArray() ?? [], + Trie = root + }; + } + + /// + /// Creates a instance from errors that were already + /// materialized, for example when a batched response was split into its items. + /// + /// The errors that apply to one result. + internal static SourceSchemaErrors Create(ReadOnlySpan errors) + { + var root = new ErrorTrie(); - try + foreach (var error in errors) + { + AddToTrie(root, error); + } + + return new SourceSchemaErrors { RootErrors = [], Trie = root }; + } + + /// + /// Adds an error to the trie at the position its path describes, creating the tries of the + /// path segments that the trie does not hold yet. + /// + /// The trie that the error is added to. + /// The error to add. Its path must not be null. + private static void AddToTrie(ErrorTrie root, IError error) + { + var currentTrie = root; + var path = error.Path!; + var rented = s_objectPool.Rent(path.Length); + var pathSegments = rented.AsSpan(0, path.Length); + path.CopyTo(pathSegments); + var lastPathIndex = pathSegments.Length - 1; + + try + { + for (var i = 0; i < pathSegments.Length; i++) { - for (var i = 0; i < pathSegments.Length; i++) - { - var pathSegment = pathSegments[i]; + var pathSegment = pathSegments[i]; - if (currentTrie.TryGetValue(pathSegment, out var trieAtPath)) - { - currentTrie = trieAtPath; - } - else - { - var newTrie = new ErrorTrie(); - currentTrie[pathSegment] = newTrie; - currentTrie = newTrie; - } + if (currentTrie.TryGetValue(pathSegment, out var trieAtPath)) + { + currentTrie = trieAtPath; + } + else + { + var newTrie = new ErrorTrie(); + currentTrie[pathSegment] = newTrie; + currentTrie = newTrie; + } - if (i == lastPathIndex) - { - currentTrie.Error = error; - } + if (i == lastPathIndex) + { + currentTrie.Error = error; } } - finally - { - pathSegments.Clear(); - s_objectPool.Return(rented); - } } - - return new SourceSchemaErrors { RootErrors = rootErrors?.ToImmutableArray() ?? [], Trie = root }; + finally + { + pathSegments.Clear(); + s_objectPool.Return(rented); + } } + /// + /// Creates an error from a JSON error of a batched response, replacing the leading segment of + /// its path with so the path reads as if the item had been + /// requested on its own. + /// + /// The JSON error to read. + /// The response name that replaces the leading path segment. + internal static IError? CreateRoutedError(SourceResultElement jsonError, string rootName) + => CreateError(jsonError, rootName); + private static IError? CreateError(SourceResultElement jsonError) + => CreateError(jsonError, rootName: null); + + private static IError? CreateError(SourceResultElement jsonError, string? rootName) { if (jsonError.ValueKind is not JsonValueKind.Object) { @@ -118,7 +163,7 @@ public sealed class SourceSchemaErrors if (jsonError.TryGetProperty("path", out var path) && path.ValueKind == JsonValueKind.Array) { - errorBuilder.SetPath(CreatePathFromJson(path)); + errorBuilder.SetPath(CreatePathFromJson(path, rootName)); } if (jsonError.TryGetProperty("extensions", out var extensions) @@ -145,12 +190,24 @@ public sealed class SourceSchemaErrors return null; } - private static Path CreatePathFromJson(SourceResultElement errorSubPath) + private static Path CreatePathFromJson(SourceResultElement errorSubPath, string? rootName) { var path = Path.Root; + var isFirst = true; foreach (var item in errorSubPath.EnumerateArray()) { + if (isFirst) + { + isFirst = false; + + if (rootName is not null) + { + path = path.Append(rootName); + continue; + } + } + path = item switch { { ValueKind: JsonValueKind.String } nameElement => path.Append(nameElement.GetString()!), diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaResult.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaResult.cs index a4982056cb3..56b23bce1e7 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaResult.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Clients/SourceSchemaResult.cs @@ -3,9 +3,8 @@ namespace HotChocolate.Fusion.Execution.Clients; /// -/// Represents the result returned by a source schema after executing a GraphQL request. -/// Provides access to the data, errors, and extensions sections of the -/// response and manages the lifetime of the underlying result document. +/// Represents the result returned by a source schema after executing a GraphQL request. Provides +/// access to the data, errors, and extensions sections of the response. /// public sealed class SourceSchemaResult : IDisposable { @@ -13,23 +12,46 @@ public sealed class SourceSchemaResult : IDisposable private static ReadOnlySpan ErrorsProperty => "errors"u8; private static ReadOnlySpan ExtensionsProperty => "extensions"u8; private readonly SourceResultDocument _document; - private readonly bool _ownsDocument; + private readonly IDisposable? _documentOwner; + private SourceSchemaErrors? _errors; private bool _errorsParsed; /// - /// Creates a new that takes ownership of the given document - /// and will dispose it when this result is disposed. + /// Creates a new that holds the given document and releases + /// its hold when this result is disposed. /// /// The path in the Fusion result where this result will be merged. /// The raw response document from the source schema. + /// + /// The owner of when it is shared with other results, or + /// null when this result is the only one that reads it. + /// + /// + /// The pre-resolved element of the root field that carries the lookup data, or null + /// when it is resolved from . + /// + /// The errors that apply to this result, or null if there are none. /// Whether this is the final message in a streaming response. /// Any additional paths where this result should also be merged. public SourceSchemaResult( CompactPath path, SourceResultDocument document, + SourceResultDocumentOwner? documentOwner = null, + SourceResultElement? lookupData = null, + SourceSchemaErrors? errors = null, FinalMessage final = FinalMessage.Undefined, CompactPathSegment additionalPaths = default) - : this(path, document, final, ownsDocument: true, additionalPaths) + : this( + path, + document, + final, + documentOwner ?? (IDisposable)document, + additionalPaths, + lookupData, + errors, + // The errors of a shared document are routed per result, so a result that shares one + // never reads its errors from the document. + errorsParsed: errors is not null || documentOwner is not null) { } @@ -37,31 +59,37 @@ private SourceSchemaResult( CompactPath path, SourceResultDocument document, FinalMessage final, - bool ownsDocument, - CompactPathSegment additionalPaths) + IDisposable? documentOwner, + CompactPathSegment additionalPaths, + SourceResultElement? lookupData, + SourceSchemaErrors? errors, + bool errorsParsed) { ArgumentNullException.ThrowIfNull(document); _document = document; - _ownsDocument = ownsDocument; + _documentOwner = documentOwner; + _errors = errors; + _errorsParsed = errorsParsed; AdditionalPaths = additionalPaths; + LookupData = lookupData; Path = path; Final = final; } /// - /// The primary path in the composite result into which this source schema result will be merged. + /// Gets the primary path in the composite result into which this source schema result will be merged. /// public CompactPath Path { get; } /// - /// Additional paths where this result should also be merged, used when a single source - /// schema response satisfies multiple selection sets at different locations. + /// Gets the additional paths in the composite result into which this source schema result will + /// also be merged. /// public CompactPathSegment AdditionalPaths { get; } /// - /// The data element of the source schema response, or an empty element if the + /// Gets the data element of the source schema response, or an empty element if the /// response did not include a data property. /// public SourceResultElement Data @@ -74,8 +102,15 @@ public SourceResultElement Data } /// - /// The parsed errors from the source schema response, or null if there were none. - /// Parsed lazily on first access. + /// Gets the pre-resolved element of the root field that carries the lookup data, or null + /// when it is resolved from . When set, it stands in for the first segment of + /// the source path. + /// + public SourceResultElement? LookupData { get; } + + /// + /// Gets the errors of the source schema response that apply to this result, or null + /// when there are none. /// public SourceSchemaErrors? Errors { @@ -83,32 +118,23 @@ public SourceSchemaErrors? Errors { if (!_errorsParsed) { - field = _document.Root.TryGetProperty(ErrorsProperty, out var errors) + _errors = _document.Root.TryGetProperty(ErrorsProperty, out var errors) ? SourceSchemaErrors.From(errors) : null; _errorsParsed = true; } - return field; - } - } - - internal SourceResultElement RawErrors - { - get - { - _document.Root.TryGetProperty(ErrorsProperty, out var errors); - return errors; + return _errors; } } /// - /// Returns true if the source schema response contains an errors property. + /// Returns true if the source schema response carries errors that apply to this result. /// - public bool HasErrors => _document.Root.TryGetProperty(ErrorsProperty, out _); + public bool HasErrors => Errors is not null; /// - /// The extensions element of the source schema response, or an empty element if + /// Gets the extensions element of the source schema response, or an empty element if /// the response did not include an extensions property. /// public SourceResultElement Extensions @@ -127,23 +153,24 @@ public SourceResultElement Extensions /// /// Creates a copy of this result associated with a different path, without taking ownership - /// of the underlying document. Used internally when the same result needs to be referenced - /// at a different location in the composite result. + /// of the underlying document. /// internal SourceSchemaResult WithPath(CompactPath path) - => new(path, _document, Final, ownsDocument: false, additionalPaths: default); + => WithPath(path, additionalPaths: default); internal SourceSchemaResult WithPath(CompactPath path, CompactPathSegment additionalPaths) - => new(path, _document, Final, ownsDocument: false, additionalPaths); + => new( + path, + _document, + Final, + documentOwner: null, + additionalPaths, + LookupData, + _errors, + _errorsParsed); /// - /// Disposes the underlying result document if this instance owns it. + /// Releases this result's hold on the underlying result document. /// - public void Dispose() - { - if (_ownsDocument) - { - _document.Dispose(); - } - } + public void Dispose() => _documentOwner?.Dispose(); } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Extensions/StringExtensions.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Extensions/StringExtensions.cs index e1d445e286a..88eaa3a433a 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Extensions/StringExtensions.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Extensions/StringExtensions.cs @@ -1,35 +1,9 @@ -using System.Buffers; using System.IO.Hashing; -using System.Text; namespace HotChocolate.Fusion.Execution; internal static class FusionStringExtensions { - private static readonly Encoding s_utf8 = Encoding.UTF8; - private static readonly ArrayPool s_arrayPool = ArrayPool.Shared; - - public static ulong ComputeHash(this string s) - { - var maxByteCount = s_utf8.GetMaxByteCount(s.Length); - byte[]? rentedBuffer = null; - var buffer = maxByteCount < 256 - ? stackalloc byte[256] - : s_arrayPool.Rent(maxByteCount); - - try - { - var byteCount = s_utf8.GetBytes(s, buffer); - buffer = buffer[..byteCount]; - return XxHash64.HashToUInt64(buffer); - } - finally - { - if (rentedBuffer is not null) - { - buffer.Clear(); - s_arrayPool.Return(rentedBuffer); - } - } - } + public static ulong ComputeHash(this ReadOnlyMemory utf8Bytes) + => XxHash64.HashToUInt64(utf8Bytes.Span); } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloEntityLookup.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloEntityLookup.cs index f62b848ea7a..8207a4ee0b7 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloEntityLookup.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloEntityLookup.cs @@ -1,4 +1,5 @@ using HotChocolate.Fusion.Execution.ApolloFederation; +using HotChocolate.Language; namespace HotChocolate.Fusion.Execution.Nodes; @@ -10,6 +11,9 @@ namespace HotChocolate.Fusion.Execution.Nodes; /// The rewritten single-lookup _entities operation that is sent for /// this lookup. /// +/// +/// The parsed syntax tree of the rewritten operation source text. +/// /// /// The xxhash64 of the rewritten operation source text. /// @@ -23,6 +27,7 @@ namespace HotChocolate.Fusion.Execution.Nodes; /// internal readonly record struct ApolloEntityLookup( OperationSourceText Operation, + Utf8OperationDocument OperationDocument, ulong OperationHash, string EntityTypeName, List RepresentationShape); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationBatchExecutionNode.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationBatchExecutionNode.cs index f622f45192f..029ee489ebb 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationBatchExecutionNode.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationBatchExecutionNode.cs @@ -85,6 +85,7 @@ internal static ApolloOperationBatchExecutionNode Create( lookups[i] = new ApolloEntityLookup( rewritten.Operation, + Utf8GraphQLOperationParser.Parse(rewritten.Operation.SourceText), rewritten.Operation.SourceText.ComputeHash(), rewritten.EntityTypeName, @@ -344,9 +345,11 @@ private int BuildRequests( SchemaName = schemaName, OperationType = lookup.Operation.Type, OperationSourceText = lookup.Operation.SourceText, + OperationDocument = lookup.OperationDocument, + OperationHash = lookup.OperationHash, + LookupTypeName = lookup.EntityTypeName, Variables = requestVariables, - RequiresFileUpload = false, - OperationHash = lookup.OperationHash + RequiresFileUpload = false }); operationByIndex[operationCount] = operation; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationExecutionNode.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationExecutionNode.cs index 1c208981681..7ada33aff27 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationExecutionNode.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationExecutionNode.cs @@ -188,7 +188,9 @@ protected override async ValueTask OnExecuteAsync( OperationSourceText = _operation.SourceText, Variables = requestVariables, RequiresFileUpload = false, - OperationHash = _operationHash + OperationHash = _operationHash, + OperationDocument = _operation.Document, + LookupTypeName = _operation.LookupTypeName }; SourceSchemaResult? result = null; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/BatchOperationDefinition.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/BatchOperationDefinition.cs index e4ce5a3538a..0618c1e2c3f 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/BatchOperationDefinition.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/BatchOperationDefinition.cs @@ -9,6 +9,7 @@ internal sealed class BatchOperationDefinition : OperationDefinition internal BatchOperationDefinition( int id, OperationSourceText operation, + string? lookupTypeName, string? schemaName, SelectionPath[] targets, SelectionPath source, @@ -20,6 +21,7 @@ internal BatchOperationDefinition( : base( id, operation, + lookupTypeName, schemaName, source, requirements, diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationBatchExecutionNode.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationBatchExecutionNode.cs index 1958e4bf2e2..2972e8f3f29 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationBatchExecutionNode.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationBatchExecutionNode.cs @@ -80,7 +80,10 @@ private async ValueTask ExecuteSingleAsync( OperationSourceText = operation.Operation.SourceText, Variables = variables, RequiresFileUpload = operation.RequiresFileUpload, - OperationHash = operation.OperationHash + OperationHash = operation.OperationHash, + OperationDocument = operation.OperationDocument, + LookupTypeName = operation.LookupTypeName, + ForwardedVariables = operation.GetForwardedVariablesArray() }; var hasSomeErrors = false; @@ -359,7 +362,10 @@ private int BuildRequests( OperationSourceText = operation.Operation.SourceText, Variables = variables, RequiresFileUpload = _requiresFileUpload, - OperationHash = operation.OperationHash + OperationHash = operation.OperationHash, + OperationDocument = operation.OperationDocument, + LookupTypeName = operation.LookupTypeName, + ForwardedVariables = operation.GetForwardedVariablesArray() }); operationByIndex[operationCount] = operation; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationDefinition.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationDefinition.cs index a3954e6a0d4..dee7185a476 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationDefinition.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationDefinition.cs @@ -83,6 +83,9 @@ internal ImmutableArray GetRequirementsArray() /// public ReadOnlySpan ForwardedVariables => _forwardedVariables; + internal ImmutableArray GetForwardedVariablesArray() + => ImmutableCollectionsMarshal.AsImmutableArray(_forwardedVariables); + /// /// Gets the result selection set that describes which fields this operation /// populates in the composite result. diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationExecutionNode.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationExecutionNode.cs index 6bed7881ed5..c02f77e06c4 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationExecutionNode.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationExecutionNode.cs @@ -93,6 +93,9 @@ internal ImmutableArray GetRequirementsArray() /// public ReadOnlySpan ForwardedVariables => _forwardedVariables; + internal ImmutableArray GetForwardedVariablesArray() + => ImmutableCollectionsMarshal.AsImmutableArray(_forwardedVariables); + /// /// Gets whether this operation contains one or more variables /// that contain the Upload scalar. @@ -122,7 +125,10 @@ protected override async ValueTask OnExecuteAsync( OperationSourceText = _operation.SourceText, Variables = variables, RequiresFileUpload = _requiresFileUpload, - OperationHash = _operationHash + OperationHash = _operationHash, + OperationDocument = _operation.Document, + LookupTypeName = _operation.LookupTypeName, + ForwardedVariables = GetForwardedVariablesArray() }; var index = 0; @@ -303,7 +309,8 @@ internal SubscriptionResult Subscribe(OperationPlanContext context) OperationType = _operation.Type, OperationSourceText = _operation.SourceText, Variables = variables, - OperationHash = _operationHash + OperationHash = _operationHash, + OperationDocument = _operation.Document }; var subscriptionId = SubscriptionId.Next(); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationSourceText.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationSourceText.cs index 38c45216a2d..88bb6e9f9cf 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationSourceText.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/OperationSourceText.cs @@ -12,7 +12,7 @@ namespace HotChocolate.Fusion.Execution.Nodes; /// Gets the type of the operation. /// /// -/// Gets the GraphQL operation document source text. +/// Gets the UTF-8 encoded GraphQL operation document source text. /// /// /// Gets the SHA256 hash of the operation source text as hex string. @@ -20,5 +20,5 @@ namespace HotChocolate.Fusion.Execution.Nodes; public readonly record struct OperationSourceText( string Name, OperationType Type, - string SourceText, + ReadOnlyMemory SourceText, string Hash); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanFormatter.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanFormatter.cs index fe061e9daff..d5f31ffc29f 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanFormatter.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanFormatter.cs @@ -354,7 +354,7 @@ private static void WriteOperationNode( jsonWriter.WriteStringValue(node.Operation.Type.ToString()); jsonWriter.WritePropertyName("document"); - jsonWriter.WriteStringValue(node.Operation.SourceText); + jsonWriter.WriteStringValue(node.Operation.SourceText.Span); jsonWriter.WritePropertyName("hash"); jsonWriter.WriteStringValue(node.Operation.Hash); @@ -599,7 +599,7 @@ private static void WriteOperationDefinitionAsNode( jsonWriter.WriteStringValue(operationDef.Operation.Type.ToString()); jsonWriter.WritePropertyName("document"); - jsonWriter.WriteStringValue(operationDef.Operation.SourceText); + jsonWriter.WriteStringValue(operationDef.Operation.SourceText.Span); jsonWriter.WritePropertyName("hash"); jsonWriter.WriteStringValue(operationDef.Operation.Hash); @@ -715,7 +715,7 @@ private static void WriteBatchOperationDefinitionAsNode( jsonWriter.WriteStringValue(operationDef.Operation.Type.ToString()); jsonWriter.WritePropertyName("document"); - jsonWriter.WriteStringValue(operationDef.Operation.SourceText); + jsonWriter.WriteStringValue(operationDef.Operation.SourceText.Span); jsonWriter.WritePropertyName("hash"); jsonWriter.WriteStringValue(operationDef.Operation.Hash); @@ -944,7 +944,7 @@ private static void WriteOperationSourceText(JsonWriter jsonWriter, OperationSou jsonWriter.WriteStringValue(operationSource.Type.ToString()); jsonWriter.WritePropertyName("document"); - jsonWriter.WriteStringValue(operationSource.SourceText); + jsonWriter.WriteStringValue(operationSource.SourceText.Span); jsonWriter.WritePropertyName("hash"); jsonWriter.WriteStringValue(operationSource.Hash); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanParser.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanParser.cs index 5eeb0780989..a2efd96085d 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanParser.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/JsonOperationPlanParser.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using System.Text; using System.Text.Json; using HotChocolate.Execution; using HotChocolate.Fusion.Language; @@ -534,8 +535,8 @@ private static ParsedOperationNodeInfo ParseOperationNodeInfo( JsonElement nodeElement, int id, FusionSchemaDefinition schema) { var (schemaName, opSource, source, requirements, forwardedVariables, - resultSelectionSet, dependencies, parentDependencies, batchingGroupId, conditions, - requiresFileUpload) = ParseCommonOperationFields(nodeElement); + resultSelectionSet, dependencies, parentDependencies, batchingGroupId, + conditions, requiresFileUpload) = ParseCommonOperationFields(nodeElement, schema); SelectionPath? target = null; @@ -574,8 +575,8 @@ private static ParsedApolloOperationNodeInfo ParseApolloOperationNodeInfo( JsonElement nodeElement, int id, FusionSchemaDefinition schema) { var (schemaName, opSource, source, requirements, forwardedVariables, - resultSelectionSet, dependencies, parentDependencies, batchingGroupId, conditions, - requiresFileUpload) = ParseCommonOperationFields(nodeElement); + resultSelectionSet, dependencies, parentDependencies, batchingGroupId, + conditions, requiresFileUpload) = ParseCommonOperationFields(nodeElement, schema); SelectionPath? target = null; @@ -698,8 +699,8 @@ private static ParsedOperationNodeInfo ParseOperationBatchNodeInfo( JsonElement nodeElement, int id, FusionSchemaDefinition schema) { var (schemaName, opSource, source, requirements, forwardedVariables, - resultSelectionSet, dependencies, parentDependencies, batchingGroupId, conditions, - requiresFileUpload) = ParseCommonOperationFields(nodeElement); + resultSelectionSet, dependencies, parentDependencies, batchingGroupId, + conditions, requiresFileUpload) = ParseCommonOperationFields(nodeElement, schema); var targets = nodeElement.TryGetProperty("targets", out var targetsElement) ? targetsElement.EnumerateArray().Select(e => SelectionPath.Parse(e.GetString()!)).ToArray() @@ -731,6 +732,23 @@ private static ParsedOperationNodeInfo ParseOperationBatchNodeInfo( }; } + // Resolves the type that a rehydrated lookup node's root selection is selected on. A source + // schema field that the composite schema does not declare, for example an internal lookup, + // cannot be resolved from the plan alone, so such a node keeps the classic transport paths. + private static string? ResolveLookupTypeName( + FusionSchemaDefinition schema, + OperationType operationType, + SelectionPath? source) + { + if (source is null) + { + return null; + } + + var type = ResolveResultSelectionSetType(schema, operationType, source); + return type is null ? null : OperationSourceText.ResolveLookupTypeName(source, type); + } + // Reconstructs the type that declares a fetch node's result selection set by walking the // source path from the operation root type, mirroring how BuildExecutionTree passes // operationStep.Type into ResultSelectionSet.Create. This is what lets a rehydrated plan @@ -776,7 +794,7 @@ private static (string? schemaName, OperationSourceText opSource, SelectionPath? List? requirements, string[]? forwardedVariables, SelectionSetNode? resultSelectionSet, int[]? dependencies, int[]? parentDependencies, int? batchingGroupId, ExecutionNodeCondition[] conditions, bool requiresFileUpload) - ParseCommonOperationFields(JsonElement nodeElement) + ParseCommonOperationFields(JsonElement nodeElement, FusionSchemaDefinition schema) { string? schemaName = null; @@ -788,9 +806,9 @@ private static (string? schemaName, OperationSourceText opSource, SelectionPath? var operationElement = nodeElement.GetProperty("operation"); var operationName = operationElement.GetProperty("name").GetString()!; var operationType = Enum.Parse(operationElement.GetProperty("kind").GetString()!); + // The parsed document string is transient: encode it to UTF-8 once and discard it. var document = operationElement.GetProperty("document").GetString()!; var hash = operationElement.GetProperty("hash").GetString()!; - var opSource = new OperationSourceText(operationName, operationType, document, hash); SelectionPath? source = null; List? requirements = null; @@ -805,6 +823,13 @@ private static (string? schemaName, OperationSourceText opSource, SelectionPath? source = SelectionPath.Parse(sourceElement.GetString()!); } + var opSource = OperationSourceText.Create( + operationName, + operationType, + Encoding.UTF8.GetBytes(document), + hash, + ResolveLookupTypeName(schema, operationType, source)); + if (nodeElement.TryGetProperty("requirements", out var requirementsElement)) { requirements = []; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/YamlOperationPlanFormatter.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/YamlOperationPlanFormatter.cs index 8f69e873bf9..b3505dd161b 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/YamlOperationPlanFormatter.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/Serialization/YamlOperationPlanFormatter.cs @@ -222,7 +222,8 @@ private static void WriteOperationNode(OperationExecutionNode node, ExecutionNod writer.WriteLine("operation: |"); writer.Indent(); - var reader = new StringReader(node.Operation.SourceText); + // Decode the UTF-8 operation text for line-by-line YAML output (cold diagnostic path). + var reader = new StringReader(Encoding.UTF8.GetString(node.Operation.SourceText.Span)); var line = reader.ReadLine(); while (line != null) { @@ -414,7 +415,8 @@ private static void WriteOperationDefinitionAsNode( writer.WriteLine("operation: |"); writer.Indent(); - var reader = new StringReader(opDef.Operation.SourceText); + // Decode the UTF-8 operation text for line-by-line YAML output (cold diagnostic path). + var reader = new StringReader(Encoding.UTF8.GetString(opDef.Operation.SourceText.Span)); var line = reader.ReadLine(); while (line != null) { @@ -468,7 +470,8 @@ private static void WriteBatchOperationDefinitionAsNode( writer.WriteLine("operation: |"); writer.Indent(); - var reader = new StringReader(opDef.Operation.SourceText); + // Decode the UTF-8 operation text for line-by-line YAML output (cold diagnostic path). + var reader = new StringReader(Encoding.UTF8.GetString(opDef.Operation.SourceText.Span)); var line = reader.ReadLine(); while (line != null) { @@ -530,7 +533,8 @@ private static void WriteApolloOperationNode( // from the lookup operation when it is created. writer.WriteLine("operation: |"); writer.Indent(); - var reader = new StringReader(node.LookupOperation.SourceText); + // Decode the UTF-8 operation text for line-by-line YAML output (cold diagnostic path). + var reader = new StringReader(Encoding.UTF8.GetString(node.LookupOperation.SourceText.Span)); var line = reader.ReadLine(); while (line != null) { @@ -593,7 +597,8 @@ private static void WriteApolloOperationDefinitionAsNode( writer.WriteLine("operation: |"); writer.Indent(); - var reader = new StringReader(opDef.Operation.SourceText); + // Decode the UTF-8 operation text for line-by-line YAML output (cold diagnostic path). + var reader = new StringReader(Encoding.UTF8.GetString(opDef.Operation.SourceText.Span)); var line = reader.ReadLine(); while (line != null) { diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj b/src/HotChocolate/Fusion/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj index 2d06bdd6be8..500d07a9627 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj @@ -20,6 +20,7 @@ + @@ -41,6 +42,8 @@ + + diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/JsonSegment.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/JsonSegment.cs index 71a10beb5bd..745b2e53445 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/JsonSegment.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/JsonSegment.cs @@ -23,6 +23,10 @@ private JsonSegment(ChunkedArrayWriter memory, int location, int length) internal int Length => _length; + /// + /// Returns the bytes of this segment as a sequence over the memory that holds them. The + /// sequence reads that memory and is valid for as long as it lives. + /// public ReadOnlySequence AsSequence() { if (IsEmpty) @@ -32,21 +36,21 @@ public ReadOnlySequence AsSequence() var start = _location; var length = _length; - var first = _memory.Read(ref start, ref length); + var first = _memory.ReadMemory(ref start, ref length); if (length == 0) { // Single chunk — common case, no allocation for segment chain. - return new ReadOnlySequence(first.ToArray()); + return new ReadOnlySequence(first); } // Multi-chunk — build a ReadOnlySequence from linked segments. - var firstSegment = new MemorySegment(first.ToArray()); + var firstSegment = new MemorySegment(first); var lastSegment = firstSegment; do { - lastSegment = lastSegment.Append(_memory.Read(ref start, ref length)); + lastSegment = lastSegment.Append(_memory.ReadMemory(ref start, ref length)); } while (length > 0); @@ -116,9 +120,9 @@ public MemorySegment(ReadOnlyMemory memory) Memory = memory; } - public MemorySegment Append(ReadOnlySpan data) + public MemorySegment Append(ReadOnlyMemory data) { - var next = new MemorySegment(data.ToArray()) + var next = new MemorySegment(data) { RunningIndex = RunningIndex + Memory.Length }; diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Planning/OperationPlanner.BuildExecutionTree.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Planning/OperationPlanner.BuildExecutionTree.cs index 065cda0694d..8e0f239bd38 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Planning/OperationPlanner.BuildExecutionTree.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Planning/OperationPlanner.BuildExecutionTree.cs @@ -598,7 +598,8 @@ private static ExecutionNode CreateOperationExecutionNode( operationStep.SchemaName, schema); var operation = RemoveInternalDirectives(sourceRewrite.Operation); - var operationSource = operation.ToSourceText(); + var operationSource = operation.ToSourceText( + OperationSourceText.ResolveLookupTypeName(operationStep.Source, operationStep.Type)); var selectionSetNode = GetSelectionSetNodeFromPath(operationStep.Definition, operationStep.Source); var sourceAliasSelectionSets = CreateSourceAliasSelectionSetLookup( @@ -1629,13 +1630,16 @@ private static int GetDependencyDepth( private static string ComputeCanonicalSignature(OperationExecutionNode node) { var replacements = BuildPrefixReplacements(node.Requirements); - var normalizedText = ApplyPrefixReplacements(node.Operation.SourceText, replacements); + var normalized = ApplyPrefixReplacements(node.Operation.SourceText.Span, replacements); // The first line contains the operation name, which embeds a // step-specific identifier. We skip it so that two operations - // with the same structure produce the same signature. - var firstNewline = normalizedText.IndexOf('\n'); - var bodyText = firstNewline >= 0 ? normalizedText[(firstNewline + 1)..] : normalizedText; + // with the same structure produce the same signature. '\n' is a + // single ASCII byte in UTF-8, so the byte scan matches the text scan. + var normalizedSpan = normalized.AsSpan(); + var firstNewline = normalizedSpan.IndexOf((byte)'\n'); + var bodySpan = firstNewline >= 0 ? normalizedSpan[(firstNewline + 1)..] : normalizedSpan; + var bodyText = Encoding.UTF8.GetString(bodySpan); var conditions = string.Join(",", node.Conditions.ToArray() .OrderBy(c => c.VariableName) @@ -1655,7 +1659,7 @@ private static (OperationSourceText operation, OperationRequirement[] requiremen /// __fusion_{N}_ variable name prefixes into a canonical /// form, so structurally identical operations produce matching text. /// - private static (string original, string canonical)[] BuildPrefixReplacements( + private static (byte[] Original, byte[] Canonical)[] BuildPrefixReplacements( ReadOnlySpan requirements) { var prefixToArgs = new Dictionary>(StringComparer.Ordinal); @@ -1687,26 +1691,79 @@ private static (string original, string canonical)[] BuildPrefixReplacements( .Select(kvp => kvp.Key) .ToList(); - var result = new (string original, string canonical)[sortedPrefixes.Count]; + var result = new (byte[] Original, byte[] Canonical)[sortedPrefixes.Count]; for (var i = 0; i < sortedPrefixes.Count; i++) { - result[i] = ($"{sortedPrefixes[i]}_", $"__fusion_{i}_"); + // Variable name prefixes and the canonical form are ASCII, so their + // UTF-8 encoding matches the source text byte-for-byte. + result[i] = ( + Encoding.UTF8.GetBytes($"{sortedPrefixes[i]}_"), + Encoding.UTF8.GetBytes($"__fusion_{i}_")); } return result; } - private static string ApplyPrefixReplacements( - string text, - ReadOnlySpan<(string original, string canonical)> replacements) + private static byte[] ApplyPrefixReplacements( + ReadOnlySpan text, + ReadOnlySpan<(byte[] Original, byte[] Canonical)> replacements) { + var current = text.ToArray(); + foreach (var (original, canonical) in replacements) { - text = text.Replace(original, canonical); + current = ReplaceBytes(current, original, canonical); + } + + return current; + } + + /// + /// Replaces every non-overlapping occurrence of + /// with , scanning left to right without + /// re-scanning the emitted replacement. This mirrors . + /// + private static byte[] ReplaceBytes( + ReadOnlySpan source, + ReadOnlySpan original, + ReadOnlySpan replacement) + { + var first = source.IndexOf(original); + + if (first < 0) + { + return source.ToArray(); } - return text; + // Count the occurrences so the destination buffer can be sized exactly. + var count = 1; + var rest = source[(first + original.Length)..]; + int next; + + while ((next = rest.IndexOf(original)) >= 0) + { + count++; + rest = rest[(next + original.Length)..]; + } + + var result = new byte[source.Length + (count * (replacement.Length - original.Length))]; + var destination = result.AsSpan(); + var remaining = source; + int index; + + while ((index = remaining.IndexOf(original)) >= 0) + { + remaining[..index].CopyTo(destination); + destination = destination[index..]; + replacement.CopyTo(destination); + destination = destination[replacement.Length..]; + remaining = remaining[(index + original.Length)..]; + } + + remaining.CopyTo(destination); + + return result; } /// @@ -2616,7 +2673,9 @@ public static Selection[] GetIntrospectionSelections(this Operation operation) return selections.ToArray(); } - public static OperationSourceText ToSourceText(this OperationDefinitionNode operation) + public static OperationSourceText ToSourceText( + this OperationDefinitionNode operation, + string? lookupTypeName) { var sourceText = operation.ToString(indented: true); var sourceTextUtf8 = s_encoding.GetBytes(sourceText); @@ -2625,6 +2684,11 @@ public static OperationSourceText ToSourceText(this OperationDefinitionNode oper #else var operationHash = Convert.ToHexString(SHA256.HashData(sourceTextUtf8)).ToLowerInvariant(); #endif - return new OperationSourceText(operation.Name!.Value, operation.Operation, sourceText, operationHash); + return OperationSourceText.Create( + operation.Name!.Value, + operation.Operation, + sourceTextUtf8, + operationHash, + lookupTypeName); } } diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.Designer.cs b/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.Designer.cs index d2f121b4b96..99c83570e50 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.Designer.cs +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.Designer.cs @@ -117,6 +117,12 @@ internal static string SourceSchemaClient_SubscriptionsNotSupported { } } + internal static string HttpSourceSchemaClient_InvalidAliasBatchResponse { + get { + return ResourceManager.GetString("HttpSourceSchemaClient_InvalidAliasBatchResponse", resourceCulture); + } + } + internal static string HttpSourceSchemaClient_InvalidRequestIndex { get { return ResourceManager.GetString("HttpSourceSchemaClient_InvalidRequestIndex", resourceCulture); diff --git a/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.resx b/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.resx index 251ee5260cd..6ecae1118eb 100644 --- a/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.resx +++ b/src/HotChocolate/Fusion/src/Fusion.Execution/Properties/FusionExecutionResources.resx @@ -54,6 +54,9 @@ The source schema client does not support subscription requests. + + The batched response does not follow the shape of the batched request that was sent to the source schema '{0}'. + The batch response contains an invalid requestIndex '{0}'. diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/AliasBatchingTests.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/AliasBatchingTests.cs new file mode 100644 index 00000000000..5ccd5a5f5ec --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/AliasBatchingTests.cs @@ -0,0 +1,250 @@ +using System.Text.Json; +using HotChocolate.Fusion.Execution.Clients; +using HotChocolate.Transport; +using HotChocolate.Transport.Http; +using HotChocolate.Types.Composite; +using HotChocolate.Types.Relay; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Fusion; + +public class AliasBatchingTests : FusionTestBase +{ + [Fact] + public async Task BatchedLookup_Should_SendOneAliasedRequest_When_AliasBatchingIsEnabled() + { + // arrange + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType(), + capabilities: SourceSchemaClientCapabilities.AliasBatching); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ]); + + // act + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + var request = new OperationRequest( + """ + { + books { + rating + } + } + """); + + using var result = await client.PostAsync( + request, + new Uri("http://localhost:5000/graphql"), + TestContext.Current.CancellationToken); + + // assert + await MatchSnapshotAsync(gateway, request, result); + } + + [Fact] + public async Task BatchedLookup_Should_RouteErrorsToTheirItem_When_OneItemFails() + { + // arrange + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType(), + capabilities: SourceSchemaClientCapabilities.AliasBatching); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ]); + + // act + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + var request = new OperationRequest( + """ + { + books { + title + errorRating + } + } + """); + + using var result = await client.PostAsync( + request, + new Uri("http://localhost:5000/graphql"), + TestContext.Current.CancellationToken); + + // assert + await MatchSnapshotAsync(gateway, request, result); + } + + [Fact] + public async Task BatchedLookup_Should_ShareTheClientVariable_When_ItIsForwarded() + { + // arrange + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType(), + capabilities: SourceSchemaClientCapabilities.AliasBatching); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ]); + + // act + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + var request = new OperationRequest( + """ + query($postFix: String) { + books { + author { + name(postFix: $postFix) + } + } + } + """, + variables: new Dictionary { ["postFix"] = "x" }); + + using var result = await client.PostAsync( + request, + new Uri("http://localhost:5000/graphql"), + TestContext.Current.CancellationToken); + + // assert + await MatchSnapshotAsync(gateway, request, result); + } + + [Fact] + public async Task BatchedLookup_Should_ProduceTheSameResult_When_ComparedToVariableBatching() + { + // arrange + const string query = + """ + { + books { + rating + author { + name + } + } + } + """; + + // act + var variableBatched = await ExecuteAsync(query, SourceSchemaClientCapabilities.Default); + var aliasBatched = await ExecuteAsync(query, SourceSchemaClientCapabilities.AliasBatching); + + // assert + Assert.Equal(variableBatched, aliasBatched); + } + + private async Task ExecuteAsync( + string query, + SourceSchemaClientCapabilities capabilities) + { + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType(), + capabilities: capabilities); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ]); + + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + using var response = await client.PostAsync( + new OperationRequest(query), + new Uri("http://localhost:5000/graphql"), + TestContext.Current.CancellationToken); + + var body = await response.HttpResponseMessage.Content.ReadAsStringAsync( + TestContext.Current.CancellationToken); + + // Reformat so incidental whitespace differences do not mask a true tree comparison. + using var document = JsonDocument.Parse(body); + return JsonSerializer.Serialize(document, new JsonSerializerOptions { WriteIndented = true }); + } + + public static class SourceSchema1 + { + public class Query + { + private readonly OrderedDictionary _books = + new() { [1] = new Book(1, "C# in Depth"), [2] = new Book(2, "The Lord of the Rings") }; + + public IEnumerable GetBooks() => _books.Values; + + [Lookup, Internal] + public Book? GetBookById([ID] int id) => _books.GetValueOrDefault(id); + + [Lookup, Internal] + public Author? GetAuthorById([ID] int id) => null; + } + + public record Book([property: ID] int Id, string Title) + { + public Author? GetAuthor() => new Author(Id); + } + + public record Author([property: ID] int Id); + } + + public static class SourceSchema2 + { + public class Query + { + [Lookup, Internal] + public Book? GetBookById([ID] int id) => new(id); + + [Lookup, Internal] + public Author? GetAuthorById([ID] int id) => new(id); + } + + public record Book([property: ID] int Id) + { + public string GetRating() => Id.ToString(); + + public string? GetErrorRating() + => Id == 2 + ? throw new GraphQLException("Rating unavailable.") + : Id.ToString(); + } + + public record Author([property: ID] int Id) + { + public string GetName(string? postFix = null) + { + var name = "Author " + Id; + + return string.IsNullOrEmpty(postFix) ? name : name + " - " + postFix; + } + } + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/BatchingCapabilityMatrixTests.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/BatchingCapabilityMatrixTests.cs new file mode 100644 index 00000000000..2b814d476c9 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/BatchingCapabilityMatrixTests.cs @@ -0,0 +1,191 @@ +using System.Text.Json; +using HotChocolate.Fusion.Execution.Clients; +using HotChocolate.Transport; +using HotChocolate.Transport.Http; +using HotChocolate.Types.Composite; +using HotChocolate.Types.Relay; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Fusion; + +/// +/// Pins the gateway to source schema wire format that every combination of the batching +/// capabilities produces for one and the same plan. The query fetches two distinct lookup +/// operations from the lookup source schema, each of which carries two variable sets, so +/// every combination is exercised on both batching dimensions: the variable sets of one +/// operation and the distinct operations of one batch. +/// +public class BatchingCapabilityMatrixTests : FusionTestBase +{ + private const string Query = + """ + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } + """; + + [Theory] + [InlineData(SourceSchemaClientCapabilities.None)] + [InlineData(SourceSchemaClientCapabilities.VariableBatching)] + [InlineData(SourceSchemaClientCapabilities.RequestBatching)] + [InlineData( + SourceSchemaClientCapabilities.VariableBatching + | SourceSchemaClientCapabilities.RequestBatching)] + [InlineData(SourceSchemaClientCapabilities.AliasBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.VariableBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.RequestBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.VariableBatching + | SourceSchemaClientCapabilities.RequestBatching)] + // The None row pins a known pre-existing defect: the client flattens a multi-set operation into + // an OperationBatchRequest JSON array even though the source schema declares no request batching + // capability (HttpSourceSchemaClient.CreateHttpRequest, no-variable-batching branch). The row + // records the actual behavior, not the intended contract; the defect is tracked separately. + public async Task BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect( + SourceSchemaClientCapabilities capabilities) + { + // arrange + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType(), + capabilities: capabilities); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ]); + + using var client = GraphQLHttpClient.Create(gateway.CreateClient()); + + var request = new OperationRequest(Query); + + // act + using var result = await client.PostAsync( + request, + new Uri("http://localhost:5000/graphql"), + TestContext.Current.CancellationToken); + + // assert + // every combination has to resolve the same data, so all rows share one inline snapshot of + // the response data; only the wire format below is pinned per combination. + var responseBody = await result.HttpResponseMessage.Content.ReadAsStringAsync( + TestContext.Current.CancellationToken); + + using var responseDocument = JsonDocument.Parse(responseBody); + responseDocument.RootElement.GetProperty("data").MatchInlineSnapshot( + """ + { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + """); + + await MatchSnapshotAsync(gateway, request, result, postFix: CreateLabel(capabilities)); + } + + /// + /// Composes the filename-safe label of a capability combination. + /// + private static string CreateLabel(SourceSchemaClientCapabilities capabilities) + { + if (capabilities is SourceSchemaClientCapabilities.None) + { + return "None"; + } + + var label = string.Empty; + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.AliasBatching)) + { + label += "A"; + } + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.VariableBatching)) + { + label += "V"; + } + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.RequestBatching)) + { + label += "R"; + } + + return label; + } + + public static class SourceSchema1 + { + public class Query + { + private readonly OrderedDictionary _books = + new() { [1] = new Book(1, "C# in Depth"), [2] = new Book(2, "The Lord of the Rings") }; + + public IEnumerable GetBooks() => _books.Values; + + [Lookup, Internal] + public Book? GetBookById([ID] int id) => _books.GetValueOrDefault(id); + + [Lookup, Internal] + public Author? GetAuthorById([ID] int id) => null; + } + + public record Book([property: ID] int Id, string Title) + { + public Author? GetAuthor() => new Author(Id); + } + + public record Author([property: ID] int Id); + } + + public static class SourceSchema2 + { + public class Query + { + [Lookup, Internal] + public Author? GetAuthorById([ID] int id) => new(id); + } + + public record Author([property: ID] int Id) + { + public string GetName(string? postFix = null) + { + var name = "Author " + Id; + + return string.IsNullOrEmpty(postFix) ? name : name + " - " + postFix; + } + } + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.CreateSourceSchema.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.CreateSourceSchema.cs index 25e63f2bc27..6f970490377 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.CreateSourceSchema.cs +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.CreateSourceSchema.cs @@ -24,7 +24,7 @@ protected TestServer CreateSourceSchema( HttpClient? httpClient = null, bool isOffline = false, bool isTimingOut = false, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, @@ -74,7 +74,7 @@ protected TestServer CreateSourceSchema( bool isTimingOut = false, Action? configureHttpClient = null, HttpClient? httpClient = null, - SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.All, + SourceSchemaClientCapabilities capabilities = SourceSchemaClientCapabilities.Default, ErrorHandlingMode? onError = null, ImmutableArray? defaultAcceptHeaderValues = null, ImmutableArray? batchingAcceptHeaderValues = null, diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs index 6b8f1cc015f..400ec2c5adb 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs @@ -7,6 +7,7 @@ using System.Text.RegularExpressions; using CookieCrumble.HotChocolate.Formatters; using HotChocolate.Buffers; +using HotChocolate.Execution; using HotChocolate.Fusion.Execution; using HotChocolate.Fusion.Execution.Clients; using HotChocolate.Fusion.Execution.Nodes; @@ -472,10 +473,10 @@ private static string SerializeSourceSchemaResult(SourceSchemaResult result) jsonWriter.WriteStartObject(); - if (result.RawErrors.ValueKind != JsonValueKind.Undefined) + if (result.Errors is { } errors) { jsonWriter.WritePropertyName("errors"); - jsonWriter.WriteRawValue(result.RawErrors.GetRawValue()); + WriteSourceSchemaErrors(jsonWriter, errors); } if (result.Data.ValueKind != JsonValueKind.Undefined) @@ -499,6 +500,91 @@ private static string SerializeSourceSchemaResult(SourceSchemaResult result) return JsonSerializer.Serialize(document, new JsonSerializerOptions { WriteIndented = true }); } + /// + /// Writes the errors a source schema result carries, the errors without a path first and the + /// errors with a path in the order of the paths they were reported for. + /// + private static void WriteSourceSchemaErrors(Utf8JsonWriter jsonWriter, SourceSchemaErrors errors) + { + jsonWriter.WriteStartArray(); + + foreach (var error in errors.RootErrors) + { + WriteSourceSchemaError(jsonWriter, error); + } + + WriteSourceSchemaErrors(jsonWriter, errors.Trie); + + jsonWriter.WriteEndArray(); + } + + private static void WriteSourceSchemaErrors(Utf8JsonWriter jsonWriter, ErrorTrie trie) + { + if (trie.Error is not null) + { + WriteSourceSchemaError(jsonWriter, trie.Error); + } + + foreach (var child in trie.Values) + { + WriteSourceSchemaErrors(jsonWriter, child); + } + } + + private static void WriteSourceSchemaError(Utf8JsonWriter jsonWriter, IError error) + { + jsonWriter.WriteStartObject(); + jsonWriter.WriteString("message", error.Message); + + if (error.Path is not null) + { + jsonWriter.WritePropertyName("path"); + jsonWriter.WriteStartArray(); + + foreach (var segment in error.Path.ToList()) + { + switch (segment) + { + case int index: + jsonWriter.WriteNumberValue(index); + break; + + default: + jsonWriter.WriteStringValue(segment.ToString()); + break; + } + } + + jsonWriter.WriteEndArray(); + } + + if (error.Extensions is { Count: > 0 } extensions) + { + jsonWriter.WritePropertyName("extensions"); + jsonWriter.WriteStartObject(); + + foreach (var (key, value) in extensions) + { + jsonWriter.WritePropertyName(key); + + switch (value) + { + case RawJsonValue rawJson: + jsonWriter.WriteRawValue(rawJson.Value.Span); + break; + + default: + JsonSerializer.Serialize(jsonWriter, value); + break; + } + } + + jsonWriter.WriteEndObject(); + } + + jsonWriter.WriteEndObject(); + } + private static void WriteSourceSchemaDocument(CodeWriter writer, string schemaText) { var document = Utf8GraphQLParser.Parse(schemaText); diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.cs b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.cs index 40b6fa64c44..9a4040c9b15 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.cs +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.cs @@ -345,7 +345,7 @@ private sealed class SourceSchemaOptions public Func>? MockHttpResponse { get; set; } - public SourceSchemaClientCapabilities Capabilities { get; set; } = SourceSchemaClientCapabilities.All; + public SourceSchemaClientCapabilities Capabilities { get; set; } = SourceSchemaClientCapabilities.Default; public ImmutableArray? DefaultAcceptHeaderValues { get; set; } diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_RouteErrorsToTheirItem_When_OneItemFails.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_RouteErrorsToTheirItem_When_OneItemFails.yaml new file mode 100644 index 00000000000..f7519a0f40f --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_RouteErrorsToTheirItem_When_OneItemFails.yaml @@ -0,0 +1,200 @@ +title: BatchedLookup_Should_RouteErrorsToTheirItem_When_OneItemFails +request: + document: | + { + books { + title + errorRating + } + } +response: + body: | + { + "data": { + "books": [ + { + "title": "C# in Depth", + "errorRating": "1" + }, + { + "title": "The Lord of the Rings", + "errorRating": null + } + ] + }, + "errors": [ + { + "message": "Rating unavailable.", + "path": [ + "books", + 1, + "errorRating" + ] + } + ] + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_628dc6ef_1 { + books { + title + id + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "title": "C# in Depth", + "id": "1" + }, + { + "title": "The Lord of the Rings", + "id": "2" + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + + type Book @key(fields: "id") { + rating: String! + errorRating: String + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Batch_54a8b37e8522415a($_0___fusion_1_id: ID!, $_1___fusion_1_id: ID!) { + _0_bookById: bookById(id: $_0___fusion_1_id) { + ..._fusion_body_1 + } + _1_bookById: bookById(id: $_1___fusion_1_id) { + ..._fusion_body_1 + } + } + + fragment _fusion_body_1 on Book { + errorRating + } + variables: | + { + "_0___fusion_1_id": "1", + "_1___fusion_1_id": "2" + } + response: + results: + - | + { + "data": { + "_0_bookById": { + "errorRating": "1" + }, + "_1_bookById": { + "errorRating": null + } + } + } + - | + { + "errors": [ + { + "message": "Rating unavailable.", + "path": [ + "bookById", + "errorRating" + ] + } + ], + "data": { + "_0_bookById": { + "errorRating": "1" + }, + "_1_bookById": { + "errorRating": null + } + } + } +operationPlan: + operation: + - document: | + { + books { + title + errorRating + id @fusion__requirement + } + } + hash: 628dc6ef7d5d2f822ed92d1d65e89e99 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_628dc6ef_1 { + books { + title + id + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_628dc6ef_2($__fusion_1_id: ID!) { + bookById(id: $__fusion_1_id) { + errorRating + } + } + source: $.bookById + target: $.books + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_SendOneAliasedRequest_When_AliasBatchingIsEnabled.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_SendOneAliasedRequest_When_AliasBatchingIsEnabled.yaml new file mode 100644 index 00000000000..3880cfe1d40 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_SendOneAliasedRequest_When_AliasBatchingIsEnabled.yaml @@ -0,0 +1,173 @@ +title: BatchedLookup_Should_SendOneAliasedRequest_When_AliasBatchingIsEnabled +request: + document: | + { + books { + rating + } + } +response: + body: | + { + "data": { + "books": [ + { + "rating": "1" + }, + { + "rating": "2" + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_490e9345_1 { + books { + id + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "id": "1" + }, + { + "id": "2" + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + + type Book @key(fields: "id") { + rating: String! + errorRating: String + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Batch_68b774cc95d814dc($_0___fusion_1_id: ID!, $_1___fusion_1_id: ID!) { + _0_bookById: bookById(id: $_0___fusion_1_id) { + ..._fusion_body_1 + } + _1_bookById: bookById(id: $_1___fusion_1_id) { + ..._fusion_body_1 + } + } + + fragment _fusion_body_1 on Book { + rating + } + variables: | + { + "_0___fusion_1_id": "1", + "_1___fusion_1_id": "2" + } + response: + results: + - | + { + "data": { + "_0_bookById": { + "rating": "1" + }, + "_1_bookById": { + "rating": "2" + } + } + } + - | + { + "data": { + "_0_bookById": { + "rating": "1" + }, + "_1_bookById": { + "rating": "2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + rating + id @fusion__requirement + } + } + hash: 490e934563f9d79a50edbb76c6b9b5cc + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_490e9345_1 { + books { + id + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_490e9345_2($__fusion_1_id: ID!) { + bookById(id: $__fusion_1_id) { + rating + } + } + source: $.bookById + target: $.books + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_ShareTheClientVariable_When_ItIsForwarded.yaml similarity index 53% rename from src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines.yaml rename to src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_ShareTheClientVariable_When_ItIsForwarded.yaml index 71de83b9b78..27fb253596a 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines.yaml +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/AliasBatchingTests.BatchedLookup_Should_ShareTheClientVariable_When_ItIsForwarded.yaml @@ -1,14 +1,17 @@ -title: Fetch_With_ApolloRequestBatching_JsonLines +title: BatchedLookup_Should_ShareTheClientVariable_When_ItIsForwarded request: document: | - { + query($postFix: String) { books { author { - id - name + name(postFix: $postFix) } } } + variables: | + { + "postFix": "x" + } response: body: | { @@ -16,26 +19,12 @@ response: "books": [ { "author": { - "id": "1", - "name": "Author 1" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" + "name": "Author 1 - x" } }, { "author": { - "id": "2", - "name": "Author 2" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" + "name": "Author 2 - x" } } ] @@ -48,24 +37,26 @@ sourceSchemas: query: Query } + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + type Author @key(fields: "id") { id: ID! } - type Book { + type Book @key(fields: "id") { + author: Author id: ID! title: String! - author: Author! @shareable - } - - type Query { - books: [Book!]! } interactions: - request: accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 document: | - query Op_fb4f667e_1 { + query Op_2fede843_1 { books { author { id @@ -83,16 +74,6 @@ sourceSchemas: "id": "1" } }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - }, { "author": { "id": "2" @@ -107,75 +88,83 @@ sourceSchemas: query: Query } - type Author { - name(large: Boolean! = false): String! + type Query { + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! id: ID! } - type Query { - authorById(id: ID!): Author @lookup @internal + type Book @key(fields: "id") { + rating: String! + errorRating: String + id: ID! } interactions: - request: - accept: application/jsonl; charset=utf-8 - kind: OperationBatch - items: - - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": "1" - } - - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": "2" - } + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Batch_21d743c9caa4fea1( + $postFix: String + $_0___fusion_1_id: ID! + $_1___fusion_1_id: ID! + ) { + _0_authorById: authorById(id: $_0___fusion_1_id) { + ..._fusion_body_1 + } + _1_authorById: authorById(id: $_1___fusion_1_id) { + ..._fusion_body_1 + } + } + + fragment _fusion_body_1 on Author { + name(postFix: $postFix) + } + variables: | + { + "postFix": "x", + "_0___fusion_1_id": "1", + "_1___fusion_1_id": "2" + } response: - contentType: application/jsonl; charset=utf-8 results: - | { "data": { - "authorById": { - "name": "Author 1" + "_0_authorById": { + "name": "Author 1 - x" + }, + "_1_authorById": { + "name": "Author 2 - x" } } } - | { "data": { - "authorById": { - "name": "Author 2" + "_0_authorById": { + "name": "Author 1 - x" + }, + "_1_authorById": { + "name": "Author 2 - x" } } } operationPlan: operation: - document: | - { + query($postFix: String) { books { author { - id + name(postFix: $postFix) id @fusion__requirement - name } } } - hash: fb4f667e3d4167a23589ae9f3b3f9182 + hash: 2fede843d6d376a00b9017bc9910abd3 searchSpace: 1 expandedNodes: 2 nodes: @@ -183,7 +172,7 @@ operationPlan: type: Operation schema: a operation: | - query Op_fb4f667e_1 { + query Op_2fede843_1 { books { author { id @@ -194,11 +183,9 @@ operationPlan: type: Operation schema: b operation: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { + query Op_2fede843_2($postFix: String, $__fusion_1_id: ID!) { authorById(id: $__fusion_1_id) { - name + name(postFix: $postFix) } } source: $.authorById @@ -207,5 +194,7 @@ operationPlan: - name: __fusion_1_id selectionMap: >- id + forwardedVariables: + - postFix dependencies: - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.yaml new file mode 100644 index 00000000000..525bad8c9d9 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.yaml @@ -0,0 +1,289 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Batch_e65691bf9b0dfdcd( + $_0___fusion_1_id: ID! + $_1___fusion_1_id: ID! + $_2___fusion_2_id: ID! + $_3___fusion_2_id: ID! + ) { + _0_authorById: authorById(id: $_0___fusion_1_id) { + ..._fusion_body_1 + } + _1_authorById: authorById(id: $_1___fusion_1_id) { + ..._fusion_body_1 + } + _2_authorById: authorById(id: $_2___fusion_2_id) { + ..._fusion_body_2 + } + _3_authorById: authorById(id: $_3___fusion_2_id) { + ..._fusion_body_2 + } + } + + fragment _fusion_body_1 on Author { + b: name(postFix: "2") + } + + fragment _fusion_body_2 on Author { + a: name + } + variables: | + { + "_0___fusion_1_id": "1", + "_1___fusion_1_id": "2", + "_2___fusion_2_id": "1", + "_3___fusion_2_id": "2" + } + response: + results: + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.yaml new file mode 100644 index 00000000000..65261f5dc2e --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.yaml @@ -0,0 +1,261 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + kind: OperationBatch + items: + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "1" + } + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "2" + } + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "1" + } + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "2" + } + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "b": "Author 1 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 2 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 1" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.yaml new file mode 100644 index 00000000000..525bad8c9d9 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.yaml @@ -0,0 +1,289 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Batch_e65691bf9b0dfdcd( + $_0___fusion_1_id: ID! + $_1___fusion_1_id: ID! + $_2___fusion_2_id: ID! + $_3___fusion_2_id: ID! + ) { + _0_authorById: authorById(id: $_0___fusion_1_id) { + ..._fusion_body_1 + } + _1_authorById: authorById(id: $_1___fusion_1_id) { + ..._fusion_body_1 + } + _2_authorById: authorById(id: $_2___fusion_2_id) { + ..._fusion_body_2 + } + _3_authorById: authorById(id: $_3___fusion_2_id) { + ..._fusion_body_2 + } + } + + fragment _fusion_body_1 on Author { + b: name(postFix: "2") + } + + fragment _fusion_body_2 on Author { + a: name + } + variables: | + { + "_0___fusion_1_id": "1", + "_1___fusion_1_id": "2", + "_2___fusion_2_id": "1", + "_3___fusion_2_id": "2" + } + response: + results: + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "_0_authorById": { + "b": "Author 1 - 2" + }, + "_1_authorById": { + "b": "Author 2 - 2" + }, + "_2_authorById": { + "a": "Author 1" + }, + "_3_authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonArray.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.yaml similarity index 54% rename from src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonArray.yaml rename to src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.yaml index c0d7df64db8..bcfe8095424 100644 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonArray.yaml +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.yaml @@ -1,11 +1,13 @@ -title: Fetch_With_ApolloRequestBatching_JsonArray +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect request: document: | { books { - author { - id - name + a: author { + a: name + } + b: author { + b: name(postFix: "2") } } } @@ -15,27 +17,19 @@ response: "data": { "books": [ { - "author": { - "id": "1", - "name": "Author 2" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" } }, { - "author": { - "id": "2", - "name": "Author 2" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" } } ] @@ -48,26 +42,31 @@ sourceSchemas: query: Query } + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + type Author @key(fields: "id") { id: ID! } - type Book { + type Book @key(fields: "id") { + author: Author id: ID! title: String! - author: Author! @shareable - } - - type Query { - books: [Book!]! } interactions: - request: accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 document: | - query Op_fb4f667e_1 { + query Op_1b3419da_1 { books { - author { + a: author { + id + } + b: author { id } } @@ -79,22 +78,18 @@ sourceSchemas: "data": { "books": [ { - "author": { + "a": { + "id": "1" + }, + "b": { "id": "1" } }, { - "author": { - "id": "2" - } - }, - { - "author": { + "a": { "id": "2" - } - }, - { - "author": { + }, + "b": { "id": "2" } } @@ -107,13 +102,13 @@ sourceSchemas: query: Query } - type Author { - id: ID! - name: String! + type Query { + authorById(id: ID!): Author @lookup @internal } - type Query { - authorById(id: ID!): Author @lookup + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! } interactions: - request: @@ -121,37 +116,43 @@ sourceSchemas: kind: OperationBatch items: - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { + query Op_1b3419da_2($__fusion_1_id: ID!) { authorById(id: $__fusion_1_id) { - name + b: name(postFix: "2") } } variables: | - { - "__fusion_1_id": "1" - } + [ + { + "__fusion_1_id": "1" + }, + { + "__fusion_1_id": "2" + } + ] - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name } } variables: | - { - "__fusion_1_id": "2" - } + [ + { + "__fusion_2_id": "1" + }, + { + "__fusion_2_id": "2" + } + ] response: - contentType: application/json; charset=utf-8 + contentType: application/jsonl; charset=utf-8 results: - | { "data": { "authorById": { - "name": "Author 1" + "a": "Author 1" } } } @@ -159,7 +160,7 @@ sourceSchemas: { "data": { "authorById": { - "name": "Author 2" + "a": "Author 2" } } } @@ -167,7 +168,7 @@ sourceSchemas: { "data": { "authorById": { - "name": "Author 2" + "b": "Author 1 - 2" } } } @@ -175,15 +176,7 @@ sourceSchemas: { "data": { "authorById": { - "name": "Author 2" - } - } - } - - | - { - "data": { - "authorById": { - "name": "Author 2" + "b": "Author 2 - 2" } } } @@ -192,14 +185,17 @@ operationPlan: - document: | { books { - author { - id + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") id @fusion__requirement - name } } } - hash: fb4f667e3d4167a23589ae9f3b3f9182 + hash: 1b3419daa4dae74e12e1ad0237002b57 searchSpace: 1 expandedNodes: 2 nodes: @@ -207,9 +203,12 @@ operationPlan: type: Operation schema: a operation: | - query Op_fb4f667e_1 { + query Op_1b3419da_1 { books { - author { + a: author { + id + } + b: author { id } } @@ -218,18 +217,35 @@ operationPlan: type: Operation schema: b operation: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { + query Op_1b3419da_2($__fusion_1_id: ID!) { authorById(id: $__fusion_1_id) { - name + b: name(postFix: "2") } } source: $.authorById - target: $.books.author + target: $.books.b + batchingGroupId: 2 requirements: - name: __fusion_1_id selectionMap: >- id dependencies: - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.yaml new file mode 100644 index 00000000000..a08bb616966 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.yaml @@ -0,0 +1,268 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + kind: OperationBatch + items: + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "1" + } + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "2" + } + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "b": "Author 1 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 2 - 2" + } + } + } + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + kind: OperationBatch + items: + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "1" + } + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "2" + } + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "a": "Author 1" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.yaml new file mode 100644 index 00000000000..65261f5dc2e --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.yaml @@ -0,0 +1,261 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + kind: OperationBatch + items: + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "1" + } + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + { + "__fusion_1_id": "2" + } + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "1" + } + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + { + "__fusion_2_id": "2" + } + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "b": "Author 1 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 2 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 1" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.yaml new file mode 100644 index 00000000000..cd045c68c0c --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.yaml @@ -0,0 +1,254 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + [ + { + "__fusion_1_id": "1" + }, + { + "__fusion_1_id": "2" + } + ] + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "b": "Author 1 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 2 - 2" + } + } + } + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + [ + { + "__fusion_2_id": "1" + }, + { + "__fusion_2_id": "2" + } + ] + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "a": "Author 1" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.yaml new file mode 100644 index 00000000000..bcfe8095424 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/BatchingCapabilityMatrixTests.BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.yaml @@ -0,0 +1,251 @@ +title: BatchedLookups_Should_UseTheProtocolTheCapabilitiesSelect +request: + document: | + { + books { + a: author { + a: name + } + b: author { + b: name(postFix: "2") + } + } + } +response: + body: | + { + "data": { + "books": [ + { + "a": { + "a": "Author 1" + }, + "b": { + "b": "Author 1 - 2" + } + }, + { + "a": { + "a": "Author 2" + }, + "b": { + "b": "Author 2 - 2" + } + } + ] + } + } +sourceSchemas: + - name: a + schema: | + schema { + query: Query + } + + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + id: ID! + } + + type Book @key(fields: "id") { + author: Author + id: ID! + title: String! + } + interactions: + - request: + accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 + document: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + response: + results: + - | + { + "data": { + "books": [ + { + "a": { + "id": "1" + }, + "b": { + "id": "1" + } + }, + { + "a": { + "id": "2" + }, + "b": { + "id": "2" + } + } + ] + } + } + - name: b + schema: | + schema { + query: Query + } + + type Query { + authorById(id: ID!): Author @lookup @internal + } + + type Author @key(fields: "id") { + name(postFix: String): String! + id: ID! + } + interactions: + - request: + accept: application/jsonl; charset=utf-8, text/event-stream; charset=utf-8, application/graphql-response+json; charset=utf-8, application/json; charset=utf-8 + kind: OperationBatch + items: + - document: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + variables: | + [ + { + "__fusion_1_id": "1" + }, + { + "__fusion_1_id": "2" + } + ] + - document: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + variables: | + [ + { + "__fusion_2_id": "1" + }, + { + "__fusion_2_id": "2" + } + ] + response: + contentType: application/jsonl; charset=utf-8 + results: + - | + { + "data": { + "authorById": { + "a": "Author 1" + } + } + } + - | + { + "data": { + "authorById": { + "a": "Author 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 1 - 2" + } + } + } + - | + { + "data": { + "authorById": { + "b": "Author 2 - 2" + } + } + } +operationPlan: + operation: + - document: | + { + books { + a: author { + a: name + id @fusion__requirement + } + b: author { + b: name(postFix: "2") + id @fusion__requirement + } + } + } + hash: 1b3419daa4dae74e12e1ad0237002b57 + searchSpace: 1 + expandedNodes: 2 + nodes: + - id: 1 + type: Operation + schema: a + operation: | + query Op_1b3419da_1 { + books { + a: author { + id + } + b: author { + id + } + } + } + - id: 2 + type: Operation + schema: b + operation: | + query Op_1b3419da_2($__fusion_1_id: ID!) { + authorById(id: $__fusion_1_id) { + b: name(postFix: "2") + } + } + source: $.authorById + target: $.books.b + batchingGroupId: 2 + requirements: + - name: __fusion_1_id + selectionMap: >- + id + dependencies: + - id: 1 + - id: 3 + type: Operation + schema: b + operation: | + query Op_1b3419da_3($__fusion_2_id: ID!) { + authorById(id: $__fusion_2_id) { + a: name + } + } + source: $.authorById + target: $.books.a + batchingGroupId: 2 + requirements: + - name: __fusion_2_id + selectionMap: >- + id + dependencies: + - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines_Large_Response.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines_Large_Response.yaml deleted file mode 100644 index 51f6e408674..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_JsonLines_Large_Response.yaml +++ /dev/null @@ -1,211 +0,0 @@ -title: Fetch_With_ApolloRequestBatching_JsonLines_Large_Response -request: - document: | - { - books { - author { - id - name(large: true) - } - } - } -response: - body: | - { - "data": { - "books": [ - { - "author": { - "id": "1", - "name": "Author 1 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - } - ] - } - } -sourceSchemas: - - name: a - schema: | - schema { - query: Query - } - - type Author @key(fields: "id") { - id: ID! - } - - type Book { - id: ID! - title: String! - author: Author! @shareable - } - - type Query { - books: [Book!]! - } - interactions: - - request: - accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 - document: | - query Op_0e997261_1 { - books { - author { - id - } - } - } - response: - results: - - | - { - "data": { - "books": [ - { - "author": { - "id": "1" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - } - ] - } - } - - name: b - schema: | - schema { - query: Query - } - - type Author { - name(large: Boolean! = false): String! - id: ID! - } - - type Query { - authorById(id: ID!): Author @lookup @internal - } - interactions: - - request: - accept: application/jsonl; charset=utf-8 - kind: OperationBatch - items: - - document: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - variables: | - { - "__fusion_1_id": "1" - } - - document: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - variables: | - { - "__fusion_1_id": "2" - } - response: - contentType: application/jsonl; charset=utf-8 - results: - - | - { - "data": { - "authorById": { - "name": "Author 1 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" - } - } - } - - | - { - "data": { - "authorById": { - "name": "Author 2 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" - } - } - } -operationPlan: - operation: - - document: | - { - books { - author { - id - id @fusion__requirement - name(large: true) - } - } - } - hash: 0e997261f5847770ca54194299b00154 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: a - operation: | - query Op_0e997261_1 { - books { - author { - id - } - } - } - - id: 2 - type: Operation - schema: b - operation: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - source: $.authorById - target: $.books.author - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE.yaml deleted file mode 100644 index 5d417f6ab14..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE.yaml +++ /dev/null @@ -1,211 +0,0 @@ -title: Fetch_With_ApolloRequestBatching_SSE -request: - document: | - { - books { - author { - id - name - } - } - } -response: - body: | - { - "data": { - "books": [ - { - "author": { - "id": "1", - "name": "Author 1" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" - } - }, - { - "author": { - "id": "2", - "name": "Author 2" - } - } - ] - } - } -sourceSchemas: - - name: a - schema: | - schema { - query: Query - } - - type Author @key(fields: "id") { - id: ID! - } - - type Book { - id: ID! - title: String! - author: Author! @shareable - } - - type Query { - books: [Book!]! - } - interactions: - - request: - accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 - document: | - query Op_fb4f667e_1 { - books { - author { - id - } - } - } - response: - results: - - | - { - "data": { - "books": [ - { - "author": { - "id": "1" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - } - ] - } - } - - name: b - schema: | - schema { - query: Query - } - - type Author { - name(large: Boolean! = false): String! - id: ID! - } - - type Query { - authorById(id: ID!): Author @lookup @internal - } - interactions: - - request: - accept: text/event-stream; charset=utf-8 - kind: OperationBatch - items: - - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": "1" - } - - document: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name - } - } - variables: | - { - "__fusion_1_id": "2" - } - response: - contentType: text/event-stream; charset=utf-8 - results: - - | - { - "data": { - "authorById": { - "name": "Author 1" - } - } - } - - | - { - "data": { - "authorById": { - "name": "Author 2" - } - } - } -operationPlan: - operation: - - document: | - { - books { - author { - id - id @fusion__requirement - name - } - } - } - hash: fb4f667e3d4167a23589ae9f3b3f9182 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: a - operation: | - query Op_fb4f667e_1 { - books { - author { - id - } - } - } - - id: 2 - type: Operation - schema: b - operation: | - query Op_fb4f667e_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name - } - } - source: $.authorById - target: $.books.author - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE_Large_Response.yaml b/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE_Large_Response.yaml deleted file mode 100644 index 9d51dffd31a..00000000000 --- a/src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/__snapshots__/LookupTests.Fetch_With_ApolloRequestBatching_SSE_Large_Response.yaml +++ /dev/null @@ -1,211 +0,0 @@ -title: Fetch_With_ApolloRequestBatching_SSE_Large_Response -request: - document: | - { - books { - author { - id - name(large: true) - } - } - } -response: - body: | - { - "data": { - "books": [ - { - "author": { - "id": "1", - "name": "Author 1 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - }, - { - "author": { - "id": "2", - "name": "Author 2 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" - } - } - ] - } - } -sourceSchemas: - - name: a - schema: | - schema { - query: Query - } - - type Author @key(fields: "id") { - id: ID! - } - - type Book { - id: ID! - title: String! - author: Author! @shareable - } - - type Query { - books: [Book!]! - } - interactions: - - request: - accept: application/graphql-response+json; charset=utf-8, application/json; charset=utf-8, application/jsonl; charset=utf-8, text/event-stream; charset=utf-8 - document: | - query Op_0e997261_1 { - books { - author { - id - } - } - } - response: - results: - - | - { - "data": { - "books": [ - { - "author": { - "id": "1" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - }, - { - "author": { - "id": "2" - } - } - ] - } - } - - name: b - schema: | - schema { - query: Query - } - - type Author { - name(large: Boolean! = false): String! - id: ID! - } - - type Query { - authorById(id: ID!): Author @lookup @internal - } - interactions: - - request: - accept: text/event-stream; charset=utf-8 - kind: OperationBatch - items: - - document: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - variables: | - { - "__fusion_1_id": "1" - } - - document: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - variables: | - { - "__fusion_1_id": "2" - } - response: - contentType: text/event-stream; charset=utf-8 - results: - - | - { - "data": { - "authorById": { - "name": "Author 1 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" - } - } - } - - | - { - "data": { - "authorById": { - "name": "Author 2 tyviMi4b8QScnd8B19pTy09Crg5qhFLcS9nvBXV7fsHQ4xUcJNZsmeM2zt1qmN33FzKnzN9dosyGtsH4LdhUpdzyxv6SgpURyNLEmqn5N5E3qFJGl7eJqjNmAW0DRr79YgRfgDRe0mGuY5IrmzqjKLlP9jDQ0jog8EfJynjip9SDcdNEOJbbBYyM4Bf79BoR7kvUa828PI3L2hwfV9CqHMekQTPwIlioVBG2s3oPQdM3enTWP9lA87JvFLDGtG0njOz1b4xcVwao9lFm92hIAipX1UwgzhgKniTPxc5ULJpMhfvdGbH1irnAjc9HHRnxPQAbS0zg6M603c0WiSZYapl54SqVcxN4g16QeULQmk4WuwHGmnjy1OXkpFh9JdDJ9CUCgj1NHJwzuOKHLjtzOYCReWlZxLGIguXscFkCwVrrchza4ZykuO5k9DiJ7ba5DnT91cpF9qD2rUy6gLfXXgXSzxtZhaEU4wozO0ibuskDLC2oOlnw5ChhPBKEtQijms75q9rqmDno5TGx4EK5wSY1OHjNpdsdKBbcE78P47J2Z3l64XKoFnwTTFrjadAIUJe42ns6G5ByIgcVfnTSTEYgOHJ8QYya7AhPYqDQoNhKl7LwmVDxKszQv7puetqrGl1H9N6zjCnFgN4R6WV4VBPOLRdaATw5h0DAFDxYZOOHEttiCYxHXvVFVm6rufyPQsiqJ3L2j6fHxHKbh4Ymfohve8pcHFo3Z81WLDYIN5ibQOSNceK0HLtmKwMLOsvdSlryQxQegPYkFGfQqbAm5xwNOPLY0N4eJFIpgd7oOpU2xJgER6fxsIiezejBl1nSU4aA8ztMdVYQd3aFsHH4sHwAhnzC46DWBBh3sgGbMSTXuRA5DeSeutkNHZcUArRgSBOcWhWLBpsZxZQPm49aoilSaTvTEvbeAxFsDijfHHdEALasJNrFs12ta6CCwDHPONYAThMEVdSgFgRP3CK1DVwJ4VSGggtEAN0xwZYlBnuOiWo3pwJt2QL2aPG8PFiyuOg1pdddoizalhkirYbtWALuC8WgTaV5E5eUzwNLTqFUavQ3phR0nzctCvzrH6JNM3VpCPs4KQZp51UQrd0wJfSPduSE7gEWh1HgZl0azWpWZwyLbi9nGWErlFMR7o6oMDIDuy0Gna7wz60r6HnYgaQKwZ4TYicKaBKVnvanr3ApZR2pPfV0BhHwx7QU3grE7wWxveDKq9qnakvehPE3NmJ23YiqeGuKL5rn5E3ubKKB0eVMMvxncx1Vmd4X5XqjPgbe3IjcWTbCcIBYCWdsTGsYEWAcKfyEekvUD1TEMUQIVz3dbfVj37PIxCZhHGR0fWh1XrVKDZf8zkCPcgApJPLgUmhAbv6GCZn9RCGuJLfecRSNAKElGmrPLBguJUsRcZ6Z6D7aZPf8tqEDTT9RrV9asXxPfWkzcOCCV3Q7MoL0Gsfe7cazUbkGZfriPs4DpqffoBsaDCEDKJT92SSD6veBo5mzLrretILaMA06t9wSWg6QMrq6Z0G3Me1sY3OVUkTB82w2cWT68LoH9WneBvE2BROsIHh0ua7wM4ST4ydDgK5A0utCQuUjfbAqoEtVydLhN24FEUjMRBV0WN1YXfk9GYRv3lo0EIPD9Xx8zo75LHSeFJUbMV8T3LbzkJLcqtHJwS18Z3ithoy9FwpuQMntJ6Jx57XqcePc9JsxSVCTwOvPXctxdbLeFY9zJDCbg2QCYW96E1c5JU75K3adOjMBSvWlK2oOSkw38s0Acxtm8QUvaEpPnjN6qOtn9YvMNOmjhD6cDZBa0kDCblKGNYltX0Mt8NBECgYunuOXHMMNhxGGLrMYOp9zm3Mr0NdzY7YTLSYqWx8AMXLjtGhRBmzWhjHuihg4sWykYx43SfBbq8mPrm7upMyvHBvmKoIzQERzilL6Lo8flYpi62C6jvOgiDdWBSsoXLKmrxqGbBjAOSKsVNqSlLQfzvRfHy426TIZOD1JM6fhMORP3vAxmaDL5ow5gK8mGqE4KudSWgFoqsSldBlWxGQgQ6ejR5nB72afJXFJRsbFUYeMWKceimz9ZioNQ3Ab3DryRxbG5cEEpKL1bRNHcIcUDbFls22YsALQrq4isWiGhuUOWxv9p38vkWu0rzXDkqWp95JvWoYGjWwSG1P5G3szBapV6D128eg1XoPbnAmBe1LOjbt0kb6q8hniPyySwgIF054clySGRqUKObveUBShhz20BqMyLTO8tGXngROvJ0ZRMdTxDU8vNlhBDEb4md57cWbIEH7CwgXraknhWYv0UcuHjWkc0UJq5bz0BLt5X68rNzlca3hNrEm9lTirgeLcWrw8vwfLp0cYeD4uvIB7w580zzOsmBY2ufUgCnqoXWi0lNeiYy6YdOqbs6I5ixinbjn9sYrIbXjZWHOlUqTxEAZgy3xGeuGky4ZBkf0AHy6FoQEkshk1dujbKHKzklnqR9lcsMBz0SqPET1iyMY7KOHDV71cVAagKPyppm2ffvBKDTW0QmAXNqgD1hGuUjez2KFzeL2MU2bYM69ClAMs9DTesvxHgHK6RLS3OhVEtyCUOI05hDJUWvzz1kHtYvqNrfHAoGyDoI9LA8Pk52jc70jfWcBnamp8IzntAzQbPFpOwoy2VgyfLNQ05loLELnCcADLVfjFmIM1LVtroJR3yJx4jwyYLEWEcnvvlnh06s3CBYpk16h53tNSNJmjrK3hwIYij8GAlb6FPu3KGOhOgbKsZdibB8IwzVQ29HA30hTcxICcQbccnpBV8qIGZo9nSKQ4eAK8NnY9Hs5RaGLjgpIJU54T94dLhqJm1I8PQdPARBOQv1qTdZGmCGjiG19TJNbaiSZRH5SCaI2TrnhHNKrHkgkvjZIYd50EjxrccYLhHEL3OQ1cT2G9fU0Brorsw3jfRyt36Fpy8KAfUrgTiqFlz1iP7pvyrduNeqmZg7fONRAUTUqAHYKGy8qaPe5RT0HeZxAoFHwkK0Xi0N5n8vqSTnYgALKCCO5WJf5gTC5Alk68kIkBiSSiJzLvYeo36th55BYUSYU6zqqsra61lIdu5WMUTJIyXBD1CADjtPtK7WsdIdE7iwSyQx9iyEAJPfiynyqqXWIVZTwjotM0FKQltOlOBeupPj4cy40TwXkLo7Z6Ba4F2JEEO7EYMbp2mdFzYUvt22ErkF6wzpNlkoxFf0N0zbGVssiL1kiqpKM9FWeJASjhNER8pATiG43bvs92gv5PGg6ZbxAJVE0h2iHnakf0QAkuQvNWXlmOXUarI2g29KMBDWiNlVc5QE8G6LIpknvtclJiIafhEm0Fxir4MAuBJq8TVTu6t0SWYcjcNAELz41nN3TYeOdj2tkvm0NypiyNUeqV8OrM5jMPyUFbAWcfXsdo2yzWxQgQGoTsM7ZPhRnThU6SuvxTGTzlBBcKZUYpC5JKBXPC7N7GEJHh1hlBdNKwyrrKfO0M28QlLwQXfuV3Vth145T1sWLzvWWUpEhsWvOF2fVEROgs1RbFJ0Qj48dfxb0za5sbMngkfb8YjOke0c8e5RKzy8yXRsSbpgoVfEgOu0js11AqY8oUcW3Ju2mOzITwIhtDjO8v6utErc777H9SE88SmflmcRZmhxkUH7GJ92XsmzcS5oQrIBsJiaaEnWToVHh32m0AB0SLlQqxDTrxBrdgFawqgCgnjsWfRiZSyPpSsgiRumAUofnnoByb0Je9Uom24Lgf3Y9vCKxi2f63BL9DFs1Pu8cpvp8E4pXjGfbQg1kdOPjVNk8IpixLTQv56T9XMtnMHWxfuthNIXBeYHcLrzYW2MPzugTM1NQfmXN0wcY6AjD5PRgy1ypXURT5H7vOZVW4Hg2A3mYObcVTJTkd9eUDh2KUDRsyrJhpNIytYf5PZb625AwyXRO4ASWOVh7l3kgR5qGAf0EdjFnG6SYDf4ba4mo4wjX1iTVz4o7P3wSgMvU5oPSDI3G9IGWSBLO6dN5QtyMSUJJtl4NJStPgQTsoMWqxRoNrhWD9zDM0D9s9uWXO3N9S6rpJeQDWIYBp6bLP0NUOhZdQkt4z9b3Ep4v0r3fi9zso8CCSLIXq3uvhOYiuWNXqf6ABqVi6rvPrqyShqmo1ENL4INmSUuMvbCJBCBm0ka8HfD0ZGBEtjgmRvG2csPm7idQooQfpAyRnODYFXMMTqdM5a1Q5IJHVyBjCxLuzfYtvP8DsrxEgCSRFQUOxAjh0q6yNdWRLcWyRtbqbyhOUElSgtevc77z513ETKzOVf3DpeAVzox8cVMvFnSd9kzOeh2Z0XXR8S3yLhnBtI6xJ8XkpH9p1WPuqpjIllfcRgAJcXkh9Qu1oBEgKSttXrZmDJHf8faIndgn7NISgbpllYFplC8T1vEkGYGSPEje0mNLfai6KbM6ByBpDc45hGQ1Z5hjGzCb2Lu8K4KKeBJZjIiRXbPxKn7tWVwj390UZuE0DCeJRtbg70SQXPMpkOROOBmzIlRfKyAyDsOU6FfbMbwfCfMoxLuKdzmCapBqb6VIzeNoB1seszCxOGwmZnr9E0UNGL4REz9QFnpiRhm5cPbnxyxT2YRxOVE9K9iz7aa30vrlbOV1AwhyZqaRXkYpiLBujqXS9w8BzixBHM2oDZxcyPkdjQcWCuUou7Bu0C2Nxf913YKKsumJYj5TF4tsUl9ENIRJKHyAgjoTQtkKGRoSILQKBso6SK3Mf4nuGAAk6lmz5mDWTilC7r6C2HHcc1sWqcxVF0EGREVgibOZoSmui0Ox8l192hHE3QJdyrRdefv2VZdb2sxKP7yzNAWe8ENt6RnSSvl7BJPCFVcjHaGKu7z5bTQyUweZSB6DvKJGG0JFsvu1ixWi8D99cr08fxmOpztDZYx6R9E4xtMqjYPhZ5bPC6lDUKlSN4Z3BqbJ9ZR88ELsfKZGhEyuXeAcwtmGYvq2TTo26Fh9odQ7u2iJuevIFpfhq9XPxKjNYTZLghKbhzG4OCr4LdW3AhwoyHM7sSMd3CjbdXmNUTlQjlSnRcEUyqN1gvXZVMsOmmALdQbx0Ijr5gEMyiqQN2pNzr5r9N2IkWo7kHJBBQepHg5AqKlwfcBu7xVvUtxmPaGi2HmrZpO6Y9GTw5BzmGmHV39xvXqRc1aqZXIji4W0NEW8rC9Ys8AJy8M8Hy5B87egiZ3YxbQstv4RhBFsXSje1R2aKJct8V2QkzZRIllQrSZCE5aGsNnpXApRhdOn9htY2nrrmykwrSwi1zWOsWAvrM2jJHupW7RKiBKbOtd4m08FNGasG95ng8qquHheD4atBmA0p4A92FI0NxWDrCiXCnnkUdqHL91saODlGjDM85vbz0c6vewBWCrX8ZgLO3y2OaZ8uu6I8WYG2MudBuWqMzWYhqmrC18FG2MZadMAioC9nlewpCJdgIpYDBbDHPFHYT999UDhhVHixWv5L0BAsei8NyVZBI2Tj5lUlfwU9m5LAHkrPf1RNFY3uBwL8nfZcx92ubUqDqAGiX7GNoJgQlGdgrjjslWVGgsNHs6yLLNgESVWDp7Ue9I0rfVD1u8cUo9Cou8erUVFYkYNWMgCnC1GY2flW37aNuMaSTsTrdmJoCcHHIqoO5zRx3owOXIyX42nX84DeMVKarcVZYeOMSLR44mZo5ETVxwtKytINnKCjp1GaSXz23lFsksdWeYiHBym5tLkpWBjHJsPCg9WiObbLqAjFPwsOl4h0OLrHwKg1C8j2dazfCA2kXaOsleZkSUfPKYyVROvE5jJsbqmz6NMlB7dx68fRv6jrcTrFmeNxOyoxRgR42jnFI4NN4AYSseS9AbQH9gNb9YWNSqgarlYLSdjhGeKlF4FufpwzPJ5VWLFtiA5Oe8lHFGrg2sAfWlWETmrm3qKhpCzGYz9Gi6HHT8oZ8P7hJa9uzAa5SSUxyDcCRkICt46ZePvU7SontnYODEQXYDxQlTSQgmIXH4xOejQkPF7AoqELoN9MTvopGpyL6fyVJQgzzKudypHTGxm4OHlTm5EVQHHyvEouQl0XKPVecgYnnUjTD36y3fsOMKjsC6rtBWCe6Ou9vG0Ghar5hxv2Iz0v2mL9qnbfypmRSFXyI7DxpmrwcoKPLylMfRlUCuTIoUR1xamca6tKwDFQ4ZhCcMUAEavBeDvXo4IUUz8BBszOEaZcLUZnNRpbARxXpk7XKVg14v5FbfAuXF5nAS0JnIKWOqUDBkWaucEt3ihZYULsQ5E4WJXWuxtCLJmNb2D0Ij95BMucvavS6cGTmZq1NAp7sCht5U8gRVjq5I2KZ5lUCbFtDTlBLLnI3CN9oAgabOBl3ZYdggcSYV4R6yqmt6UGsaw353fZYK2xae0n4HepsVtiH6C0T4rf443cmfinAC3OdH1c8CrlcoXWqOv91pFecX2flXAZj1ppbfFAFk2RMGDPhgvYtivV7ZvGOV0kBSCk9r5LJv4QwyRWUm8FlmpAFTsBt8vttRP4DcQzkkP8ofiJIZwlXv9ZmCep93bK9KgfiWS1WJeAXrVkvi3UMKW8SzSB8kzqJE8d8DkvG4OOQ8C4q44aAH7zyiMsER3wTx1St2ls8HOS5HsUxXUDqZqCHIoa02ryBc5cGtLySLc22p4q025q7zF3HzLkNL1FZZRcMPNDMfve6yJbN7j86A0LXBVQiklGTWccYceko1ecEl6SqtWPm3JZjFFL46el4oKkVqDvd8UFgYHvECkzNVeaND3SXSqrW3hZaW6AplvniD2K8TG1WpXiKtWSwuYKSntn0rUrGkJmj11KKsUDLzUrf9PrAoN4MkV5UPUR9Zvwfv8S2MIDaV8cSBI1bnrcWPZ8g5z4YCEwEiLtA6yxgKd1l2nSHczVrTaQV9w6WNpXQMYu0Y0ey35MviWnShx5NsFvH5YAK2bSfFkZe3ctmUgxXOewmIozZtKhGmm49zU6cmrp87JYFDT2MRY3alYBOl3v5CT1RhtwAkVugzyp9PuWZSVzOsdXbTs0t5u5oSHhTh1l6nWlxsC81hWmrdmiDWUr2eAlE3BqHMC2at3kV2ktQt8MjIOKqid7MKtbnvg4qW0oeeL7kBNLvlaIgxC6o1AjtEpP9c7kVqC42TrF6RkoVRLluk5zskPzWR5ay67IEm0FifQMF7AXRVNb2EeZhH1vaNikYRQATcksbFCPUstuj2hAEdhtbik6uEpV6pxyqADzueAwBPEyXHLipig5thiv1n8WarTo45EjysQjcurLdwjn3HpYI2EJbS8GgoWU6Z3bClt6R7c9zXREEUdTB4fB14IguJCyYXPD2HkRXsGLaFUEA3CLLDSB41kIdNLI4nlcHNM7tL5TyUlvjEf1H1nUENJAgcyJg8Rwe26wrEc9H9NjQyiZsUADAQX3ELaRXvwzDyRrHsKCYnNEAkur3ZbM7NwOeCsgoKmVNXgcg0R9K8oWCS3easX8Uj2zBDME9oXOB11mDRKDHbC8jaLMJOF5xoBnfradnMAfkaVLbRaJhU02h3Ql2A5vjcaW0OHW0rZ5bgYIEAu2x6YdxIFlazkmQO6I98VMKESz55aBfHg2PD7mD7jrIf5BHwoMjPIGoistoih2rEFTSsXNRTECZoEoIQsIQObQ8aNrUN8fZq9EZmsZZa5PKGqAdDkXzZldmzU2ep2DUimtoAOghTtzSMF1tMORnlqAEfbkR04th14me7VdzEzfpwLatcIRblat2loJioOrY9RaRdXw1ucivKVSUB0zsnS6bKt2SM5KzIGpeuIQFVaqJ18sQWzgxZ8vqV9GuedpzRsmDpyj2ktWNmwjMAm6WYXaKV8IuCgk1v02JWpkiPoNpliEiZ3t1hSb3Scrqpy0DJfbw4a0VBXGuJviw4jVIxtTcZ804732axKgGGSo9DXzJMrug35wGdrQZL9X5j6YIfp69Pbqm4WEa3KQrOUACHv7G3G5H5sZH8roguuRcOKLHmzgBtprP5WBts0FIgjqM67cLft6dCix6kzdEj3YQBKLlq4y4pI5pd9LpXUf9sOMXjEJ2XBimLaKwv0fl5Cx4mHckoxqOYYhw7xClu5hojSeDyY4hz3DpaSvbmjOkUUNw2Yy7y31AfJUTmZwP2JZfV2WpCk9Lr6TPFsKak6s6BDKQ8bzNx8rL4sbACJ4O4qSi0EO4OVp5addRsFrlvwYsPHVWRKYbCeBVula4M48bTvvbOJS6cScISkStt2nE6O35bIhGoxZ0x6ZeV3HH2b9tC3CKSqKUR4eE10AGmLSp3mVVKyXzufMfPK3hFWy7mEj2bVme2AfqJTzZiqAeSUjvs9zr7cAPWUCyCc4zL27tAfV5Ud9YWUpRfxKcf5haAPTzRAXFwKSZXzuNo4Xedm3CpvTOScTQVgtvLgoTF3mLBP3pC6ylhD7XVRKfrIxU0CE0F9BHQEYj9rBZ1nMVossRjVZ4VIm7GRV9KDjD5qVdpXXoPuoD6bqITxRujHwHbacsWBPyEIa8XPmL7uokdiBolMpXwzdy3NBP4pSNe09xBsvEKFwycLo3YyGJV2COolEJNXQScaFnjNn3blMqDoVrjI0GjJ1myuIZnl0xyeWBFAULKNsupVKAQWkFhKsTjdzyFNQzuZ2jRUmiyo5WaH6djIJQBvQnvDcmLfG7729Qcls5uBQ2OW2bgVO6E9y9IOyO2AWSi8YhIqA8aOg9eYZYKAFzQJ37EAHNxdDto8TP7VT0UQg0cyeuzZD14hBZFacHixK6KwUgEJazrPfAnCfQfXYXaLzH63Kg2LShFjppd7pp9NKpBBwC5MmKZwf87NkK937f674DXzwirsYNBJF4HHlqjHITDqsQXfqGPpsEGspFZDdqYS7xHpD1RR5zzl9qHgKMCS7WbByZcfQfnb4vs5Irczy8t2Ofs8823RoGVlVG1nYwAaLXqO8MXduNe8miwSqehXmWxyZHjC0yaC7Tr1yeAweahblW8xTi74Pnxzk1z0nVm5wcBT15eMdu2MyVMCIvsR1fxUf1Q6pJJJxloJVp6YEuaeulAOows1mUERpryAohhUltZNrCrdzUNGESj40CR2aRgchWeo16thNG2BLxglFPCSH7MWH3JmPo3TM6pUiCm3kq38ZhsCfpxLPOVjKIg7wHSjMjzPIMDCmIsaEN6kLGHj1rD8lFKZgoGdYTw0sc4SmuiHf4f6M6wp9ssef0oCBog8COCubF1sMy6GJ6cqkONk2aeplRV1y2R8OkER1ueGEDdKwlViY8bxa6FluXJJt93Uh82i1Ly0tGfz7T396xd0adhSfdgelVWEJJmxtwqNJlDTaQnbeJM6gD3DbkDYoTOXtbpyqGQJGQqyZN1O0FAcIaiGPjVJtSizWqk9kzuY2D0QWFnOsyhjTwPT2jiHuHayr0btn2oAUljFjStK5Ha5u9fkaQGBRnnvmCign3k0KgOrNJtk0XMnqfDsV1TWvmtr8xchtNgBgkuNuxWQgfL3bAFH9zKwkNEhxhtZrM1n1KGGuz7heC0Qb0Q7sVi4CuaSfMaNE6jUoiCQ48WJ2nSiXyG7RwrVn7kGuxliYtdhdgl2x9Dt8YBYc25qFd6RPNqr75gGXyvIKuE1NNJRt8XO5Mo125c5xLRPz352c6VKn3OrxEc1UoiR0bwvRoOcVzU9czBTSQywmMlB86DxcklImAZXHKlxr2yxiOP8CJjD0von0uwUlaAvOMWcZoMHpAFtYxctrEvTBiS0VvgWXRMQ2DjW2xiX7bXzq5PDRDmgprtq3fGoHzuYyy0VOG04gXWkKdJagdFToqlLT2cWq4PHq9B2E3zLNrARUJgaVqHouauHMpBVoeOlHO3LcRVmo3G6pT0KWBAAxlXQP3pZ2dhtdZJGPU8EUeA0Txc2y09mdOxg1m6il6uKWXcQKu4BD6pSkh6bbxkBd4PPlnPnYZdYuzd6ULsE67ihif6UqeHyVsqbHMpgeRnodQiuDAGPEgFgWsqFr563RoDBJByHgLjoT4ES7LQqX2uzmKFZgjzjUuWyMglBL9t26aMboYIfoQfZ4OZ85Yl6W9UjhPFakOeYI12L8nvHaT5DO748HmFwXwf7Gm4YSr5ZwGQCVNASnefCEQUkVGT7IrBVV5EVtWysYfRHr1n3mxJ3Rd20STDMY8RFF4raIpiRpwoj8N3ddZUViHE2CODaSmUaNMBwKMv7O1OeyS1EZjs8n5h8zyX4mI8CcOVwLGTQoXGq3kDtW8As4WxSoD6Vy1UG2LCk7F3SQbTPz0EPvoinIPIGaDHHK7bxCAxrhcwQErccChcx8qkKTr7mD6K47vIT9gMzDXrS1RjbxpD2kTIdWReVCKnlS2TSiIcfVnul8RSBHgzY2RTnmp6sC0w2tGA97Q2oMih6jheE8cOfVPtBipq3Mudf0212RTE1oKLUtXEFK1ujmRgeW9bRk9ccEBFqplxpYW1LDZRLlksUA33jVXfS1wRprtPsRXZiDELPaVa7rQq9QHcLIgVRGfxlELdTJi3OKJQ5rnIA6hklGSYkREkvBIciRkKO1GyIWcyH0gdeXVUi4Mfwx3CF8IMCqsoHc4IztbOodQtukFXqx4oEEYa8EtJOPwaI2VCdNezc71ThKRe3ugPwDjDEdKvASAYqzk2OD4dSFLHME3xwPQdtgoFSS7ACtyK7dmrjZPz0C7r1c09jW8vBgpKLfj6F4aiQBKtcMOX9anqj7N0b8aquDJaycfE0St6mYa0RHhWHlvk28kORseHdtxM2t59rJhqrrEKgXiUaDiJSiiz1QwHymc2kO7iMhp7EE3K4as4JKrZKo4TLFIaXZ2EPLjSZAH2YkFNpX5bi27n5Cs6TnWGZPkoMy5t0aeJCyBjjqoyKq1fcOJMdn8vnBdJAaB0bLkIXxlGBIXm9i6sXFM7otQNbsgBV2jIpxW8GtHomCKUPVwEEuv5ODMs5WqpRkvJiO6MM7mo8iUli57G6b6kGo4mloCtCbWCRBvBYj2GIH6qskJAZktznKC4UTli52mgLSUhJ6rWjzc9rO4BeCUbsgZG91rE8ULPfaeaPm0c3WQxsCNFZkD2iKyo2NhSPmYPoMeRtev2L2iWQmY6nlpXQTrUl0hBEiMQ7AJfi5V4yLqqmcXPzkoo7A8UfJp36txnpRYQd2YrPvjFnBsJcRMe3iT6ByAYQb7FYCAVDHw7L6YMb3rdbgbphTuG7cOo1AbyxdrkAWGVfPS6KHeHGg6uAShES3Xl2HFLfjY8MHcEZGJSAx6z7GiVDrxe5mRG8fcXJGbktg59D2U4IPDf7inwjuIxw3CkzWF4nwI4VVGaLiRLX3WqiwIa1qyZ7oyzeUKrwZQWHJJmbMkAc7a2hVCCNpD78s6rhR60YjY7n9jYmg8oFx6AO5RISHeGWSYYMcFKQtl3icPiwnZqrY1Kw6dl9xiQESlUlKLKaxXWLDbvqtWpsxZ7aNmQ9eKdLVyQ046lbPP3Af8ser5Qb2iQ2o4Xi5K6n4K0OL5vwuNdig64P3wSj3CSwhYMAjCgETPGVHeSvJeqpFsVr9IpI2Xt21EqxsvNrrYOQ0jIZdgZZVnrzCfAbXXL5gNdCxfDXQ87qdF0Z9QoW7TgOX1uNuwUTNTunGFl8cCIXqAV7olbHtz8MqPp6u0menndKUNT4pp35KJhWgxiJVNkXVh60ZoNmaotChKmbSgbD6CChrTa6SdJaDFzxQcfAbQegZfyVLG1yvhbSfZIGORU6eT8cUyLzAblqifHLeEvLlUogohS0UYvK6iBFhWAW5CxU5vu9R7mJfJUKpcxxgUempau9dCoHDYPjgUk3xSjXwmowN1aFiN0lhLofAugPSeFH3vnV149NvHzDv7wllij0hoCUpF2DwTESgh3cNFNoOn0ZWltD74ot4PkPsTpwB6bbDghODUXgV4m4xn8EVyF1pUXQ7nt4ZbmRLYV0Df9ngHY9nqbEUlaN0jwtIQRakdG3SUsZSIA0ycUh5XmRMpjyBZamllrwOjDDAfrT7BwMkkYYPPyuoAN53S233GxqaNmPZRhZqTTK2WOaACWWx6INVHKsnyZ1NGwW8J97rYEUrDDgDb21tb2dEY3RHyw24b6vk1c1CZoY2ygSEnoL5hIwNSRjPr03mMaPGR5M9AyTwelQ1kNdKl6WSKiSk2lUivwqYQLwscM4ty9trAroeWsAPE76tnlGZdvBr52lZavsZBmdKyljL70LCvaUTPDE0FfPD8BwIGPElAlNbdv4CC5bnj85eiRKWq1TgXaMwzaErvkBKN30dICyKDle9GRkzFr4JSrDDjINl1t286vQpbqOoCJcv5Mqh0PmDp21gzw3AzNTTtfCVB5XYdQGJORHWbqumHyTD3uzoxOzzzIBZKVf51NkZwsRhpgiJcrM4M8bQFtlObQTGPsMGKzv3O4RKdS9QqqWI6HNL3PzHmV7fYLR6Ub8n6SqSrQxxuViv4LJIfAM4AnR36vvRAC5OrtMna4embBXQwMlNBIbUOEnSAxV6efxrZUDK8gskfkc8QBGtJiQ1kl9nG3nnjiI6Op0cJaPfa1yoloC9qlw6P5GyUaEF2FB7cgtkKoksTvbtwVBb0n67vLrTjBIsWJmV01ME4czCBEnddXC9YmOPIDLQzaAIg2VJJG24I6gYy45rhNzL9ITt5XMwq5PebqgJseUWeI0bF0aOIdtlkyIXimOw3FOMrC6HXw9D3cr1R2oE68oMMo3nhJlGQhdY4ouD3S0VeqrHHRFp7Jz5bBADITjOL2xV9S6nHkKnITrg6wfQD5IGsh72or4ktlJm3WHzUbhX8MwHUeHWxTKQuqnbUE9aqk4gJFmkoq5mXvHfvziKkiwZa32MsqeQcGrYRQ8O1grHYi28iHqegy0HxeFPNZ18LoJQEtOe1TSD0oB2B3nk99uoPjkxKsBbpt5tZm4z3LnMfxRIdNOUvR8M4fAeIbUIS1YGsRcZ8xqxWhIcScT6drpXvtz4lZrc1e4oZKZMuzV7kLzWXiMqHXplLAV8bixiGO62ndCICGMoVrxj4chCNBUdzTcZyavMCw1VO7t3gEnBLBPdMvE8BvVE3cCUAmTlV9mj0bV6tngJXTSyD8MDWwLQbxcw4Z23uCpLZqnuaIPXOLqjJOQBaQPjyVID9iBTvnYVoGZXVcmOgxCPG2mqI0dexGXDikv2G5mlxV5Dz3q8nBCAS26H5VL4K3hisVzuquHkLabu6j0PJf1wDXupnn6uurb3xXUeD6R33cy2bMKWf5upCveVkKGCxWze9h7jPWLNN72ki2NbdkPy6w1B28330OFgmU23PlHIuhbE24xr6ojNHAhNq5qQcSX92W8N9UM2dGEZVwJ8LM6Lo1ZlwpMT40qbKbMg5jrmcruA5I14wsEPVLUA7WaTH27manO3kmCmeUt7HYpoxRhLwaF8GLjiIXejtIkS38UJpcvBcX3irwg0Vw09hQwYDedG0KN9yWuz7YgTpEfsRA1W1oN7SkvnL5FL9pLSK4tUBq27QgUcuEGDmHOM6QqNlHnBSUT93NiXQhULvQrvQS3HzCi2a8W3Nfs4D1o5MUjgftwFwDapj57TNfMQvbj41pKvyaH3mvi5sWmGQdFWiqURiZqhpXKvuopziBQW5gCyXBk03FARWMWKV2MZtkOOkxLEqwhPNsbBnf4gyznjX2YiSfeqy0nVSyNk0gKHiuEnvVgz8pk37o0sYmvLR1aWFGszSTqSpgBnxuw69prIPtXn7eMNu8zrTsipmqgp9SNanN4n0yMmJSGVsF1xHchrrTTFMHUSJCI7f79tkiX5wNhBlM7hyshhugtT4yate3dGKJ0uFINiEm4dwSeAJwdaekM9NpzvIoa2ua0cVMcqe9dIlPhmUZjsaCmj61gZScaaLCtVbBo7Ux5fHEX8INasFscryRfepCXCiC7jfMKTumYnHGb2diRFBrUcjCgKfJRRZ27EGxc5CH7dUzksznAHuSB0seAdpAxkUGNOJWvqFVC3u1IucyU2JJhG0GWmx9QCTWINlVjc1UBYPIG0VQA1p5bKiHYCAI3FFAjYt4IHO1AyHI1s9gRh8YWY47oe7gctb6TOisHaH3mx5nCaQpCe1VGqoLdwQoKsZQXLzmKRY1ZFwicR4OORd71FzmkWOVKct4YoQ1lnfvFA5B4FtM1Ba2ObYRWMBxCDq7V1KxBDnkws21JxsenCdIC0q6P8eYlrsBT8qD55LyY0GgjhIiehKAki4eLNiCiO8E90iKHois1ouMuJXs054EhsavEL2rXIQJ1Bgs87bz8bI6ystB0zMmU4hRZxG5w0VtYkUtnot2eEFFje7Wb11h5oz7ePSL1fCHGZhNXAXMFUIPybr5zue59xxuvXOXWiB8B79K6t8adpclfjICiXVGBHITmxc9v9zhSJO0ch8GvDbUUMOMOMz9M474zpiIR9pdz5SWVSkAYPV7px8ZjQvjK0UXMTBw9zywY8fZ3106lzk6j9OCrIiBOFT8k4JBQxBjbijrSjfsZy7VQXyNE9F0QwiTogy9rzpyxAfBZhuHm0mZH8sNG66RsKSoAQCvugAkIJhP1wxhP7OaKILqyl3v2YFns1AJf8XG0CR8acVTIZCv62d2FV6JnOruE4hAwoBQkHjI0MPWPjncVTqzYIDJBNdlUh4g4VhdYwLySVB2Gk3DlOYuNslnl1OWo8xTStb4CJEjI2gCGLDaTZ9FIKSMt32ghyJUhrjWI9AcKylVLjgZxxDO8rLIaPLJRhCUsMfZlrSUZh5Ti7AKWcttu5Vzgb63x1LnwQm9DHyGftzbw1jdPBxyyTjx0p2KuYghWRhRUAGOomNBF4Dp1cowEWzcqzIYPnVHMSEfUSIO5iJLGis6mNTRuud9cElf2r9ARGyxziVjTa1fNnWIHMwBUDWczECPrnWNjI3At5GD2u8U37wyrcXp47qNtW8vfF2qEn6EuWYMGsJkFBi1SNhOQqTlcpQX6Vix2SQPAsEVDLjLyFIsxGcRhnZXUVlEGBPvKWsxvT1kJMKEHHwXhij02QPO225oGAOC6yBcWV6eP2IUcVQNjOgibY34Gd52XMdJ7IHTFTAMlFl9I4vgmsF2dqkh4HW2ZEGDZ8WUN7HPNU6Wx3vLsYPpGlqRijY87Hwg8hkJibSplzoItNuBVKKAyb6xSFwniISGiaYPTmnRFkER6hiUzXnw7vsglw0copGcgikTyersh34OXo0vhbyLefJwr2ogvKmaeluY7OgVp4PD0eI66F5M047BZxl60K6WReuw4cxS5cgkPF5NurkqOZjjnt9Jnjee73wWuWCeRnRYYXvT2XLJkQH14KIKcooV7BmWTjdXoGYlILLQ8pRPYV4rv4cjN2Bn85aWvZAS3yfe2gts92MxXZ7mH5kYG4KvEumNvyejo8Vj0ayOLukVpNQj7yP0ylM9otZH4g7KXnJYDYvqGWNWTyG1eDP7iovCwW5HBrUoxZ8CE1gjCiubXzpzmhm1Q9ls2GmqcopYCij40Dxnhq4A4To6qGedEcYxyPK7OzGY2VZzQv9ju9UjFlyibq9WJMTjKvFl3zYrjgHi3zp5G5sEIysMblghzuOqBzoepYq5lmAiePplBEPOdObVD2JRS02ySbhDKKPsOxdfyJsL64guf9MwYTbwOYmuuLQCrla0zg9qv5h4K8VYUHTSOup1tce0Ltvm3qdVdp589fBcvgmQCNZm17x75jHWCJfBK4BeeA4oMVTttNFMzOx7TIu52gZ4hi50AAS0fIvCTuagnENsd5gyVhrBKFl7k9Hnadst4OrrcvnisOSxSrbmCHecSQqZgybUnxGKWexONyWk4IT5xyo3hekS9PaoiRLnTT55IHbx3NYNv3iK7umsJhwJMxLGEJq6nsQkNXxpW0AUGXhFqQrxocewgwtU6UtugbjCm76j66VShbDzPFZyb2RKOeEbodtBHPyoxecsTH0sHLOFt3E155SnKYyI3f5dNTLRnYBvmqeUCjDCP8suY1GM7KdZpUzxMWeyA7bU2TOOa7lkVw25xKFVM8Ud5lFS1rIpEPCSgX1En2w9i2E3c49BRJlBm8ZQO6Wsz6gFtjYZSAsUMU4ChL07rGY5oAqi8l0qfDKmW8J2fktQaQzREWsCGZBshlbs30brKBzJKRpjB7bHXHeXLYdm2xkGBbEvga9pIBGZbpHwqJBI74VaGEheWyyWbtHtM4Ck7v8VBF6fRr5swbIHGooc3eTUMt7siXjwGaLL59YBHBNo3Gk9k9miQjrdcoISHO73IIlWQ7MGQnU2RpaGI8HjvBghtstR1F33DUgueOtnxfRmPyLxOBJJGYIHmEniN4PLtaz6Jpm4OevPt3R4g6Dz5uxpMZIZkLZ2QG3y9PoiZP4mm2XtwsBR1aP8nJutgMTDE29n9d5RSeZqzLCTBZm2JHAz14Kze4BN51ht3utTwu9XAiIcHasHjb371JvESFwXcMu8oSZRpTFYHnzSwssDM3ne7j1u8oAq7l5xxJxyAacQVfzOTdSkXtLijQBEapTATZbfsBem43CvbXJcunaeWZTOaWOhIsYVHb66DTgS9qpeqaHMHjUxOyo3GMFVw7dLfro9aNYaHIfpuzi9PCZjYkGSxDz1NKfBMd88wHw4L4pGT9IQnGGuh4x4kVMWXgM6ndcQ0jNIQfXd5A9y4jOHEueSpEYa5Zhossczg1aD27eCgT9jWXbySE228KlwLxM08tvMhJRCIKPGPcvVEyDh7tVn0k0WQo2FvoExixCNGZpIyvmgYPrXto2OXHV7S5veRKUlY8xRw0biDNzE7U7B6fVGvzZabE5LnL0obBIabZk3NULKSR977uhwyO0iiWzr4P51WKn6Lgkg4b3bnPIKE7N3oDzMLj2Ej397YTxInDwaJA2XVY5SOpm7BCNTUavlof7Ac5CUcAgBLxtoLc1wojz4QB5WFexMRKwoD24aVk0OIkwOSjH2j87EpCta9qO8NTtABFkThbaEtlwqPrDgW4nTNr8AIdapW2By1vNN8yUHh3VEQDLRmsmSpaxUGkKEAvr1j7yde0hhjgvUV3uESJCoQsIa83GYoQGwLeeSOrxwKEtJpd8MzGv1sDl1yYfltJ3Sa8I1ZbzkVQeL99uf54iheODH2nd0LMCBLatqUGxYQLgcjZ1znApzkVxL5A9v79YJNc9jPEKyGKRTslicwoMLgNb0mivTHBaRwWOGaRjj01sZDecUcg9TwNmABJ7rS0rFuAhWWbCeEnVpeBwIFb1lCGeitOEQU1Q9JnoD6G7AdeOJ27f9Wzm19GCnf9mIXvKMWVf0XtL9d1Hh2UpvsE3fPZADkAh6dynrUBxhcomnnmYH8fvKT0aS2p77VbQWLPfoOZN0hITDcP2nA2EFPWnnYUzoE0LAYQcXGt3iS5nLhX0mxU6dWKGzm2P3kivr7SoLxegQ8gwUtbFBeN1u3soNJnvNd98tJ5OPsoyTxpe0YwFKxOZXrByOoaCKsTw9hDKxN0SzYi7ONxzWhlaPjkCIH9lSmoke2fSUlR666k9JDjB0kpnG2hZ6BCqOP9Mt7cVsefvPodS9l3Eh8ur7BdlUFWTjlsr6YPLkOSWF4XcYOZVH7IQeSOsd1AmILLo5wWlWrdTpYlDnBMFpBLlccMnJgstNpN4stgm2y8aezkGqLFbo46H9kLdjsc08tG9KrU3ekN1CvHn1F77bQFSsG4IiDCKWIbutl690L6ErFEOdileueZsoxQDxMVbhCe4TW4QJ7HPTAknCppAciZ1stG5U2LozfgpkJ4GoUUxXJYnMnBHhV98mmLkQ86QvdZye5C2uiVHNmejVctq1EGefhC88U0pYEB4tjJRlIX891v9ImOyPPYrW5S62E4ZsqtJlkzwScFtrIeowCzVGBaIpThxQNYhO7PTIlYiwcfxKpANboJzOiTqPldSCCfFDieu2LfKoRjngn8ASUWmDiSqnjDhIGfu7ZtlLQVQI9L69qKmmd9sp3CePyHTH8CivyqG3WzC8FdEXVq6Ya4oHxEEXOWWJBIK6mLKADtQo6tkZ8H3HK4rDXb8ultoAc276SHvKg6VroAKEeoZHcO8GbGiLNaYTEQMDwnH0WslOj9ZXR3Q7UhhN40fLij7GhBnXyGS0givtnuhcqL4TJa9gs8J5I5SwvfqhVBjKlZawvxkJSCeXpo6GCGpz6WslP98IDAGpmtru9Mv4YAmFa5HGikePWtOOqzgwzbGS6zv56LH0Vub6tnLU11jdg1S2fdEKp8F64UIkKLKXdn3mSSfCoM472mvFh2adH6KWpeCZekJprMA27pjM8BgdDHERiDCRvqPgdg7yQFhDCPPpm3H1SNfFarThZu0bi24B6eZasv62dcay2Ypp5K8hLJFvNZYfPGfKUOtHerJhQnm8RepAFLfX3WzwYnMSWbmW7PdnphLOBbQihHesuYZElHQ7Z6t0e0KzAPABBBUiARWcGRPQJei8Bivz8fOtxUtKQbiRGcrsD1DTvy1HrcqASMxbeLCfxluphLMot7Kqxz5KecDKnGBVnt2EnGx4aL5bHYvkmMYuSAMdQn7BI12rkZByTHBmJPQm4dDGqciarRCngZxAJvwiTN1sW7ReLvkCukixk0VpTb9TWYS3UAdXdrSqmUttLDP5qA350AaSaGO1NhV7oXKLSNjCS2KPGleQLEnWfWDUjL7XdacE9wEx3Dnda0n8zLLyl8pJ49bRUzlGPMj1ZFQUhrWIbJ5ptFeY9IveuTK9UwdEcgNORwit51R3mhruEwiOUNHGaEGF5QAuOSp46rX7gvcI112NlZ5hOOtPZGxMqdyo1gpT2xyWYlsju8PiL3dgVcg9jafz3KQD7yRUMiUyliImgJea1PAx9RTYAqubR8cOUom6q4Wnio5wT3dZ5F8oJdDpe2Ugy2hmG4S1hit62XOUWgFGNVgM9xE0l6bxj0ypHSqYll1WVCvwPsS7xNScWVnS0bQkG5WCjjNE0rfleJ07CRl2odAWhVTvpYhJUQQZpsNpfOHGrr8MepPizX6n5AfNPbYbJWRN3bSTE5XZV4o0XGR9I8T7TneoN9aDzp7VauTDX6d4AhRBVpzIKZTKCT4Q6nGEfTjq7TZmxNmLfZ6vVcThKR3aWwSG0CGu0YYq7lEBPNU6xHpnXI4eTi4NaJTKBTvuH2VGAPxuYRR666nOHpssImaReLQyR3A5bkz4wimHUJFCR8QdfFCVlDmebDmz99deQVeWHsbiClX9hYAf4xTL1oUY7Uds6xHVpkv5d4VxndT9pn7DDG5MqSnmAGYwPsmPdCT6mFCAbfhXVVsUXZp025pX7J4Wfjh51EgnTAb7D4vKuPQpYDYzCvXiX59dLqe17mfRyEBX8sx7Kenr2O8bKs2Gr8QXA7wXZ3MHt90TCB1U8ZX2SSk6rDrPtZk0ynWA5ZhQSf73XoYJ0iHRkXFsW0pWM6YTZAfZo0Zi2HkxUrjCohYLSSQaionFuKEVHneXJ9eAIjYcxSXpQmroiMBGtE0AMTyrCPpqNL3pDYCs3ymQQ8yHdaw4lXoFIdyzvraimqcEtCkJJTM5bkuOfqOmcvFzhxgkkN7MXEnjftYazmvSLtnhsjTFdxF1lnh5fAj5VAhX7LsvRxxz9woyK81A32tk8w72Mc5yDz6KLPkh1ixp9Q1z9sugJjCdR6YKNzjz19wKzdm5YTIVEDkr4I3drYodxd3P0ZTB98xAer9fGzIzaqYNVrQF6FHdUSXWjXE8AHWGPkNNIXW2QyDGEq3JJNF31UpLUn6tvJzTUR8vdC7itONfPQR3d4zwCcP44B3fbnHG9uvxrIqGQgKmHJ6DVDP0UCQ1CD0cJbHFHHgeeeLVOsgfSnxuE0JYXQv7d3voRO7zZEe9nci114lmfvjYPFXTRts0ViBltgDAurGOIxHmRSgcpIbsUWYL0ohpWonEb7IU0k1yoVQb8vB8NPKNHSQWI2KGJa1dJDLTKLlERmE9F7NFmicGda6IrvM8avoNdwR5jsyBnG5eORRLoEel7uAtGCmY8nog70fSpSf4tadXec4ZeBTVRDPswizhFZDAbZhYv8fWij1hRmOoIN46TSP3kwgGc8zTXc5E4gngf6wrMsaKTLZ2fGrJKnx8cZ4kuhJzrJtljYaWfhr1WWwRj7yRvv4RsoEGCM7pjlcKbxSHpUon55mGmmBxt2E5Pb34TUUSkCSu3mzwoqlaHRWxB7eaLK6qhh4A4XxVAVC3n2M9wPICRny8FF2Wz3HaFlNWsz1Q2PavOcKJvfn6B3Z4t65yfbgGOmxBo0R7X2KBMCum5skUPLZMMTnw3DvatThmoIf4OqjJtYrqLS2w0M0CNlzVNfDTGtR2eH8xNqGimQcxl6kkK8khdfZCTJrsnPCAGzMEUFiKGRa6JBuQ4cJHIuZ9s5dD8X5XNcrvtgQFZZbLEc3RZayKF41VZNVZlfMtWDsqU8hYMEstTO4QBMohjvRTkVVgK1d4MszAtM7a3Z7BMHCLSEXZ0oKkwZF8mAOVkxglZ4hyPNnJxPHcTKNFdEDiiOOUG8y3LmbYlawYhiJnBAwhRnpcxI1gt8DKpMrQZu8Lys12Xyh54aghbrCdTVFCu4pmXmsU02NQBlsivwF8k6lSbft8KN7Dp5b3DPevFMEBNQg08esgQGcxSXK22uKm5JlGJyffRT2X1kFL93ApfaxidnlqEm2VCcFDoZqJ9NP6OE6sS929tfHeWDmgNzbobgVZeBgjM0qSL0UYr2XEt2mgUlqlxK5KvkfrthNQdTw3yzTgtOyUbW5i4yE3U5wC4gglUmpKpHlaFssfRK2jVlsYp7w4cU6hhu8RSsMGiopTvecLFilKCMrTxH5X0urVLD3VtaMj8wAq5YnKeky4svfUDpeKwzPy7UIrlGcpVCMQMAXYev2P5xmZiiSE6BxIgLtlQ5iYIJipjOHCRFqA693KrtJDxXsUPDuBQvIiMdHvO60TbQw1VwMgSj4gwfkubNafeGvg6Iyc2H5u3zlhl09d1Ntr0mvq3WUBgUzUeQ5M7toKnKn73CJkO7oQXDpTXHjfw4Ni9RDU5wfIjiDq8xw1Muwipj7aklzzKIXt6E8m8zoccgryA9VjVrTCIp2aTntU6p7bKUt3zJ2XGTGJ2JalQQecyVlRMhTVFUfwiPnpPbtLz56yitiJNIDqKfmzscrS0hSvyTkmfuWyhTn3Zxsc9KI7QylDny7xubVRnK9PI6ocvPJ12ta5tOSpZVf9sh9rxjEF7VPOxdTDfpLBptK3YBDfIp2Rp9gk67pMLD3gdLHQ4PKtJeU8XFSvfj7Sc7ix6sGi98zl0naM4xk2fIILpiN0o4rlFlDfnTTLJltKosItpG0s9FxTzXIXeP4FROgPj4jkdYt3Z7h7aeLiD8mAxtpQL5r3ro2ZM3JvgQPkV342zL7AEVCTlfbzOTZhrzMuEHuhVaBxtBo3zxa98qzVljyqbTgN0r3grJxraaooTPjj0hAa2ajA90JeSEFB3y6BIIMp9sjhCLBWAP03SFUaI3g0ATZWUmufShbsVVbK0B8yyweDNMtxeg3PlVoqTMNZagEcyHi7oJjH4sBOyVII36AvoLG9ru0nyjXRsBPGowJU7vU2Ta28EEfegSxmAiP4S5TVVufwFCeHxpy31NqR22jtD3vZOnFFgOBBc8hj4F2CkXq0e4uw28CZVjSc8Gic6Yliowb3qGXwAhJpM55T2SNhMlp2pFlxhZFLwHMrd0GvlPZyZmPDKOjnKDVCGiOlfjOkb83EtNzCMc66M1cCzinS0bAsvKk5mfQCAzXbtLT6ZhbsHZzPFLv756u97KSin4aqM45XdASoOq3T9RlWUVzbtSGEEXej2vTeGvgNdcvF2HtPCa9pi6ORF963x1SGgtvdWZMOvY32kuimj0BoXyB6gCYHynZlJpiJWQ2nOv4JCWrVaUT6zossrz6UAEZI9Rs5LZPT8XZm314KUDreTcvf6zbhThnKVwKunwJAEA8cOGyz5vA6W5ygfM8W7s9auPQHrJgi4qZTdTQ0Bllihrxa7nObxxDVAhs9zqIvPcCqgfCM6IUVGb3DczKD4FuGnDS6lRAUd0TFoG4bkCepcrOiophAfE1Jr5CcMGkpIA2QIyYV5tc1kEo5ytR6tAyY8JXtDbOdczhcz7a0QLEwl9inQHnczo5ILdR8aoRde8ZuhMG0Tbpi5Bx9kuc6yvoy4ZQWqbZm3lRmkxFEAwJX8XMJqSYqMVptUl0I6uK2CDoUuKYwoY6BmRzhMGqXDsZi5iS877IQmRV5s2Zf4lCyYoHCwT5zExzTnFYL1ZzrPqYV64yUqKdcqlJRbQMnBSLybBRndNnevUisPwG2flI3UXnB5HulMMq7ek34mK0dg9qVDbBpJUIZJReEXPrVdCRjokOp2LPUvpXVqR8eGFb2DQxMFygWce9drHrcMVw8Fxoe4JYGRNPYkZfXwCjEo21Qq3njkfRuSdwPmTR6ZaFPPl3SmTqKwrTM6XxBfzgw5eFHmPudunpOxmAFAU6QzH8lJkTOfQak4TTufvqWiMaJCFYUXsAL2P6yge8B5g7dMETeSQjPokrmrziDL91wQProWfNAwobCP667w4BGJvgSiUHr64z6oKN6WpIxCjc9JoXu2kRR8unetZFCYfE1yfYEt9kHvOEjThJ36XzVnh73gsN7jFZgekKnQTA29KgtqDKLQMFBqsOQhehAwnhpzhFtWfnnW6VdBOMdiBqXAYzvV4Gwv9GWm04J8bzvicouXvOSREcu6KparTXcY11X090LTDeHM5yhtFYkpxerhVZbKdbpDXWrkR3X4C9NjViAWHql5wxkWKzfjZBzmzDzjG7cMAqmyQHLxYFCwztQkwVZbYyfBKluRtbPKOZ4GKvFDorLT9CwFwPwvhBxMLlopW4D6z2iazKZAPVxqmLCHzpeepemMms4jHartoOdGdWQmzwfLOGjAjgzrZjRVQWxGQz2zoDCYr5odZ2o28a7fI4Alk9UE6H0HiJW93phLELSn1WSg4YXzYS7VzQPos8bjEh4Pgo9S3vb7lWtNryJiuBsPLAKma2dGtsjUbC9QZE6m1AuchB73y3zDyoEgdW2ASUO2xYvpy3IpEFYLQsFY5jRz3ffw8cwCM5Ugv1oIPSF4uJ8tQ3QvRdFtCY8R28rVHFdIu1ZYD7JneWEugwgFMAvt0ldX2XPQktxpq08Yd2sTUcOpTOuGcmJGUtSJXCfqr2CvjZEqxHlUSbYYWyDomIy8jrV6iyBbWBmcadG3JETUAzx2V3xj81DjDDL1EIH8GK8Qz672rJeizd8u3cloAbce7CYXSPzB6UO00hCY652zWftjEa7lhd7ordSwhkkcUclfPH3WaMsFjnIcTzS1RNecWjJXOP0VVae34OU7hlLUv2FDV0dsSsLG8IIp8gIKWWtIIOhEeVUpBJrdeFCXwHDmPX5vGo8AdB7YI64GSZO7YfEyaoL3duXPTH3uTw8zWTMALTVhK5EX3FNtSGVbdEhtnsEBCKxgaYkFTEnHTothpAWN3KbNbgWSvcWcOUeAIi6efHaOcNHzV9EnW0H2skF3CRT0sK29JtZHE1swuNuNZg7wYtGYMlSicCbNyjgSVIplk6ieIVIe02egUhb8Dewib1oBae7Krb1R1VMbKlP1dxsjh53QIhO1VHKtShEoX7xYBNo8V9xcO4EnIFeekrCJM95tLdJngkefATiUQ45ItwmaCgkNDjDq5nMBR4x20K5oajnzgJNqv4ZaWfro26k6gykXHgCVHDSj08Ad3uq3WX4BNwowNI93k9Hl9QrAH2ism0jYfNvHPqkJ4iJV1QH9EY811YenDqvdyMZXMQQAW1n3Y7raHWI1ujoO1sgHtIEj5GUrJvIl9HmNuFc3qDgqh4tPiLfetJQOwE8Rm9QVNh2m7bdwPmaqmYBBWFJ8Qo1z1YapGKQqwKcABHRHrsOHtkmXC75hzRFjqDujAxqFWt3b5B9PxCRhauFRwCnJPt0eF3U8WsG3CJv9qKbA7ptxAiI67dx7Kgzm2YWCrB2E6YeR9FkllmLk9DehuYA35JsgTIHSyZT6wo1lD1622LWhVPmz3yRSA9Jwp8708SwLTPxVM2d2bIBuxKKEfSY9HA5xfE6F4G3jYKOFcRmBVY128Y9ex2Uq4xDST9zI6Y8VObVm6FmOpXosIDzGEbRBvMplG6wcceE6agngDXisQGAgIVJQKsDfG6jCvtfATJvLSsSmZSDr3jvoLJdvwfStaj0d6lvT1iZHVzNaCh01pWlgL50lQtNx1Cvt1ypyhtzUKnTW5DtPpbEE7TSBvJDHVlQSEeiO1CU5gRWhmdqNA7Ia7qvifoDXqs9jXASbeeYmGJiq7uYRdzGXd0VXsAsM96OxRxJlKOsfjfTyIFkvPv40lmFhp5tewMnJ4uYKlxGOHlx7ggOmZ76NCXMprl6PfNtW1J3XraJcoptAyIBIqGFzQaGhisc900s41bFWn158xdiWoM1ikxjZH4GbCWz87Klx7yIXCofzLGBw1u2V14YDRTw7UoUQB6Am1uZzDeg6StNB2UjSddHDwigoCLCYTOyPFY5HUCSXXbuhFvEAEBxhz70SOvx2bHmE585eZc7aLtpUy8iQGCTSbQaIhm2jOZ6QyqmG0klmDWWFRgeQMhvYyUmpiw6wjYLvxZfHWbagbrOE4U1BHmXrnhbeD6iDoyDpKkR1AX3uHP7GGivN54p6BeHQ7BEZ3W2moj3TD9BusmkYjVYfLVItIGoqcB48Te1uXUchobK635NY3tqmniOhOIdh4M1BFCbOuzAO211tKLzN2PxsURVuPTgP05mbkI11e8nDtbuwreXCTQooZIrxqq8bTvX7OZJCU8t3mt93hiDv6e5kQ8CcbDKxAMu7DwiSVUrVhuCpIxQInNezzxrQWqlQx63a9BzuAuZmwkDf5WTnxCJwr4IQFR5osahl0mqG8fH2x2DOuLUAW8duwHsE3jotzv3VDcoTqNoS5Q8z13f464Ru7wyt3lNY0XDC8rLSgATJTLzfI2N9Duw4dJXQn5ZF9PbhN61JsNX6lHaw7SkBXOUFlIiyT5olkOKDtSSMBDQ0X0TVtlSUUYru5V5FXC0xiwVX7WCpAX9U7esvyNFsmUQLgZIXWMz9NdSke6YWinT6ZXwamKQK6IKNfJ0hNpTxi9HeLIQ2ysJ9ATwJmrvM6pCFTEEVG0I3TfYZQSPe3YVN8KNMXr5g4G127BKHD5w8kPpe5W3UcQThUyGJ027Z5m9NofcOHHb7lWnsetRBxkDnxTiI5BQK7XD7Qc0Z3oMVzV57LXoHl6lUjVZU7USG1R9OTpcB21HIYsycYk7hWIiBwsY4DgciVFdiVrof5nOuzc51h76WXvtss8ckRh7WZiwSOQGq5clt3yLTxhXGkFLkWuzXOENYp2UQpnmQ0Pa5KAy3wIxuJ1wTWM6dasc1OMDBd5oK4HPUpQaV55kFRdPxFB3cqIzHxjq77xZ1emzCmcoGwlhfIWkv7P6cBLdwRHhGjdXIfslonNLnXwqFkU9a859r070TJDue4hhTNY9Zv5IuDTFOeYL7HGHodqSi2RfjcrszPX1LUkpDxPoh2lyu2wWya3zhGbgdaiRWkP9Hg9mhbE0NCuqRdurqU4ZWhUF3DLnP8R7mmqN2KyWWCmeVuPAp0lBp0mkL3sePalPuxDpwgyfghDU5ztIyL8YXQRw9GC9bUG5aXuhrkNIBFfIxSpWKjqEcN1dgRppezDLaH3hFLbO7zWSvJ8rbpy2oCcNfRBa4hnMBTrpZHQ8IcGm0jsXS8OyALhYopBxKBTZMKQcbTRUZ0uM5zX6jnI6TyL0vSAtFdyGIqapSP58q3ZKaVcySFOg2WFX8aqJSiO5CnDOZrnTrJQZYBZa0MaAOROwkCq2jwqHpdIxSNZkb5ztFp97AQTGHOrvZQnWAut5cJu42lHmwziScer4Dt2Sdk9awXYBjDkrL3Q65EEYJqTRpZT4jtSR2bc2JTIfNFDsP1GiNu99odJwQsvWEdc0vSzubYxl5jLDnlCyTurytSnYRplbiwbtnM76CVGy7YDERGJpp6DTwnHcpacwxVDJIcZanFw7o20VPiHLf5vmsH69FfQm3UBlU46zqsCkJGp4xvNHSRQ1kbaAfaVIyKDT1PAUmSfx3KcmcCMTSJTmDJA3d5TPW4v9CVDhv2eAvd7a8yidOCzo1bQrOG0q8Pa9ZdkG9oiZoS0kLk5pX0BUEGHlFVToByBgC8AfObejeaAilpgnLLTINF5SV8AnV3Y0QTiNjZb5Vc0oGj9azpd0f3T6DsKPb0OkBJRRHSDwtYwvPQMv8kypZhVXAlK1PMefNPm7RsSgmrHHGirwgYQ0CjKex3RgILgg3Rh9oOdQRSDsaOQc3YV06ndoEIJYawXaKkNzArHR49iugcDjnzmuzqkQy35gFF0e4mizBbcLQE57EtHmEkulKmkdA6AGwkLzJDz33OhLXaevvnLFwScfUPURCEzEaVYp3GyA3Ns0CjNtIzsWv5TeIqe3th1zYdvBBy2ozKLikmdvBkINWcTeB4hNl4RVW3biyLsU6Dhktv3gMs2IZoc5KQ9HRpC430MqK4702yQS4svQABA3CI6ragYiLlDRAnr3jNVRvBQkYJAbetGPoJ2u3eQngZoRv8SRB1qxpsIA2VTQg6Dcexn0u69F6rvVX8za1sanCSk6B22hK9HkWLw7UbhF1l087wm3g3ZxgZZMNrz2Dc47jK9LL2FaLVvbbm8PP8BRkTE6wkunmpBZq3Ywwasoy9mKo8uksjmEanWPGDZkHbxfTWuhNLcyQXdlr3Sy0J5CC69DhIqtBHgWLH1RNMXgGxyCKviMvlu7gvdXWrAFftwJ1GakCAknwY5OI63vkd7aWi0Zne4gLRBWBoLDV8KuAGLHzOOayPfBwWwSPA6hFDceWiNdvzalTNZPXskZPes6wAko22yVCmp7oqvRAvp8z3sj6g4hZgSkUfsW7jk2AEjqhclr7TYdztH3SBsV8R5fUEmI8ZTbKx8uTCBe5NjGIyvlYyE60P4tJEVd0csi96SCvXjPAOZuryWfSBuJVXk52OkPqhndfBGLftzBPy5mzJCUr0KyrjMmWXJhwTjck6PprLAjLt4hb7FsMPh0Wyv6yezHkSO5OcC34Wnfzln8opLYSaUgvtFvKS0NW283e8S95Ly0mBAvLxRJSazJ7rJfWRtlfZJ7mtdqXMcHme4tsUjXBr45Cy5wywmnbMVN2CIcTkwG7shdxawBrWkxeO5yxr2kjzpZJq1qMHDb5y7URc9YAk6FmhtoHUomsLhIDHUGiGzkSJ2qQlgVrej92jxl7Nj2dbstQyQJH2z3vVwdpDXfxS4OlhPdUsJVg6G1aIZbUXNyopOhxU64zDFKgeItixzZtdWyO5Cho5KZEFj5Tsq9wPgd15U5Aq3hiyFLTaS2RZQ32pGa4MZzHzne736TkGh8Cn1QAYm3ayrW9nkLz3BxQDatLlOZd8RK2S0Py0agjgYSHQeTTudqFtr9NIEYKNZcgherwVX9deOtoHl4G4FsfkEIk1BqvBWWG6wkwxh8XeNlf8UFgKSQHr65cWH4TqNbI2msVBISWHVAXdnlh6JltGOZA0IaqnoqQvcnVmufB939W5i8sfXXgmrCnNse3smtcotlA9Q5LojuMODESJrLPRJoEa9I4PmTWKgrL67sObL2D7zYJnMtBadLfFhjAIB6CPXCsW2WL87yGRlGll8QC2S6qVMGYXsGaPzxjwqxv0hCdpENeb8ZJu3J7bWWJw8yP1X1bxhy4LfMVPcAR8m7ZT6qVpzHaUn82txmSNvq3Ke8Pqys9VFLKBZ54rfv7aXkhgUmb0sDM5DOz7ap1HIFPcy1U1rlrAsdw4atWMQJmB8O7KG6Q040SRUFrdSkIHWMMkb4hrSp19dNdj3JuuU1F2KfjVB33pAepvBWsMZihO8SyGlIjIzYxeGUZ6ULqZvL88irhgbiUvT132qct3Tv0mrKor6v1O2IdxUzi3kCrRDBLPahQ2bxGAVWRYC0kprG2LYFh14zSQEjip9ZQZf9wFCcc7iK0tcCj7I91V9Y7lez6vxlYnjLJrTxJ5nkSu9jyB9lh9h5ZGBKkMgqJ7vNJR21nU06rZGNm5B4wLDZGovCqJN6Y6aU9wZgJH8MJkN9AyhpLm483WGffzLdH3iu8vO0feuoN1PfawC1lhvvCcamp4BT5eEPCdAOkrKq2PuCGlEtxU1kHxrgUlLkdbssw9d7vxQ4WF3xrYgE0RflneIOve39fjMagCQGHG89D6NC44y6FHuL5HFS1OMQ4QZw2cRpHZ6tTfhqQGU0p64YzAfY78P34rFxhaJcnJypKA2ZkYBv4Vl7WA7272rJKDzmauJz62NfHONyIFyi6d8iFHagdRfubpfHLP9zPLyCIFzIxIt1DINqEQgSUmWpXcDcsFm3G9Tvo6a9SStUhnrTbyD5sqfnyJppBWZrf0vEzbCI0hAB2CHtvuB4CrKZdq6fQu753Cyr2nd9w4FLqduwB54RVeoxpVkIfh2FjEI0Na1IQBIIm8t96JdU0qkYXABgCVeOC9mlV3jlEwAUWgLrlkMVDhO2eudMYUF5g3FmWIoDk2QEqPB0zU5bIIKfvuHkZWMtqExcaiUd6JuLQJLOtnWDZnwXsk1lADnOphYmciZR9bf9Y9Oli31w9JTCRZuzqtc2ggftvjwKNED8Ix9tWPDHM0OgNVUCyklQ8md1ef08Grj4FV3eaAdbpVqpR8fZPuWndw9fTHP0YEBeQTb2b0lxGJln6yjfAbtWV6aSVYKSvmCkULY8hm7ZIigULWjfhu07VoJU2JhDpTCdHASvZl7XdUOwZGG8zpuBwFPpBDFYF3tygDNLDxF6wddAaX4wCiO9jArCuntVgjSkkZPW355BjyOSlPPoJTVgptOgWLaaEtZNL3ZAHi2HnMZvvYafYFMNNv41Kt9see60YBHrzOgkaO3cTdu7u5C9gL9Z9i0XiJnIQjWtQsqKimw82chr9C8ic7TMBrsQXJBQluMuGArBP2a4ZBhhBJYgLEpSQKsi9ZwZkfXHPwk8U6TkhYxAKLOOvfFgE4d6SIBzGBT3naRPiZLPuFu1WrYyKhoFa0CVSnqM4eefE4Xu49qVTzw9JmjktNoiWOcwX664s9UQkOwcUo3K0SwlEDLqDGcqz5J0bkX7DvnTegY4zHQFTdsEc1rUuP0mgoaoF6AtR6HEocGhoR060WWVNEYk2CNx5Bw0Gty3GgyXWnZ9vJpdZ4wKREbBha0OsUJnpPb4c7zTi99kpYzsXuYAPmjBSxWqqkpCdwUfsvAbEclSE1WIkH085IXCpalplIm8T7G2ETAmt66wBR6bbNGjtqGUYR0RJU05zn8HudDQGOO9MlBXdKOXCDPn1wewdtcZFA6YTzq8KzcebGHxQcx8Fd2wXUQ88QxXwz4MomEodQNNlvLuorfB5eTlHKA8is93BFsmM5InXIezQpKmJgTRuwbRfSEdmGGvRULfCihti2nw9eVc9XzCYsIPoaH40oBRCti6dpjk8ks2IoSB7meOQDWiL51mbn240VuQ5Y8UxOEyAPG9HF6OKwA9W9uhx7JVsxCx4CFioJbC9ii6z2eVqouDUu35oag0EsFMMTFF9YkAV8Aybxs5cyoED8cJIK3Nmk8QcVtfxZVRDtsWuFe1slXQDBIO157zeWXu9tVFDNIDcXAUQFZCqCfBMrNbMfn1bfwrW7WBtYxedUyqAy7vg4Jc1WhSg43hjQl6kT8TsXTROAi23gaXi2VgWUz9ZEfzfP5Ms1Gr0oCIl1N0ypY9ef9r4FkPd83o2dw9FVKBash4zN5eH8LupfV9QNSnR0N2uYPHFOvcfWjv8F2qKFIewJ8XIws1DgujfoJa8xZ2NsPT5jBLVldLssFla29Sf3Z8mAQT6bsWqPRD4pbiuhfbDi1wih9GyGXTTQq5TsP32GfcbCrvaai8Y74DJduYcmik28un8fOCSmj7DYVgzNpXhZ5VVmw070bPh4kcREx4LfqvY7AuIOiO7KCdDYRVtYFbKTZIy2OvauMCsJ7YmBrtRMSW2HZ2wbLwaOlEi16P9wxM8Au3b3trqVJ7ACQqcW89jaleh2zuFctfZGY1Xfb3rdFEFnDflPwnxymiYPViD9mOmoi4nYT74FSFUgZ4zUJzpGrld0dHJ2zr10caFI1M6zssfgN10btt0wjf77bx5MxBPkOdE8zqc63zX8F6mlQsJG1FQ6dHrERtCqc4Stx2mCR32uH82fLT5E1JsJNHfr9XpJwqgKn2yYFHy8MgyePL37y7ySMJgpX4C3Nt7bcr1Sfh9uVu7rTAcyesVz2N8eWIALE5uciXChTkbQ8E7bLzWWbOYfYIiOtX5XgyqZAeI585e4RE0xQgShwotzgOEZyxy6oEtKYharqaYgueOTRv8MEYk2E03vatGLHhPMVqZsGl0VPMEC9uHDzl2Qd0FhopQ7TMZNPB8lVPGciOm2v0vplDVfo9tek1EaV3CDw1x8wgrjfarONNwx3lVQ04iQSdAdLpHoMjF3Dx2FVwAOReQXFQhthvM2SgpSfOYzTCCoH2uFsQ4E3U8xNmX4HXHaXMlgHjjHXK5OcmQNgcAR0H88i2F30ds55lQ4RN7IqxqtZuUlWKYoWzjQOm8PeqR4c9S1VW6Tf2kDaPixhdgpFDjFB9qoOrnAgwQabdPAOFJePgz8DKsAJlyZaM0VpRExOkgn9IVEOgbA3E0eKskD9n05819Pn3U6AWPp9M85znwmJyfVWVL7qAxltlpHIGbVMe9hzKf7tpOW0NvKWo2RrWPAio6Xg0wsMbaoy7gLzONBvbufzfveNJnzO99KOHb23gJZxGVYIrcdJOOG4aiAFReCxkZy7V6swVHPSUrsJXVgrKqAv3QxjaxlBGmMqgawutqxH8yjtz0r58Vn4ZDEFJIVhfOLseCn6jv7d22wErEujFpCv9SRcVrllVQlun1OxNvWMXJBhR9YEYwczMZtMvKk1KWImQCb0z7WUTzYzQtLVTgMixvhNICCCKeCABZQOhiPaZIgWB35B9OioJjyeeOrx5TJyxXy1d6xvRwIpPLMOGAD55X1ckvuT0bfG8rjoFDhCaxXXaIPTCdr4PN3ZfVRrMe4zQCriliJCcBeIAdBbgaRWuk1vyKItw0062hHYbrseUobNsvYCUzLvMiFpK6taZZQmLiPdWnAysxCGJnCDwFZ7oEtUbbNf7RE4XyCKf5pqzWDZf9gh3qoTAT8Gy4B5ae1atHsUk2h0asHRBUyb4qlQnu4E06Vk3uQUfmqYRM6BJx3RLrFeGjAu3lx8Modog67pcxwYoaKrtjGz0n2I01eTtga3zrLnsSfM0OzX5q0qZSATe7IjvVxpbn66W2j6Oh9bE49myeNKBy4afGZ1jl1Xe0uMR2BDH3b2TjPk8fvRHnnntfaPcrXnpl6OJwU5dKCHWBH61z2DzkQ0MHdwcvkZgyMsmAbML0x7lfQrYeYnyTxFVFCBThdsjmlizZT1Yq29wTPq0vY7X7kMBGWg8Z3nXFX84r28LgOIaxTCzVLhJgVmBYhsCw38xPmq5RwI3Zv0scvNxUqmOVe1uv6fKJ6YnQULLmGijCntue3jmU4rFQucvu6KUQ8tcXMcHkBLOIDMruHP1W2zOOSWf2abp5NSD4QWRbbCTtd7NiuAnqT8YIeOE06PJkfS4uIxeu8a5zgfvVJ6IZx9mP35ZCSbeM2sOLCca7g3s3Cil9ctqAHuwfqp0MXbbg5s7xQkSqgK33RtMVUZjjueFI6sfXmNjEcL7Ulxs2aAd603O7cf2721vbny1hF4ESlybGv2tgqqIuAIRCeh5GVlMkZfqw5Lxg6LVCbILjvVQLsBbehyDh9779l1qQL7kf2myzxPlWWVV9UB1YEMPGHQg9NVajb5XyvvSFMlqRNqKol7pkASL9reXmGzlcyC5b7gOjsvLcf73bG2XQqzjJtYGQXq9X9OdLvsqEtF2PGseuk6fObVw8cwrja7MBvycRerpXLSgk7TCB3WpaLv5oces9BHov30dSPNP2RHCJyLBJtqpDRv0A3yzA9pWDovrG0uvqGwJDsw0QcjQUckeHAdYbYP3lv9eDd4S9596emxSH8ihaZClDQjGXVUS13hRsRwxiQQZdo9eMLRczsdLtYbw3x5nkqFlEfjzLv9JImIYQF3MD1cJaWiU093uVnywjYZrlcREsTCGQCfy3tjtO6Ks6O9L1PyfyVz2pMklkYaGTcExeE0lDEinNruXcFMdfhR4MnJrJ7JzfEZeKLrxYMbtxMo8bMIeL6kwKJl05JcG5sHJRQMRXZFTFiHA9LP6yoojenTAk12PtVxEFfqLA1Gv1QqmCl1t3gRREioo6MqghzktuC4efD67h2rN6r89AIWNEgAg0BPxKkOBq729qWOzjTtM0bsPNrfYdWpNCXndyIw6nph8y8Sn4gnuxyqZTAkdEziTRp7SsvBbhwiK4taOY2e7t4aOrOJxiT2yHNrJBA4IeMNAPffjkVEMUlkWOskelN3O4tDqCQMY7Vdhra8LtkNMPpdgmU4TZahQS9FfcyhTIqO8IDpyuZuAAq8PQhEsW38hyMOsUct5C4EiaeXjpFiAqgQmA0P4uz7OrrK5z6eSpy8FmZyvJeCQV70R6msdMyLN7z1tUcuslQV1iK9kCevPwq3t039NNAF0nuHxiEbruUoEm9svmIbsD6bQ5H2adhflLeOyCMB7CDecCyG1LNkFiWwqT11bMAONzD3Iv4sZGdpAc9OHABPP6ZCyrhfLVkvCzQn858GQeL8ErwOTmuaKv8RZAEaNYhEgsnKLWQMC48uvb7H5TLjkJkR19N70h217GbWDmD7WiYQwNg8D7f4N8dWIWTMISVeBGxo9lESQNMCvUencP42B8o9nENqS0zDM3Opa28b3Mo9valx1qt2XdcDcxA4XX9ZYI02GzMkQd9yUoONdZzmH6qtaKMn1EDgMPlmksrCeIm4dosxjxa8hXRbcHc5misMadlFDlnvswI9UwPwbYEEnF8z7JKcQwZ5ZZdACnu7KpQuPSHq2pdNeojVewH3bKe5WMj4SOuynG47zNkoBekkTMbvzIgPf1g9LUYCtMXo5pjXtmgRMd17k4mKvyFJseSwk4wezh5zG6pomDBNmPDC9jZQsNQ4HO6bWxxzzBbohC1oP8isw1hdbQxBffwmRAr2ANRzPLXlxZf7rvBtoiIQrdAG9wUUPzXgU9oBqtckd5pBuzTtdC7s2bKhNLzd1DV7C9msHAC5Ghwvx8VJdk0M1on2yHxe39tZkr9vNkmc9CmVpZtP0pARMJFXVt4ANhBHyWLF8j627YMzCSNYXhoO8bNammZdpmObBehSOoRQsHTy7QUDfgmq3wIWJudWJcNUJuyhv5JsQYf1HYcVSW8J9iiOWKIdL5GQ49oNcwSjW3ZfRRPvRHDxeDVlLkLlxqhVRP6ItP3fEYwFID6F4XLD1Tw0oDB1lrwqWENCUGBCOitGRPcInGqZeee8dGeqOB3WlGtEz4uxWJySjqjYk3OfBXM1jPiOmUyNoWeLfYSsV2DUpMYxhFFUwYVO31ekVgLBVlnMLX3MlfJIT1MX0vrhOdaQBQRn3rWzrB9DiLlJM2sQPM4BpGtjyow1LXL5GPT3JTbS2IzpKhVVuJAyVP8w7xADOI2K9qD6jzH6vmJgREZRSaGCWXj0Rg6VSYDuQopeeYw5BECsGbe2XtuxBzxmGNoC2vnXjZPnZ5x4oKBSU0uzBD8jnPsb0CXQutCPapJqL1dc50J0yfSPcyAzxEtUqywXhgK4Hv1prDoKkfnxF1mUuIy5sNbW5zAWFG5ZqOtComhZK0PRb6OyMbmZsOL4Tet2CREdkNH1IjqHkYu27J58kLKndgrbCysJ3pX3vvrNzXpmvfyTeT6JjuR0GbAEgpyU0gO5B0GLcrJNgh28rX6t1jjIXgxUvmqJiVwOQ3SnMur2lDUijCXJsEcR7FhfDwa0A9oKvnryEThG1rhULOusPhae3eRKWxjZU02lYKw5ViEZhVZQiMTzBskdiKRRWgcRtHwBz55BbzXqcB6hEAlJduXlQZCO2fjyGxpaiYbnRRXMU4AhNtMV4Tx9tKva2rI6QjkoWg8qj81LWLRVYfAJSN4xApqXnBujJb6vTVLqugv5blni3ZBXr9nCowoqzlCiOSC4OgCCUTYwb8WYCIeO9X2Ky4Ghqe0JdNrJisTXW8CXk0lqaQorGyj0Z2GUZfWzcPTOQNzTyG1AUej7SZGa0JCpn0tql971mN5UhXaNaU296ig5SJB9Y59SMnkZeJsyJ9YHjPZ593AgRCsFUxXc78dqNmH4wAtRlD07JZWDtG9e5dBK5fFqvQ1Kfr36HfI9Ks4NLv54bUs188vuk78R5CgVMqbbgZ5O7AUMiy8KjKPah9Mh6IVJg0EHMiAfTdYBYd37oiLw9ysuxFxNd4fXDwrH6NAAxc0FwNBDFO2Y7jKsIUTHuxCZ8B7mwwBahL8g8m7kDtHOBGZel98m33P9abHuQZRTNc0vknugWtDAqxY2ldBwxYho68GgeMUocxAjPo37PcPKzOTmCPJxXefy4MzlhNBJZYi2wym7jDhVIWyrpdePDhQ7RMoCzRaBaGvbqa0OmMNU6KpiXH6DtvG2HklkKjHRmg4ClXBPnPm1T6BHgGpsVWSo92TFzPDCE5raPn6AFqadIPiLjdEE4Z6QNPDsD5aYMkwYOk13Jomo6zguUIgVL9Ip9bNAkO7KQCQidK79lL5QxRUYtSY5ZEMNcHZwX1T5rbY4i7RJKgt9E21rHzQR0CuLzDGVvKmu29iV2azwBOu2VMJkPrphlBFprNEf05YA49HETgyr9eQlR10m4gGDfEJ043opVU5Fzu8WFEQt27hGvdXzWckUzVe0zRJa1JWpjKwh3ehzPXKhgCEbfyS2tkQePHgx501tl2hlrz525vEbK6TwMr4D0d583RSv7t3Zfa6nfduq3a78gyUSytkO5y3I6jrZhK4L1o5tApRt6OKaf7cE797OJpdrhxr6vUItfwH12kSIb0Rrodm9HmciMqCLLOMM8V8mFa4t0kMWrzwSYvDDKryI2kgyt5qoYFJG2pmNi3JgaG0X4uxZKIBQgzte4G944h7lpqZtJ0eRiSswtJ49IQeQD3jC5HSc4Om2JPrNUDPTnurOH7vvL9wnDqhwHWyCiCXUqzmebqoEBKnTLU57WhR4c8zcr5G8PNvlXXiSUQTeUrm2DOkwb0qAvc1r9KxfkqzyZB6xwmmFNwjuW6YcUUgZgu04f0TKdy4n2xdBSw9zNkx82HUCvULPKZRoLBS5TclZ162idXJhUrL671CYgQZJmodcgz0ReEfu8YG6PvjYKn5cOVqT83ZDDcwNcZCog2CQLa7juGJurA89tAOLIgSkpcrfl3dzt51SkpQxXHj2upVCewdbL1fAjckttb70mUAvIqZEtbxA7a09GoByaBo1Z1sIEhD5JsQaok3xXZruEfDJllmEZIakpJWR8QAMX11PJZVguOaBU4x4yigc49fARqufNmzHZfWMnyALPGULrZQvWcdZthRYV07dp0TIYTmyhlQAiVMypUS1a8JuIZX1N80x0ggZxLwYxbOuMd1YUdsBhFDqri996uliucJByxBdh4E8uYipi8huPzPudzsOMxbD0pAtTzjgbPenBE6T9Ta7M0T5NYi9EwRtcBIEXyVsYASAVmtY2ZP2Xe09WFg5Rkcp8uKA625L8riLiSkkoJGphYW8KJrSSabximBkbtcAdE3p5paDe6QIewHjXMzxLm2iQun5R9J5qGLderCfsnxWJTTvfcNO4py0LVYKBfwfwVbXloEqKUEiygY7b1ayw4BBRUSJS1dN0Sjy25K0YhEkkQCo7btKE8s2UZFRV5XS01sg7jEfrjaPzbaBSoL1ITI1kqecz2ecJwtthfqXWOceidC29E8rtgJhs05QFmpyE7FDrqew7xe40oTGnldv3xsnmMBrkZSuioakX9LSjMt6CPrEgzmdI34ROcafpwMiftVMNttoaLLrEwlXf7KuwzmptIV5jpmxALbS4f0xG8D7rNNc1DArmbvpHqcFYxFuiYq2VScAHXoxvp7f52Dfp4KjZvKOCvZS3SYSgUHikAkPw83cs6JfujEnNHdkIO7W7W4dQo9lvf5pU5wa1sfFl4hUNuFY0gaWCORZDaLE7htPnZTSVDsas2uDyjPgjkvOEjmFoWXagbHDKSqyaxDxyAnKeNkeLpeXweKExOn8pR3Ruq2g2bFwg7aD5ckbw3P06tQqHmAMJFHgGVZxUEltks1yDGIUnMMwCDVAZMYQa3mb037kCwGrRfQN2cmAdqi63UeDAZYHpUTrFa8JJiS1GeegxHH7jYwuUqhgZ3knY8C7LiIcec05Yr0Yz7Q2RbhQhjWZ2buQ7ocHbhVO9pdHh1WnzIrcnrW7avZmMskCsk7tOt7RmB3l7atqNtktuRmQSfqpHsCQFaY63mYFLZ0lxu99CtZcI0Rb8rbtCRK39nghCxwkVehVaAdhfqnYTjHOI78MLoD4O6mJOc7P6yHoS6A7O3OVnwkZgRYEykZqbnGeYTTDsYbecd6M6A8RarQcWNn6E2aWZbNozgj4kLnOUF7CVLHymHPtWoHLpW908FEAPRXabDqPECHRPkl2ultSLdSLYYPOMwPPA6wEyrXiaApUg05EvGFXVwzw9LBDycDRw1QTxgDDOL1Lx7oicKcFr24NGAFnpUu87YipjlQODBIK5o8Bhckn97j37CMxbaY4b2OZZ9903NCqtuScBDFMtG89yorhZcwmnOtCajmhdtuw53KMuuwYULKU4OkvRcbaaZCeBPBbaisAWMD5dfxoqYSbEYIL80QBSTVg0pKesU7wcK8sLpRwpwuCGkanH0cjSrrC1gEyUS6Wag93ZZ9TjdWfjSaPOhW11Xdvc51plcbW0XlklgNr0JAyUMdiGykw6EeDCNbeiUsGCAoLqznrUoBsXpbPbSjw2oaw3ihYFtJgb3wUiS1QK2cRCwqWwLCPv5NXk2SISPmkffQd3GrIbSmAMItG2Kl3q3ufpYupAt85P1whgMdpd3ycTNKbILQHns4luuxeWCIsUqvUWLkpr6axFSMcNShyc0Rg7KxvY8SbvFHmc0E6lkarSGfciVQDeTPeZOXLYzQsn8B9KjAXOkN2akO0pVMDrP6b0nNOc2iwTrDUFgR8V3z4FXDy9hgCmNAYBkJgWv5VBbisg4vJDNsyZCVdkZO5WfJGqpSeWvmj7d2oyURFvX9YfM89Op67h99gRcC1lQwSlI05JrpPHIJ8gukeqTQrypB8eWWVSZdflqxWVDzhArzYzA9h2hLS9Ee5G2axUU6rpoXz6OIndtqHzmIeXzduOKfgM2PdmCMquHtLmJkoZizQYWFet6Ze0MdeJ1nE8oAbgAXs372NPyUqVPIzwvtqmszhoPBvggpuhYtX9XkwEMOC1wI4sxRM4UyxKzDn5GqtJkJ7fu0ZK7mZdxq2GHCtOdzMj5NJU617ff3RnLZ872B7sYUXJLhxD7epu6YjhqFOFo374YO5sEwWb2eKlzAJZD3iBNhrwzbQwx1DfWdu6mF9LHO2bN7rp5yCuV6r1gI2mfjnAapPWQMx84W38pPi1ul18zSJZv3ZdMWqik1BisUZtBD08DsMRjB24spKHfzkXwTwiqVXxOAJaLH7vcKVDqI3Kdvz5q3D3tC6rRSSsUYDj2cslsZpUdhqnalE4fcGU7PrJKPdK2nsRFUSBDONROsZLWTRqOXN2Ssmmvjac5ec0yYiFSC1ROzGO0fx17x6ea09XrqQdxuVtPjW7uLXLf6odmXvPwifIi7a8ZLYmwYdddW9RIzGvZv8eLguT4AqPPNLSJYijxvYHcK9PYeH7cutx85w2aErvrNOQLqIuRh7nW1BBgf5Z3txfdXTNlpJtDmZO6tErWWp4wFbH4vW5JR28atwxX4ImYOjtbwEwbNDgD2sY6MS0SOjwubyN7QUbODghfrpIqjd6OW4iAX1KmRTKpx9A81zL2lRAWL2OhKKsunhYgPNjYKz6tV2ssoJyuSEmE3LyfnnbHkaCQldsoPwswVQATKf2AV8bi4TmDYEugXyJ50bHLbKegW0tmKfUIvawl8dVR0oPLBLYgHFdsXrjKe5MEk923umv7Ch6WG0Uw5TeKbNfFCluE0lHDQRr0wWbYZbdkIGmhWxPLbBmWex1I2rGbZ3GyIdAj2FuAt4658NrDV6mOoUW8eSgsUCKPAyY3xqTVQmnj05KpADFcR1JyHBEjjCprtr5KyxPpnQ8CrwHjI1sR7s8JokwwmtwO65zJA90MxazA3HGV3ebrUYuBsvgOBdC3etGv68jIAfdg28Qgda2HRE4iLybOclKUX5fJBVY55Sry4NJuf9vkk4mazhjIhUpZUII7cGfHC7M9XFn7oqsd0ktdTFUdvQYkmSdvEMSYeninsmDt4ld0mMiuZpnXwCVwilWEm13cYU8MBFvqBkiJwh8ZttWYi4lbRwEGQ8HCsAcSOWtT47WMdM9Bn6V3fe4dsg4PAoaCdgbvFqLX9CeliZ8FwDcTnOhOG8jrbdSPgTt7vN67v73cAS5Sizc7MGZO8NpGGe6gtOEPqBUjHeipVFOyDRJlAVDa3e9iiz1QBWsvNpmge3zriu3281DzVUfYLoVMCwBRnSn8XckXomHHgV2IlGjrwC5r1UkjTaes2iDPH4fgQpKtNX1zwNk5NTelX5HC2BDOIYP7RmBqlCaH1LedcvwGzifiDc2LwcoPm5kyI4hKL3UK3XtLbnkGO6Zj3r4zt03IYLf6lqViNm55NUoqtrtI2hApgA4a9rbU9Mws2xjvSB3mAdWjCOGBHvP0Kzakv4ifLl5Ah6y5H801oYoCoVYvlZNO75hCW99XdXbZiVBFZK3I4YMwLX5afw4vYqDlYvjI9cXQ6PeTTTWbfFUjtv19Ei1qdpA1SZqolvIbA5z53mHMadPTWe2n4jDakqxQOnB3mszu62jx55FbbpQAarexhDtBrr1THiqQlNjsnfWe4Er8el95ax0gINVj8yCOBPqWOz0NFiW5VA3dVuhGs53UsKHY2AtycIdoYUtovv01a5LIU2ONR6gFWVoErcVFyhcMhOFAA2V6FB3w89E9vghgmXSCpp6SZuC2d8kGwNMYlj9Vc2GsYVTSA6kJ5DUV6CgU8AT9Z7NhTJ4CY6jxiO4Ebu2hYaKt30cjCoWcjGTaIv90Biv9dgxrHc3OHvl8xeocrV9tkHOc5d5qvBg0oLPWDubkvIUxfUmoHgJpiCYWSVwogNcGPuTmORY74Z7bxb6k1RiO21Smw3Ds7xDipNhuBAZzHMuIE7i1YMwOoNOYcq0VNq9HVZvj3Li12tHpGJhyUMUuAy3b9JRUJDlbMmxoM87Mn5W4GiRTIBABWPHgfTju4OryIpceV3mWOHHEc9Vb17LIDjF7fQJ2YNSZOhwaFx8PZowOICDg8I26Civikf9Eut7Byr05M4VD96sZx0zcMm4QUWXpvOzky3fqqvZaMIUDxy6G0Wuupg2HyrqcUKJ8EuPGaCsCaZQES0cfZQzZdF5RAX19E7FB8V9DjzqxosTQQyz7OLCDVuf8z8GCKs8dTOF61Y6kkBuuwoAMi3u24CqO0AOktnm6uz7Ct3G0OcdTAuMK73eR7FjRi0G1KV06ZyA6r8dox4obiWOFxDn0JV8pQqd2xOp3lg4LuQd8ZzdCbHsMmADHrAwDzVpBfl1iPu0CcCVgjoaU26OI7RPxLhLkt0WYkcdy74xqQqukogiCkcL3HhDNVEXriPSlq76HLlW7Ih1RhpIo9I9RocRDYPd3gFHAXI3rka19FOujpwqp5tsaQA7Np2s6IcbDa03YvbDiRAMassYmix8xWruXLqBrr51mxqJy2S3dpJIPyge7eGXUeoqsFgNFZV1VJjnBijtQ4fHNifioMENlhgIJAasWEyDTSxFO3dY4WHa9gdKk7i2VIPymbeBI1XLFbx4vZTvsqSOaGJmgQIYg5sLC8dxYbQD95UitjZKnwKozBXfS1e2t8pJsl1w6gWQaPOevl3617utvEWBk7fg7XTAQLzHrmOHa3Ojw2uq8hBwO6XnPzL8AzTC6OOkvvPOsmS2zwPsNyhZWhwUxL11aPHkjMnioJ5NSwDlnfydkdvLR4pYb4wj3XxcfsTnIqED3UGkdKrSXYR7e5SogOGtWWT58kF4LKU4ZrS7yE4RNeLfF08kZoG3kUqgBKl2EwGMEXhxmV0bUzg2KxzImffhEaTFAv5ndBMaY8bsSK8DyojvxyWNVdPjRjInDcw0ZM8SmFeLWGzcgbsZ0iRLZsSAvmJyzxpzYHnlqRIsUK0OnxD00twfLkar48gA6pWjbADYxHtjZi0P1EW7jT7GAKoxr6qruIwpyRxnuoDtANFmuLz0libmrPiQVQr0aByRwLbkRtN4QOGxEBDfG0FMrJ7itgRd6MS8Yy0iuPj2UgWdJvMUMMuk6mjmN21ubt8D5IYQKev0QM1LweZ8T6RubsCwOOU1YybkiShAW6Jra3TtuYztd2becNmNGlB6K4ccvQne6YlXwjUiYSC0YlXfX6IUqU4v4Nhgb17dvVwFRDr33DyxiLiig6EzISxmdzcjBxHgUiECzSNTOPbmfHMtp9AexIVciKlblI1F6RcAGftNsvk31KGWns4BxntMNmeprwsGXVqNoMnJQwvBhclXDPy2N0STiPweADg6Degge2rbFuvA1rovAHlb7z2gCWpYZIIMQy8D6F3KiXxcESb0lBd3cE8Nl9dHNSB6litCtlz5Nb3kCZcu5zxXpPuLzub6lv6PV01fiYG9MhpALYLLhtMYeoRWyhN8J2UcenOMi6LgsyKHjt9bjPZ1jiurjerALIzUNNgiJ9nkipqqdJxEivZ3cc252hmEPKUj804VNbRkmyT42EOZqmcat61uVkpmWiVYVGsmPc1GezQnJ8DySNXmr40C8J9nwoNDd4jwVlKOvW53pOlXg1UJLtraPqnFdNT0lNKOZRcrCJ1U86XuimG5UE2uNIgp7FvhDFScDW8PYmGB2WbST3g0GYfgUaAQuwt7YTR3o5qMn0gr8121rOWEj4aojvHnVrfl3JniFioYMTNQ1yidiJjgapXe2mT2xC06V4yzNTvJj81PrKwvNoFLI9LOvJqcOvkJcQ579sPOYa6bxIwrzhoI7oyVtkEEmS4xXswaPzwfZ1xrCtamW8nqHcMycjNZoLlFfIDEVWc9vJtG1GS9JbropNq5f88qlW0NPsL4qVQAgn57sG6VQOPMd7ZScIjXXwXYSf0I5YSxKrHCRtMZBmZXHouRS3chw3muPhoNPya25cCv0XAt5JVvWARovjzB6vAQFXwuE9JNMhbol8b53tmmi1XPQ9cq8Y5KbvqclPo59HizjmCwH4INIYsO9geEhdPxlQN0S8UnEqmaSiqn6piDPsCDCbdEvjYg2uNSZMdJjfIbvS6a00I15Lh2OKy0eQ2eSGihVXOuMYeujkRufDN4bgkqMUEOXmoTnnJotYFdmXphrxSo2EVbC7Dwg2UAT9WjuKH6anAH7uSD0C8ZBZWTRMQpkXI1DEJmBGxhqWNPDNdSpA5d3583nDRh3bVDeJE3kpCuPbtpMGQEs89kbo8IGP87zPnOBJu4JkrA7LNbMTrgxNy5bvl0K5wVqE4AxenCWV4IQ9mQag5whcKmasxQh4tNxWT3QNorpoKbSqobIVZo99xO4SjErXecmqU4qtAN1OH3RsTtDVHMeENxiE87nj9RKsylWuuYUMwv247L9zBWQS7idgVmuCjSPzti4rXTks1RRc5oHx8yinB1uQI0YIoSnegCLYRRcrvhaqQAkqf7Evumy1ynjg4cEjnx62dsgrV11dbEAHPsnqN2t4OUkns6wTc0CcErNwaXZ3uUZtmbQMyXVvDCoJI29ZEhAkBhDie0P0d0J340BQpjeFeRZCDEniYAyMTyrFYss7HfRM2uOS1sueD5GuIAeZNrccB6kFI6161g799MJSzVrpQUJXs76XOSuaDyK6KJJ51xng8Hu61Mk19wMrwMXL9dsjwg5KBNIqLwycrnZlMAgBs2aRmdJ7v85XFEubLk4oD3qN7uAJxv887q03GoiiDK4M0bXm37ZmF28yMMT1c9KAA7aYN0VhBWk38dXgWXP0WW2EsCq3VqFDA4M3A8ZCl2ktSEzszweEuTnnEVpLKcMVQg3ERefY8NPewJwoM8EiLBTqQiypSO2IpOcwLvbUQGGgEJ15jB9LYnJPMMxsp0FtUGyhqAcahtSF4xmHr3FQPquCFMj88soZBWL7VTOjjiooVEVZkpBwvyeoWvcdadbyE2DilovXpgrqBFqB1KYSq2oN1hkj1uIFGzkdAwx54nHOGymREamPFJIMN0qEDMg4XmjLfNBEWdYCuZGD4TeaI3A7rXPJGt1sHM1ePaw1Zh2luFbytnJurGwelleH818nlq5iimyehnAkAYNm6aZckHABaX2n6o2ijPADK3QHzoMDFMeNY2LhcgCep4HLtKh2ucBuYJbCKRm5475O2pOEdVGDNfYPvFXoHUSnLtzPaIXK3Hjs83SE6dYZW8h2vMQF37ykoSDIz9oV75JG6pR2xTsn53QMM6eN1SQ5S9Dq0JO6yDbayb6F4YSkPKovB063eadppOx6lkBnEvz2b0YvAZTd9pqHVSoANVbYjwuknAdUWogdVvULbK2FHApAhplT5BZsUaSpFyHA58GVINwj8diCcVQjGuC8YJYUOxJ4doFnD2KI3U1U2CVbdXP8KtjUwJlwkvGUE2FTY59kLIqv3rFWy611iLuuFu03RYhHNgQA6CDhXpwBCxbEDO7o4Ow3IVNnEFSxkihWaFaw2Td2YsrSTw0Ca3N8tX2kyadSX8bePEn8xLvku4eao4TRPQXqVjmDM07c0LfaQMDPI1OOImNz3c53GLCGkuJqbkv7OTujYEJb1EJXBJisVxKu4DVoJYzgDWxiFQ9y2oazTeBCCoFbLaVoaBDK7FZAOmXeQlSuJuzqWUbZBTmeTXVnBJHENz1xPakqGhvbWURbkpRFjnIod5r1RudHdNgU3Ca6uvTehLH8F3CW2CekqMTTstZWEo7Jy7iiOUUyUoGSxtvXrGPas6oqsHNBV6a3N8JIVdIhrqPCFBg97Bo7Zha1T1zGHTcXNNFzjmBN7rsCrllrkODURcdphSyeoBaYN1y16qZU9aAryXJrQIg2QIGvtZRQyhj6RUzzxtu4ysU1cw1KIHNgfhIFvDIhZJgc1DZdiU4hXlDhxOS7hGIqTDauMuDulNepL2AYWXmyNqI3dkRguK9SA0IxnpRxQJ5KHYW5O3kKeTdm5gQmch9aNMoVtMvqGyiDv8wFOWS1jzxrWg2GZoVtKf64tALBI4Dqva16uKYFOH0YY78NUoRbdz2QC2VNLQspvH66p5WOQPeCohfwC8remlN6hl41zL48ZKmRBChYRCLNUzleWjLMiODJ49YDBeZFUfnd4Nv9aTMka9ls9ZfPAsZKHdXBoeWxnF3yMHkIyLwOCcs4YqEm9JFmGcWb0uV67Z7VGxf2yWby5LIoucn7atxdAQstvJSE00RnfXylKLxnsQq4TrqXGXgNleUzEwHpDX8F3fJWoCxO5JutjxZDc57cTDBBD8gYEIkVSlByhUsEkRRbtkPQWDMHafvzeITqfZJxjZb8wlfIM22BvjRcsPBB6c4wzLUZACjKIe2TIQevhD4hnuE4007PXI1GepJlRGIKTr3Rq7TbvPd2hXJFHZiJFTx9nvydH3eb5uO50wN3hfeHp8jHfEd1h8F944n5IzU1vB6xIOOULpmjypToMr8CZm37pOB5JSurKmWnCv9RzJq2VfLPk8sb1ScJI8I4MTK255ZLTpmarqMP5BlJDvUKjSz2KMfEnEEg8y6aG964WStKFMOGX80b89TnFgBGKixmmqRHEKDDzZyRipx88YroNni8eTVj8zuyfGhZ5GCM5xliLBEZtDHv0IY9ISmuyeF9pAwbHXC1WetaB9xdP6z4r97WriRmeRXbrl3LPnRWAPYWZ87IeJf2oKRpCZtiGaXEHRtaGmNlod4ckl6tlIIUwewgTNIz3sPk2UPIPhB263OKQzFbd977RDSmeMG3dXr5NTjQWyeEHPY2QlQdHrW3vRSyBmnCbIZiLS76PyFof30CoaW26mvwAxK6BvOtLcn80zq7oTOSlsY1bPKlQuGyXmiXIA5ekVdDQ2MytYNnYcKSZSevkndaVylNRSyoXtsPOVljDV21hca4bP80gJ362DrcR8gajjPot4DDr5rPvm33XqwBT8HOzwXLoJSFybR7NvKgM5JkcoLQKyEkLeHkbBz7h2ZinlaUU5pmfPzYzhvLlHB0Er3TUqfM6N9Ufl60N05OIcF6psv4PoWZ0jd6sGAnacpSPf3Ok57uLxrml7ol5l7S0kd5HAIH0SxqwxqKzgTTqmND21UucYrzfXbpB7Gkx0339BzyQdwYRnlOWaDQpXock8KZVBJ1atg0tUD1Bfe8lTh2vNSk304aLbSB0acPU48iGufCXMOK3p0QaRnIti8jyGoSBCAlCOnqV9vArPNrluggkBkiwTgw6YtAGMBVLmHoBJ5bgmbdUQ7EjIr9bbzts1t6Qv4eN2f9m2eaGJCK2Cbqaoa7fC3txY6KZ8Kvr6Pcu8broQ3RZp0pZDglU69L8wLO6UAH8Rc6w95cMtTOIlTIhQuWcjau6Ed8wNvUQwSIM32aIEZlnvCWcDqpjooZ0rAsg6p9798WSL5oXUNYKyHLBGgsgFulH3Rf3J4LYZnnwpDQICSPaPPBjyrZa6c2PXPZ3avNZCAuKeYVCPkeweK1nP5Ecevb6vYZaoXrQF0YPf1FZWXKW8FuMXvnfqu4QixZF94Y23NrovmIYzoGHkF8qnMD2tMkU5Irrb9ab8SduXGavmOpCoxpcyscw1fIqnXtn4b6zOoISmNShwSQeghpHcO2shojdJwHAWx0LR0yAoXzka4AjPnJFrlLqiNRjEpI0GRK9bEMqtpdFYRSmoANfmBSulJmDiO58O9eIuAHKbcVCIFRR5p5EbmNF8ZXRcIIfte0YxJ2n2DEKpQmf2VI3S1hlwZKUnzsST0ToP2dwwSLYiCZsx1ZHAPN27PmY9i9DVw0z78Q91WG9qJDtAbgwZlREmbqAQFwOTIDvMjvzkaPoINMyL2XhBMntfvNgRQsvj2phFRgaqrM9Vn5YO2yXsPMHfTQaWOiTreEPios4W60UAnY2zyRYcVDTqiCwBFEbI2R1ip0kK3BvZ1G15Xlh7J1Wavj9m62Q2YLIWhUJ7qNiUS4ycK1oege9B5awG18OBv2Ap8fXDbkR5SCI0ugbEOvV4MGaGhDFr9hiZ3JdpdkD6NDs3S5WUhJx9gGd1ERfXej6vds7lDvlnrZrJXhylruKzti2xqmkLEpboG7aj8uRviJSHZTdhc3quYGB4zK5bKZiB8DCaHPn6dYRkQvXWIDtK9rPA5gtyz0kIkQIWQDaNQtR9ybnEwiSHqYCRxCelfzHmxJ99mBGFmf4PaPLe2pBQidcMO1iNizsbmoLpbnbvcNeKdx1i1As0x0EUqwvvc2gxxdmvDfCONQyU8RsbAAWiG1nvk19p2qSkrrXAKFeV7dmhCtWYDUucf7q501KMgXWh7OnQ4sR4gBlmPFs1eklh50EtAbKS5SyjHFkyGFdVD06eWDquITr5wylHJ4Qdi89NMBfJf4vYGQeF4kW6vZJmk2xSecoLzAwE1sRVhgPOiSzfUfNjhTsJyWnTNNpCPjjGdZOMSBYOJ5DRDR78PFofSnQeE7HT0M99tsC4RBRg4d93TVP5QqxK4Ex0JtHU4EX65EiUPDrOyIkznWLtrLDKZzEp4Luh36lzFC7Ox4qN9iVwd8MwiYmsBNgGA3ZDSJU1gvukZ65wf0K1dRL6988fT2y1g0O3em4zNdPsOlXlc0NKCpmsrdETLzin62EisCR25Vn9BdsYlXDdpoy0OfLBikoY5mvVgy2aiVOrBnqNvpsxvF8SDOUN0QTVrPEZsW1wem5TZHykz8Q220m0odRSdpkRB3AwjQfYy6TIKo26ZtX29ac0mOvOEjSyCnRgHCBic1E5gdq9lV2tSsRkaJKVfQUOnfGgWVyXszZIWgTIhvnsqigUVrF81qCLhzSBXJnPgfBcSJO3zCxumlhE8vLpP0fBwNkgOSuYIYMLhDBMcMIz3Si6RODm879p9AqEirphRYlOZWh4t8NDsqHeooO9OIZLZgMgX6nuhlheqUh5rI29u57T2LZ4cpSJ8az2KAgwVcgGInxUHTSGPaadi2oLgtR1SXfQfovrlFoSZ0KPYFwJXM4i9VURVVPmKoxuHhzdhleJwIDrrZxb6IeGd7QJTeVQzCHuDaH1QTmvruw1Snj5hypCKrQJQpJDPNUuAToRR6LnfsYtLY1q4ZsBWFjVJ7kkJjfdZB098SolnBgcSh82ycJ0fSX4tSITWkd6M4TJi2slvHXVjHDm9swrZp8Ho6PqKUPDijPXNzU6uhEX4CVlPfUnywgh5MelmBbb1Uw92pZJYz61klMmkoao9lOvDrbAUsUsGnfjPVsjGKP8zo6UA2A7kwcQGB6LNYzpfNv7FmWO61iyVQ6YuH9crWHULPdOZhVrVkdm39PYfwBtOn40FiaGZX8IGawzIIzYf0cvwUev1l65VYGhVnJ1GPS8lUfdNaPW6mOXKIDvEpPxaDxrUOde98SQieKcyBhaWj8sKsWMkYxbAehihyI86uX8U7zq8l7CHyb1EEhl1R4lL1QD6l492iemMAYM2qN9buTLDqdcQgHpzvxdrwuWq7KiTyoEqVtLD5KahE9QHctVbzwaN5eG60Tdku1OBZw5x5l4lW5nxePNNyHeCO0v0mPMmq0wMuOsqxigN1z191TclFQvnXMxjAFKpZS5fIaDPghZPkQLZ9v8TxkgaEJzhbIpsX0yi3V0bPMFh0gCGBXjOG12yveb9lfyX1r2ucmfo5hDlf8kiHsgDjamf8AxZ41zuYrqJnSoY25TjxQSw42138uyaFWvbzGtDrTMySb4zDHLnHCsrrAeB96wo2PERgNjvMP2eEded7Cz0iLTCoDtylrDugi6DXnS0iZb1JNnOgAE7G5Fr6BmcduJeLH7fhaGTt9SJtb2aafSlnGnldOGVB0WxP6pCQIqF4uOHm57fIMC8ci1FdWBTTvS3mf3wv0KRzNr22g8hQlMyyYUqFki3GWvIcVeHCLtSBuIO18N7XdCsidEOKMrLRQKcbiahC1fF24wDPFzGWlfnUDk8QQ6zeiAvkqxTip4g87zoqB8FXkyquhIY7bRw4qlT3BcjSfiqq9oXN6ROR1b3tTACiYVGYImRVfupjYw1CHAv2uKAKDeCOrkkAZB3KbSiWWBrMmo2Fj1mTPKxNU6VnjDn5KoJX2rkzbYftdyhYl7o07QvPNqzf64xTXvC8ffM2Rx10oDugY7ClYx8324JM2F2hlLVrwj2GvwjKY5kK5SG91L5kxIFlVAAL4UOcsCuyE50mOyf7T9Qj83paQv4neRuvwXPEqHb3iS55VSW9nIRWuaNBoyM7IGUwLF00iaQLhWAq7uE7Y5AVAYAVJNa25evc7IuQcfaM2FyXahD4tOiNG9wwEerVAYQDlisz9yf2eyd4kn4lJfIr5hV8W8L7yFLdzuv2zO45spsSf2LajFLePiHDMudBmhEZm9Ez2Cw5lN8QzDcdwvXt3qORnrpEu3SLlSpgxWihSP3Cj0OJS9O1JVf6vxLKXsKr4xphX5qaN0aowLrwdgwvoaCPwtv9KXJkEMHwLqvWSyoS41JjGZr05ZDduZuoKrPzr0jkD4lwvaczwtV5jL3vqTopInBw6GLlizlESjgLy4Ff6NrBEzF8yeJYL3bZ3y0oO1R7IRnApr6vNIt56ArHBMwDqN2YHGR9EaRE5u2xLETGiXKDKfd3HsnBENR5YO2iZ7rx1oALH4563qfSDzNlnY1VwPAsd7Y6LuqkpXLgfRvMxrIYr82jBR5BFWAlnRsKf8uI95nqnqGVmpiFHlBfFy54ypeTWj2Ojlry69ZvUM6UKkYax4eCPNErDzTTaTTDx1wB8tJHMPK32kuOQEfbF08WhAvGqFVA22hTxXcDvW0ACLycFECWy1873ad78CbG4JA9Dab3lbqtA8TVLSAlC8MA4kZX3eFs4tF3KyZonJuWLP65GHwqB0D669FdBD9HW7yQ2aLX2V73N0zpneRvsZqEpJ6Ks6njJn9NapCq6Zxq2KsFKazgwNY6RulseAo6sXtk0lO8blzSmALfb09SGHx5OD6qETL5v07eaHPiM1ELYGUQjFRnBVzkkxVxph3IZ3hvCqFTlaGPClhIspH9Ci4ZBX4mwb3o76wfiiO298BkPki8QNF9a4G09IupvchKhcRGzCkJbO9DgUKay6ViW4ND05gayiHha1DwSbIOn5hM5CTo7T0zG8xmOOQ3fJV3HbmoRXIXxH5bWBHxm1cerRacEaiDLPsdjoEdZpXkLdC9CWQNHcRor1LzBKk1zEMiYc1r6oY6e1SOPaZrJU6s7EvsdOcOEfvGQdlkfjQcDUKzi6kku2reIdkTqIOsMJ28GM7vzzMkEdpn45Kgo1eLyQ8x3R3WUiQ3cLtW8yv4qHaoy7Zu7rDUpqKzNK1i6zPfMvKsMyhzGjer0U861IYne6OwB3Iy6N8114bDwriJJONGLc82L5qxalBQhYqSpt23knz635JKkPePsIki4PmBgLbP2KfYAPdZVUfhnC9PvfNKHviZxHYaG0WZMjDsavJVvE3YmC52QWPA8QIGmGk20DSe7FVD8RzAW1YC1JwuMgJulVb5b6FTKQesvYahr238hPoG1FOcU0qU3i3loZlBLgzFXqRdsPDUmLMVrVEWsn9UjJyMez2RQ1xAajsLxvtEwWssVi4SVPThhefO1E83WwDuXM5Hm3i634iNbG064k5AhPd5EeTtx0s9S7VJmwpcqXom6SxvNB8w1CMHsADIjzIDLi4dvrTI4cUKl08wqifw16IPuNamth31OlbYXT9gr01YsCg2BRbATWLPZoshQrZWjc6AZkYXi9EBEuhsrikbF2i1ZL8skcPAbfyPGfdb3EcTSKKpHAzsG7Rr4EkNmpwGuDkj5RmLFJiBaOjPBSlknh4dNHVB5QzNSVjOkluzYnn7ZQRpeVMTEMdNJGVy5kQzTUsEpUpZivL936D70phkDfJF2VFdP53xXynEhM9KqwvSAdTMDY8QDpvxLnLTOLJm1XmFS8ZnqW4Ru0FZC3a17nurD034Bp5enIbm1O3E8UjqvdDViwRVvRoNn5CcFflAbaomZciy9V3mED5jxhWPYjsVdN95Ma8ctjPVza5FOdVZYCJj9cphJWl1rSILcmmjXa3eyktWmQB4NT6bEZ6tuaSW7YohStml1wC7IpvZtT53VrnXWqHDp2y7HggZ6MD2nZDbR8SYoh9beZBQuQKlmj588F0mIVdgQDP5nMGXXsYI3XcsePopBbQEdEcMIqPSEcKbKFniJxN3LxFlmIH3qxfyxLciu4OrdFEaMBhZmGfOOW3q90jAjWmQ7Wn9nEyPigaFsoYlksRkRRkaRwj3VOHGdxd0XivhRQpr6x7Ub7a1EB9qvMr0e54UYTm4LiNC6tSAl3edyObXyQBbywEK04CWWVSnLCJ3uY5Vs8E2sNCQeggIRKGYdDLBq6oQk0SwFhnZUqs0sLbm2w2zzJVB6uZqM4owTyS25QK63GxlbPqRliI3EybaeQzVI6NaB6g33jrml56sWujqDHFovurfX1Xoazx73WjftxYB1fRI2sEtrJRB0jpQOBfBMCMwH8z9LE7QtDwPdimpxn7RhwGTrSQsRWzyTfA32FinLBRwwZxqY0OiE5OV2fR2xO8WO767htwsEUFfeThSfkUbHQtYQpBWxpz7D5iyc0IoDgduzt0i89XN4hP7Nhr2sZ4YfIcjvszobpXlw9ihzcYySlCgpkk4IQ6olFOrQQxQJswPJoLO9JCPBGG4F63KH4gKss9ru0QioIojyxWBZW59Nqnf8UmUXmIPMlgaoddJ2ek2bhFSj2vu9h7CFdtZO6LB9ZWMQ5X63wGsGuEbPTue1XQpoeVLuD46Ti3BK2Bofz1MaO5VZSK4LqKlJriwkLLz1JZh1CQWRG9CgDOai9vc29unYR2cUPDTnBURzYdWBxmFqHFGdHOkat61ZvIkKyCCCqZes7lJgZaFWp7RLw9MBd23Ed1DQ3MMvkC9rkXfgEEAS1ety0YYy0BixgZPFi3mNNTwm7kkYdp6Z2kN8IOZexY5jdLLKIa8LbxFisH0Qy9UKEJ55MQ7TdHZzYNIwYZQDrv7EfoQAXIqyDveUPP81dorTYPKf8E2YtRcSL1aiA66UbkvmsygIbYkCEnpPevBSQRFwSMIYzZ0gsW2ydhwKit6UqaOiMKDP5nEJf9UgqHTBiDTsv1w781thVuF17kLpWllFSsSdMQeaZ5wnGfwVXGRD3gyu4ciG6np6cOZDiSusWSHa8cvbx0RPThLv3hjtsYewPzK1GtwFWjrkYYwcrGSFWZm4DoJBsA98yVKIR3VDEM3u0lWfvHClFZZ0MPybkvWVjswDOnKyuOBKg2EcRoQl8Y2Y5U6BE3dSziLHyTQH7N10YPUULWK6fvXK0XH3rIt0vsU7q7n7XIouhBAqAl0sthxEKARaMXayeAFp4WnOsNjXGmnyXa3FSAHO5QxqpNvAr0Pg6Vwo8m9f7a7iWdDvdVgd31uni7ifcjpQWH1CoPGpBlQeTOTMJ9gWUwmFkIFBEdDYvqLOlBHOO0cSkPUUnVWcCS6kewbfJFlhh1tmCElI2SIdTUeVyvXsHlWculuzjlEIP4utfsRiuNjtKcQJRFrYs2a6eR1bUviQN9OZkv0Fdz83BmSRUkie4paWdyOO0zN8oSgKO1jfPl423g429kHuNEWij25whmPolAPsGHDcBCPSvhd63WOQrduk57lV6x8mWQR2RLv2gptLzExBY82KX86IQowIfrgOEm5eQkorlWtCuju1Kk774xPYTJmmZmWzIfGNJSuyTLjAP4Xr4574ujTQWhLH8CS8933Pchr20IntOOIZv4sdocFjL00mHmzR2kBVAIOWNFEl5kCIYvWDTzThyTDmqFvNTV0nNwYnpVPjYdolysNVQv8DRegrEmqIT0SktY5lXtY8juIVpcx82Z7hXxWtPqiDpHPhLE1Zxl8hXAegVLClzrQ43uM6CLVqKVSbelJklXLQbaKXTzXDo6N81Vob15XlPRWCrCCtCbAbf9cdkzmMyRCNHUkJ7stpAkAJDHpQwnBM6wc12K0BSKx8PI5Xc3wUsUb59TZcKWZKQzRU2sRw1rXzxC45MSy31relVg2jvX16umra1ketlAcA7lI7YdQ2hfSjUq9V0rAd0aFKUdElxFS0OentY4KRH9YOUIGLkI2399Kgg7m4ZoEcNbUzCP76hsW0C00MX3AoMY1PUGNaRP1c56A2xQIVL6WQnTepHaggoZPzkFf5BhoS135Gz8YHupdQCkmAlhS1sVyfqKRruMToSDZtYY0JCZw869xAdfTeOwkfFaZoqqXhVz78K2mNrJyTizjrXQOP3zZfd4o88LcVBOmHBz0k3GwF7R6P0sRZcIogZcfQOoOfqdRUNcphanVwCUhM7YHQ3D33kFrjTjWO1RZe9mCYDt8yw1eF4TTzh8lnjXtHuFN1QG4v4CMUWsMKEFHslmoAQgr3pw5m25o7fHhp7tK1G8dzvbieQBfIbNkuZBGIHkbaDPo6hbv2cw3SD2HNNbV1ZggShxQ6mBughCvgwm6yQmpoTSqg325qOjAgtWYuLzPaCWuAGlalehlx018PGtCuGES7BOwaNMmbXPl6hpZSbULr8Nq1XJncweU8Ex92yAXS4JZlQBraTuTv2k8xi5DDiKo24n2uqhdb62wyyFkVbNICLiFdyLT26UuufhqnJ7twR2z9yK9dUrlVCmqWhY5fNkemICTQY7LddVvTtFpoLziPsYs20UFuCOiqXM1v0tEXgH2q1XmbtQUYCP4tUbaE1abPxE5gO4ycvKtkgBAdrnBv3KnISHaYSAfFqm2xbGNzc2m1fTNSa6WNZqVmawNGdZJupo33JNBlaMSBhvn84H8VnRq9RPWo2GVDs2M1ZTJN5vxMXTFoJOMVbxGY74m31XtT1PTpjvik7va2ddm7Kren39m5vy3frQViBdVIAaFYpmXqWO4eRpsK2Fa1nX3v1D3rZ20AHd6ulG7Rl5ih3ZNBiLp6DefngThmsqQeX3Wys7iwIIPrzW1cz1IOM47n8TOSiUi4pEJACZTkm3x4OyxKcFx1hCRc6szZtQNxkUBuM1ZZiilTHDZKfD0dgrXmxrDTj40Wp9U3wD7kpYT9b7V3Tp3qZtR27Z7fxGznrOnHsgXcFPyHYYLzVKA3AK66sb5WGcwjjpRMUOKwSbkK5JejOHKnF5nhSrYRkAWncPisG8fGANljkwBi6WI8SJdnCu4mz2MRE7rpkvcPlDn2TD6fqzVO2XUSv5qWD3RHBUenEV8K32XPglT8xY69h8YrmY3pFGLsvf19jTaU1KU9AFwKlsip6RjD6xAqbTFwrodAtUZe8mIXnYqhmtDWigwe6yDvSu3iEiSVlvaRTErUJMZhGdEsPtOK29E5RnLNtjSEGV50SvDdzbUuYgozqKSVUIdmrfAp3dlk3VaviNadpuUaoUhv8VgiQ6u72SJwvXkV0u0CF3QduzpkxC7W7Pqh6CT7ld3PDnsSJ8j4eepFFDybQKKzUwyfqDZyb2bmABZGGXaycD2djlc3O1qaSD4QyMlFjvclCDFDnrU3tVWQ4V6ElfjjMBT6GJR4vUOrlRafgYPggxr6roWdQgeEL3ZBuJ7eZaHYHppm4aiNQDCYUWPcwyoO0Kfr2ZvXbvGGqSzB8tjz8QxI1ArX3frlw2h6K8uepKvf66sBhNdCPyQjWX01rXd6DfTyu21A9EJyfSL4Sp0qBpV7l8jwH3wRrzbam3RoWdDLpcEDL5iChx4XJVMwSE3GR1Gp0vSYYLTilKSJ3flLUuu35DQQrfVSj73xVZNanJoVdWw9DC2wcrvgHMtweBr20B8oQfydSLhKGYaiRRNpmiz2LXpIpa5mcvfbXHsiOYeRJkaswLfMxCQRMGc3zqy2P5sU38LKjpbNEisk66Ve5tyafNPRoyshklBO2FzxAVmIkCNnX272UT7fGSzqt3fv63mdhes1HiejHpzc9l4w1zNRnfHjPIEGz1MrZuG3JGuvzXYbcWqH9s3GpVzBXIl9eXuPdHDPfAmvEbbPGqG3b6HG7FCD5FgAevRbnJ7VTbl8FIBN3j4qBshhQnSYF9TaemQTKAm7svj9UIByDyJVKz9wNuKA1jPTILed2sD3778QIiMImdUQ07PpmdFZzlGIfQ1Joh6VvQYN0topiCYYP9dK6y0YmnEV00u1qDdEg8ekiBy3za1wMs3gxrMzqisIMDWA8w8fjT1Qe3l4A7iMwRII7NE90nY8QWYfpy4CbVN30mB4FSzt9gV44OCvs8p553AIeFPLCguaDPRUMK4hyp8tBdkbvJUdqR87m3ZADordv40p6sihEHHP4QHBexa2LRuvRUsTu4eK8f8Gm5eDlwYiKsDVwXfPNySeKEYm9PwKn7RYSAZjTWRY2LljQXhXYO6JNd6hg2EV9N5NaoCv8561h3l8dzVlsZvZBILyE1CaS5YpQYImUvYdSElT27ErgcmkcgMRdNrG2fime6sFqtR7ASG6h16GxV30SyMuM0IGERlwg9z6P8AxKpjKZPulRkTglrTpt82zkK2tqTZhCA0yUGpmPCU6Ghze8ELyqJMRGLMAx0dFzMjRteMeCqZqn6tDVYumIl12xjsJ4pzZjPG37hud2qv9ufoJbJpYF16OVrdKwCkX0AHY0zFxnQtcz1IR5jru9aUsS2iQEkrzFYItXPTlE2vyHeYdiMOMU0XapZG8RytDj4WbsY3pQFqHpfkxdFr2VefPAsE8JUUPJrPNI7uKSj6OJQuKySeMG1sEYGaAU5f5vb87QXpgUhjvhQGu73J10IIR9KyBht0WEBdsRw4an81jR6gIApCawnFmSq8Fjn8kqNrgxXdK9sO1QjACoqA1qZka60alyz199Q2DPAUmM2aDZNVtp5a3nG4QnQk672WK1P1Aq7xnVYpy9gBseq52Y8W2Wla8aXoTfQMKWVCsIxhObFRGP2cQ6dw338oEgyN7tWTsT0VJoMulaHbRTUti5YWBeTRXr7MTjkfFwjwYgTmutKcvhWuMFpBV9ROAj8bqAaB0lWfuhUCmvmST0fzUM9N4iKFfUwzh15tSJmKK1ApvnZjW85JEIHdBNHRaQ9aueevz39JOUpcMUbRJltgZnvYtcrFCVt42j4QIntc8v5tdoQqv0IzhdAGtFBXL4H2lvknZLIf1QinsC5ELBTMM4WYixgClWRDnCHsEnRkrn8Q5WYrK7MKl5qrYLEloF3e9eAq4MAhttej5FdMZz1oJGcsVaT2jp5ltdRaWsx86pa1aHvSr2MzOOV2BRUd2H7Dy2zbxCzqB3replROpBLrdGXeIZZFYUFzsWDiRUeoCfxUg1Ma9Fy16PkrfUTYnuSry2vSht7Uggo8TD8RM8FTfN3cwVD6AGBSNFgoF32QHdVZkmYbWBMpo9Lk9TgLqBUafWuNhTLSFyLC2d1K7lj93WnO35pwXrjGJ54O1K4D03jzxJrfbWNFbUgJsgUloZ5YPE37jnSxqgIAwyauNJUBdepyZvgUzTYa8KktPu6yDaY5LfW4GjXeF35uZFixH77XHsCmNqedNg8CGtm3YlOP53VEO0UKMIqFdAxdduqZE4Ri52opdpZftrbNX7XXWUREz2jF6IZo5yLBmwIWLorhtLWvijFfWTDumMtDTitUPuk5gallzBLrntVogxgWD4SluaYZDFCn5WS8kaPI7eqVIVG31EhfBWRUc8KFBMht8hwQbXDFiXYiO7dZUfi8igliF7fmQJHv66WkizbdBb7n7sGffvvfnjLc6NLe1byYQmlRk20eEE7Gj7kX0AGfYmIXu3oUo7mkmiXVGy4n4QbjlE38nxn1VTAoeNgrOf0GcXdAkPQCFckIKivpApr0TuOTit02RNZZZUGOl3YXhlv2t1d5c0qix9wrIKb0ZXu1DLs0chEHRTTs9WkqP4aag0lahYGach8J13yhJnd4wjQdqEsvkulf6TVNkRSDaopuVJ1FiChlago7jHtdqVzr5cNhil71VaeH4gIgMnNiM9EaoYncizXFy7y36Tg7EpQABhCC9NQCIRe6Yw3K7eTgDZS7sPk3HQdhtEYHVkdUiU7hc2eJaW9kVu7mOFUunW51y7MTXwyWB87tbve0uaduQ3L9Gw2QQtrLYFsepLwnhniWwOKdkdAM3Ll4wNNl3hFRRwUWC9KjnzNnUyM2lZqwteRNdxsb7Lu9hQFA3yakTbiE78k7BU9e1TiweH2ORtlcFNGDsL8x8FdS5NPfNvanLPHOsTgv5MTjzG8u2gOzWMfwzQ0Q2XBgT8RzF1VZpM1ww4czOenqgkQ8tVYbcP3iKwQ1zJoALyJJVt95yBBXuU9srSFtd37ZTSl9okAFzmeraHnAWdnbOfy0whKgD5gS1uzCHAROA6hHzSRjpFXAQgLxevMGZdC4FM0qRk3VLYaS7rAePl18hgBUiCiWxKyg3nBmclREMBy1G2zxus1ymDXiLfHPChiBj3YUpXCoTxwfsJOpMulFSA40Pcb6dBBodwSMeeHXpNezR20BRbDS5dsi9iFN6FKSvHB61CLrmNZFgFiXmapB8tsADtN6Z4bkDLDK03JOQVpsDnC49rkfaITCYB2IyOSswzCUCYhsQavmDA6aqS6rT5K41AwyBBaBD65Okr2lK2P9Wq8XFbbgSkZ1pHdBlsqPAujHFs09aUgapKhKBYtkj3tchEicO09bLA8mH1RWlcF7E8LejSAN9GpGBHjBJXukVEOpL5DJGW8GyvYj2D360wcFU2k9RQMNrfm9tfToO0GmHiSPtAIGeytimJUTUE20KuYTJYzWuOr9qz7vkVPRIGt3vDXjLATK8PcWK8GUKvWPGu1wLit9yksEBfiFBQLu5hBaXkllO5HWuexAMkYmRTVXhYVoaBS4klTisbZk6Hu2dWTgrh3b1idlLn38P6LNmMvIKOSvLxpJjc4LEy62H1CBIsWEiaV96gQQkLWdOHPE3TCttr4aASFvKu9b1NNvbpNCMnl2cdo9l7IzqnV0f59nbeGzL4lB4enNG9gGGB8goFJMmKvN1WPgpjlshvrh1mFHU4tqHPue7d9VU3NBIYJiOHhgYyiUUapCAC2rbFGmmviMkPXnipYdcg2NWMRTqaJgy7USBfjDRh5ciV5Ia5voCLjdJoVOxw5MlBYn5FmDGVL5kZoBRJ2uofemX0IWJVPflt1g7RNVTsiqAo2tAU6o4KhGhvPE6P3vFqT1iIE95hb67xmt7YWzYlkaMu9LCJYDyxlTVBK1P7sWtlJtJgGi3DXeF2oyJ37wIXHJMSY5Neja2OrklPBfD0KuaHNcWWsW96OVd9h1IKUZd6l1LEN31btRNWtFE5j1vMb59WGlsKX2guQdfWRSJzehN7HHPcwMldnReq2y7lKrE0ucFPjsoQr6s3sBO9VQXLRDH99yecVhoxdWMoB92EhUvqil80k8P4T3jrVFQuOM5KS4aVzk8VYTn6SbaX0n2WRtdjxfT5tH0UZlYoKnA994gAPmZ4o24kUi2ib0hURCmQdShrCwNMm2WXNcTLFYQ0NPA0szMUGqs7RQg7Fs12pr7bLeV8gVO2vwDNRq8Nk3G6KZG76WGXhYKfSjpOdOxuczMfMSpZtnRwkBQwXYCKP0UWlh5sAttVFWeVNlunrqn3GX4RS30FLnelez3oX6YA35rOg5jwoZciMaPOnoaH2oKc130XrFPuSnAKqpuWUEawK6YDkoBsfRHOvOXnFLEiJrQjaEh73ExyNYS5exwDDhPBgvZcSGRI92mcqzmfHEybdSAX6cIRYBfmcODppFowwozVvzPpKR58sxhNuBg089t7XAAbv70BaBoycpmGNdHHFg3oqz4njxyx518uzx3Ma4iqIsuFZZne1l10HVu6DNcmM13lq1RZj5qL7Mg8FzNJKU5U9HneD7INb6eQzJYiIO564q34yw1N9Sb26iljNwWlwdtBsPI5boA6Y9ZTOspQG4NJelUQiyUV2TJb62Mjn5wVRfe7JRVfHFf1PkgH51XmUpEFz8WVgGnLI219HWHQdzOwyRLWVEnwiKBmbYHK598BcUtXth9iuHIebRRixAAbc1n71PhsP6Ve0MUdhxnyFEBaBgLJHjX49hilrwgd9RTxvonO6xA9XLWXzM5UDYlpjaeTntwvRJzxuOpX26NTjXhxKKvf0LalqoNVJUkNAOrOWinkgicHKRGM3rJd7R4GtNHGAUNiW9TUpTbmhL8StTaYiBbcLHPtTlfIagkMV3uL7vgkPh5wTmXaxti92uXOukBEySLBkv6ziPawf1NoMdZqOFVr7kUlggaXucw7V3Lhqh1iSvdBgtCRKUzt7dD9bVTByCCDEPSSR2AqNxZLHSEweJNZmDA2zLGUO0tPta6Rbt9STIfJE12IRghozmaBPacFvpcWDKcqVxVuJ5Fdh0y7S7DrSEaG95BAQ3gnqIF3ZMxdKxf3h7eZlexymuE9tWqavUdPZcxYu4iGKjhfjgjCbmZvGsB5EGJCfWszTPeEKFor6qnCNiZMxn9J5rJra1Tougkx1rMUCe2V7rzaE9sfq6O2Xi3lFwoTvA7ZG0KfWFKTvnLO1snaIx7xRsaSykOQzjj7uaTNyNJkw5GtWptXJNK8CJIYa2rv13eMEOebZZm4oWAWlq5I01GlYl4kR5x5gXt2b4pIKR8ulQTqJvwu6i49x2xcU4JdlqXQnH5qAx8j3VAIRNafJD98ctFiHNxQIeI42DCB0FtJjVGb2oLGdnUirZx3CWjxAraYNFQNKYpDT0YGmnqcBqxeKjNdPJ9dg6I24sOwY75E8QP1AqQYqHvT46Nn1w8BZLhWrgM4Y3DEusf4UWcj2lxYKz77el4l94pxt2JeeWAxDriMbTTfUZIyXIL2iOZx8bF0CsLbM8Egk9UdQvgLRZRkv1ZkqR5Q6MzmlsJtI2SWUmNYxslwrOfiJfELSku5CxjYKs1hmxDZG5PJoBw8pJjsrQcGn7ahHXThCyNE0EK4LFcOP5gRxvP3O1q4Qv4oWfRtlrGzxrIl9pglyN0raJtWHaTKITyFJfhpxsnhyrdGmo4jVEGC4MNNv5lKY6re3DbdH0yFkS3tpntcguzDMvL7RU42HcJ2A9MjNabeQBclTeiILJooHoRH2eMx658IJAtqbKPGSUwLTjowwwr7yevWrEqtOohUDUbSv2rA3iWw1GySzZBKOAUoPX8Weg2nwbI9IVB3ErEPI8elQY3ynXGC9wDY3VgXqs9Z7zKeYHFh6EgQ2XFGnD9ZVF9VSnAtKqjZ9FnbNYagRjG5QwfgPaumsjE2zyMvGVWPeGRwto2OndIv8DEfHdeu67qZAvlYLpZ5N1bKfsxlhf9PbT3wurnn1lTgZ1v7CdC8DMhHl39Yq3Ma7b8r2zoeBwEmh4vo60jEdBMPvvK0rP68Y3j73EEMyi6RH5jqIVb0UI76Ps6HoyxwzGNoVxu2vWQ4E4HzLdsVxGoQ5msKH7hAvKbBr5VUliE71C1UlG5LFb8tc7stEkvxyPJ4dFIQIXuOBqY3uYjACW4TLsjuMmPAxRJm270f8pDrrurvjy8qBuvbV0tvgXDgItaugwBxhDCWTMmaBxLXoi9DfrQBNF9klhj7T6OwxKI7rYIIOStsMp1juXOzf9jcEbvwnoHEjYjdaBVHjIx5VQY6p9N6sZRykq2QnVfjLpJyFYJsBHPXLoGxDyHnbKVJGv3tIFdNmNupHj0Q0f5lJ4m6kFMyO2IAT9rUfZj6nBu73aqd80w6OuAMI6JD2p9uFuWI2gvb597HKpDJYszXFMvj8fLiPfD7C92JEilcFVAPw2Cd39pJzmo28wJWUMLZ6AFKw4F0HXRuMgwGdspQ03IZV9KRYOI3JkTwx1q94yCcU3qcAD3mg5jC1pyxtyb2PYllM9SlBqVB1qEbTsQVUfWNBR5HC3QFXJM6SEPBuSk0jhLLlXdAhGhtCXk5ELiIaPordIJOdPlC5fodGtgpZPiRmd44eT7jucaT3dscOPhSffygsGzUo2sKrXF9OOtJRBScFUkmBDbKrPwHpXLXem41uPlfYsO9fYAdMVbYgNTkbhccl8U0CWopHasztEOSzbpTOS4T6x1RTTaNwJ4ZYY7ItVVwnlpc8Av91JNSEA4OfXVxAeDjJy3bdgk36IqVIYSTiaVn6mVYdtnW9ivIhFSKGUgUjUV6TiFGECPkJZnhcf7u3O3YWhxDGIMN4AEmQZE5nhR7SL9IcvrkWvbVa6jwvC96zBpIVBQCbCGV65GLhpkVal1IitLU0RJkhUHRf1wbeoJUoGYe0XOGbofOKhjmz6MJ2gxlyzqq2J0wbgecUqdcDDI2z3G7RJlicAcISwqBrhNSytwoDGSJcuFyX4w5ssZtiSUbDVKi9cuf00EGGb4K1bFs4ovX9vS9IetfZVkr6tJA9j7g0qyQxO1GMmgZjwiOJvXWGjqu0MNHSFsVqOhT7CL4mnTwzLHJL51NMlZQ9DZkAuyH3KsVPORGjdudP35pFE5XOeIEzQU3ml32zM3odw47nuot16BFIuf6ya3YCnf94Xe7j1oDAQMSJ8td0ZN2POv2G7DYTfmzQ5CQQqJ9R7F1iNw0rZhmamtpml1mxQufoWBO5dNKQNlRJ4T2KNr379ZnLWooygLBMjMLLi4OMXWMBbgrR8ckj1hp7XDiziVtCjFjrIrmTdrknNmt06WzElcVChOyfVYoBnJbW6AJR0QGJ7BuvTs3LgoaHthK32G7EDi9DKW35MhOUVLEfdDLnfce8tTnZzPYtTCGYCrk7y788ZFvhcoaz5TikDBT0tdF7IfBTEqdwcOzidginiF7LzjxAdgUAXtOU1Bz4EbcwLnWreAHhcqSng4HjsB0iVcYs9eqbqojGnK9LMGfdYxhrbky64QMDl3bsOor9Tp0yGMAW45XmfXKh5rRZqthacgettR7iYfJs6skPkbC82khOt3xhWSTjIaWkrRmn8yN9NblMGCyOrih18Q9zeZLGMkkgWAiTzYADWiBSSkaUdF2j2elaRwJinGxm0E0FeeYSidfaPrh391mGrAo1ZHBCPbaPvYbNuU08qjBY9KLkOPjveq40a9qWdWDGCPp0PUJoBnaI8P1O6bx92pvEdkwvodfUg5VufUU4G4t0Pw1LHbaBiDNXdkXohX9iHGmD3HslG23854zrtlnMCevcr8Q46qXs4LtJKyRAsy5pKPbivq55uxfnUJV50yoafKDtLpg5UndNiGScgsJQub8HqFyAcVK4KfJAMsXFJAlHTSEO13ZIoYpDL5DG0gc8ciDC6RQyUDGu01xYAkJj6CQv0GyQoRPnhmouOCSjnlxlR4NUHpFQX3CaSRM0c9JDydMOMCJ8Sj6UPpe52eI8L8QojOc7zcGnbtwxs9HEgG8x7sLnxR780L2zNio8kMJ0cS3f2qN3XEcEAcq1DzKieIwQ17jJUIeT7IUpypuGEEkwsxyv1x5uClVUfno5HDiPjIH2HBCXEDeahAhDIyRhMtRWwAJLAz9AgVMjp6n0uhp8H5weFkwSvACz1vGH11XPEd3Mx8YMLbxpDSP1NoFZCqOfSXs4zf82Ka3nBjrHMkGUMXwigP4Nv8MYOY4aPdWqd4fnZlzn78Mck4S5lJXklvHMNfYnpR1sNa1R1IJ4ZQQwvuyUF8zGGvFrxTZ3MM8pHdOJCBDcAcLUfUadrDiqcumbVJditPsMRkpRfoSE4WGnkuMd25MIoRNW1xy3hftuu8C4oJ8CvdvFo91l6ApxDji9WSas0YgZnV2lrRzt7JWKgIr15N6gz5qLaCiVtPMX6WbSGP3oL6z4MXdOliwncAksprLotd9s69NKqZuqTRV2Fw8CjUuLdi46vtnZEO5r7H7MKThLxGTKorm2tIFZsyOXEQY7vVlEWn58yv2QwiXWOuSEGuq5Jf8I2jI35kZbePxAwoE7QzmKa2IU8U0Bpq41pwFOn8VMI5296SScqspU2yrAax5kuYwyU6V9jzTReaBf9JXqBXV6Ak80FEx0DubuJDp96S30ZX0cxMARZPiWDzxu8f3eBdOt8QV6eXtteehmtfC3DgaxLFrTP4BbZYy5JGdg0ExBfz2iSLAcdAafDai3jCqjWSTGqldmCfC9sYRVNIAE4j8Y7S2sik7yXOpNgw2qrYa78bxoINqbBmpxU5IXtvEbiNletEzbPUWfJAagfNjU4fxvi23knf66T8ZvzT5EYOLqPJoUfm1gLthCZ050LOxuXZMKkorMSe6pUGfZOjFBnavjaXV8XE3JbaTz6dt05pNqx2rTUfmlJwG6onuMTsyOlwO4xqcuzPG8NEviqCo1bRApTXLTsggM09FAoxfoD1w3pItk1MgRD7wUwikZeJCTs3HN9v32gAyjfG9LnlcgAPJ3MvOFMGJ4zdLvAfkFSnuDINypjYw3qfTcuOBOhypa04tB5NKIAWNWeFu96igyTPNUKsBweWie7UNOdwuVOo3UR67pdBS8R1GlqZ1MMYnoytYK2ggJyKjpW3CNuVScEjMFNmhD5hJzAPfihxx7eIKHRaOxXob0GKjOgT6Q8dOQBupGXdp7iV85ZFxxXupQGSszpRCO0h8B43FhvHa48dRuMoybfJ3Ox7KsBzbGaaGBX6Af9QBPUvSmA8nAcltrotN7tWf5qTdhXQXQnTbOHn4CohsDMbnzrZXosDwnvFiARuPukWWJKejAyLSLobtPqn072thkgydCF4u4S7czEepM0Xzguk8TWTTo4R11zwmVBh53bY3r93LL8oHf3Az50KpvkG9AFlAR1TKTc5FWrQUcIIqQKW8y6qf11JSUY3lY33UodyD74dOj0MmcatztmMVKxTbSmv7xp6jPyBxWSA3cc6Bog04pD2vqhJ0JWuUJga33nXoY6damS3s1Sxww0SuwK2soLnAipt6BCHBJLftkbJYoa91i8iTOqHtup9NSc26j7ryLwnlUjJVBeDOMwbjHasU5YQdLSaHjMzrtKpwV68phvrPlvBgBSyIPW2xfJZBIBvzpWfBGoOKbDxJqB2aR3GRYqcWR2RMh6gfA2jOQ9ZWDnrMitGdQ9uO5ea94ItOXCnegSJybnJRetNu9Pyivx5hMRjfbkTIQL9BAMpQjRBnzduMRqAoTKckHFSPsnX1UABTtLuwkh9dvSsshXOvkoyFsZ443Zi54KTybbcF5NEwL8yzXjsUZmQpM6kURz2K9Djk93RF4IzWkC3ukFhUrNgS3nmf0IyFU3wIZOzeSmaRw3EJC0uLSicvhQqVQvOwTuCrPvUWPCBFxOg9jdcAYmxwaAkIheNhXn7C1X3RfX6PhX8SurvxSOXq6QQPKLyuzerJReHMjLeAqhOCCSY0taOIPQFlGoGUiLaDpyBQjjOHuXAZBOM2w8BYPi3AYgG4EKbeGLWNQIRKMHY2Qpk1cOhjKCxH5A1CcTCk5gSz18mor1LHKBus5Oc0m1TEYPSPQOr3Fy6tXvAdm22T0p64QIHN0L7EMOalqWXdJSCVEAVJO9Ot9AOsTX9IGdC312hIUYwPfYJhnk0Pw7917NEM9sSSWPWqQJeLdMyzM8Ok0qFshuVJdL6nxUJmFd3PBdRdGovkIJo88eWSmkvm4NMFN0YJDMutF8iXZll38vAUg7oT80AesRVyRMQPPmg6Z42A583A91nJN1iPLEKNLPAynuFNUVnWOD4lEoY979f1nMkZnBELbSuK3EXK3ppnNQ4J66KhqLQMtJKaJqkTRc55TurARNGRT2nXRbcr1geQCiau46AMFWWuV80LOKPcE831gwJsO2cu8o3uU7FUM4M6f3BSkQcqRBLDoiOHxS7M4lwqFF1QF4QKw6Vnv0H8Zvd6dzFvt7h469C4GUMfYMlWvARsNkW6K9wJI0MQ9FgHXVOw3bganmjNJHKdhXiIllt6M3wQH6fTpe9awfzwE5SiajAApttmgYgvmRjAoPSrGPhoIurCiwEpSKgn3vlYN3wR7Nxe5yHynlcKBV24CrEuT1dbv6G3o4eMdQq46MGtpPBrrVli2qVfzC7GtWs9rNJsGQrvo87zkUFDzwtZViB8j8WbSkLkdGBbGSkboz34sf4e63Q7nToJMLJI3PcDxXWeTn7hLRufpGPDD1eYUN7Kc2P4IciZW0HUJaLT6twVjIeF6GEBvEtjaMBaYCYttVIy944mqKclbllTYJ8CYgnSHh47Zu43UClNApFBLbVkmIIzkrCOEVUMr0rcA7N5PiQY9XTtD617LCq9ZEWrspz9sZfK7nBONZUD1tzNYTLHeXBpKsC5lfNktQqk1Jva5mtwsmHpPITYereUY0APkFnsLuTkDPWOiuM1oO7hlXqcLzFCwVMAJf0z9Bl7SgmAwF0uenqJ3cnMZKgVpRyrDVFC4X1nn9OFvqqG9VhIpCGq2nZzePRBr46a9yzHvCg4NibteZWUtqCAOYKR7CIXrNX1tPGLfaWmfMcTLqVF27RA16LlniKt4IMAKkAOSLyTTZeC51FQqDft6X9wDfh7QmsXAcIlqGwqJ8rcbJpwc3C0ncExlNKxo1CqqHCdsekkRyk7qgV40ufXj2uhYU9c59CR5AwUGLE7Scjy1GHE1P63VpGyXeEYeHoRwTBpuBxoqiEHS6pSN5kqCI5Q376mGqcKyRBiEbT0cRNxk9gaywKjg8PoXvwxELiAF4TA4HNvluNv4Hp4bgxUf2nzCWLTpgvQtMsqqfgrjZ7wudtPF2ViYNfMQd8i63FF87BsZ9N5AFuF51Fin5OxKN1frfZNg8vqU2xwbBzFoZiTdaRZXa4ApS4vFgA4kAZCUEvDDSGlFIIupiCRN9zGDuAB7Cq5A5foAg9YoOWETT4gJKFhetqkKS9jDtFAlLkKnetJjnm9nvxtze2x6JaRO5dshZV5IVdItu3pa681Hr6ZfPtj1SDcuT6sABlJSq0RRoAFlMXALjJg8EMRpvE0RAYaxLoYUyja0pH1Po7o5DQKJZt5zUdgmA9RQkRah8pWAtqT7VCByZ5OtNRYbsjAUDx0p0koWhG6X3KZta8dRbrNFvhCT39yYpC750nGuXpQS800D1oAuFs2Vkv3TiVciRhs1Ne3w2s4wb4G4r9bO8ES6JmUFuxMBNrBaH80WvN2XyG3qo8li3NjMOwrkKyCEg2it3qxsJFcvM5HCsoavLoHAIyLUQPM7Kx16hKw8L3YyuxATpp2fXQ21uilFecc42flZEKei2ckSPTPUy2plWrk359L9irdtbe5PMkOeKTn4qjmbTQRlw0hL4rdF9f9K811uX9HNoLbCDpNVXuqSZ26k6tUfHJfoUc6zr1DTID7lZfHPeIrPzruG4RynpmGepwsltXnfqWJW4VLblFB8bPznrz5aDZof7d5mwggGeMjchYMjGWCjlHCa7F43cMcQsnYbZioFj5ePqWFSnVUrXE40aforlmnRuSt3AvJhr69qnxtk9mPG2v2othA336d6RMfXnLR2Lw9bFONmwEs9XgZ9aFKduQnucCYbSV7xUX5FvaieUYHzOdjuwf7hByI5IO8CzwUaG4pAlTN9gpJWIyg9coowYZwgO96gcgphDrsTyjJcS7BVowxUs9jLIhCrIIvmXrhAAlSbGMK2eLeaYa1cLmxc6eZgoBLpygFlaAVCdWOgzrq6DmTrQSau3EEgMwwFBfE8F29XFz8zYQnPxccBrdYfFUrV6z0rjJfUms1Kn5mbTlWmbzstTuXiGi2uLnbP8RQPvTmFkRYw06Le8F4GGGXyv6NEzG99eWdCUH0HMnICVksJWXwGtUJ13bdyFiPeSZRddJK0Ow3d7VcLOErcU3QKNlJ3oCBoXou6SOqNN516ap3h8SjB0xJYJHP1AQMMuPGSlg2AYePZBUtirl4VcAxjfVxL8yN6spLLik6cajnWitXyYrJYW0tubgxQtrBjRSqVIi9Gpc52WbBv88wRoyk15atCxptthDFPDBqzsCt441X9fBRu4u4csyary6T9tMVSWvs7S7ilEq7EDuhwX8yxJmhOl8BvtuKrgFntSUc7LTYC1VoEZhluYhJtOeWU5x1UfPi7GxdDf1lzNfWPT6VMJaT853fy8IBYbEgmwr7mDiOg6UgtIGA9bpKF5kCMSpEXzNYJ8tcm8tIlLxBlXwq2HC6w3brMovTYd1qt5WuYnYAsgj3Iibzf9MPxQlQgCQ7NZuHTGSpABROsBOQThinN5xZRl3dUGOVXawSvbkCQvyer7hwCV68dmuSlU0sNzV4w51RO5e27gXbGTsTEGa8KP2uqeqbl1zaa4rvGPhG1EA6PSLSmhoGYWtgDH" - } - } - } -operationPlan: - operation: - - document: | - { - books { - author { - id - id @fusion__requirement - name(large: true) - } - } - } - hash: 0e997261f5847770ca54194299b00154 - searchSpace: 1 - expandedNodes: 2 - nodes: - - id: 1 - type: Operation - schema: a - operation: | - query Op_0e997261_1 { - books { - author { - id - } - } - } - - id: 2 - type: Operation - schema: b - operation: | - query Op_0e997261_2( - $__fusion_1_id: ID! - ) { - authorById(id: $__fusion_1_id) { - name(large: true) - } - } - source: $.authorById - target: $.books.author - requirements: - - name: __fusion_1_id - selectionMap: >- - id - dependencies: - - id: 1 diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/ApolloEntityBatchWireFormatTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/ApolloEntityBatchWireFormatTests.cs index f58a9e2f0ae..117d6565b53 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/ApolloEntityBatchWireFormatTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/ApolloEntityBatchWireFormatTests.cs @@ -1,5 +1,3 @@ -using System.Text.Encodings.Web; -using System.Text.Json; using HotChocolate.Execution; using HotChocolate.Fusion.WireFormat.Left; using HotChocolate.Fusion.WireFormat.Right; @@ -11,9 +9,9 @@ namespace HotChocolate.Fusion.WireFormat; /// execution path produces over the uniform default transport. The query selects /// child twice with different sub-selections, so the planner forms two /// _entities sub-requests against the right subgraph. No batching -/// capabilities are declared, so the gateway's default transport allows request -/// batching and the subgraph accepts it, sending the two sub-requests as a single -/// JSON-array operation batch. The snapshot captures the HTTP requests that reached the +/// capabilities are declared, so the gateway defaults to alias batching and the +/// subgraph accepts it, sending the two sub-requests as a single aliased operation. +/// The snapshot captures the HTTP requests that reached the /// subgraphs plus the merged gateway result, recording both the number and the body /// shape of the requests the source schema client produced. /// @@ -31,11 +29,11 @@ public sealed class ApolloEntityBatchWireFormatTests [Fact] [Trait("Category", "WireFormat")] - public async Task ApolloEntityBatch_Should_SendOneOperationBatch_When_CapabilitiesUndeclared() + public async Task ApolloEntityBatch_Should_SendOneAliasedOperation_When_CapabilitiesUndeclared() { // arrange - // no batching capabilities are declared, so the gateway uses the uniform default - // transport (request batching allowed) and the subgraph accepts the batch. + // no batching capabilities are declared, so the gateway defaults to alias batching + // and the subgraph accepts it, merging both sub-requests into one operation. var capture = new SubgraphRequestCapture(); await using var gateway = await FusionGatewayBuilder.ComposeAsync( capture, @@ -46,7 +44,7 @@ public async Task ApolloEntityBatch_Should_SendOneOperationBatch_When_Capabiliti var result = await gateway.Executor.ExecuteAsync(Query, TestContext.Current.CancellationToken); // assert - await MatchExchangeAsync(capture, result); + await WireFormatSnapshot.MatchExchangeAsync(capture, result); } [Fact] @@ -54,9 +52,9 @@ public async Task ApolloEntityBatch_Should_SendOneOperationBatch_When_Capabiliti public async Task ApolloEntityBatch_Should_SendSequentialSingleRequests_When_OperatorDeclaresRequestBatchingFalse() { // arrange - // the operator declares that the 'right' subgraph supports neither variable nor request - // batching, so the gateway must send the two _entities sub-requests as two sequential - // single requests instead of a single JSON-array operation batch. + // the operator declares that the 'right' subgraph supports neither variable, request, + // nor alias batching, so the gateway must send the two _entities sub-requests as two + // sequential single requests instead of a single batched operation. var capture = new SubgraphRequestCapture(); var settings = new Dictionary { @@ -68,7 +66,8 @@ public async Task ApolloEntityBatch_Should_SendSequentialSingleRequests_When_Ope "capabilities": { "batching": { "variableBatching": false, - "requestBatching": false + "requestBatching": false, + "aliasBatching": false } } } @@ -87,37 +86,6 @@ public async Task ApolloEntityBatch_Should_SendSequentialSingleRequests_When_Ope var result = await gateway.Executor.ExecuteAsync(Query, TestContext.Current.CancellationToken); // assert - await MatchExchangeAsync(capture, result); + await WireFormatSnapshot.MatchExchangeAsync(capture, result); } - - private static async Task MatchExchangeAsync(SubgraphRequestCapture capture, IExecutionResult result) - { - var snapshot = Snapshot.Create(); - var requests = capture.Requests; - - for (var i = 0; i < requests.Count; i++) - { - var request = requests[i]; - snapshot.Add( - FormatJson(request.Body), - $"HTTP Request {i + 1} to '{request.SubgraphName}'", - "json"); - } - - snapshot.Add(result, "Gateway Result"); - - await snapshot.MatchMarkdownAsync(); - } - - // Reformats the captured request body with indentation for readability while - // preserving the wire escaping (embedded quotes stay as \" rather than "), - // so the snapshot shows the body shape the client actually sent. - private static string FormatJson(string body) - { - using var document = JsonDocument.Parse(body); - return JsonSerializer.Serialize(document, s_indented); - } - - private static readonly JsonSerializerOptions s_indented = - new() { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/EntityBatchingCapabilityMatrixTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/EntityBatchingCapabilityMatrixTests.cs new file mode 100644 index 00000000000..77552656b0e --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/EntityBatchingCapabilityMatrixTests.cs @@ -0,0 +1,188 @@ +using HotChocolate.Execution; +using HotChocolate.Fusion.Execution.Clients; +using HotChocolate.Fusion.WireFormat.Left; +using HotChocolate.Fusion.WireFormat.Right; + +namespace HotChocolate.Fusion.WireFormat; + +/// +/// Pins the gateway to subgraph wire format that every combination of the batching capabilities +/// produces on the Apollo Federation entity path. The query selects child twice with +/// different sub-selections, so the planner forms two distinct _entities operations against +/// the right subgraph in one wave. The entity keys of an _entities operation travel +/// in its representations list, so the operation always carries one variable set and +/// variable batching never applies. The snapshot captures the HTTP requests that reached the +/// subgraphs plus the merged gateway result, recording both the number and the body shape of the +/// requests the source schema client produced. A second query covers the case where one of the +/// merged _entities operations resolves several representations at once. +/// +public sealed class EntityBatchingCapabilityMatrixTests +{ + private const string Query = + """ + { + parent { + a: child { a: value } + b: child { b: value(suffix: "!") } + } + } + """; + + private const string MultiEntityQuery = + """ + { + parents { + a: child { a: value } + } + parent { + b: child { b: value(suffix: "!") } + } + } + """; + + [Theory] + [Trait("Category", "WireFormat")] + [InlineData(SourceSchemaClientCapabilities.None)] + [InlineData(SourceSchemaClientCapabilities.VariableBatching)] + [InlineData(SourceSchemaClientCapabilities.RequestBatching)] + [InlineData( + SourceSchemaClientCapabilities.VariableBatching + | SourceSchemaClientCapabilities.RequestBatching)] + [InlineData(SourceSchemaClientCapabilities.AliasBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.VariableBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.RequestBatching)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching + | SourceSchemaClientCapabilities.VariableBatching + | SourceSchemaClientCapabilities.RequestBatching)] + public async Task EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect( + SourceSchemaClientCapabilities capabilities) + { + // arrange + var capture = new SubgraphRequestCapture(); + await using var gateway = await FusionGatewayBuilder.ComposeAsync( + capture, + CreateSettings(capabilities), + (LeftSubgraph.Name, LeftSubgraph.BuildAsync), + (RightSubgraph.Name, RightSubgraph.BuildAsync)); + + // act + var result = await gateway.Executor.ExecuteAsync(Query, TestContext.Current.CancellationToken); + + // assert + // every combination has to resolve the same data, so all rows share one inline snapshot of + // the gateway result; only the wire format below is pinned per combination. + result.MatchInlineSnapshot( + """ + { + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } + } + """); + + await WireFormatSnapshot.MatchExchangeAsync(capture, result, CreateLabel(capabilities)); + } + + [Fact] + [Trait("Category", "WireFormat")] + public async Task EntityLookups_Should_KeepEntitiesAligned_When_AliasBatchingMergesAMultiEntityLookup() + { + // arrange + // 'parents' yields two children through one lookup while 'parent' yields a third through a + // second lookup, so the merged aliased document carries one prefixed representations list + // with two elements next to a list with one element. + var capture = new SubgraphRequestCapture(); + await using var gateway = await FusionGatewayBuilder.ComposeAsync( + capture, + CreateSettings(SourceSchemaClientCapabilities.AliasBatching), + (LeftSubgraph.Name, LeftSubgraph.BuildAsync), + (RightSubgraph.Name, RightSubgraph.BuildAsync)); + + // act + var result = await gateway.Executor.ExecuteAsync( + MultiEntityQuery, + TestContext.Current.CancellationToken); + + // assert + await WireFormatSnapshot.MatchExchangeAsync(capture, result); + } + + /// + /// Declares the batching capabilities of the right subgraph the way an operator would in + /// the gateway settings. + /// + private static Dictionary CreateSettings( + SourceSchemaClientCapabilities capabilities) + => new() + { + [RightSubgraph.Name] = + $$""" + { + "transports": { + "http": { + "capabilities": { + "batching": { + "variableBatching": {{Declares( + capabilities, + SourceSchemaClientCapabilities.VariableBatching)}}, + "requestBatching": {{Declares( + capabilities, + SourceSchemaClientCapabilities.RequestBatching)}}, + "aliasBatching": {{Declares( + capabilities, + SourceSchemaClientCapabilities.AliasBatching)}} + } + } + } + } + } + """ + }; + + private static string Declares( + SourceSchemaClientCapabilities capabilities, + SourceSchemaClientCapabilities capability) + => capabilities.HasFlag(capability) ? "true" : "false"; + + /// + /// Composes the filename-safe label of a capability combination. + /// + private static string CreateLabel(SourceSchemaClientCapabilities capabilities) + { + if (capabilities is SourceSchemaClientCapabilities.None) + { + return "None"; + } + + var label = string.Empty; + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.AliasBatching)) + { + label += "A"; + } + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.VariableBatching)) + { + label += "V"; + } + + if (capabilities.HasFlag(SourceSchemaClientCapabilities.RequestBatching)) + { + label += "R"; + } + + return label; + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/LeftSubgraph.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/LeftSubgraph.cs index 69ede21692d..6bc62835cd6 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/LeftSubgraph.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/LeftSubgraph.cs @@ -8,10 +8,12 @@ namespace HotChocolate.Fusion.WireFormat.Left; /// /// The left Apollo Federation subgraph for the entity-batch wire-format -/// tests. Exposes Query.parent and owns the Child key. Each -/// Parent.child selection yields a Child reference that the gateway -/// resolves against the right subgraph, so a query that selects -/// child twice produces two same-subgraph entity lookups. +/// tests. Exposes Query.parent and Query.parents and owns the +/// Child key. Each Parent.child selection yields a Child +/// reference that the gateway resolves against the right subgraph, so a +/// query that selects child twice produces two same-subgraph entity +/// lookups, and a child selection below parents produces one lookup +/// that carries one representation per list item. /// public static class LeftSubgraph { @@ -61,6 +63,16 @@ protected override void Configure(IObjectTypeDescriptor descriptor) .Field("parent") .Type() .Resolve(_ => new Parent { Id = "1", ChildId = "1" }); + + descriptor + .Field("parents") + .Type>>>() + .Resolve( + _ => new Parent[] + { + new() { Id = "1", ChildId = "1" }, + new() { Id = "2", ChildId = "2" } + }); } } diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/WireFormatSnapshot.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/WireFormatSnapshot.cs new file mode 100644 index 00000000000..b0529fe7aa6 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/WireFormatSnapshot.cs @@ -0,0 +1,55 @@ +using System.Text.Encodings.Web; +using System.Text.Json; +using HotChocolate.Execution; + +namespace HotChocolate.Fusion.WireFormat; + +/// +/// Renders the gateway to subgraph exchange of a wire-format test as a markdown snapshot: one +/// section per captured HTTP request, in the order the requests were sent, followed by the merged +/// gateway result. +/// +internal static class WireFormatSnapshot +{ + private static readonly JsonSerializerOptions s_indented = + new() { WriteIndented = true, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + + /// + /// Matches the captured exchange against the markdown snapshot of the calling test. + /// + /// The recorded gateway to subgraph requests. + /// The merged gateway result. + /// + /// Distinguishes the snapshots of a test that is executed for several inputs. + /// + public static async Task MatchExchangeAsync( + SubgraphRequestCapture capture, + IExecutionResult result, + string? postFix = null) + { + var snapshot = Snapshot.Create(postFix); + var requests = capture.Requests; + + for (var i = 0; i < requests.Count; i++) + { + var request = requests[i]; + snapshot.Add( + FormatJson(request.Body), + $"HTTP Request {i + 1} to '{request.SubgraphName}'", + "json"); + } + + snapshot.Add(result, "Gateway Result"); + + await snapshot.MatchMarkdownAsync(); + } + + // Reformats the captured request body with indentation for readability while + // preserving the wire escaping (embedded quotes stay as \" rather than "), + // so the snapshot shows the body shape the client actually sent. + private static string FormatJson(string body) + { + using var document = JsonDocument.Parse(body); + return JsonSerializer.Serialize(document, s_indented); + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneAliasedOperation_When_CapabilitiesUndeclared.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneAliasedOperation_When_CapabilitiesUndeclared.md new file mode 100644 index 00000000000..b53ec1e14ae --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneAliasedOperation_When_CapabilitiesUndeclared.md @@ -0,0 +1,48 @@ +# ApolloEntityBatch_Should_SendOneAliasedOperation_When_CapabilitiesUndeclared + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query Batch_86274262454d197e($_0_representations:[_Any!]!,$_1_representations:[_Any!]!){_0__entities:_entities(representations:$_0_representations){...on Child{b:value(suffix:\"!\")}} _1__entities:_entities(representations:$_1_representations){...on Child{a:value}}}", + "variables": { + "_0_representations": [ + { + "__typename": "Child", + "id": "1" + } + ], + "_1_representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_KeepEntitiesAligned_When_AliasBatchingMergesAMultiEntityLookup.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_KeepEntitiesAligned_When_AliasBatchingMergesAMultiEntityLookup.md new file mode 100644 index 00000000000..fb928d7a905 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_KeepEntitiesAligned_When_AliasBatchingMergesAMultiEntityLookup.md @@ -0,0 +1,61 @@ +# EntityLookups_Should_KeepEntitiesAligned_When_AliasBatchingMergesAMultiEntityLookup + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_5328c9ea_1 {\n parents {\n a: child {\n id\n }\n }\n parent {\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query Batch_86274262454d197e($_0_representations:[_Any!]!,$_1_representations:[_Any!]!){_0__entities:_entities(representations:$_0_representations){...on Child{b:value(suffix:\"!\")}} _1__entities:_entities(representations:$_1_representations){...on Child{a:value}}}", + "variables": { + "_0_representations": [ + { + "__typename": "Child", + "id": "1" + } + ], + "_1_representations": [ + { + "__typename": "Child", + "id": "1" + }, + { + "__typename": "Child", + "id": "2" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parents": [ + { + "a": { + "a": "child-1" + } + }, + { + "a": { + "a": "child-2" + } + } + ], + "parent": { + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.md new file mode 100644 index 00000000000..6c88eccdd26 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_A.md @@ -0,0 +1,48 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query Batch_86274262454d197e($_0_representations:[_Any!]!,$_1_representations:[_Any!]!){_0__entities:_entities(representations:$_0_representations){...on Child{b:value(suffix:\"!\")}} _1__entities:_entities(representations:$_1_representations){...on Child{a:value}}}", + "variables": { + "_0_representations": [ + { + "__typename": "Child", + "id": "1" + } + ], + "_1_representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneOperationBatch_When_CapabilitiesUndeclared.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.md similarity index 92% rename from src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneOperationBatch_When_CapabilitiesUndeclared.md rename to src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.md index 966dea2196c..a2f15c79646 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/ApolloEntityBatchWireFormatTests.ApolloEntityBatch_Should_SendOneOperationBatch_When_CapabilitiesUndeclared.md +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AR.md @@ -1,4 +1,4 @@ -# ApolloEntityBatch_Should_SendOneOperationBatch_When_CapabilitiesUndeclared +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect ## HTTP Request 1 to 'left' diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.md new file mode 100644 index 00000000000..6c88eccdd26 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AV.md @@ -0,0 +1,48 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query Batch_86274262454d197e($_0_representations:[_Any!]!,$_1_representations:[_Any!]!){_0__entities:_entities(representations:$_0_representations){...on Child{b:value(suffix:\"!\")}} _1__entities:_entities(representations:$_1_representations){...on Child{a:value}}}", + "variables": { + "_0_representations": [ + { + "__typename": "Child", + "id": "1" + } + ], + "_1_representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.md new file mode 100644 index 00000000000..a2f15c79646 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_AVR.md @@ -0,0 +1,55 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +[ + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n b: value(suffix: \"!\")\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + }, + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n a: value\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + } +] +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.md new file mode 100644 index 00000000000..d1521dec41c --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_None.md @@ -0,0 +1,58 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n b: value(suffix: \"!\")\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## HTTP Request 3 to 'right' + +```json +{ + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n a: value\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.md new file mode 100644 index 00000000000..a2f15c79646 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_R.md @@ -0,0 +1,55 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +[ + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n b: value(suffix: \"!\")\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + }, + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n a: value\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + } +] +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.md new file mode 100644 index 00000000000..d1521dec41c --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_V.md @@ -0,0 +1,58 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +{ + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n b: value(suffix: \"!\")\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## HTTP Request 3 to 'right' + +```json +{ + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n a: value\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } +} +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.md b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.md new file mode 100644 index 00000000000..a2f15c79646 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Compliance.Tests/WireFormat/__snapshots__/EntityBatchingCapabilityMatrixTests.EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect_VR.md @@ -0,0 +1,55 @@ +# EntityLookups_Should_UseTheProtocolTheCapabilitiesSelect + +## HTTP Request 1 to 'left' + +```json +{ + "query": "query Op_88f73202_1 {\n parent {\n a: child {\n id\n }\n b: child {\n id\n }\n }\n}" +} +``` + +## HTTP Request 2 to 'right' + +```json +[ + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n b: value(suffix: \"!\")\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + }, + { + "query": "query($representations: [_Any!]!) {\n _entities(representations: $representations) {\n ... on Child {\n a: value\n }\n }\n}", + "variables": { + "representations": [ + { + "__typename": "Child", + "id": "1" + } + ] + } + } +] +``` + +## Gateway Result + +```json +{ + "data": { + "parent": { + "a": { + "a": "child-1" + }, + "b": { + "b": "child-1!" + } + } + } +} +``` diff --git a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Tests/LookupEntityQueryRewriterTests.cs b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Tests/LookupEntityQueryRewriterTests.cs index b8c89970c6d..ce03db2345c 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Tests/LookupEntityQueryRewriterTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Connectors.ApolloFederation.Tests/LookupEntityQueryRewriterTests.cs @@ -1,10 +1,10 @@ +using System.Text; using HotChocolate.Execution; using HotChocolate.Fusion.Execution.ApolloFederation; using HotChocolate.Fusion.Execution.Nodes; using HotChocolate.Fusion.Language; using HotChocolate.Fusion.Logging; using HotChocolate.Fusion.Options; -using HotChocolate.Fusion.Planning; using HotChocolate.Fusion.Types; using HotChocolate.Language; using NameNode = HotChocolate.Language.NameNode; @@ -203,7 +203,7 @@ query GetProduct($__fusion_1_id: ID!) { // assert Assert.Equal("Product", rewritten.EntityTypeName); - rewritten.Operation.SourceText.MatchInlineSnapshot( + Encoding.UTF8.GetString(rewritten.Operation.SourceText.Span).MatchInlineSnapshot( """ query($representations: [_Any!]!) { _entities(representations: $representations) { @@ -237,7 +237,7 @@ public void Rewrite_Should_StripBothKeyArguments_When_CompositeKey() // assert Assert.Equal("Product", rewritten.EntityTypeName); - rewritten.Operation.SourceText.MatchInlineSnapshot( + Encoding.UTF8.GetString(rewritten.Operation.SourceText.Span).MatchInlineSnapshot( """ query($representations: [_Any!]!) { _entities(representations: $representations) { @@ -268,7 +268,7 @@ public void Rewrite_Should_StripRequireArgument_And_RetainForwardedArgument_When var rewritten = LookupEntityQueryRewriter.Rewrite(schema, "shipping", operation); // assert - rewritten.Operation.SourceText.MatchInlineSnapshot( + Encoding.UTF8.GetString(rewritten.Operation.SourceText.Span).MatchInlineSnapshot( """ query($representations: [_Any!]!, $__fusion_3_currency: String!) { _entities(representations: $representations) { @@ -304,7 +304,7 @@ ... on Bar { var rewritten = LookupEntityQueryRewriter.Rewrite(schema, "inested", operation); // assert - rewritten.Operation.SourceText.MatchInlineSnapshot( + Encoding.UTF8.GetString(rewritten.Operation.SourceText.Span).MatchInlineSnapshot( """ query($representations: [_Any!]!) { _entities(representations: $representations) { @@ -340,7 +340,7 @@ ... on Product { var rewritten = LookupEntityQueryRewriter.Rewrite(schema, "shipping", operation); // assert - rewritten.Operation.SourceText.MatchInlineSnapshot( + Encoding.UTF8.GetString(rewritten.Operation.SourceText.Span).MatchInlineSnapshot( """ query($representations: [_Any!]!, $__fusion_3_currency: String!) { _entities(representations: $representations) { @@ -455,7 +455,12 @@ ... on Query { // GraphQL), so the multi-candidate tie-break cannot be constructed realistically here. private static OperationSourceText CreateOperation(string sourceText) - => new("Op", OperationType.Query, sourceText, "hash"); + => OperationSourceText.Create( + "Op", + OperationType.Query, + Encoding.UTF8.GetBytes(sourceText), + "hash", + lookupTypeName: null); private static OperationRequirement CreateRequirement( FusionSchemaDefinition schema, diff --git a/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/FusionActivityExecutionDiagnosticListenerTests.cs b/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/FusionActivityExecutionDiagnosticListenerTests.cs index 12abfcaff61..2a634a630e0 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/FusionActivityExecutionDiagnosticListenerTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/FusionActivityExecutionDiagnosticListenerTests.cs @@ -5,6 +5,7 @@ using HotChocolate.PersistedOperations; using HotChocolate.Resolvers; using HotChocolate.Types; +using HotChocolate.Types.Composite; using Microsoft.Extensions.DependencyInjection; using static CookieCrumble.TestEnvironment; using static HotChocolate.Fusion.Diagnostics.ActivityTestHelper; @@ -14,6 +15,8 @@ namespace HotChocolate.Fusion.Diagnostics; [Collection("Instrumentation")] public class FusionActivityExecutionDiagnosticListenerTests : FusionTestBase { + private const string BatchOperationCountTag = "graphql.source_schema.batch.operation_count"; + [Fact] public async Task Track_Events_Of_A_Simple_Query_Default() { @@ -224,6 +227,49 @@ public async Task Track_Events_Of_A_Query_With_Multiple_Sources() } } + [Fact] + public async Task StepSpan_Should_ReportTheOperationCount_When_TheStepBatchesOperations() + { + using (CaptureActivities(out var activities)) + { + // arrange + using var server1 = CreateSourceSchema( + "a", + b => b.AddQueryType()); + + using var server2 = CreateSourceSchema( + "b", + b => b.AddQueryType()); + + using var gateway = await CreateCompositeSchemaAsync( + [ + ("a", server1), + ("b", server2) + ], + configureGatewayBuilder: b => b + .AddInstrumentation(o => o.Scopes = FusionActivityScopes.All) + .ModifyPlannerOptions(o => o.EnableRequestGrouping = true)); + + var executor = await gateway.Services.GetRequestExecutorAsync( + cancellationToken: TestContext.Current.CancellationToken); + + // Both root selections read from the same source schema, so their two operations are + // sent by one step. + var request = OperationRequestBuilder.New() + .SetDocument("{ first { rating } second { deliveryEstimate } }") + .Build(); + + // act + await executor.ExecuteAsync(request, TestContext.Current.CancellationToken); + + // assert + var batchStep = Assert.Single( + activities.Exported, + a => a.GetTagItem(BatchOperationCountTag) is not null); + Assert.Equal("2", batchStep.GetTagItem(BatchOperationCountTag)); + } + } + [Fact] public async Task PersistedOperation_LoadsFromStorage_DefaultScopes() { @@ -904,6 +950,37 @@ public async Task SubscriptionRequestFails_When_SourceSchema_Is_Offline() } } + public static class BatchSourceSchemaA + { + [EntityKey("id")] + public record Product(int Id); + + public sealed class Query + { + public Product GetFirst() => new(1); + + public Product GetSecond() => new(2); + } + } + + public static class BatchSourceSchemaB + { + [EntityKey("id")] + public record Product(int Id) + { + public int Rating => Id + 4; + + public int DeliveryEstimate => Id + 1; + } + + public sealed class Query + { + [Lookup] + [Internal] + public Product GetProductById(int id) => new(id); + } + } + public class Query { public string SayHello() => "hello"; diff --git a/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/__snapshots__/FusionActivityExecutionDiagnosticListenerTests.Source_Schema_Transport_Error.snap b/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/__snapshots__/FusionActivityExecutionDiagnosticListenerTests.Source_Schema_Transport_Error.snap index 1b257be2f6d..3062793c6b4 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/__snapshots__/FusionActivityExecutionDiagnosticListenerTests.Source_Schema_Transport_Error.snap +++ b/src/HotChocolate/Fusion/test/Fusion.Diagnostics.Tests/__snapshots__/FusionActivityExecutionDiagnosticListenerTests.Source_Schema_Transport_Error.snap @@ -80,7 +80,7 @@ }, { "Key": "exception.stacktrace", - "Value": "System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).\n at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()\n at HotChocolate.Fusion.Transport.Http.GraphQLHttpResponse.ReadAsResultAsync(IMemoryArena arena, CancellationToken cancellationToken) in GraphQLHttpResponse.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs" + "Value": "System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).\n at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()\n at HotChocolate.Fusion.Transport.Http.GraphQLHttpResponse.ReadAsResultAsync(IMemoryArena arena, CancellationToken cancellationToken) in GraphQLHttpResponse.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs" } ] } @@ -239,7 +239,7 @@ }, { "Key": "exception.stacktrace", - "Value": "System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).\n at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()\n at HotChocolate.Fusion.Transport.Http.GraphQLHttpResponse.ReadAsResultAsync(IMemoryArena arena, CancellationToken cancellationToken) in GraphQLHttpResponse.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|14_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs" + "Value": "System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).\n at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()\n at HotChocolate.Fusion.Transport.Http.GraphQLHttpResponse.ReadAsResultAsync(IMemoryArena arena, CancellationToken cancellationToken) in GraphQLHttpResponse.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.ReadAsResultStreamAsync(OperationPlanContext context, ImmutableArray`1 variables, GraphQLHttpResponse response, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.WithResultCallback(IAsyncEnumerable`1 results, OperationPlanContext context, ExecutionNode node, Action`3 onSourceSchemaResult, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+MoveNext() in HttpSourceSchemaClient.cs\n at HotChocolate.Fusion.Execution.Clients.HttpSourceSchemaClient.g__CreateStreamAsync|26_0(OperationPlanContext context, SourceSchemaClientRequest request, CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource.GetResult()\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs\n at HotChocolate.Fusion.Execution.Nodes.OperationExecutionNode.OnExecuteAsync(OperationPlanContext context, CancellationToken cancellationToken) in OperationExecutionNode.cs" }, { "Key": "graphql.operation.type", diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Configuration/DefaultGraphQLClientConfigurationParserTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Configuration/DefaultGraphQLClientConfigurationParserTests.cs index a715a8767e9..8f948196c11 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Configuration/DefaultGraphQLClientConfigurationParserTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Configuration/DefaultGraphQLClientConfigurationParserTests.cs @@ -123,8 +123,8 @@ public void DefaultGraphQLClientConfigurationParser_Should_Disable_VariableBatch public void DefaultGraphQLClientConfigurationParser_Should_Honor_Declared_VariableBatching_When_Schema_Is_ApolloFederation() { // arrange - // the source schema is composed as an Apollo Federation connector, yet the - // kind-blind parser honors the batching capability declared in its settings. + // the source schema is composed as an Apollo Federation connector, so it defaults to + // alias batching; the declared variable batching is added on top of that default. var schema = ComposeApolloFederationSchema("products"); Assert.Equal("ApolloFederation", schema.GetSourceSchemaConnectorKind("products")); var sourceSchema = GetSourceSchemaProperty( @@ -155,7 +155,118 @@ public void DefaultGraphQLClientConfigurationParser_Should_Honor_Declared_Variab // assert Assert.True(claimed); var http = Assert.IsType(Assert.Single(configurations!)); - Assert.Equal(SourceSchemaClientCapabilities.All, http.Capabilities); + Assert.Equal( + SourceSchemaClientCapabilities.VariableBatching + | SourceSchemaClientCapabilities.AliasBatching, + http.Capabilities); + } + + [Fact] + public void DefaultGraphQLClientConfigurationParser_Should_Default_To_AliasBatching_When_Schema_Is_ApolloFederation() + { + // arrange + // a federation subgraph is only assumed to speak plain GraphQL, so the settings that + // declare no batching capabilities at all leave alias batching as the only default. + var schema = ComposeApolloFederationSchema("products"); + var sourceSchema = GetSourceSchemaProperty( + """ + { + "sourceSchemas": { + "products": { + "transports": { + "http": { + "url": "http://localhost:5000/graphql" + } + } + } + } + } + """, + "products"); + var parser = new DefaultGraphQLClientConfigurationParser(); + + // act + var claimed = parser.TryParse(schema, sourceSchema, out var configurations); + + // assert + Assert.True(claimed); + var http = Assert.IsType(Assert.Single(configurations!)); + Assert.Equal(SourceSchemaClientCapabilities.AliasBatching, http.Capabilities); + } + + [Fact] + public void DefaultGraphQLClientConfigurationParser_Should_Add_RequestBatching_To_The_AliasBatching_Default_When_Schema_Is_ApolloFederation() + { + // arrange + var schema = ComposeApolloFederationSchema("products"); + var sourceSchema = GetSourceSchemaProperty( + """ + { + "sourceSchemas": { + "products": { + "transports": { + "http": { + "url": "http://localhost:5000/graphql", + "capabilities": { + "batching": { + "requestBatching": true + } + } + } + } + } + } + } + """, + "products"); + var parser = new DefaultGraphQLClientConfigurationParser(); + + // act + var claimed = parser.TryParse(schema, sourceSchema, out var configurations); + + // assert + Assert.True(claimed); + var http = Assert.IsType(Assert.Single(configurations!)); + Assert.Equal( + SourceSchemaClientCapabilities.RequestBatching + | SourceSchemaClientCapabilities.AliasBatching, + http.Capabilities); + } + + [Fact] + public void DefaultGraphQLClientConfigurationParser_Should_Disable_The_AliasBatching_Default_When_Schema_Is_ApolloFederation() + { + // arrange + var schema = ComposeApolloFederationSchema("products"); + var sourceSchema = GetSourceSchemaProperty( + """ + { + "sourceSchemas": { + "products": { + "transports": { + "http": { + "url": "http://localhost:5000/graphql", + "capabilities": { + "batching": { + "aliasBatching": false + } + } + } + } + } + } + } + """, + "products"); + var parser = new DefaultGraphQLClientConfigurationParser(); + + // act + var claimed = parser.TryParse(schema, sourceSchema, out var configurations); + + // assert + Assert.True(claimed); + var http = Assert.IsType(Assert.Single(configurations!)); + Assert.Equal(SourceSchemaClientCapabilities.None, http.Capabilities); } [Fact] diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchRequestSelectionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchRequestSelectionTests.cs new file mode 100644 index 00000000000..a882f81d241 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchRequestSelectionTests.cs @@ -0,0 +1,442 @@ +using System.Collections.Immutable; +using System.Net; +using System.Text; +using System.Text.Json; +using HotChocolate.Buffers; +using HotChocolate.Execution; +using HotChocolate.Fusion.Execution.Nodes; +using HotChocolate.Fusion.Text.Json; +using HotChocolate.Fusion.Transport.Http; +using HotChocolate.Fusion.Types; +using HotChocolate.Language; +using HotChocolate.Types; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.ObjectPool; +using static HotChocolate.Fusion.Execution.Clients.AliasBatching.AliasBatchTestData; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +public sealed class AliasBatchRequestSelectionTests : FusionTestBase +{ + private const string Lookup = "query($__fusion_1_id: ID!){fieldById(id: $__fusion_1_id){field}}"; + + private const string TwoRootFieldLookup = + "query($__fusion_1_id: ID!){fieldById(id: $__fusion_1_id){field} field}"; + + [Theory] + [InlineData(SourceSchemaClientCapabilities.AliasBatching, true)] + // Variable batching is the native protocol for the many variable sets of one operation, so it + // is preferred over alias batching whenever the source schema declares it. + [InlineData( + SourceSchemaClientCapabilities.AliasBatching | SourceSchemaClientCapabilities.VariableBatching, + false)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching | SourceSchemaClientCapabilities.RequestBatching, + true)] + [InlineData( + SourceSchemaClientCapabilities.AliasBatching | SourceSchemaClientCapabilities.Default, + false)] + [InlineData(SourceSchemaClientCapabilities.Default, false)] + [InlineData(SourceSchemaClientCapabilities.None, false)] + public async Task ExecuteAsync_Should_SelectTheBatchedBody_When_CapabilitiesAllowIt( + SourceSchemaClientCapabilities capabilities, + bool expectsAliasBatching) + { + // arrange + await using var fixture = await Fixture.CreateAsync(capabilities); + + // act + var body = await fixture.SendAsync(fixture.CreateLookupRequest()); + + // assert + Assert.Equal(expectsAliasBatching, body.StartsWith("""{"query":"query Batch_""", StringComparison.Ordinal)); + } + + [Fact] + public async Task ExecuteAsync_Should_KeepTheClassicBody_When_RequestUploadsFiles() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + var request = fixture.CreateLookupRequest() with { RequiresFileUpload = true }; + + // act + var body = await fixture.SendAsync(request); + + // assert + Assert.StartsWith("""[{"query":""", body, StringComparison.Ordinal); + } + + [Fact] + public async Task ExecuteAsync_Should_KeepTheClassicBody_When_OperationIsAMutation() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + var request = fixture.CreateLookupRequest() with { OperationType = OperationType.Mutation }; + + // act + var body = await fixture.SendAsync(request); + + // assert + Assert.StartsWith("""[{"query":""", body, StringComparison.Ordinal); + } + + [Fact] + public async Task ExecuteAsync_Should_IncludeOnError_When_TheCapabilityProvidesAMode() + { + // arrange + await using var fixture = await Fixture.CreateAsync( + SourceSchemaClientCapabilities.AliasBatching, + ErrorHandlingMode.Propagate); + + // act + var body = await fixture.SendAsync(fixture.CreateLookupRequest()); + + // assert + Assert.EndsWith("""},"onError":"PROPAGATE"}""", body, StringComparison.Ordinal); + } + + [Fact] + public async Task ExecuteAsync_Should_KeepTheClassicBody_When_OperationSelectsTwoRootFields() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + // The plan resolved a lookup type for this operation, but its document reads from two root + // selections, so it cannot be rewritten into an aliased copy of itself. + var request = fixture.CreateLookupRequest() with { OperationDocument = fixture.TwoRootFieldDocument }; + + // act + var body = await fixture.SendAsync(request); + + // assert + Assert.StartsWith("""[{"query":""", body, StringComparison.Ordinal); + } + + [Fact] + public async Task ExecuteBatchAsync_Should_SendTheRequestOnItsOwn_When_ItSelectsTwoRootFields() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + var batched = fixture.CreateLookupRequest(); + var isolated = fixture.CreateLookupRequest() with + { + OperationDocument = fixture.TwoRootFieldDocument, + Variables = [fixture.CreateVariableValues("3")] + }; + + // act + var requestIndices = await fixture.SendBatchAsync([batched, isolated]); + + // assert + // The two variable sets of the batched request are answered by the batched response, and + // the request that cannot join it is answered by a round-trip of its own. + Assert.Equal([0, 0, 1], requestIndices); + } + + [Fact] + public async Task ExecuteAsync_Should_PrefixTheVariable_When_TheClientDeclaresItButTheNodeDoesNotForwardIt() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + // The client request declares a variable that carries the name of the per-item variable of + // the operation, but the node does not forward it, so its value still differs per item. + var clientVariables = fixture.CreateClientVariables("__fusion_1_id"); + + // act + var body = await fixture.SendAsync(fixture.CreateLookupRequest(), clientVariables); + + // assert + ReadVariables(body).MatchInlineSnapshot( + """{"_0___fusion_1_id":"1","_1___fusion_1_id":"2"}"""); + } + + [Fact] + public async Task ExecuteBatchAsync_Should_PrefixEveryValue_When_AnotherRequestCarriesTheNamePerItem() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + var perItem = fixture.CreateLookupRequest(); + // The second request forwards a client variable that carries the name the first request + // carries a value per item for, so the name cannot be declared once for the whole batch. + var forwarding = fixture.CreateLookupRequest() with + { + Variables = [fixture.CreateVariableValues("B")], + ForwardedVariables = ["__fusion_1_id"] + }; + + // act + await fixture.SendBatchAsync( + [perItem, forwarding], + fixture.CreateClientVariables("__fusion_1_id")); + + // assert + ReadVariables(fixture.Body).MatchInlineSnapshot( + """{"_0___fusion_1_id":"1","_1___fusion_1_id":"2","_2___fusion_1_id":"B"}"""); + } + + [Fact] + public async Task ExecuteAsync_Should_FreeTheDocument_When_TheEnumerationIsAbandoned() + { + // arrange + await using var fixture = await Fixture.CreateAsync(SourceSchemaClientCapabilities.AliasBatching); + + // act + // The caller stops after the first item, so the items it never received are freed with the + // enumeration while the item it received keeps the response document alive. + var first = await fixture.ReadFirstAsync(fixture.CreateLookupRequest()); + var root = first.LookupData!.Value; + var readWhileHeld = root.GetProperty("field").GetString(); + first.Dispose(); + + // assert + Assert.Equal("A", readWhileHeld); + Assert.Throws(() => root.GetProperty("field").GetString()); + } + + private static string ReadVariables(string body) + { + using var document = JsonDocument.Parse(body); + return document.RootElement.GetProperty("variables").GetRawText(); + } + + private sealed class Fixture : IAsyncDisposable + { + private readonly ServiceProvider _services; + private readonly IRequestExecutor _executor; + private readonly OperationPlan _operationPlan; + private readonly ChunkedArrayWriter _memory = new(); + private readonly Utf8OperationDocument _document = ParseLookup(Lookup); + private readonly Utf8OperationDocument _twoRootFieldDocument = ParseLookup(TwoRootFieldLookup); + private readonly CapturingHandler _handler = new(); + private readonly HttpSourceSchemaClient _client; + private readonly List _contexts = []; + private readonly List _ctsList = []; + private readonly List<(ObjectPool Pool, PooledRequestContext Context)> + _requestContexts = []; + + private Fixture( + ServiceProvider services, + IRequestExecutor executor, + OperationPlan operationPlan, + SourceSchemaClientCapabilities capabilities, + ErrorHandlingMode? onError) + { + _services = services; + _executor = executor; + _operationPlan = operationPlan; + _client = new HttpSourceSchemaClient( + new DefaultGraphQLHttpClient(new HttpClient(_handler), disposeInnerClient: true), + new HttpSourceSchemaClientConfiguration( + "A", + new Uri("http://localhost:5000/graphql"), + capabilities: capabilities, + onError: onError)); + } + + public static async Task CreateAsync( + SourceSchemaClientCapabilities capabilities, + ErrorHandlingMode? onError = null) + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddHttpClient(); + var services = serviceCollection + .AddGraphQLGateway() + .AddInMemoryConfiguration( + ComposeSchemaDocument( + """ + type Query { + field: String! + } + """)) + .Services + .BuildServiceProvider(); + + var executor = await services.GetRequestExecutorAsync(); + var schema = (FusionSchemaDefinition)executor.Schema; + var operationPlan = PlanOperation(schema, "{ field }"); + + return new Fixture(services, executor, operationPlan, capabilities, onError); + } + + /// + /// Gets a document that reads its data from two root selections. + /// + public Utf8OperationDocument TwoRootFieldDocument => _twoRootFieldDocument; + + public SourceSchemaClientRequest CreateLookupRequest() + => new() + { + Node = _operationPlan.RootNodes[0], + SchemaName = "A", + OperationType = OperationType.Query, + OperationSourceText = Encoding.UTF8.GetBytes(Lookup), + OperationHash = 1, + Variables = [CreateVariableValues("1"), CreateVariableValues("2")], + OperationDocument = _document, + LookupTypeName = "Foo" + }; + + public VariableValues CreateVariableValues(string id) + => new(CompactPath.Root, CreateSegment(_memory, $$"""{"__fusion_1_id":"{{id}}"}""")); + + /// + /// Creates the variables of the client request that the plan is executed with. + /// + public VariableValueCollection CreateClientVariables(string name) + { + var schema = (FusionSchemaDefinition)_executor.Schema; + var stringType = new NonNullType(schema.Types.GetType("String")); + + return new VariableValueCollection( + new Dictionary(StringComparer.Ordinal) + { + [name] = new(name, stringType, new StringValueNode("client")) + }); + } + + /// + /// Gets the body of the last request the client sent. + /// + public string Body => _handler.Body!; + + public Task SendAsync(SourceSchemaClientRequest request) + => SendAsync(request, VariableValueCollection.Empty); + + public async Task SendAsync( + SourceSchemaClientRequest request, + VariableValueCollection variables) + { + var context = CreateContext(variables); + + await foreach (var result in _client.ExecuteAsync( + context, + request, + TestContext.Current.CancellationToken)) + { + result.Dispose(); + } + + return _handler.Body!; + } + + /// + /// Executes a request and returns its first result, leaving the remaining results of the + /// request unread. + /// + public async Task ReadFirstAsync(SourceSchemaClientRequest request) + { + var context = CreateContext(VariableValueCollection.Empty); + + await foreach (var result in _client.ExecuteAsync( + context, + request, + TestContext.Current.CancellationToken)) + { + return result; + } + + throw new InvalidOperationException("The request produced no result."); + } + + public Task> SendBatchAsync(ImmutableArray requests) + => SendBatchAsync(requests, VariableValueCollection.Empty); + + /// + /// Executes a batch and returns the request index of every result it produced. + /// + public async Task> SendBatchAsync( + ImmutableArray requests, + VariableValueCollection variables) + { + var context = CreateContext(variables); + var requestIndices = new List(); + + await foreach (var result in _client.ExecuteBatchAsync( + context, + requests, + TestContext.Current.CancellationToken)) + { + requestIndices.Add(result.RequestIndex); + result.Result.Dispose(); + } + + return requestIndices; + } + + private OperationPlanContext CreateContext(VariableValueCollection variables) + { + var contextPool = _executor.Schema.Services.GetRequiredService(); + var context = contextPool.Rent(); + var cts = new CancellationTokenSource(); + var requestContextPool = + _executor.Schema.Services.GetRequiredService>(); + var requestContext = requestContextPool.Get(); + + requestContext.Initialize( + _executor.Schema, + _executor.Version, + OperationRequestBuilder.New().SetDocument("{ field }").Build(), + requestIndex: 0, + requestServices: _services, + requestAborted: CancellationToken.None); + + context.Initialize( + requestContext, + variables, + _operationPlan, + cts, + new MemoryArena()); + + _ctsList.Add(cts); + _requestContexts.Add((requestContextPool, requestContext)); + _contexts.Add(context); + return context; + } + + public async ValueTask DisposeAsync() + { + await _client.DisposeAsync(); + + foreach (var context in _contexts) + { + await context.DisposeAsync(); + } + + foreach (var (pool, requestContext) in _requestContexts) + { + pool.Return(requestContext); + } + + foreach (var cts in _ctsList) + { + cts.Dispose(); + } + + _document.Dispose(); + _twoRootFieldDocument.Dispose(); + _memory.Dispose(); + await _services.DisposeAsync(); + } + } + + private sealed class CapturingHandler : HttpMessageHandler + { + private readonly List _bodies = []; + + public string? Body => _bodies.Count == 0 ? null : _bodies[^1]; + + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken) + { + _bodies.Add(await request.Content!.ReadAsStringAsync(cancellationToken)); + + return new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent( + """{"data":{"_0_fieldById":{"field":"A"},"_1_fieldById":{"field":"B"}}}""", + Encoding.UTF8, + "application/json") + }; + } + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchResponseSplitterTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchResponseSplitterTests.cs new file mode 100644 index 00000000000..c159093ddb0 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchResponseSplitterTests.cs @@ -0,0 +1,244 @@ +using System.Text; +using System.Text.Json; +using HotChocolate.Buffers; +using HotChocolate.Execution; +using HotChocolate.Fusion.Text.Json; +using HotChocolate.Fusion.Types; +using HotChocolate.Language; +using static HotChocolate.Fusion.Execution.Clients.AliasBatching.AliasBatchTestData; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +public sealed class AliasBatchResponseSplitterTests : FusionTestBase +{ + private const string Lookup = "query($__fusion_1_id: ID!){productById(id: $__fusion_1_id){name}}"; + + [Fact] + public void TrySplit_Should_RouteFieldsByName_When_ResponseIsOutOfOrder() + { + // arrange + using var fixture = new Fixture( + Lookup, + """{"data":{"_1_productById":{"name":"B"},"_0_productById":{"name":"A"}}}""", + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Split, status); + Assert.Equal("A", ReadName(fixture.Results[0])); + Assert.Equal("B", ReadName(fixture.Results[1])); + } + + [Fact] + public void TrySplit_Should_LeaveItemUndefined_When_ItsFieldIsMissing() + { + // arrange + using var fixture = new Fixture( + Lookup, + """{"data":{"_1_productById":{"name":"B"}}}""", + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Split, status); + Assert.Equal(JsonValueKind.Undefined, ReadItem(fixture.Results[0]).ValueKind); + Assert.Equal("B", ReadName(fixture.Results[1])); + } + + [Fact] + public void TrySplit_Should_ReturnInvalid_When_FieldCarriesNoItemPrefix() + { + // arrange + using var fixture = new Fixture( + Lookup, + """{"data":{"productById":{"name":"A"},"_1_productById":{"name":"B"}}}""", + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Invalid, status); + } + + [Fact] + public void TrySplit_Should_ReturnInvalid_When_FieldNamesAnUnknownItem() + { + // arrange + using var fixture = new Fixture( + Lookup, + """{"data":{"_0_productById":{"name":"A"},"_7_productById":{"name":"B"}}}""", + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Invalid, status); + } + + [Fact] + public void TrySplit_Should_ReturnBroadcast_When_ErrorCarriesNoPath() + { + // arrange + using var fixture = new Fixture( + Lookup, + """{"errors":[{"message":"Unknown variable."}],"data":null}""", + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Broadcast, status); + } + + [Fact] + public void TrySplit_Should_RewritePathHead_When_ErrorIsRoutedToItem() + { + // arrange + using var fixture = new Fixture( + Lookup, + """ + {"errors":[{"message":"Boom.","path":["_1_productById","name"]}], + "data":{"_0_productById":{"name":"A"},"_1_productById":{"name":null}}} + """, + itemCount: 2); + + // act + var status = AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + Assert.Equal(AliasBatchSplitStatus.Split, status); + Assert.Null(fixture.Results[0].Errors); + Assert.Equal("productById.name", ReadRoutedErrorPath(fixture.Results[1])); + } + + [Fact] + public void TrySplit_Should_ReportErrorsPerItem_When_OnlyOneItemFails() + { + // arrange + using var fixture = new Fixture( + Lookup, + """ + {"errors":[{"message":"Boom.","path":["_1_productById","name"]}], + "data":{"_0_productById":{"name":"A"},"_1_productById":{"name":null}}} + """, + itemCount: 2); + + // act + AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + // The items share one response document, so an item that no error was routed to must not + // report the errors of its siblings. + Assert.False(fixture.Results[0].HasErrors); + Assert.Null(fixture.Results[0].Errors); + Assert.True(fixture.Results[1].HasErrors); + Assert.Equal("productById.name", ReadRoutedErrorPath(fixture.Results[1])); + } + + [Fact] + public void TrySplit_Should_ExposeTheSameExtensions_When_ResponseIsSplit() + { + // arrange + using var fixture = new Fixture( + Lookup, + """ + {"data":{"_0_productById":{"name":"A"},"_1_productById":{"name":"B"}}, + "extensions":{"trace":"abc"}} + """, + itemCount: 2); + + // act + AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // assert + var first = fixture.Results[0].Extensions; + var second = fixture.Results[1].Extensions; + Assert.Same(first._parent, second._parent); + Assert.Equal(first._cursor, second._cursor); + } + + [Fact] + public void TrySplit_Should_FreeTheDocument_When_TheLastResultIsDisposed() + { + // arrange + using var fixture = new Fixture( + Lookup, + """ + {"data":{"_0_productById":{"name":"A"},"_1_productById":{"name":"B"}, + "_2_productById":{"name":"C"}}} + """, + itemCount: 3); + AliasBatchResponseSplitter.TrySplit(fixture.Document, fixture.Items, fixture.Results); + + // act + // The results of a batched response are disposed in whatever order the plan consumes + // them, so the first item goes before the item that is still being read. + fixture.Results[0].Dispose(); + fixture.Results[2].Dispose(); + + // assert + var item = ReadItem(fixture.Results[1]); + Assert.Equal("B", item.GetProperty("name").GetString()); + fixture.Results[1].Dispose(); + Assert.Throws(() => item.GetProperty("name").GetString()); + } + + private static SourceResultElement ReadItem(SourceSchemaResult result) + => result.LookupData ?? default; + + private static string? ReadName(SourceSchemaResult result) + => ReadItem(result).GetProperty("name").GetString(); + + private static string? ReadRoutedErrorPath(SourceSchemaResult result) + { + var trie = result.Errors!.Trie; + Assert.True(trie.TryGetValue("productById", out var productTrie)); + Assert.True(productTrie!.TryGetValue("name", out var nameTrie)); + return nameTrie!.Error!.Path!.ToString(); + } + + private sealed class Fixture : IDisposable + { + private readonly ChunkedArrayWriter _memory = new(); + private readonly Utf8OperationDocument _operation; + private readonly AliasBatchItem[] _items; + + public Fixture(string lookup, string response, int itemCount) + { + _operation = ParseLookup(lookup); + _items = new AliasBatchItem[itemCount]; + + for (var i = 0; i < itemCount; i++) + { + _items[i] = CreateItem(_memory, _operation, $$"""{"__fusion_1_id":"{{i}}"}"""); + } + + var payload = Encoding.UTF8.GetBytes(response); + Document = SourceResultDocument.Parse( + CommonTestExtensions.CreateArena(), + payload, + payload.Length); + Results = new SourceSchemaResult[itemCount]; + } + + public SourceResultDocument Document { get; } + + public ReadOnlySpan Items => _items; + + public SourceSchemaResult[] Results { get; } + + public void Dispose() + { + Document.Dispose(); + _operation.Dispose(); + _memory.Dispose(); + } + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchTestData.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchTestData.cs new file mode 100644 index 00000000000..fa674cce424 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchTestData.cs @@ -0,0 +1,69 @@ +using System.Text; +using HotChocolate.Buffers; +using HotChocolate.Language; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +/// +/// Builds the parsed lookup documents, variable segments and items the alias batching tests +/// operate on. +/// +internal static class AliasBatchTestData +{ + public static Utf8OperationDocument ParseLookup(string sourceText) + => Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(sourceText)); + + public static AliasBatchItem CreateItem( + ChunkedArrayWriter memory, + Utf8OperationDocument document, + string values, + int requestIndex = 0, + string lookupTypeName = "Product") + => new( + requestIndex, + GetRootField(document), + lookupTypeName, + new VariableValues(default, CreateSegment(memory, values))); + + public static JsonSegment CreateSegment(ChunkedArrayWriter memory, string values) + { + var start = memory.Position; + var bytes = Encoding.UTF8.GetBytes(values); + bytes.CopyTo(memory.GetSpan(bytes.Length)); + memory.Advance(bytes.Length); + return JsonSegment.Create(memory, start, memory.Position - start); + } + + public static Utf8FieldNode GetRootField(Utf8OperationDocument document) + { + foreach (var operation in document.GetOperations()) + { + foreach (var selection in operation.SelectionSet.GetSelections()) + { + return selection.GetField(); + } + } + + throw new InvalidOperationException("The document declares no root selection."); + } + + public static Utf8VariableDefinitionNode GetVariableDefinition( + Utf8OperationDocument document, + string name) + { + var utf8Name = Encoding.UTF8.GetBytes(name); + + foreach (var operation in document.GetOperations()) + { + foreach (var definition in operation.GetVariableDefinitions()) + { + if (definition.Utf8Name.SequenceEqual(utf8Name)) + { + return definition; + } + } + } + + throw new InvalidOperationException($"The document declares no variable '{name}'."); + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchVariableWriterTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchVariableWriterTests.cs new file mode 100644 index 00000000000..a878abb565b --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchVariableWriterTests.cs @@ -0,0 +1,175 @@ +using System.Text; +using HotChocolate.Buffers; +using HotChocolate.Language; +using HotChocolate.Text.Json; +using static HotChocolate.Fusion.Execution.Clients.AliasBatching.AliasBatchTestData; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +public sealed class AliasBatchVariableWriterTests +{ + [Fact] + public void Write_Should_PrefixEveryName_When_NoVariableIsShared() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup("query($__fusion_1_id: ID!){productById(id: $__fusion_1_id){name}}"); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"__fusion_1_id":"2"}""") + }; + + // act + var json = Write(items, []); + + // assert + json.MatchInlineSnapshot("""{"_0___fusion_1_id":"1","_1___fusion_1_id":"2"}"""); + } + + [Fact] + public void Write_Should_WriteSharedValueOnce_When_VariableIsShared() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup( + "query($search: String, $__fusion_1_id: ID!){productById(id: $__fusion_1_id){name(q: $search)}}"); + var shared = GetVariableDefinition(document, "search"); + var items = new[] + { + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"2"}""") + }; + + // act + var json = Write(items, [shared]); + + // assert + json.MatchInlineSnapshot( + """{"search":"abc","_0___fusion_1_id":"1","_1___fusion_1_id":"2"}"""); + } + + [Fact] + public void Write_Should_CopyValuesVerbatim_When_ValuesAreNested() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup("query($__fusion_1_key: KeyInput!){byKey(key: $__fusion_1_key){name}}"); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_key":{"a":[1,2,{"b":null}],"c":"x\"y"}}"""), + CreateItem(memory, document, """{"__fusion_1_key":{"a":[],"c":true}}""") + }; + + // act + var json = Write(items, []); + + // assert + json.MatchInlineSnapshot( + """{"_0___fusion_1_key":{"a":[1,2,{"b":null}],"c":"x\"y"},"_1___fusion_1_key":{"a":[],"c":true}}"""); + } + + [Fact] + public void Write_Should_CopyValuesVerbatim_When_AValueCrossesAChunkBoundary() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup("query($__fusion_1_key: KeyInput!){byKey(key: $__fusion_1_key){name}}"); + // The values start shortly before the boundary, so the value of the variable is stored in + // two chunks while its name is not. + PadToBoundary(memory, bytesBeforeBoundary: 22); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_key":{"a":[1,2,{"b":null}],"c":"x\"y"}}""") + }; + + // act + var json = Write(items, []); + + // assert + json.MatchInlineSnapshot("""{"_0___fusion_1_key":{"a":[1,2,{"b":null}],"c":"x\"y"}}"""); + } + + [Fact] + public void Write_Should_PrefixTheName_When_ANameCrossesAChunkBoundary() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup("query($__fusion_1_id: ID!){productById(id: $__fusion_1_id){name}}"); + // The values start six bytes before the boundary, so the name of the variable is stored in + // two chunks. + PadToBoundary(memory, bytesBeforeBoundary: 6); + var items = new[] { CreateItem(memory, document, """{"__fusion_1_id":"1"}""") }; + + // act + var json = Write(items, []); + + // assert + json.MatchInlineSnapshot("""{"_0___fusion_1_id":"1"}"""); + } + + [Fact] + public void Write_Should_PrefixTheName_When_ANameExceedingTheScratchBufferCrossesAChunkBoundary() + { + // arrange + // 257 bytes, one more than the stack buffer a name is gathered into, so the gathered name + // is held by pooled memory while the prefixed name is composed from it. + var name = "__fusion_1_" + new string('x', 246); + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup($"query(${name}: ID!){{productById(id: ${name}){{name}}}}"); + // The values start six bytes before the boundary, so the name of the variable is stored in + // two chunks. + PadToBoundary(memory, bytesBeforeBoundary: 6); + var items = new[] { CreateItem(memory, document, $$"""{"{{name}}":"1"}""") }; + + // act + var json = Write(items, []); + + // assert + Assert.Equal($$"""{"_0_{{name}}":"1"}""", json); + } + + [Fact] + public void Write_Should_WriteSharedValueOnce_When_ASharedNameCrossesAChunkBoundary() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup( + "query($search: String, $__fusion_1_id: ID!){productById(id: $__fusion_1_id){name(q: $search)}}"); + var shared = GetVariableDefinition(document, "search"); + PadToBoundary(memory, bytesBeforeBoundary: 6); + var items = new[] + { + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"2"}""") + }; + + // act + var json = Write(items, [shared]); + + // assert + json.MatchInlineSnapshot( + """{"search":"abc","_0___fusion_1_id":"1","_1___fusion_1_id":"2"}"""); + } + + private static string Write( + AliasBatchItem[] items, + List sharedVariables) + { + using var buffer = new PooledArrayWriter(); + var writer = new JsonWriter(buffer, default); + AliasBatchVariableWriter.Write(writer, items, sharedVariables); + return Encoding.UTF8.GetString(buffer.WrittenSpan); + } + + /// + /// Fills the memory so that the next write starts the given number of bytes before the + /// boundary of the next chunk. + /// + private static void PadToBoundary(ChunkedArrayWriter memory, int bytesBeforeBoundary) + { + var padding = JsonMemory.BufferSize - memory.Position - bytesBeforeBoundary; + memory.GetSpan(padding)[..padding].Fill((byte)' '); + memory.Advance(padding); + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchedRequestBodyTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchedRequestBodyTests.cs new file mode 100644 index 00000000000..acc1ec17637 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/AliasBatching/AliasBatchedRequestBodyTests.cs @@ -0,0 +1,132 @@ +using System.Text; +using System.Text.Json; +using HotChocolate.Buffers; +using HotChocolate.Language; +using HotChocolate.Text.Json; +using static HotChocolate.Fusion.Execution.Clients.AliasBatching.AliasBatchTestData; + +namespace HotChocolate.Fusion.Execution.Clients.AliasBatching; + +public sealed class AliasBatchedRequestBodyTests +{ + private const string Lookup = "query($__fusion_1_id: ID!){productById(id: $__fusion_1_id){name price}}"; + + [Fact] + public void WriteTo_Should_MergeItemsIntoOneOperation_When_ItemsShareABody() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup(Lookup); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"__fusion_1_id":"2"}""") + }; + + // act + var json = Write(items, []); + + // assert + json.MatchInlineSnapshot( + """ + {"query":"query Batch_0000000000000001($_0___fusion_1_id:ID!,$_1___fusion_1_id:ID!){_0_productById:productById(id:$_0___fusion_1_id){..._fusion_body_1} _1_productById:productById(id:$_1___fusion_1_id){..._fusion_body_1}} fragment _fusion_body_1 on Product{name price}","variables":{"_0___fusion_1_id":"1","_1___fusion_1_id":"2"}} + """); + } + + [Fact] + public void WriteTo_Should_ProduceAParsableOperation_When_ItemsAreMerged() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup(Lookup); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"__fusion_1_id":"2"}""") + }; + + // act + var query = ReadQuery(Write(items, [])); + + // assert + using var merged = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(query)); + Assert.Equal(["_0_productById", "_1_productById"], ReadRootAliases(merged)); + } + + [Fact] + public void WriteTo_Should_DeclareSharedVariableOnce_When_ItemsShareIt() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup( + "query($search: String, $__fusion_1_id: ID!)" + + "{productById(id: $__fusion_1_id){name(q: $search)}}"); + var shared = GetVariableDefinition(document, "search"); + var items = new[] + { + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"search":"abc","__fusion_1_id":"2"}""") + }; + + // act + var query = ReadQuery(Write(items, [shared])); + + // assert + query.MatchInlineSnapshot( + "query Batch_0000000000000001($search:String,$_0___fusion_1_id:ID!," + + "$_1___fusion_1_id:ID!){_0_productById:productById(id:$_0___fusion_1_id)" + + "{..._fusion_body_1} _1_productById:productById(id:$_1___fusion_1_id)" + + "{..._fusion_body_1}} fragment _fusion_body_1 on Product{name(q:$search)}"); + } + + [Fact] + public void WriteTo_Should_IncludeOnError_When_TheModeIsConfigured() + { + // arrange + using var memory = new ChunkedArrayWriter(); + using var document = ParseLookup(Lookup); + var items = new[] + { + CreateItem(memory, document, """{"__fusion_1_id":"1"}"""), + CreateItem(memory, document, """{"__fusion_1_id":"2"}""") + }; + + // act + var json = Write(items, [], ErrorHandlingMode.Null); + + // assert + Assert.EndsWith("""},"onError":"NULL"}""", json, StringComparison.Ordinal); + } + + private static string Write( + AliasBatchItem[] items, + List sharedVariables, + ErrorHandlingMode? onError = null) + { + var body = new AliasBatchedRequestBody(items, items.Length, sharedVariables, 1, onError); + using var buffer = new PooledArrayWriter(); + body.WriteTo(new JsonWriter(buffer, default)); + return Encoding.UTF8.GetString(buffer.WrittenSpan); + } + + private static string ReadQuery(string json) + { + using var document = JsonDocument.Parse(json); + return document.RootElement.GetProperty("query").GetString()!; + } + + private static List ReadRootAliases(Utf8OperationDocument document) + { + var aliases = new List(); + + foreach (var operation in document.GetOperations()) + { + foreach (var selection in operation.SelectionSet.GetSelections()) + { + aliases.Add(Encoding.UTF8.GetString(selection.GetField().Utf8Alias)); + } + } + + return aliases; + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/BatchBufferTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/BatchBufferTests.cs index d7d23931ac6..29fcc90c5c2 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/BatchBufferTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Clients/BatchBufferTests.cs @@ -116,13 +116,16 @@ public async Task ExecuteBatchAsync_Should_IsolateFailure_When_OneRequestFailsMi private static SourceSchemaClientRequest CreateRequest(ExecutionNode node) { + var sourceText = "query { field }"u8.ToArray(); + return new SourceSchemaClientRequest { Node = node, SchemaName = "A", OperationType = OperationType.Query, - OperationSourceText = "query { field }", + OperationSourceText = sourceText, OperationHash = 1, + OperationDocument = Utf8GraphQLOperationParser.Parse(sourceText), Variables = [new VariableValues(CompactPath.Root, JsonSegment.Empty)] }; } @@ -132,14 +135,14 @@ private static OperationBatchRequest CreateBatchRequest() return new OperationBatchRequest( ImmutableArray.Create( new FusionOperationRequest( - "query { field }", + "query { field }"u8.ToArray(), id: null, operationName: null, onError: null, VariableValues.Empty, JsonSegment.Empty), new FusionOperationRequest( - "query { field }", + "query { field }"u8.ToArray(), id: null, operationName: null, onError: null, diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs index 1ff303d0b04..94105fcff9e 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs @@ -388,7 +388,7 @@ public async Task CreateHttpClientConfiguration_Should_UseDefaults_When_NoCapabi Assert.Equal("a", httpConfig.Name); Assert.Equal(HttpSourceSchemaClientConfiguration.DefaultClientName, httpConfig.HttpClientName); Assert.Equal(new Uri("http://localhost:5000/graphql"), httpConfig.BaseAddress); - Assert.Equal(SourceSchemaClientCapabilities.All, httpConfig.Capabilities); + Assert.Equal(SourceSchemaClientCapabilities.Default, httpConfig.Capabilities); Assert.Equal(SupportedOperationType.All, httpConfig.SupportedOperations); Assert.Equal(DefaultAcceptHeader, httpConfig.DefaultAcceptHeaderValue); Assert.Equal(BatchingAcceptHeader, httpConfig.BatchingAcceptHeaderValue); @@ -437,7 +437,7 @@ public async Task CreateHttpClientConfiguration_Should_UseCustomClientName_When_ Assert.Equal("a", httpConfig.Name); Assert.Equal("my-custom-client", httpConfig.HttpClientName); Assert.Equal(new Uri("http://localhost:5000/graphql"), httpConfig.BaseAddress); - Assert.Equal(SourceSchemaClientCapabilities.All, httpConfig.Capabilities); + Assert.Equal(SourceSchemaClientCapabilities.Default, httpConfig.Capabilities); Assert.Equal(SupportedOperationType.All, httpConfig.SupportedOperations); Assert.Equal(DefaultAcceptHeader, httpConfig.DefaultAcceptHeaderValue); Assert.Equal(BatchingAcceptHeader, httpConfig.BatchingAcceptHeaderValue); @@ -596,7 +596,7 @@ public async Task CreateHttpClientConfiguration_Should_DisableSubscriptions_When Assert.Equal("a", httpConfig.Name); Assert.Equal(HttpSourceSchemaClientConfiguration.DefaultClientName, httpConfig.HttpClientName); Assert.Equal(new Uri("http://localhost:5000/graphql"), httpConfig.BaseAddress); - Assert.Equal(SourceSchemaClientCapabilities.All, httpConfig.Capabilities); + Assert.Equal(SourceSchemaClientCapabilities.Default, httpConfig.Capabilities); Assert.Equal(SupportedOperationType.Query | SupportedOperationType.Mutation, httpConfig.SupportedOperations); Assert.Equal(DefaultAcceptHeader, httpConfig.DefaultAcceptHeaderValue); Assert.Equal(BatchingAcceptHeader, httpConfig.BatchingAcceptHeaderValue); @@ -657,7 +657,7 @@ public async Task CreateHttpClientConfiguration_Should_UseCustomFormats_When_Spe Assert.Equal("a", httpConfig.Name); Assert.Equal(HttpSourceSchemaClientConfiguration.DefaultClientName, httpConfig.HttpClientName); Assert.Equal(new Uri("http://localhost:5000/graphql"), httpConfig.BaseAddress); - Assert.Equal(SourceSchemaClientCapabilities.All, httpConfig.Capabilities); + Assert.Equal(SourceSchemaClientCapabilities.Default, httpConfig.Capabilities); Assert.Equal(SupportedOperationType.All, httpConfig.SupportedOperations); Assert.Equal("application/json, text/plain", httpConfig.DefaultAcceptHeaderValue); Assert.Equal("application/jsonl", httpConfig.BatchingAcceptHeaderValue); diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/ApolloOperationBatchExecutionNodeTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/ApolloOperationBatchExecutionNodeTests.cs index fbd7b0534b9..b7473bd87cf 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/ApolloOperationBatchExecutionNodeTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/ApolloOperationBatchExecutionNodeTests.cs @@ -1,3 +1,5 @@ +using System.Text; + namespace HotChocolate.Fusion.Execution.Nodes; public sealed class ApolloOperationBatchExecutionNodeTests : FusionTestBase @@ -55,8 +57,8 @@ public void Create_Should_BuildPerLookupDocuments_When_TwoLookupDefinitions() Assert.Equal("b", node.SchemaName); string[] documents = [ - node.Lookups[0].Operation.SourceText, - node.Lookups[1].Operation.SourceText + Encoding.UTF8.GetString(node.Lookups[0].Operation.SourceText.Span), + Encoding.UTF8.GetString(node.Lookups[1].Operation.SourceText.Span) ]; documents.MatchInlineSnapshots( [ diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/OperationSourceTextTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/OperationSourceTextTests.cs new file mode 100644 index 00000000000..618b7362f2f --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Nodes/OperationSourceTextTests.cs @@ -0,0 +1,267 @@ +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +using System.Text; +using HotChocolate.Execution; +using HotChocolate.Fusion.Configuration; +using HotChocolate.Fusion.Execution.Clients; +using HotChocolate.Fusion.Execution.Nodes; +using HotChocolate.Fusion.Text.Json; +using HotChocolate.Fusion.Types; +using HotChocolate.Language; +using Microsoft.Extensions.DependencyInjection; + +namespace HotChocolate.Fusion.Execution; + +public sealed class OperationSourceTextTests : FusionTestBase +{ + private const string SourceSchemaA = + """ + type Query { + books: [Book!]! + bookById(id: ID!): Book @lookup @internal + } + + type Book @key(fields: "id") { + id: ID! + title: String! + } + """; + + private const string SourceSchemaB = + """ + type Query { + bookById(id: ID!): Book @lookup @internal + } + + type Book @key(fields: "id") { + id: ID! + rating: String! + } + """; + + [Fact] + public void Plan_Should_CarryTheParsedDocument_When_NodeIsCreated() + { + // arrange + var schema = ComposeSchema(SourceSchemaA, SourceSchemaB); + + // act + var plan = PlanOperation(schema, "{ books { rating } }"); + + // assert + // The root node and the lookup node both carry the syntax tree of their operation. + Assert.All( + plan.AllNodes.OfType(), + node => Assert.NotNull(node.Operation.Document)); + } + + [Fact] + public async Task Client_Should_ReceiveTheNodeDocument_When_TheLookupIsExecuted() + { + // arrange + var client = new RecordingClient(); + var executor = await CreateExecutorAsync(client); + + // act + await using var result = await executor.ExecuteAsync( + OperationRequestBuilder.New().SetDocument("{ books { rating } }").Build(), + TestContext.Current.CancellationToken); + + // assert + var request = Assert.Single(client.Requests, r => r.LookupTypeName is not null); + var node = Assert.IsType(request.Node); + Assert.NotNull(request.OperationDocument); + Assert.Same(node.Operation.Document, request.OperationDocument); + } + + [Fact] + public void Plan_Should_CarryTheLookupTypeName_When_NodeReadsFromALookupField() + { + // arrange + var schema = ComposeSchema(SourceSchemaA, SourceSchemaB); + + // act + var plan = PlanOperation(schema, "{ books { rating } }"); + + // assert + Assert.Equal("Book", GetLookupNode(plan).Operation.LookupTypeName); + } + + [Fact] + public void Plan_Should_CarryNoLookupTypeName_When_NodeReadsFromTheRoot() + { + // arrange + var schema = ComposeSchema(SourceSchemaA, SourceSchemaB); + + // act + var plan = PlanOperation(schema, "{ books { title } }"); + + // assert + var root = Assert.Single(plan.AllNodes.OfType()); + Assert.Null(root.Operation.LookupTypeName); + } + + [Fact] + public void Create_Should_CarryTheDocument_When_OperationIsNoLookup() + { + // arrange + var sourceText = "query { books { title } }"u8.ToArray(); + + // act + var operation = OperationSourceText.Create( + "Op_1", + OperationType.Query, + sourceText, + "hash", + lookupTypeName: null); + + // assert + Assert.True(OperationSourceText.TryGetSingleRootField(operation.Document, out _, out var rootField)); + Assert.Equal("books", Encoding.UTF8.GetString(rootField.Utf8Name)); + Assert.Null(operation.LookupTypeName); + } + + [Fact] + public void Create_Should_CarryNoLookupTypeName_When_OperationSelectsTwoRootFields() + { + // arrange + var sourceText = "query { bookById(id: 1) { title } authorById(id: 1) { name } }"u8.ToArray(); + + // act + var operation = OperationSourceText.Create( + "Op_1", + OperationType.Query, + sourceText, + "hash", + lookupTypeName: "Book"); + + // assert + Assert.Null(operation.LookupTypeName); + } + + [Fact] + public void Create_Should_Throw_When_SourceTextDoesNotParse() + { + // arrange + var sourceText = "query { books "u8.ToArray(); + + // act + void Act() => OperationSourceText.Create( + "Op_1", + OperationType.Query, + sourceText, + "hash", + lookupTypeName: null); + + // assert + Assert.Throws(Act); + } + + private static OperationExecutionNode GetLookupNode(OperationPlan plan) + => plan.AllNodes + .OfType() + .Single(t => !t.Source.IsRoot); + + private static async Task CreateExecutorAsync(ISourceSchemaClient client) + { + var services = new ServiceCollection(); + services.AddHttpClient(); + + var builder = services + .AddGraphQLGateway() + .AddInMemoryConfiguration(ComposeSchemaDocument(SourceSchemaA, SourceSchemaB)); + + builder.Services.AddSingleton(new RecordingClientFactory(client)); + + FusionSetupUtilities.Configure( + builder, + setup => + { + setup.ClientConfigurationModifiers.Add(_ => new RecordingClientConfiguration("a")); + setup.ClientConfigurationModifiers.Add(_ => new RecordingClientConfiguration("b")); + }); + + return await services.BuildGatewayAsync(TestContext.Current.CancellationToken); + } + + /// + /// Answers every request with a canned response and records the requests it received, so a + /// test can inspect what the execution nodes handed to the transport. + /// + private sealed class RecordingClient : ISourceSchemaClient + { + private static readonly byte[] s_books = """{"data":{"books":[{"id":"1"},{"id":"2"}]}}"""u8.ToArray(); + private static readonly byte[] s_book = """{"data":{"bookById":{"rating":"5"}}}"""u8.ToArray(); + private readonly List _requests = []; + + public IReadOnlyList Requests => _requests; + + public SourceSchemaClientCapabilities Capabilities => SourceSchemaClientCapabilities.None; + + public async IAsyncEnumerable ExecuteAsync( + OperationPlanContext context, + SourceSchemaClientRequest request, + [EnumeratorCancellation] CancellationToken cancellationToken) + { + await Task.Yield(); + _requests.Add(request); + + if (request.Variables.IsDefaultOrEmpty) + { + yield return CreateResult(context, s_books, CompactPath.Root, default); + yield break; + } + + foreach (var variables in request.Variables) + { + yield return CreateResult(context, s_book, variables.Path, variables.AdditionalPaths); + } + } + + private static SourceSchemaResult CreateResult( + OperationPlanContext context, + byte[] response, + CompactPath path, + CompactPathSegment additionalPaths) + { + var document = SourceResultDocument.Parse( + context.MemorySource.GetNextArena(), + response, + response.Length); + + return new SourceSchemaResult(path, document, additionalPaths: additionalPaths); + } + + public IAsyncEnumerable ExecuteBatchAsync( + OperationPlanContext context, + ImmutableArray requests, + CancellationToken cancellationToken) + => throw new NotSupportedException(); + + public IAsyncEnumerable SubscribeAsync( + OperationPlanContext context, + SourceSchemaClientRequest request, + CancellationToken cancellationToken) + => throw new NotSupportedException(); + + public ValueTask DisposeAsync() => ValueTask.CompletedTask; + } + + private sealed class RecordingClientFactory(ISourceSchemaClient client) : ISourceSchemaClientFactory + { + public bool CanHandle(ISourceSchemaClientConfiguration configuration) + => configuration is RecordingClientConfiguration; + + public ISourceSchemaClient CreateClient( + FusionSchemaDefinition schema, + ISourceSchemaClientConfiguration configuration) + => client; + } + + private sealed class RecordingClientConfiguration(string name) : ISourceSchemaClientConfiguration + { + public string Name { get; } = name; + + public SupportedOperationType SupportedOperations { get; } = SupportedOperationType.Query; + } +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/OperationPlanContextRoutingTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/OperationPlanContextRoutingTests.cs index 110e6a9a699..c3f8a070c45 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/OperationPlanContextRoutingTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/OperationPlanContextRoutingTests.cs @@ -249,13 +249,16 @@ public async Task ExecuteAsync_Should_Throw_When_RequestIsSubscription() GraphQLHttpClient.Create(new HttpClient()), new HttpSourceSchemaClientConfiguration("a", new Uri("http://localhost:5000/graphql"))); + var sourceText = "subscription { field }"u8.ToArray(); + var request = new SourceSchemaClientRequest { Node = fixture.GetRootNode(), SchemaName = "a", OperationType = OperationType.Subscription, - OperationSourceText = "subscription { field }", - OperationHash = 0 + OperationSourceText = sourceText, + OperationHash = 0, + OperationDocument = Utf8GraphQLOperationParser.Parse(sourceText) }; // act diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Results/FetchResultStoreRepresentationTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Results/FetchResultStoreRepresentationTests.cs index 69e0f33f83d..44e5fb34d86 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Results/FetchResultStoreRepresentationTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Execution/Results/FetchResultStoreRepresentationTests.cs @@ -2842,7 +2842,8 @@ private static SingleOperationDefinition GetLookupDefinition( foreach (var operation in batchNode.Operations) { if (operation is SingleOperationDefinition definition - && definition.Operation.SourceText.Contains(lookupFieldName, StringComparison.Ordinal)) + && Encoding.UTF8.GetString(definition.Operation.SourceText.Span) + .Contains(lookupFieldName, StringComparison.Ordinal)) { return definition; } @@ -2865,7 +2866,7 @@ private static RepresentationValue CreateLookupRepresentation( [], definition.Requirements, entityTypeName, - ParseLookupField(definition.Operation.SourceText)); + ParseLookupField(Encoding.UTF8.GetString(definition.Operation.SourceText.Span))); // The representation shape is a plan-time constant, so the production code // builds it once at node creation. These harness helpers mirror that by diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/GeneratedOperationNameTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/GeneratedOperationNameTests.cs new file mode 100644 index 00000000000..70373c26466 --- /dev/null +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/GeneratedOperationNameTests.cs @@ -0,0 +1,56 @@ +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Fusion.Execution.Nodes; +using HotChocolate.Fusion.Types; +using HotChocolate.Language; +using Microsoft.Extensions.ObjectPool; + +namespace HotChocolate.Fusion.Planning; + +public sealed class GeneratedOperationNameTests : FusionTestBase +{ + [Fact] + public void CreatePlan_Should_KeepTheShortHash_When_ItHoldsNameCharactersOnly() + { + // arrange + var schema = CreateCompositeSchema(); + + // act + var plan = CreatePlan(schema, "abcdef12"); + + // assert + Assert.Equal("Op_abcdef12_1", GetOperationName(plan)); + } + + [Fact] + public void CreatePlan_Should_ReplaceInvalidCharacters_When_TheShortHashIsNotBase16() + { + // arrange + var schema = CreateCompositeSchema(); + + // act + // A base64 document hash carries characters that a GraphQL name cannot hold. + var plan = CreatePlan(schema, "ab-cd+e/"); + + // assert + Assert.Equal("Op_ab_cd_e__1", GetOperationName(plan)); + } + + private static string GetOperationName(OperationPlan plan) + => plan.AllNodes.OfType().First().Operation.Name; + + private static OperationPlan CreatePlan(FusionSchemaDefinition schema, string shortHash) + { + var pool = new DefaultObjectPool>>( + new DefaultPooledObjectPolicy>>()); + var planner = new OperationPlanner(schema, new OperationCompiler(schema, pool)); + + return planner.CreatePlan( + "operation-id", + "0123456789abcdef", + shortHash, + ParseOperation("{ productBySlug(slug: \"1\") { id } }")); + } + + private static OperationDefinitionNode ParseOperation([StringSyntax("graphql")] string operationText) + => Utf8GraphQLParser.Parse(operationText).Definitions.OfType().First(); +} diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/OperationMergePolicyTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/OperationMergePolicyTests.cs index 28879c6a240..0bd254082db 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/OperationMergePolicyTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/OperationMergePolicyTests.cs @@ -1,3 +1,4 @@ +using System.Text; using HotChocolate.Fusion.Execution.Nodes; using HotChocolate.Fusion.Execution.Rewriters; using HotChocolate.Fusion.Types; @@ -109,6 +110,26 @@ public void Balanced_Same_Depth_Merges() Assert.Equal(2, batchOps[0].Targets.Length); } + [Fact] + public void Merge_Should_Dedup_Into_Single_Batch_When_Forwarded_Literal_Is_MultiByte() + { + // arrange + // The canonical plan signature is computed over UTF-8 bytes. A multi-byte + // literal ("café") in the forwarded selection combined with the + // __fusion_N_ variable-prefix rewriting would break dedup if the signature + // used character indexing instead of byte indexing. + var schema = CreateMultiByteLiteralSchema(); + + // act + var plan = PlanOperation(schema, MultiByteLiteralQuery, OperationMergePolicy.Aggressive); + + // assert + var batchOps = GetBatchOperationsForSchema(plan, "b"); + Assert.Single(batchOps); + Assert.Equal(2, batchOps[0].Targets.Length); + Assert.Contains("café", Encoding.UTF8.GetString(batchOps[0].Operation.SourceText.Span)); + } + [Fact] public void Balanced_Produces_More_Nodes_Than_Aggressive_For_Distant_Depths() { @@ -439,4 +460,53 @@ type Product @key(fields: "id") { } } """; + + private static FusionSchemaDefinition CreateMultiByteLiteralSchema() + { + return ComposeSchema( + """ + # name: a + schema { + query: Query + } + + type Query { + first: Product + second: Product + } + + type Product @key(fields: "id") { + id: ID! + } + """, + """ + # name: b + schema { + query: Query + } + + type Query { + productById(id: ID! @is(field: "id")): Product @lookup @internal + } + + type Product @key(fields: "id") { + id: ID! + translation(language: String!): String! + } + """); + } + + private const string MultiByteLiteralQuery = + """ + { + first { + id + translation(language: "café") + } + second { + id + translation(language: "café") + } + } + """; } diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/PlannerEventSourceTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/PlannerEventSourceTests.cs index 35132a70983..73dfd841e43 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/PlannerEventSourceTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/PlannerEventSourceTests.cs @@ -16,7 +16,7 @@ public void PlannerEventSource_Emits_Start_And_Stop_With_Perf_Metrics() // arrange using var listener = new PlannerEventListener(); var schema = CreateCompositeSchema(); - const string operationId = "planner-etw-start-stop"; + const string operationId = "planner_etw_start_stop"; // act var plan = CreatePlan( @@ -81,7 +81,7 @@ type User { doesNotExist } """); - const string operationId = "planner-etw-error"; + const string operationId = "planner_etw_error"; // act Assert.ThrowsAny( @@ -112,8 +112,8 @@ public void PlannerEventSource_Can_Aggregate_Perf_Metrics_Across_Plans() // arrange using var listener = new PlannerEventListener(); var schema = CreateCompositeSchema(); - const string operationId1 = "planner-etw-aggregate-1"; - const string operationId2 = "planner-etw-aggregate-2"; + const string operationId1 = "planner_etw_aggregate_1"; + const string operationId2 = "planner_etw_aggregate_2"; // act CreatePlan( @@ -162,7 +162,7 @@ public void PlannerEventSource_Emits_Guardrail_Event_When_Guardrail_Is_Exceeded( // arrange using var listener = new PlannerEventListener(); var schema = CreateCompositeSchema(); - const string operationId = "planner-etw-guardrail"; + const string operationId = "planner_etw_guardrail"; var planner = CreatePlanner( schema, new OperationPlannerOptions diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/ShareableFieldRuntimeTypeRoutingPlanningTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/ShareableFieldRuntimeTypeRoutingPlanningTests.cs index 463a06ba6ff..994c9205d92 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/ShareableFieldRuntimeTypeRoutingPlanningTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Planning/ShareableFieldRuntimeTypeRoutingPlanningTests.cs @@ -335,7 +335,7 @@ private static string[] GetRootFragmentTypeNames( params string[] fieldPath) { var root = Assert.IsType(Assert.Single(plan.RootNodes)); - var document = Utf8GraphQLParser.Parse(root.Operation.SourceText); + var document = Utf8GraphQLParser.Parse(root.Operation.SourceText.Span); var operation = Assert.Single(document.Definitions.OfType()); var selectionSet = operation.SelectionSet; @@ -375,7 +375,7 @@ private static string[] GetFragmentTypeNamesForField(OperationPlan plan, string foreach (var node in plan.AllNodes) { - var sourceText = node switch + ReadOnlyMemory? sourceText = node switch { OperationExecutionNode operationNode => operationNode.Operation.SourceText, ApolloOperationExecutionNode operationNode => operationNode.Operation.SourceText, @@ -387,7 +387,7 @@ private static string[] GetFragmentTypeNamesForField(OperationPlan plan, string continue; } - var document = Utf8GraphQLParser.Parse(sourceText); + var document = Utf8GraphQLParser.Parse(sourceText.Value.Span); var operation = Assert.Single(document.Definitions.OfType()); Collect(operation.SelectionSet); } diff --git a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Transport/Http/DefaultGraphQLHttpClientTests.cs b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Transport/Http/DefaultGraphQLHttpClientTests.cs index 2a73264d340..738d20ceefa 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Transport/Http/DefaultGraphQLHttpClientTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Execution.Tests/Transport/Http/DefaultGraphQLHttpClientTests.cs @@ -19,7 +19,7 @@ public async Task Fetch_Large_Json() using var client = new DefaultGraphQLHttpClient(server.CreateClient(), disposeInnerClient: true); var operationRequest = - new OperationRequest("{ items }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ items }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -49,7 +49,7 @@ public async Task ReadAsResult_Application_GraphQL_Response_Json_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -78,7 +78,7 @@ public async Task ReadAsResult_Application_Json_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -107,7 +107,7 @@ public async Task ReadAsResultStream_Single_Application_GraphQL_Response_Json_Re using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -145,7 +145,7 @@ public async Task ReadAsResultStream_Single_Application_Json_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -186,7 +186,7 @@ public async Task ReadAsResultStream_Single_Application_Json_ApolloRequestBatchi var operationRequest = new OperationBatchRequest( [ - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty) + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty) ]); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); @@ -233,8 +233,8 @@ public async Task ReadAsResultStream_Multi_Application_Json_ApolloRequestBatchin var operationRequest = new OperationBatchRequest( [ - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty), - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty) + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty), + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty) ]); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); @@ -274,7 +274,7 @@ public async Task ReadAsResultStream_Single_Application_Json_Lines_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = new VariableBatchRequest( - "{ number }", + "{ number }"u8.ToArray(), null, null, null, @@ -320,7 +320,7 @@ public async Task ReadAsResultStream_Multi_Application_Json_Lines_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = new VariableBatchRequest( - "{ number }", + "{ number }"u8.ToArray(), null, null, null, @@ -370,7 +370,7 @@ public async Task ReadAsResultStream_Single_Text_Event_Stream_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -420,7 +420,7 @@ public async Task ReadAsResultStream_Multi_Text_Event_Stream_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -468,7 +468,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Multi_Line_Data() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -515,7 +515,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Event_Split_Across_Reads( using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -571,7 +571,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_With_KeepAlive_Comments() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -614,7 +614,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Payload_Spanning_Several_ using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ value }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ value }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -667,7 +667,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Payload_And_Next_Event_In using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -705,7 +705,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Data_Without_Event_Is_Ign using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -742,7 +742,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Complete_With_Data_Ignore using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -780,7 +780,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Unknown_Event_With_Data_I using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -820,7 +820,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Id_Line_Inside_Event_Yiel using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -862,7 +862,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Comment_Inside_Event_Yiel using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -902,7 +902,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Multi_Comment_Block_Is_Ig using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -945,7 +945,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Id_Line_After_Data_Yields using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -990,7 +990,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Comment_After_Data_Yields using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1034,7 +1034,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Extra_Blank_Line_Between_ using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1077,7 +1077,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Complete_Prefix_Is_Ignore using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1117,7 +1117,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Event_Name_Trailing_White using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1160,7 +1160,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Complete_With_Id_Line_Ter using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1201,7 +1201,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Lone_Blank_Line_At_End_Co using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1242,7 +1242,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Stray_Blank_Then_Untermin using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1286,7 +1286,7 @@ public async Task ReadAsResultStream_Text_Event_Stream_Yield_Then_Stray_Blank_Th using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1315,7 +1315,7 @@ public async Task ReadAsResult_Large_Application_Json_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ items }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ items }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1336,7 +1336,7 @@ public async Task ReadAsResult_Large_Application_Graphql_Response_Json_Response( using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ items }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ items }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1368,7 +1368,7 @@ public async Task ReadAsResultStream_Large_Application_Json_Lines_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = new VariableBatchRequest( - "{ number }", + "{ number }"u8.ToArray(), null, null, null, @@ -1405,7 +1405,7 @@ public async Task ReadAsResultStream_Large_Application_Json_Array_Response() [ ..Enumerable.Range(0, LargeTestBatchSize) .Select(_ => - (IOperationRequest)new OperationRequest("{ number }", null, null, null, VariableValues.Empty, + (IOperationRequest)new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty)) ]); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); @@ -1453,7 +1453,7 @@ public async Task ReadAsResultStream_Large_Text_Event_Stream_Response() using var client = new DefaultGraphQLHttpClient(new HttpClient(handler)); var operationRequest = - new OperationRequest("{ number }", null, null, null, VariableValues.Empty, JsonSegment.Empty); + new OperationRequest("{ number }"u8.ToArray(), null, null, null, VariableValues.Empty, JsonSegment.Empty); var request = new GraphQLHttpRequest(operationRequest, new Uri("http://localhost:5000/graphql")); // act @@ -1499,7 +1499,7 @@ public async Task Post_Variables_Do_Not_Escape_Apostrophe_To_Unicode() var variableValues = CreateVariableValues( new Dictionary { ["description"] = description }); var operationRequest = new OperationRequest( - "mutation($description: String!) { updateDescription(description: $description) }", + "mutation($description: String!) { updateDescription(description: $description) }"u8.ToArray(), null, null, null, diff --git a/src/HotChocolate/Fusion/test/Fusion.Subscriptions.Kafka.Tests/KafkaSubscriptionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Subscriptions.Kafka.Tests/KafkaSubscriptionTests.cs index 8b53ffb091d..0331a395a52 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Subscriptions.Kafka.Tests/KafkaSubscriptionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Subscriptions.Kafka.Tests/KafkaSubscriptionTests.cs @@ -210,7 +210,7 @@ directive @fusion__eventStream( private static string GetRootResponseName(SourceSchemaClientRequest request) { - var document = Utf8GraphQLParser.Parse(request.OperationSourceText); + var document = Utf8GraphQLParser.Parse(request.OperationSourceText.Span); var operation = document.Definitions.OfType().Single(); var field = operation.SelectionSet.Selections.OfType().Single(); diff --git a/src/HotChocolate/Fusion/test/Fusion.Subscriptions.NATS.Tests/NatsSubscriptionTests.cs b/src/HotChocolate/Fusion/test/Fusion.Subscriptions.NATS.Tests/NatsSubscriptionTests.cs index a8cc3717076..4681c018274 100644 --- a/src/HotChocolate/Fusion/test/Fusion.Subscriptions.NATS.Tests/NatsSubscriptionTests.cs +++ b/src/HotChocolate/Fusion/test/Fusion.Subscriptions.NATS.Tests/NatsSubscriptionTests.cs @@ -189,7 +189,7 @@ directive @fusion__eventStream( private static string GetRootResponseName(SourceSchemaClientRequest request) { - var document = Utf8GraphQLParser.Parse(request.OperationSourceText); + var document = Utf8GraphQLParser.Parse(request.OperationSourceText.Span); var operation = document.Definitions.OfType().Single(); var field = operation.SelectionSet.Selections.OfType().Single(); diff --git a/src/HotChocolate/Language/HotChocolate.Language.slnx b/src/HotChocolate/Language/HotChocolate.Language.slnx index 9d8d8ea31cc..38f62406eb3 100644 --- a/src/HotChocolate/Language/HotChocolate.Language.slnx +++ b/src/HotChocolate/Language/HotChocolate.Language.slnx @@ -2,6 +2,7 @@ + diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/HotChocolate.Language.Utf8.SyntaxTree.csproj b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/HotChocolate.Language.Utf8.SyntaxTree.csproj new file mode 100644 index 00000000000..c4802711532 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/HotChocolate.Language.Utf8.SyntaxTree.csproj @@ -0,0 +1,22 @@ + + + + HotChocolate.Language.Utf8.SyntaxTree + HotChocolate.Language.Utf8.SyntaxTree + HotChocolate.Language + This package contains the packed UTF-8 syntax tree representation used by Hot Chocolate. + + + + + + + + + + + + + + + diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/IUtf8SyntaxNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/IUtf8SyntaxNode.cs new file mode 100644 index 00000000000..b69a7ea084b --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/IUtf8SyntaxNode.cs @@ -0,0 +1,39 @@ +using System.Buffers; + +namespace HotChocolate.Language; + +/// +/// Represents a node in the packed UTF-8 syntax tree that can write its own GraphQL source text. +/// +public interface IUtf8SyntaxNode +{ + /// + /// Writes this node's GraphQL source text to the specified buffer writer, substituting + /// variable names through . String and block string literals are + /// preserved in either formatting mode. + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments, which reproduces the node's verbatim source range. + /// Formatting verbatim with an empty map reproduces the original source byte for byte. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default); +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/SharedOrdinalSet.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/SharedOrdinalSet.cs new file mode 100644 index 00000000000..c71dcc24420 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/SharedOrdinalSet.cs @@ -0,0 +1,54 @@ +namespace HotChocolate.Language; + +/// +/// Represents the set of document-scoped variable ordinals that a batched lookup item keeps +/// unrenamed because they are shared across items. The set is a bitmask, one bit per ordinal. +/// The default value is the empty set. +/// +internal readonly ref struct SharedOrdinalSet +{ + private readonly Span _words; + + /// + /// Initializes a new instance of the struct over + /// , which is cleared so the set starts empty. The span must hold at + /// least one bit for every ordinal that will be added or tested. + /// + /// + /// The backing storage, one per 64 ordinals. + /// + internal SharedOrdinalSet(Span words) + { + words.Clear(); + _words = words; + } + + /// + /// Gets the set that contains no ordinal. + /// + internal static SharedOrdinalSet Empty => default; + + /// + /// Adds to the set. + /// + /// + /// The document-scoped variable ordinal. + /// + internal void Add(int ordinal) + => _words[ordinal >> 6] |= 1UL << (ordinal & 63); + + /// + /// Determines whether is in the set. + /// + /// + /// The document-scoped variable ordinal. + /// + /// + /// when the ordinal is in the set; otherwise, . + /// + internal readonly bool Contains(int ordinal) + { + var word = ordinal >> 6; + return word < _words.Length && (_words[word] & (1UL << (ordinal & 63))) != 0; + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FieldNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FieldNode.cs new file mode 100644 index 00000000000..f5bae46b449 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FieldNode.cs @@ -0,0 +1,226 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over a field selection in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8FieldNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8FieldNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.Field); + } + + /// + /// Gets the document this field belongs to. + /// + internal Utf8OperationDocument Document => _document; + + /// + /// Gets the field name. + /// + internal string Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(NameCursor()); + return _document.GetString(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the UTF-8 encoded field name. + /// + public ReadOnlySpan Utf8Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(NameCursor()); + return _document.GetSource(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets a value indicating whether this field has an alias. + /// + public bool HasAlias + { + get + { + CheckValidInstance(); + return _document.GetRow(_cursor + 1).Kind is Utf8SyntaxKind.Alias; + } + } + + /// + /// Gets the field alias, or when no alias is declared. + /// + internal string? Alias + { + get + { + CheckValidInstance(); + var aliasRow = _document.GetRow(_cursor + 1); + return aliasRow.Kind is Utf8SyntaxKind.Alias + ? _document.GetString(aliasRow.Location, aliasRow.SizeOrLength) + : null; + } + } + + /// + /// Gets the UTF-8 encoded field alias. + /// + public ReadOnlySpan Utf8Alias + { + get + { + CheckValidInstance(); + var aliasRow = _document.GetRow(_cursor + 1); + return aliasRow.Kind is Utf8SyntaxKind.Alias + ? _document.GetSource(aliasRow.Location, aliasRow.SizeOrLength) + : []; + } + } + + /// + /// Gets a value indicating whether this field has a selection set. + /// + public bool HasSelectionSet + { + get + { + CheckValidInstance(); + return SelectionSetCursor() >= 0; + } + } + + /// + /// Returns the cursor of the field selection set, or -1 when the field declares no + /// selection set. + /// + internal int SelectionSetCursor() + => _document.FindSelectionSet( + NameCursor() + 1, + _cursor + _document.GetRow(_cursor).NumberOfRows); + + /// + /// Gets the field selection set. + /// + public Utf8SelectionSetNode SelectionSet + { + get + { + CheckValidInstance(); + var cursor = SelectionSetCursor(); + return cursor >= 0 + ? new Utf8SelectionSetNode(_document, cursor) + : throw new InvalidOperationException("The field has no selection set."); + } + } + + /// + /// Writes this field's GraphQL source text to the specified buffer writer, substituting + /// variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + /// + /// Writes this field's GraphQL source text to the specified syntax writer in compact form, + /// inserting in front of every variable name whose ordinal + /// is not in . The delimiters of a JSON string value are not written. + /// + /// + /// The syntax writer that receives the UTF-8 encoded output. + /// + /// + /// The bytes inserted in front of each renamed variable name. + /// + /// + /// The ordinals of the variables that keep their original name. + /// + internal void Format( + Utf8SyntaxWriter writer, + ReadOnlySpan variablePrefix, + SharedOrdinalSet shared) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Write(_document, _cursor, writer, variablePrefix, shared); + } + + /// + /// Writes this field's GraphQL source text without its selection set to the specified syntax + /// writer in compact form, inserting in front of every + /// variable name whose ordinal is not in . The delimiters of a JSON + /// string value are not written. + /// + /// + /// The syntax writer that receives the UTF-8 encoded output. + /// + /// + /// The bytes inserted in front of each renamed variable name. + /// + /// + /// The ordinals of the variables that keep their original name. + /// + internal void FormatWithoutSelectionSet( + Utf8SyntaxWriter writer, + ReadOnlySpan variablePrefix, + SharedOrdinalSet shared) + { + CheckValidInstance(); + Utf8SyntaxFormatter.WriteFieldWithoutSelectionSet( + _document, _cursor, writer, variablePrefix, shared); + } + + private int NameCursor() + { + var next = _cursor + 1; + return _document.GetRow(next).Kind is Utf8SyntaxKind.Alias ? next + 1 : next; + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentDefinitionNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentDefinitionNode.cs new file mode 100644 index 00000000000..899e31d1a89 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentDefinitionNode.cs @@ -0,0 +1,205 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over a fragment definition in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8FragmentDefinitionNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8FragmentDefinitionNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.FragmentDefinition); + } + + /// + /// Gets the fragment name. + /// + internal string Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetString(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the UTF-8 encoded fragment name. + /// + public ReadOnlySpan Utf8Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetSource(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the fragment type condition. + /// + internal string TypeCondition + { + get + { + CheckValidInstance(); + var typeRow = _document.GetRow(_document.SkipVariableDefinitions(_cursor + 2)); + return _document.GetString(typeRow.Location, typeRow.SizeOrLength); + } + } + + /// + /// Gets the UTF-8 encoded fragment type condition. + /// + public ReadOnlySpan Utf8TypeCondition + { + get + { + CheckValidInstance(); + var typeRow = _document.GetRow(_document.SkipVariableDefinitions(_cursor + 2)); + return _document.GetSource(typeRow.Location, typeRow.SizeOrLength); + } + } + + /// + /// Gets the variable definitions declared by this fragment. + /// + public Utf8VariableDefinitionEnumerable GetVariableDefinitions() + { + CheckValidInstance(); + return new Utf8VariableDefinitionEnumerable(_document, _cursor + 2); + } + + /// + /// Gets the root selection set of this fragment. + /// + public Utf8SelectionSetNode SelectionSet + { + get + { + CheckValidInstance(); + return new Utf8SelectionSetNode( + _document, + _document.FindSelectionSet( + _document.SkipVariableDefinitions(_cursor + 2) + 1, + _cursor + _document.GetRow(_cursor).NumberOfRows)); + } + } + + /// + /// Writes this fragment's GraphQL source text to the specified buffer writer, substituting + /// variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} + +/// +/// Provides pattern-based enumeration over fragment definitions without collection interfaces. +/// +public readonly struct Utf8FragmentDefinitionEnumerable +{ + private readonly Utf8OperationDocument? _document; + + internal Utf8FragmentDefinitionEnumerable(Utf8OperationDocument document) + { + _document = document; + } + + /// + /// Gets an enumerator over the fragment definitions. + /// + public Enumerator GetEnumerator() => new(_document); + + /// + /// Enumerates fragment definitions without implementing enumerator interfaces. + /// + public struct Enumerator + { + private readonly Utf8OperationDocument? _document; + private int _next; + private int _current; + + internal Enumerator(Utf8OperationDocument? document) + { + _document = document; + _next = 0; + _current = -1; + } + + /// + /// Gets the current fragment definition. + /// + public readonly Utf8FragmentDefinitionNode Current + => _document is null || _current < 0 + ? default + : new Utf8FragmentDefinitionNode(_document, _current); + + /// + /// Advances to the next fragment definition. + /// + public bool MoveNext() + { + while (_document is not null && _next < _document.RowCount) + { + var cursor = _next; + var row = _document.GetRow(cursor); + _next = checked(cursor + row.NumberOfRows); + + if (row.Kind is Utf8SyntaxKind.FragmentDefinition) + { + _current = cursor; + return true; + } + } + + _current = -1; + return false; + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentSpreadNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentSpreadNode.cs new file mode 100644 index 00000000000..4499c8b06e5 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8FragmentSpreadNode.cs @@ -0,0 +1,89 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over a fragment spread in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8FragmentSpreadNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8FragmentSpreadNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.FragmentSpread); + } + + /// + /// Gets the referenced fragment name. + /// + internal string Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetString(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the UTF-8 encoded referenced fragment name. + /// + public ReadOnlySpan Utf8Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetSource(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Writes this fragment spread's GraphQL source text to the specified buffer writer, + /// substituting variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8InlineFragmentNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8InlineFragmentNode.cs new file mode 100644 index 00000000000..b1feb5cc3fb --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8InlineFragmentNode.cs @@ -0,0 +1,121 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over an inline fragment in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8InlineFragmentNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8InlineFragmentNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.InlineFragment); + } + + /// + /// Gets a value indicating whether this inline fragment has a type condition. + /// + public bool HasTypeCondition + { + get + { + CheckValidInstance(); + return _document.GetRow(_cursor + 1).Kind is Utf8SyntaxKind.TypeCondition; + } + } + + /// + /// Gets the type condition, or when none is declared. + /// + internal string? TypeCondition + { + get + { + CheckValidInstance(); + var typeRow = _document.GetRow(_cursor + 1); + return typeRow.Kind is Utf8SyntaxKind.TypeCondition + ? _document.GetString(typeRow.Location, typeRow.SizeOrLength) + : null; + } + } + + /// + /// Gets the UTF-8 encoded type condition. + /// + public ReadOnlySpan Utf8TypeCondition + { + get + { + CheckValidInstance(); + var typeRow = _document.GetRow(_cursor + 1); + return typeRow.Kind is Utf8SyntaxKind.TypeCondition + ? _document.GetSource(typeRow.Location, typeRow.SizeOrLength) + : []; + } + } + + /// + /// Gets the inline fragment selection set. + /// + public Utf8SelectionSetNode SelectionSet + { + get + { + CheckValidInstance(); + return new Utf8SelectionSetNode( + _document, + _document.FindSelectionSet( + _cursor + 1, + _cursor + _document.GetRow(_cursor).NumberOfRows)); + } + } + + /// + /// Writes this inline fragment's GraphQL source text to the specified buffer writer, + /// substituting variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDefinitionNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDefinitionNode.cs new file mode 100644 index 00000000000..8ff50f6b032 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDefinitionNode.cs @@ -0,0 +1,224 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over an operation definition in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8OperationDefinitionNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8OperationDefinitionNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind + is Utf8SyntaxKind.OperationQuery + or Utf8SyntaxKind.OperationMutation + or Utf8SyntaxKind.OperationSubscription); + } + + /// + /// Gets a value indicating whether this operation has a name. + /// + public bool HasName + { + get + { + CheckValidInstance(); + return _document.GetRow(_cursor + 1).Kind is Utf8SyntaxKind.Name; + } + } + + /// + /// Gets the operation name, or when the operation is anonymous. + /// + internal string? Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return nameRow.Kind is Utf8SyntaxKind.Name + ? _document.GetString(nameRow.Location, nameRow.SizeOrLength) + : null; + } + } + + /// + /// Gets the UTF-8 encoded operation name. + /// + public ReadOnlySpan Utf8Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return nameRow.Kind is Utf8SyntaxKind.Name + ? _document.GetSource(nameRow.Location, nameRow.SizeOrLength) + : []; + } + } + + /// + /// Gets the operation type. + /// + public OperationType Operation + { + get + { + CheckValidInstance(); + return _document.GetRow(_cursor).Kind switch + { + Utf8SyntaxKind.OperationMutation => OperationType.Mutation, + Utf8SyntaxKind.OperationSubscription => OperationType.Subscription, + _ => OperationType.Query + }; + } + } + + /// + /// Gets the variable definitions declared by this operation. + /// + public Utf8VariableDefinitionEnumerable GetVariableDefinitions() + { + CheckValidInstance(); + return new Utf8VariableDefinitionEnumerable(_document, VariableStart()); + } + + /// + /// Gets the root selection set of this operation. + /// + public Utf8SelectionSetNode SelectionSet + { + get + { + CheckValidInstance(); + return new Utf8SelectionSetNode( + _document, + _document.FindSelectionSet( + VariableStart(), + _cursor + _document.GetRow(_cursor).NumberOfRows)); + } + } + + /// + /// Writes this operation's GraphQL source text to the specified buffer writer, substituting + /// variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + private int VariableStart() + { + var next = _cursor + 1; + return _document.GetRow(next).Kind is Utf8SyntaxKind.Name ? next + 1 : next; + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} + +/// +/// Provides pattern-based enumeration over operation definitions without collection interfaces. +/// +public readonly struct Utf8OperationDefinitionEnumerable +{ + private readonly Utf8OperationDocument? _document; + + internal Utf8OperationDefinitionEnumerable(Utf8OperationDocument document) + { + _document = document; + } + + /// + /// Gets an enumerator over the operation definitions. + /// + public Enumerator GetEnumerator() => new(_document); + + /// + /// Enumerates operation definitions without implementing enumerator interfaces. + /// + public struct Enumerator + { + private readonly Utf8OperationDocument? _document; + private int _next; + private int _current; + + internal Enumerator(Utf8OperationDocument? document) + { + _document = document; + _next = 0; + _current = -1; + } + + /// + /// Gets the current operation definition. + /// + public readonly Utf8OperationDefinitionNode Current + => _document is null || _current < 0 + ? default + : new Utf8OperationDefinitionNode(_document, _current); + + /// + /// Advances to the next operation definition. + /// + public bool MoveNext() + { + while (_document is not null && _next < _document.RowCount) + { + var cursor = _next; + var row = _document.GetRow(cursor); + _next = checked(cursor + row.NumberOfRows); + + if (row.Kind + is Utf8SyntaxKind.OperationQuery + or Utf8SyntaxKind.OperationMutation + or Utf8SyntaxKind.OperationSubscription) + { + _current = cursor; + return true; + } + } + + _current = -1; + return false; + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.DbRow.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.DbRow.cs new file mode 100644 index 00000000000..ea49f3375a4 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.DbRow.cs @@ -0,0 +1,80 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace HotChocolate.Language; + +public sealed partial class Utf8OperationDocument +{ + [StructLayout(LayoutKind.Sequential)] + internal readonly struct DbRow + { + internal const int Size = 12; + + /// + /// The largest number of rows a single node can span, including its own. + /// + internal const int MaxNumberOfRows = 0x07FFFFFF; + + /// + /// Selects the row count from . The row count occupies + /// the low 27 bits, so the mask and the largest representable row count are the same value. + /// + private const int NumberOfRowsMask = MaxNumberOfRows; + + // Sign bit is currently unassigned + private readonly int _location; + + // Sign bit is currently unassigned + private readonly int _sizeOrLength; + + // Top five bits are the Utf8SyntaxKind + // the remaining 27 bits are the number of rows this node spans (including its own) + private readonly int _kindAndNumberOfRows; + + internal DbRow( + Utf8SyntaxKind kind, + int location, + int sizeOrLength, + int numberOfRows) + { + Debug.Assert(kind is > Utf8SyntaxKind.None and <= Utf8SyntaxKind.NonNullType); + Debug.Assert((byte)kind < 1 << 5); + Debug.Assert(location >= 0); + Debug.Assert(sizeOrLength >= 0); + Debug.Assert(numberOfRows is >= 1 and <= MaxNumberOfRows); + Debug.Assert(Unsafe.SizeOf() == Size); + + _location = location; + _sizeOrLength = sizeOrLength; + _kindAndNumberOfRows = ((int)kind << 27) | numberOfRows; + } + + /// + /// Byte offset of the first byte of this node's source text. + /// + internal int Location => _location; + + /// + /// Byte length of this node's source text. For a row that represents a single token this + /// is the token length; for every other kind it is the length of the node's source range. + /// + internal int SizeOrLength => _sizeOrLength; + + /// + /// Exclusive byte offset one past the last byte of this node's source text. + /// + internal int SourceEnd => _location + _sizeOrLength; + + /// + /// Number of metadata rows this node spans, including the node itself. + /// + internal int NumberOfRows => _kindAndNumberOfRows & NumberOfRowsMask; + + /// + /// The kind of syntax node represented by this row. + /// + internal Utf8SyntaxKind Kind + => (Utf8SyntaxKind)(unchecked((uint)_kindAndNumberOfRows) >> 27); + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.MetaDb.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.MetaDb.cs new file mode 100644 index 00000000000..49f221c2668 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.MetaDb.cs @@ -0,0 +1,111 @@ +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace HotChocolate.Language; + +public sealed partial class Utf8OperationDocument +{ + /// + /// Holds the packed metadata rows that describe the structure of a + /// . + /// + internal struct MetaDb + { + private byte[]? _buffer; + private readonly int _length; + private readonly bool _pooled; + private int _rowCount; + + private MetaDb(byte[] buffer, int length, bool pooled) + { + _buffer = buffer; + _length = length; + _pooled = pooled; + _rowCount = length / DbRow.Size; + } + + /// + /// Gets the logical byte length of the metadata. + /// + internal readonly int Length => _length; + + /// + /// Gets the number of rows stored in the metadata. + /// + internal readonly int RowCount => _rowCount; + + /// + /// Creates a metadata database over . The buffer may be larger + /// than ; all access is bounded by . + /// + /// + /// The buffer that holds the packed rows. + /// + /// + /// The logical byte length, which must be a whole number of rows. + /// + /// + /// When , is returned to + /// on disposal. + /// + /// + /// is not a whole number of rows. + /// + internal static MetaDb Create(byte[] buffer, int length, bool pooled) + { + if (length % DbRow.Size != 0) + { + throw new ArgumentException("The metadata is not row aligned.", nameof(length)); + } + + return new MetaDb(buffer, length, pooled); + } + + /// + /// Reads the row at . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly DbRow GetRow(int index) + { + if ((uint)index >= (uint)_rowCount) + { + ThrowIndexOutOfRangeOrDisposed(); + } + +#if NETSTANDARD2_0 + ref var start = ref MemoryMarshal.GetReference(_buffer!.AsSpan()); +#else + ref var start = ref MemoryMarshal.GetArrayDataReference(_buffer!); +#endif + return Unsafe.ReadUnaligned( + ref Unsafe.Add(ref start, (nint)(uint)index * DbRow.Size)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private readonly void ThrowIndexOutOfRangeOrDisposed() + { + if (_buffer is null) + { + throw new ObjectDisposedException(nameof(Utf8OperationDocument)); + } + + throw new ArgumentOutOfRangeException("index"); + } + + /// + /// Releases the metadata buffer, returning it to the pool when it was rented. + /// + internal void Dispose() + { + var buffer = _buffer; + _buffer = null; + _rowCount = 0; + + if (_pooled && buffer is not null) + { + ArrayPool.Shared.Return(buffer); + } + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.VariableTable.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.VariableTable.cs new file mode 100644 index 00000000000..42d22adbca0 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.VariableTable.cs @@ -0,0 +1,194 @@ +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace HotChocolate.Language; + +public sealed partial class Utf8OperationDocument +{ + /// + /// Holds the position-sorted table of variable occurrences recorded while parsing a + /// . Each occurrence is a site that points at the + /// name token of a variable, together with a document-scoped ordinal that identifies the + /// distinct variable name it refers to. + /// + /// + /// A site packs an int name-token position, a ushort ordinal and a + /// ushort reserved slot. The reserved slot is always zero for now; it is the future + /// site-kind field for the rename-site generalization, for example fragment names. + /// + internal struct VariableTable + { + // Layout: siteCount site entries of SiteSize bytes, immediately followed by + // ordinalCount directory entries of DirectoryEntrySize bytes. A site entry is + // [int position][ushort ordinal][ushort reserved]; a directory entry is + // [int nameStart][int length]. + private const int SiteSize = 8; + private const int DirectoryEntrySize = 8; + + private byte[]? _buffer; + private int _siteCount; + private int _ordinalCount; + private readonly bool _pooled; + private bool _disposed; + + private VariableTable(byte[]? buffer, int siteCount, int ordinalCount, bool pooled) + { + _buffer = buffer; + _siteCount = siteCount; + _ordinalCount = ordinalCount; + _pooled = pooled; + } + + /// + /// Gets an empty table that records no variable occurrences. + /// + internal static VariableTable Empty => default; + + /// + /// Gets the number of recorded sites. + /// + internal readonly int SiteCount => _siteCount; + + /// + /// Gets the number of distinct variable names. + /// + internal readonly int VariableCount => _ordinalCount; + + /// + /// Creates a table over . The buffer may be larger than the + /// logical size; all access is bounded by the counts. + /// + /// + /// The buffer that holds the packed sites and directory. + /// + /// + /// The number of recorded sites. + /// + /// + /// The number of distinct variable names. + /// + /// + /// When , is returned to + /// on disposal. + /// + internal static VariableTable Create(byte[] buffer, int siteCount, int ordinalCount, bool pooled) + => new(buffer, siteCount, ordinalCount, pooled); + + /// + /// Gets the source offset of the name token of the site at . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly int GetSitePosition(int index) + { + if ((uint)index >= (uint)_siteCount) + { + ThrowIndexOutOfRangeOrDisposed(nameof(index)); + } + + return Unsafe.ReadUnaligned( + ref Unsafe.Add(ref BufferStart(), (nint)(uint)index * SiteSize)); + } + + /// + /// Returns the index of the first site whose name-token position is at or after + /// , or when no such site exists. + /// Sites are position-sorted by construction, so this is a binary search. + /// + internal readonly int FindFirstSiteAtOrAfter(int position) + { + var lo = 0; + var hi = _siteCount; + + while (lo < hi) + { + var mid = (int)(((uint)lo + (uint)hi) >> 1); + if (GetSitePosition(mid) < position) + { + lo = mid + 1; + } + else + { + hi = mid; + } + } + + return lo; + } + + /// + /// Gets the ordinal of the distinct variable name that the site at + /// refers to. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly int GetSiteOrdinal(int index) + { + if ((uint)index >= (uint)_siteCount) + { + ThrowIndexOutOfRangeOrDisposed(nameof(index)); + } + + return Unsafe.ReadUnaligned( + ref Unsafe.Add(ref BufferStart(), ((nint)(uint)index * SiteSize) + 4)); + } + + /// + /// Gets the source offset and token length of the name of the first occurrence of the + /// distinct variable name identified by . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal readonly void GetVariableName(int ordinal, out int nameStart, out int length) + { + if ((uint)ordinal >= (uint)_ordinalCount) + { + ThrowIndexOutOfRangeOrDisposed(nameof(ordinal)); + } + + ref var entry = ref Unsafe.Add( + ref BufferStart(), + ((nint)_siteCount * SiteSize) + ((nint)(uint)ordinal * DirectoryEntrySize)); + nameStart = Unsafe.ReadUnaligned(ref entry); + length = Unsafe.ReadUnaligned(ref Unsafe.Add(ref entry, 4)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private readonly ref byte BufferStart() +#if NETSTANDARD2_0 + => ref MemoryMarshal.GetReference(_buffer!.AsSpan()); +#else + => ref MemoryMarshal.GetArrayDataReference(_buffer!); +#endif + + [MethodImpl(MethodImplOptions.NoInlining)] + private readonly void ThrowIndexOutOfRangeOrDisposed(string paramName) + { + if (_buffer is null) + { + throw new ObjectDisposedException(nameof(Utf8OperationDocument)); + } + + throw new ArgumentOutOfRangeException(paramName); + } + + /// + /// Releases the table buffer, returning it to the pool when it was rented. + /// + internal void Dispose() + { + if (!_disposed) + { + var buffer = _buffer; + _buffer = null; + _siteCount = 0; + _ordinalCount = 0; + + if (_pooled && buffer is not null) + { + ArrayPool.Shared.Return(buffer); + } + + _disposed = true; + } + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.cs new file mode 100644 index 00000000000..22a6a6bccf5 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocument.cs @@ -0,0 +1,225 @@ +using System.Buffers; +using System.Runtime.InteropServices; +using System.Text; +using HotChocolate.Buffers; + +namespace HotChocolate.Language; + +/// +/// Represents an executable GraphQL document as a packed, immutable UTF-8 syntax tree over +/// operations and fragments. The document preserves the original source ranges and formats them +/// verbatim, splicing in variable-name substitutions on demand while every other byte is +/// reproduced unchanged. +/// +public sealed partial class Utf8OperationDocument : IDisposable, IUtf8SyntaxNode +{ + private static readonly Encoding s_utf8 = Encoding.UTF8; + private readonly ReadOnlyMemorySegment _source; + private readonly byte[] _sourceBuffer; + private readonly int _sourceStart; + private MetaDb _metaDb; + private VariableTable _variables; + private int _disposed; + + internal Utf8OperationDocument( + ReadOnlyMemorySegment source, + MetaDb metaDb, + VariableTable variables) + { + if (source.IsEmpty) + { + throw new ArgumentException("The source must not be empty.", nameof(source)); + } + + _source = source; + _metaDb = metaDb; + _variables = variables; + + if (MemoryMarshal.TryGetArray(source.Memory, out var array)) + { + _sourceBuffer = array.Array!; + _sourceStart = array.Offset; + } + else + { + // The owner is not array-backed; copy once so hot reads stay array based. + _sourceBuffer = source.Memory.ToArray(); + _sourceStart = 0; + } + } + + /// + /// Gets the operation definitions in this document. + /// + public Utf8OperationDefinitionEnumerable GetOperations() + => new(this); + + /// + /// Gets the fragment definitions in this document. + /// + public Utf8FragmentDefinitionEnumerable GetFragments() + => new(this); + + /// + /// Writes the GraphQL source text of this document to the specified buffer writer, + /// substituting variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + if (_disposed != 0) + { + throw new ObjectDisposedException(nameof(Utf8OperationDocument)); + } + + Utf8SyntaxFormatter.FormatDocument( + this, writer, indented, formatAsJsonStringValue, variables); + } + + internal int RowCount => _metaDb.RowCount; + + internal int SourceLength => _source.Length; + + internal int MetadataLength => _metaDb.Length; + + internal DbRow GetRow(int index) => _metaDb.GetRow(index); + + /// + /// Gets the number of distinct variable names recorded in this document. + /// + public int VariableCount => _variables.VariableCount; + + /// + /// Gets the number of recorded variable occurrence sites in this document. + /// + internal int VariableSiteCount => _variables.SiteCount; + + /// + /// Returns the name, without the leading dollar sign, of the distinct variable identified by + /// . Ordinals are document-scoped and assigned by first occurrence + /// in document order. + /// + public ReadOnlySpan GetVariableName(int ordinal) + { + _variables.GetVariableName(ordinal, out var nameStart, out var length); + return GetSource(nameStart, length); + } + + /// + /// Returns the source offset of the name token of the site at . + /// + internal int GetVariableSitePosition(int index) => _variables.GetSitePosition(index); + + /// + /// Returns the ordinal of the distinct variable that the site at + /// refers to. + /// + internal int GetVariableSiteOrdinal(int index) => _variables.GetSiteOrdinal(index); + + /// + /// Returns the index of the first variable site whose name-token position is at or after + /// , or when no such site exists. + /// + internal int FindFirstVariableSite(int position) => _variables.FindFirstSiteAtOrAfter(position); + + /// + /// Returns the index of the first row at or after that is not a + /// variable definition, hopping over each variable definition and the rows it spans. + /// + internal int SkipVariableDefinitions(int start) + { + var index = start; + var rowCount = RowCount; + + while (index < rowCount) + { + var row = GetRow(index); + if (row.Kind is not Utf8SyntaxKind.VariableDefinition) + { + break; + } + + index += row.NumberOfRows; + } + + return index; + } + + /// + /// Returns the index of the selection set row in the sibling run [start, end), or + /// -1 when the run declares no selection set. Each sibling and the rows it spans are + /// hopped over. + /// + internal int FindSelectionSet(int start, int end) + { + var index = start; + + while (index < end) + { + var row = GetRow(index); + if (row.Kind is Utf8SyntaxKind.SelectionSet) + { + return index; + } + + index += row.NumberOfRows; + } + + return -1; + } + + internal ReadOnlySpan GetSource(int start, int length) + { + if (start < 0 || length < 0 || start > _source.Length - length) + { + throw new InvalidOperationException("The syntax node contains an invalid source range."); + } + + return _sourceBuffer.AsSpan(_sourceStart + start, length); + } + + internal string GetString(int start, int length) + { +#if NETSTANDARD2_0 + return s_utf8.GetString(_sourceBuffer, _sourceStart + start, length); +#else + return s_utf8.GetString(GetSource(start, length)); +#endif + } + + /// + /// Releases pooled resources held by this document. Any further use of the document + /// is invalid. + /// + public void Dispose() + { + if (Interlocked.Exchange(ref _disposed, 1) != 0) + { + return; + } + + _metaDb.Dispose(); + _variables.Dispose(); + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocumentBuilder.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocumentBuilder.cs new file mode 100644 index 00000000000..ef4f9a7018d --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8OperationDocumentBuilder.cs @@ -0,0 +1,560 @@ +using System.Buffers; +using System.Buffers.Text; + +namespace HotChocolate.Language; + +internal struct Utf8OperationDocumentBuilder +{ + private const int InitialCapacity = 4; + private const int PrefixBufferLength = 12; + private const int StackWordThreshold = 64; + + private readonly Utf8SyntaxWriter _writer; + private Utf8FieldNode[]? _items; + private int _itemCount; + private Utf8VariableDefinitionNode[]? _sharedDefinitions; + private int _sharedCount; + private WriterStage _stage; + private bool _opened; + private bool _keywordWritten; + private bool _parenOpened; + + private Utf8OperationDocumentBuilder(IBufferWriter writer, bool formatAsJsonStringValue) + => _writer = new Utf8SyntaxWriter(writer, formatAsJsonStringValue); + + /// + /// Creates a new builder that streams a batched lookup operation into . + /// + /// + /// The operation is streamed as it is built, so when a call fails after the first content byte + /// was written, the destination buffer holds a partial operation and must be discarded. + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The new builder. + /// + /// + /// is . + /// + internal static Utf8OperationDocumentBuilder New( + IBufferWriter writer, + bool formatAsJsonStringValue = false) + { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + return new Utf8OperationDocumentBuilder(writer, formatAsJsonStringValue); + } + + /// + /// Sets the name of the operation and writes it immediately. The name must be set before any + /// shared variable or root selection is added. + /// + /// + /// The operation name. + /// + /// + /// The builder for chaining. + /// + /// + /// is . + /// + /// + /// The name is set out of order. + /// + internal Utf8OperationDocumentBuilder SetName(string name) + { + if (name is null) + { + throw new ArgumentNullException(nameof(name)); + } + + EnsureCanSetName(); + EnsureKeyword(); + _writer.Write(" "u8); + _writer.Write(name); + + _stage = WriterStage.Named; + return this; + } + + /// + /// Sets the name of the operation and writes it immediately. The name must be set before any + /// shared variable or root selection is added. + /// + /// + /// The UTF-8 encoded operation name. The bytes are written immediately and need not outlive + /// the call. + /// + /// + /// The builder for chaining. + /// + /// + /// The name is set out of order. + /// + internal Utf8OperationDocumentBuilder SetName(ReadOnlySpan name) + { + EnsureCanSetName(); + EnsureKeyword(); + _writer.Write(" "u8); + _writer.Write(name); + + _stage = WriterStage.Named; + return this; + } + + /// + /// Declares a variable that is shared across all items and writes its definition immediately. + /// A shared variable is declared once and keeps its original name, so items that use it are not + /// prefixed. Shared variables must be added before any root selection. + /// + /// + /// The variable definition to declare. Its source range is written in compact form. + /// + /// + /// The builder for chaining. + /// + /// + /// The shared variable is added out of order, or is not + /// associated with a document. + /// + internal Utf8OperationDocumentBuilder AddSharedVariable(Utf8VariableDefinitionNode definition) + { + EnsureCanAddSharedVariable(); + + // Reading the name validates the view before any bytes are written. + _ = definition.Utf8Name; + + EnsureKeyword(); + WriteDefinitionSeparator(); + definition.Format(_writer, indented: false); + + if (_sharedDefinitions is null || _sharedDefinitions.Length == _sharedCount) + { + GrowSharedDefinitions(); + } + + _sharedDefinitions![_sharedCount++] = definition; + _stage = WriterStage.SharedVariables; + return this; + } + + /// + /// Adds a root selection to the batched operation and writes its renamed variable definitions + /// immediately. The field is emitted as an aliased copy whose variables are renamed per item, + /// and its body is written when the operation is completed. + /// + /// + /// The root field selection to add. + /// + /// + /// The builder for chaining. + /// + /// + /// The selection is added after the operation is completed, the selection is not associated + /// with a document, or the source document does not contain exactly one operation. + /// + /// + /// carries an alias, or its source document contains a fragment + /// spread. Batched lookup selections must be plain fields, and fragment spreads are not + /// supported. + /// + internal Utf8OperationDocumentBuilder AddRootSelection(Utf8FieldNode selection) + { + EnsureCanAddRootSelection(); + + var document = selection.Document; + + if (document is null) + { + throw new InvalidOperationException( + "The root selection is not associated with a document."); + } + + if (selection.HasAlias) + { + throw new NotSupportedException( + "A batched lookup root selection must be a plain field without an alias."); + } + + if (IsNewDocument(document) && ContainsFragmentSpread(document)) + { + throw new NotSupportedException( + "Fragment spreads are not supported in batched lookup selections."); + } + + var operationCursor = FindSingleOperationCursor(document); + + EnsureKeyword(); + WriteItemVariableDefinitions(document, operationCursor, _itemCount); + + if (_items is null || _items.Length == _itemCount) + { + GrowItems(); + } + + _items![_itemCount++] = selection; + _stage = WriterStage.RootSelections; + return this; + } + + /// + /// Writes the item bodies and closes the batched lookup operation. The builder is single use, + /// and a second call throws. + /// + /// + /// The operation has already been completed, or no root selection was added. + /// + internal void Complete() + { + EnsureCanComplete(); + _stage = WriterStage.Completed; + + ulong[]? rentedBits = null; + try + { + EnsureOpened(); + + if (_parenOpened) + { + _writer.Write(")"u8); + } + + _writer.Write(" { "u8); + + var maxVariableCount = MaxVariableCount(); + var wordCount = (maxVariableCount + 63) >> 6; + var bits = maxVariableCount <= StackWordThreshold + ? stackalloc ulong[1] + : (rentedBits = ArrayPool.Shared.Rent(wordCount)).AsSpan(0, wordCount); + + Span prefixBuffer = stackalloc byte[PrefixBufferLength]; + + for (var i = 0; i < _itemCount; i++) + { + if (i > 0) + { + _writer.Write(" "u8); + } + + WriteItem(i, prefixBuffer, bits); + } + + _writer.Write(" }"u8); + _writer.WriteDelimiter(); + } + finally + { + if (rentedBits is not null) + { + ArrayPool.Shared.Return(rentedBits); + } + + ReleaseBuffers(); + } + } + + private readonly void WriteItem(int index, Span prefixBuffer, Span bits) + { + var field = _items![index]; + var document = field.Document; + var prefix = ComposePrefix(prefixBuffer, index); + + _writer.Write(prefix); + _writer.Write(field.Utf8Name); + _writer.Write(":"u8); + + var variableCount = document.VariableCount; + var shared = new SharedOrdinalSet(bits.Slice(0, (variableCount + 63) >> 6)); + + for (var ordinal = 0; ordinal < variableCount; ordinal++) + { + if (ContainsSharedDefinition(document.GetVariableName(ordinal))) + { + shared.Add(ordinal); + } + } + + field.Format(_writer, prefix, shared); + } + + private void WriteItemVariableDefinitions( + Utf8OperationDocument document, + int operationCursor, + int index) + { + Span prefixBuffer = stackalloc byte[PrefixBufferLength]; + var prefix = ComposePrefix(prefixBuffer, index); + + var cursor = VariableStart(document, operationCursor); + var rowCount = document.RowCount; + + while (cursor < rowCount + && document.GetRow(cursor).Kind is Utf8SyntaxKind.VariableDefinition) + { + var definitionRow = document.GetRow(cursor); + var nameRow = document.GetRow(cursor + 1); + var name = document.GetSource(nameRow.Location, nameRow.SizeOrLength); + + if (!ContainsSharedDefinition(name)) + { + WriteDefinitionSeparator(); + + // The name of the definition is its only variable site, so every site in the + // definition is renamed and no ordinal has to be excluded. + Utf8SyntaxFormatter.Write( + document, + cursor, + _writer, + prefix, + SharedOrdinalSet.Empty); + } + + cursor += definitionRow.NumberOfRows; + } + } + + private void WriteDefinitionSeparator() + { + if (_parenOpened) + { + _writer.Write(", "u8); + } + else + { + _writer.Write("("u8); + _parenOpened = true; + } + } + + // The delimiter that opens the JSON string value is written with the first content byte, so a + // builder that throws before it writes anything leaves the destination buffer untouched. + private void EnsureOpened() + { + if (!_opened) + { + _writer.WriteDelimiter(); + _opened = true; + } + } + + private void EnsureKeyword() + { + if (!_keywordWritten) + { + EnsureOpened(); + _writer.Write("query"u8); + _keywordWritten = true; + } + } + + private readonly void EnsureCanSetName() + { + if (_stage != WriterStage.New) + { + throw new InvalidOperationException( + "The operation name must be set before shared variables and root selections " + + "are added."); + } + } + + private readonly void EnsureCanAddSharedVariable() + { + if (_stage > WriterStage.SharedVariables) + { + throw new InvalidOperationException( + "Shared variables must be added before root selections and before the operation " + + "is completed."); + } + } + + private readonly void EnsureCanAddRootSelection() + { + if (_stage > WriterStage.RootSelections) + { + throw new InvalidOperationException( + "Root selections cannot be added after the operation has been completed."); + } + } + + private readonly void EnsureCanComplete() + { + if (_stage == WriterStage.Completed) + { + throw new InvalidOperationException("The operation has already been completed."); + } + + if (_stage != WriterStage.RootSelections) + { + throw new InvalidOperationException( + "A batched lookup operation requires at least one root selection."); + } + } + + private readonly bool ContainsSharedDefinition(ReadOnlySpan name) + { + for (var i = 0; i < _sharedCount; i++) + { + if (_sharedDefinitions![i].Utf8Name.SequenceEqual(name)) + { + return true; + } + } + + return false; + } + + private readonly bool IsNewDocument(Utf8OperationDocument document) + { + for (var i = 0; i < _itemCount; i++) + { + if (ReferenceEquals(_items![i].Document, document)) + { + return false; + } + } + + return true; + } + + private readonly int MaxVariableCount() + { + var max = 0; + for (var i = 0; i < _itemCount; i++) + { + var count = _items![i].Document.VariableCount; + if (count > max) + { + max = count; + } + } + + return max; + } + + private static ReadOnlySpan ComposePrefix(Span buffer, int index) + { + buffer[0] = (byte)'_'; + Utf8Formatter.TryFormat(index, buffer.Slice(1), out var written); + buffer[written + 1] = (byte)'_'; + return buffer.Slice(0, written + 2); + } + + private static bool ContainsFragmentSpread(Utf8OperationDocument document) + { + var rowCount = document.RowCount; + for (var i = 0; i < rowCount; i++) + { + if (document.GetRow(i).Kind is Utf8SyntaxKind.FragmentSpread) + { + return true; + } + } + + return false; + } + + private static int FindSingleOperationCursor(Utf8OperationDocument document) + { + var operationCursor = -1; + var index = 0; + var rowCount = document.RowCount; + + while (index < rowCount) + { + var row = document.GetRow(index); + if (row.Kind is Utf8SyntaxKind.OperationQuery + or Utf8SyntaxKind.OperationMutation + or Utf8SyntaxKind.OperationSubscription) + { + if (operationCursor >= 0) + { + throw new InvalidOperationException( + "A batched lookup source document must contain exactly one operation."); + } + + operationCursor = index; + } + + index += row.NumberOfRows; + } + + if (operationCursor < 0) + { + throw new InvalidOperationException( + "A batched lookup source document must contain exactly one operation."); + } + + return operationCursor; + } + + private static int VariableStart(Utf8OperationDocument document, int operationCursor) + { + var next = operationCursor + 1; + return document.GetRow(next).Kind is Utf8SyntaxKind.Name ? next + 1 : next; + } + + private void GrowItems() + { + var capacity = _items is null ? InitialCapacity : _items.Length * 2; + var next = ArrayPool.Shared.Rent(capacity); + + if (_items is not null) + { + Array.Copy(_items, next, _itemCount); + ArrayPool.Shared.Return(_items, clearArray: true); + } + + _items = next; + } + + private void GrowSharedDefinitions() + { + var capacity = _sharedDefinitions is null ? InitialCapacity : _sharedDefinitions.Length * 2; + var next = ArrayPool.Shared.Rent(capacity); + + if (_sharedDefinitions is not null) + { + Array.Copy(_sharedDefinitions, next, _sharedCount); + ArrayPool.Shared.Return(_sharedDefinitions, clearArray: true); + } + + _sharedDefinitions = next; + } + + private void ReleaseBuffers() + { + if (_items is not null) + { + ArrayPool.Shared.Return(_items, clearArray: true); + _items = null; + } + + if (_sharedDefinitions is not null) + { + ArrayPool.Shared.Return(_sharedDefinitions, clearArray: true); + _sharedDefinitions = null; + } + + _itemCount = 0; + _sharedCount = 0; + } + + private enum WriterStage : byte + { + New, + Named, + SharedVariables, + RootSelections, + Completed + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionKind.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionKind.cs new file mode 100644 index 00000000000..cd6861467bc --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionKind.cs @@ -0,0 +1,27 @@ +namespace HotChocolate.Language; + +/// +/// Specifies the kind of executable selection represented by a . +/// +public enum Utf8SelectionKind +{ + /// + /// The selection is not initialized. + /// + None = 0, + + /// + /// The selection is a field. + /// + Field = 1, + + /// + /// The selection is a fragment spread. + /// + FragmentSpread = 2, + + /// + /// The selection is an inline fragment. + /// + InlineFragment = 3 +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionNode.cs new file mode 100644 index 00000000000..7be113ecc9c --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionNode.cs @@ -0,0 +1,148 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a heterogeneous view over an executable selection in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8SelectionNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8SelectionNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind + is Utf8SyntaxKind.Field + or Utf8SyntaxKind.FragmentSpread + or Utf8SyntaxKind.InlineFragment); + } + + /// + /// Gets the selection kind. + /// + public Utf8SelectionKind Kind => _document is null + ? Utf8SelectionKind.None + : _document.GetRow(_cursor).Kind switch + { + Utf8SyntaxKind.Field => Utf8SelectionKind.Field, + Utf8SyntaxKind.FragmentSpread => Utf8SelectionKind.FragmentSpread, + Utf8SyntaxKind.InlineFragment => Utf8SelectionKind.InlineFragment, + _ => Utf8SelectionKind.None + }; + + /// + /// Gets this selection as a field. + /// + public Utf8FieldNode GetField() + => Kind is Utf8SelectionKind.Field + ? new Utf8FieldNode(_document, _cursor) + : throw new InvalidOperationException("The selection is not a field."); + + /// + /// Gets this selection as a fragment spread. + /// + public Utf8FragmentSpreadNode GetFragmentSpread() + => Kind is Utf8SelectionKind.FragmentSpread + ? new Utf8FragmentSpreadNode(_document, _cursor) + : throw new InvalidOperationException("The selection is not a fragment spread."); + + /// + /// Gets this selection as an inline fragment. + /// + public Utf8InlineFragmentNode GetInlineFragment() + => Kind is Utf8SelectionKind.InlineFragment + ? new Utf8InlineFragmentNode(_document, _cursor) + : throw new InvalidOperationException("The selection is not an inline fragment."); + + /// + /// Tries to get this selection as a field. + /// + public bool TryGetField(out Utf8FieldNode field) + { + if (Kind is Utf8SelectionKind.Field) + { + field = new Utf8FieldNode(_document, _cursor); + return true; + } + + field = default; + return false; + } + + /// + /// Tries to get this selection as a fragment spread. + /// + public bool TryGetFragmentSpread(out Utf8FragmentSpreadNode fragmentSpread) + { + if (Kind is Utf8SelectionKind.FragmentSpread) + { + fragmentSpread = new Utf8FragmentSpreadNode(_document, _cursor); + return true; + } + + fragmentSpread = default; + return false; + } + + /// + /// Tries to get this selection as an inline fragment. + /// + public bool TryGetInlineFragment(out Utf8InlineFragmentNode inlineFragment) + { + if (Kind is Utf8SelectionKind.InlineFragment) + { + inlineFragment = new Utf8InlineFragmentNode(_document, _cursor); + return true; + } + + inlineFragment = default; + return false; + } + + /// + /// Writes this selection's GraphQL source text to the specified buffer writer, substituting + /// variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionSetNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionSetNode.cs new file mode 100644 index 00000000000..dd3f9d0d203 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SelectionSetNode.cs @@ -0,0 +1,146 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over a selection set in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8SelectionSetNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8SelectionSetNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.SelectionSet); + } + + /// + /// Gets the selections in this selection set. + /// + public Utf8SelectionEnumerable GetSelections() + { + CheckValidInstance(); + var row = _document.GetRow(_cursor); + return new Utf8SelectionEnumerable(_document, _cursor + 1, _cursor + row.NumberOfRows); + } + + /// + /// Writes this selection set's GraphQL source text to the specified buffer writer, + /// substituting variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, + _cursor, + writer, + indented, + formatAsJsonStringValue, + variables); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} + +/// +/// Provides pattern-based enumeration over selections without collection interfaces. +/// +public readonly struct Utf8SelectionEnumerable +{ + private readonly Utf8OperationDocument? _document; + private readonly int _start; + private readonly int _end; + + internal Utf8SelectionEnumerable( + Utf8OperationDocument document, + int start, + int end) + { + _document = document; + _start = start; + _end = end; + } + + /// + /// Gets an enumerator over the selections. + /// + public Enumerator GetEnumerator() => new(_document, _start, _end); + + /// + /// Enumerates selections without implementing enumerator interfaces. + /// + public struct Enumerator + { + private readonly Utf8OperationDocument? _document; + private readonly int _end; + private int _next; + private int _current; + + internal Enumerator(Utf8OperationDocument? document, int start, int end) + { + _document = document; + _next = start; + _end = end; + _current = -1; + } + + /// + /// Gets the current selection. + /// + public Utf8SelectionNode Current + => _document is null || _current < 0 + ? default + : new Utf8SelectionNode(_document, _current); + + /// + /// Advances to the next selection. + /// + public bool MoveNext() + { + if (_document is null || _next >= _end) + { + _current = -1; + return false; + } + + _current = _next; + _next = checked(_next + _document.GetRow(_next).NumberOfRows); + return true; + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.RowWalker.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.RowWalker.cs new file mode 100644 index 00000000000..1cae70c8e66 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.RowWalker.cs @@ -0,0 +1,502 @@ +using System.Diagnostics; +using DbRow = HotChocolate.Language.Utf8OperationDocument.DbRow; + +namespace HotChocolate.Language; + +internal static partial class Utf8SyntaxFormatter +{ + /// + /// Walks the packed metadata rows of a in document order + /// and writes the GraphQL source text the rows describe. Every token that carries content is + /// written from its own row's source range, and every punctuation and keyword is written from + /// the row kinds, so the output never depends on the formatting of the source document. + /// + private ref struct RowWalker + { + private readonly Utf8OperationDocument _document; + private readonly Utf8SyntaxWriter _writer; + private readonly Utf8VariableNameMap _variables; + private readonly ReadOnlySpan _prefix; + private readonly SharedOrdinalSet _shared; + private readonly int _siteCount; + private int _siteIndex; + + internal RowWalker( + Utf8OperationDocument document, + Utf8SyntaxWriter writer, + Utf8VariableNameMap variables, + ReadOnlySpan prefix, + SharedOrdinalSet shared) + { + _document = document; + _writer = writer; + _variables = variables; + _prefix = prefix; + _shared = shared; + _siteCount = variables.IsEmpty && prefix.IsEmpty ? 0 : document.VariableSiteCount; + _siteIndex = 0; + } + + /// + /// Writes every definition of the document, separated by a single space. + /// + internal void WriteDocument() + { + var rowCount = _document.RowCount; + var cursor = 0; + + while (cursor < rowCount) + { + if (cursor > 0) + { + _writer.Write(" "u8); + } + + cursor = WriteNode(cursor); + } + } + + /// + /// Writes the node at and the rows it spans. + /// + internal void Write(int cursor) + { + SeekVariableSites(_document.GetRow(cursor).Location); + WriteNode(cursor); + } + + /// + /// Writes the field at and the rows it spans, leaving out the + /// selection set it declares. + /// + internal void WriteFieldWithoutSelectionSet(int cursor) + { + var row = _document.GetRow(cursor); + Debug.Assert(row.Kind is Utf8SyntaxKind.Field); + + SeekVariableSites(row.Location); + WriteField(cursor, row, writeSelectionSet: false); + } + + private void SeekVariableSites(int position) + { + if (_siteCount > 0) + { + _siteIndex = _document.FindFirstVariableSite(position); + } + } + + private int WriteNode(int cursor) + { + var row = _document.GetRow(cursor); + + switch (row.Kind) + { + case Utf8SyntaxKind.OperationQuery: + WriteOperation(cursor, row, "query"u8); + break; + + case Utf8SyntaxKind.OperationMutation: + WriteOperation(cursor, row, "mutation"u8); + break; + + case Utf8SyntaxKind.OperationSubscription: + WriteOperation(cursor, row, "subscription"u8); + break; + + case Utf8SyntaxKind.FragmentDefinition: + WriteFragmentDefinition(cursor, row); + break; + + case Utf8SyntaxKind.VariableDefinition: + WriteVariableDefinition(cursor, row); + break; + + case Utf8SyntaxKind.SelectionSet: + WriteSelectionSet(cursor, row); + break; + + case Utf8SyntaxKind.Field: + WriteField(cursor, row, writeSelectionSet: true); + break; + + case Utf8SyntaxKind.FragmentSpread: + WriteFragmentSpread(cursor, row); + break; + + case Utf8SyntaxKind.InlineFragment: + WriteInlineFragment(cursor, row); + break; + + case Utf8SyntaxKind.Argument: + case Utf8SyntaxKind.ObjectField: + WriteNamedValue(cursor); + break; + + case Utf8SyntaxKind.Directive: + WriteDirective(cursor, row); + break; + + case Utf8SyntaxKind.ListValue: + WriteListValue(cursor, row); + break; + + case Utf8SyntaxKind.ObjectValue: + WriteObjectValue(cursor, row); + break; + + case Utf8SyntaxKind.Variable: + _writer.Write("$"u8); + WriteVariableName(row); + break; + + case Utf8SyntaxKind.ListType: + _writer.Write("["u8); + WriteNode(cursor + 1); + _writer.Write("]"u8); + break; + + case Utf8SyntaxKind.NonNullType: + WriteNode(cursor + 1); + _writer.Write("!"u8); + break; + + default: + WriteToken(row); + break; + } + + return cursor + row.NumberOfRows; + } + + private void WriteOperation(int cursor, DbRow row, ReadOnlySpan keyword) + { + _writer.Write(keyword); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + var nameRow = _document.GetRow(index); + + if (nameRow.Kind is Utf8SyntaxKind.Name) + { + _writer.Write(" "u8); + WriteToken(nameRow); + index++; + } + + index = WriteVariableDefinitions(index, end); + index = WriteDirectives(index, end); + WriteNode(index); + } + + private void WriteFragmentDefinition(int cursor, DbRow row) + { + _writer.Write("fragment "u8); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + WriteToken(_document.GetRow(index++)); + + var afterVariables = WriteVariableDefinitions(index, end); + + if (afterVariables == index) + { + _writer.Write(" on "u8); + } + else + { + _writer.Write("on "u8); + } + + index = afterVariables; + WriteToken(_document.GetRow(index++)); + index = WriteDirectives(index, end); + WriteNode(index); + } + + private int WriteVariableDefinitions(int cursor, int end) + { + if (cursor >= end + || _document.GetRow(cursor).Kind is not Utf8SyntaxKind.VariableDefinition) + { + return cursor; + } + + _writer.Write("("u8); + var index = cursor; + + while (index < end) + { + var row = _document.GetRow(index); + + if (row.Kind is not Utf8SyntaxKind.VariableDefinition) + { + break; + } + + if (index > cursor) + { + _writer.Write(","u8); + } + + WriteVariableDefinition(index, row); + index += row.NumberOfRows; + } + + _writer.Write(")"u8); + return index; + } + + private void WriteVariableDefinition(int cursor, DbRow row) + { + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + + _writer.Write("$"u8); + WriteVariableName(_document.GetRow(index++)); + _writer.Write(":"u8); + index = WriteNode(index); + + if (index < end && IsValue(_document.GetRow(index).Kind)) + { + _writer.Write("="u8); + index = WriteNode(index); + } + + WriteDirectives(index, end); + } + + private void WriteSelectionSet(int cursor, DbRow row) + { + _writer.Write("{"u8); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + + while (index < end) + { + if (index > cursor + 1) + { + _writer.Write(" "u8); + } + + index = WriteNode(index); + } + + _writer.Write("}"u8); + } + + private void WriteField(int cursor, DbRow row, bool writeSelectionSet) + { + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + var aliasRow = _document.GetRow(index); + + if (aliasRow.Kind is Utf8SyntaxKind.Alias) + { + WriteToken(aliasRow); + _writer.Write(":"u8); + index++; + } + + WriteToken(_document.GetRow(index++)); + index = WriteArguments(index, end); + index = WriteDirectives(index, end); + + if (writeSelectionSet && index < end) + { + WriteNode(index); + } + } + + private void WriteFragmentSpread(int cursor, DbRow row) + { + _writer.Write("..."u8); + + var index = cursor + 1; + WriteToken(_document.GetRow(index++)); + WriteDirectives(index, cursor + row.NumberOfRows); + } + + private void WriteInlineFragment(int cursor, DbRow row) + { + _writer.Write("..."u8); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + var typeRow = _document.GetRow(index); + + if (typeRow.Kind is Utf8SyntaxKind.TypeCondition) + { + _writer.Write("on "u8); + WriteToken(typeRow); + index++; + } + + index = WriteDirectives(index, end); + WriteNode(index); + } + + private int WriteDirectives(int cursor, int end) + { + var index = cursor; + + while (index < end) + { + var row = _document.GetRow(index); + + if (row.Kind is not Utf8SyntaxKind.Directive) + { + break; + } + + WriteDirective(index, row); + index += row.NumberOfRows; + } + + return index; + } + + private void WriteDirective(int cursor, DbRow row) + { + _writer.Write("@"u8); + + var index = cursor + 1; + WriteToken(_document.GetRow(index++)); + WriteArguments(index, cursor + row.NumberOfRows); + } + + private int WriteArguments(int cursor, int end) + { + if (cursor >= end || _document.GetRow(cursor).Kind is not Utf8SyntaxKind.Argument) + { + return cursor; + } + + _writer.Write("("u8); + var index = cursor; + + while (index < end) + { + var row = _document.GetRow(index); + + if (row.Kind is not Utf8SyntaxKind.Argument) + { + break; + } + + if (index > cursor) + { + _writer.Write(","u8); + } + + WriteNamedValue(index); + index += row.NumberOfRows; + } + + _writer.Write(")"u8); + return index; + } + + private void WriteNamedValue(int cursor) + { + var index = cursor + 1; + WriteToken(_document.GetRow(index++)); + _writer.Write(":"u8); + WriteNode(index); + } + + private void WriteListValue(int cursor, DbRow row) + { + _writer.Write("["u8); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + + while (index < end) + { + if (index > cursor + 1) + { + _writer.Write(","u8); + } + + index = WriteNode(index); + } + + _writer.Write("]"u8); + } + + private void WriteObjectValue(int cursor, DbRow row) + { + _writer.Write("{"u8); + + var index = cursor + 1; + var end = cursor + row.NumberOfRows; + + while (index < end) + { + if (index > cursor + 1) + { + _writer.Write(","u8); + } + + index = WriteNode(index); + } + + _writer.Write("}"u8); + } + + private void WriteVariableName(DbRow row) + { + if (_siteCount == 0) + { + WriteToken(row); + return; + } + + var ordinal = ReadOrdinal(row.Location); + + if (!_prefix.IsEmpty) + { + if (!_shared.Contains(ordinal)) + { + _writer.Write(_prefix); + } + + WriteToken(row); + return; + } + + if (_variables.TryGetReplacement(ordinal, out var name)) + { + _writer.Write(name.Span); + return; + } + + WriteToken(row); + } + + private int ReadOrdinal(int position) + { + while (_document.GetVariableSitePosition(_siteIndex) < position) + { + _siteIndex++; + } + + Debug.Assert(_document.GetVariableSitePosition(_siteIndex) == position); + return _document.GetVariableSiteOrdinal(_siteIndex++); + } + + private void WriteToken(DbRow row) + => _writer.Write(_document.GetSource(row.Location, row.SizeOrLength)); + + private static bool IsValue(Utf8SyntaxKind kind) + => kind is Utf8SyntaxKind.ListValue + or Utf8SyntaxKind.ObjectValue + or Utf8SyntaxKind.Variable + or Utf8SyntaxKind.IntValue + or Utf8SyntaxKind.FloatValue + or Utf8SyntaxKind.StringValue + or Utf8SyntaxKind.EnumValue; + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.cs new file mode 100644 index 00000000000..0676fca26bd --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxFormatter.cs @@ -0,0 +1,153 @@ +using System.Buffers; + +namespace HotChocolate.Language; + +/// +/// Writes the GraphQL source text of a while splicing in +/// variable name replacements driven by the position-sorted variable-site table. A node is written +/// either verbatim, reproducing the formatting of the source document, or in canonical form, which +/// walks the packed metadata rows and emits every token the rows describe with the minimal +/// separators the grammar requires. +/// +internal static partial class Utf8SyntaxFormatter +{ + /// + /// Writes the whole document as a complete document fragment, substituting variable names + /// through . When is + /// the output is written as a JSON string value, delimiters included. + /// + internal static void FormatDocument( + Utf8OperationDocument document, + IBufferWriter writer, + bool indented, + bool formatAsJsonStringValue, + Utf8VariableNameMap variables) + { + var target = new Utf8SyntaxWriter(writer, formatAsJsonStringValue); + target.WriteDelimiter(); + + if (indented) + { + WriteVerbatimRange(document, 0, document.SourceLength, target, variables); + } + else + { + var walker = new RowWalker(document, target, variables, default, default); + walker.WriteDocument(); + } + + target.WriteDelimiter(); + } + + /// + /// Writes the node at as a complete document fragment, substituting + /// variable names through . When + /// is the output is written + /// as a JSON string value, delimiters included. + /// + internal static void Format( + Utf8OperationDocument document, + int cursor, + IBufferWriter writer, + bool indented, + bool formatAsJsonStringValue, + Utf8VariableNameMap variables) + { + var target = new Utf8SyntaxWriter(writer, formatAsJsonStringValue); + target.WriteDelimiter(); + Write(document, cursor, target, variables, indented); + target.WriteDelimiter(); + } + + /// + /// Writes the node at , substituting variable names through + /// . When is + /// the node's source range is reproduced verbatim; otherwise the node is written in canonical + /// form. + /// + internal static void Write( + Utf8OperationDocument document, + int cursor, + Utf8SyntaxWriter writer, + Utf8VariableNameMap variables, + bool indented) + { + if (indented) + { + var row = document.GetRow(cursor); + WriteVerbatimRange(document, row.Location, row.SourceEnd, writer, variables); + return; + } + + var walker = new RowWalker(document, writer, variables, default, default); + walker.Write(cursor); + } + + /// + /// Writes the node at in canonical form, inserting + /// in front of the name of every variable whose ordinal is + /// not in . Shared variables keep their original name. + /// + internal static void Write( + Utf8OperationDocument document, + int cursor, + Utf8SyntaxWriter writer, + ReadOnlySpan variablePrefix, + SharedOrdinalSet shared) + { + var walker = new RowWalker(document, writer, default, variablePrefix, shared); + walker.Write(cursor); + } + + /// + /// Writes the field at in canonical form, leaving out the selection + /// set it declares, and inserting in front of the name of + /// every variable whose ordinal is not in . Shared variables keep + /// their original name. + /// + internal static void WriteFieldWithoutSelectionSet( + Utf8OperationDocument document, + int cursor, + Utf8SyntaxWriter writer, + ReadOnlySpan variablePrefix, + SharedOrdinalSet shared) + { + var walker = new RowWalker(document, writer, default, variablePrefix, shared); + walker.WriteFieldWithoutSelectionSet(cursor); + } + + private static void WriteVerbatimRange( + Utf8OperationDocument document, + int start, + int end, + Utf8SyntaxWriter writer, + Utf8VariableNameMap variables) + { + var siteCount = document.VariableSiteCount; + if (variables.IsEmpty || siteCount == 0) + { + writer.Write(document.GetSource(start, end - start)); + return; + } + + var copyStart = start; + for (var i = document.FindFirstVariableSite(start); i < siteCount; i++) + { + var position = document.GetVariableSitePosition(i); + if (position >= end) + { + break; + } + + var ordinal = document.GetVariableSiteOrdinal(i); + if (variables.TryGetReplacement(ordinal, out var name)) + { + writer.Write(document.GetSource(copyStart, position - copyStart)); + writer.Write(name.Span); + copyStart = position + document.GetVariableName(ordinal).Length; + } + } + + writer.Write(document.GetSource(copyStart, end - copyStart)); + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxKind.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxKind.cs new file mode 100644 index 00000000000..d30806e5269 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxKind.cs @@ -0,0 +1,31 @@ +namespace HotChocolate.Language; + +internal enum Utf8SyntaxKind +{ + None = 0, + OperationQuery = 1, + OperationMutation = 2, + OperationSubscription = 3, + FragmentDefinition = 4, + VariableDefinition = 5, + SelectionSet = 6, + Field = 7, + FragmentSpread = 8, + InlineFragment = 9, + TypeCondition = 10, + Name = 11, + Alias = 12, + Argument = 13, + Directive = 14, + ListValue = 15, + ObjectValue = 16, + ObjectField = 17, + Variable = 18, + IntValue = 19, + FloatValue = 20, + StringValue = 21, + EnumValue = 22, + NamedType = 23, + ListType = 24, + NonNullType = 25 +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxWriter.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxWriter.cs new file mode 100644 index 00000000000..965dfa575fd --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8SyntaxWriter.cs @@ -0,0 +1,253 @@ +using System.Buffers; +using System.Text; + +namespace HotChocolate.Language; + +/// +/// Writes GraphQL source text to a buffer writer, either as plain UTF-8 text or as the content of +/// a JSON string value. In JSON mode the quotation mark, the reverse solidus and every control +/// character are replaced by their JSON escape sequence, while all other bytes, including +/// multi-byte UTF-8 sequences, are written unchanged. The delimiters that frame the JSON string +/// value are written by . +/// +internal readonly struct Utf8SyntaxWriter +{ +#if NET8_0_OR_GREATER + private static readonly SearchValues s_escapedBytes = CreateEscapedBytes(); + private static readonly SearchValues s_escapedChars = CreateEscapedChars(); +#endif + private static readonly Encoding s_utf8 = Encoding.UTF8; + + private readonly IBufferWriter _writer; + private readonly bool _escape; + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// to write the output as the content of a JSON string value; + /// otherwise, to write it as plain GraphQL source text. + /// + internal Utf8SyntaxWriter(IBufferWriter writer, bool escape) + { + _writer = writer; + _escape = escape; + } + + /// + /// Writes the delimiter that opens or closes the JSON string value. Nothing is written when + /// the output is plain GraphQL source text. + /// + internal void WriteDelimiter() + { + if (_escape) + { + _writer.Write("\""u8); + } + } + + /// + /// Writes to the underlying buffer writer. + /// + /// + /// The UTF-8 encoded GraphQL source text. + /// + internal void Write(ReadOnlySpan value) + { + if (!_escape) + { + _writer.Write(value); + return; + } + + while (!value.IsEmpty) + { + var index = IndexOfEscaped(value); + + if (index < 0) + { + _writer.Write(value); + return; + } + + if (index > 0) + { + _writer.Write(value.Slice(0, index)); + } + + WriteEscapeSequence(value[index]); + value = value.Slice(index + 1); + } + } + + /// + /// Encodes as UTF-8 and writes it to the underlying buffer writer. + /// + /// + /// The GraphQL source text. + /// + internal void Write(string value) + { + if (!_escape || IndexOfEscaped(value.AsSpan()) < 0) + { + WriteUtf8(value); + return; + } + + var start = 0; + + while (start < value.Length) + { + var index = IndexOfEscaped(value.AsSpan(start)); + + if (index < 0) + { + WriteUtf8(value, start, value.Length - start); + return; + } + + if (index > 0) + { + WriteUtf8(value, start, index); + } + + WriteEscapeSequence((byte)value[start + index]); + start += index + 1; + } + } + + private void WriteUtf8(string value) + { + var byteCount = s_utf8.GetByteCount(value); + var destination = _writer.GetSpan(byteCount); + _writer.Advance(s_utf8.GetBytes(value, destination)); + } + + private void WriteUtf8(string value, int start, int length) + { +#if NET8_0_OR_GREATER + var segment = value.AsSpan(start, length); + var byteCount = s_utf8.GetByteCount(segment); + var destination = _writer.GetSpan(byteCount); + _writer.Advance(s_utf8.GetBytes(segment, destination)); +#else + WriteUtf8(value.Substring(start, length)); +#endif + } + + private void WriteEscapeSequence(byte value) + { + switch (value) + { + case (byte)'"': + _writer.Write("\\\""u8); + return; + + case (byte)'\\': + _writer.Write("\\\\"u8); + return; + + case (byte)'\n': + _writer.Write("\\n"u8); + return; + + case (byte)'\r': + _writer.Write("\\r"u8); + return; + + case (byte)'\t': + _writer.Write("\\t"u8); + return; + + case (byte)'\b': + _writer.Write("\\b"u8); + return; + + case (byte)'\f': + _writer.Write("\\f"u8); + return; + + default: + var destination = _writer.GetSpan(6); + destination[0] = (byte)'\\'; + destination[1] = (byte)'u'; + destination[2] = (byte)'0'; + destination[3] = (byte)'0'; + destination[4] = HexDigits[value >> 4]; + destination[5] = HexDigits[value & 0xF]; + _writer.Advance(6); + return; + } + } + + private static ReadOnlySpan HexDigits => "0123456789ABCDEF"u8; + +#if NET8_0_OR_GREATER + private static int IndexOfEscaped(ReadOnlySpan value) + => value.IndexOfAny(s_escapedBytes); + + private static int IndexOfEscaped(ReadOnlySpan value) + => value.IndexOfAny(s_escapedChars); + + private static SearchValues CreateEscapedBytes() + { + Span values = stackalloc byte[34]; + + for (var i = 0; i < 32; i++) + { + values[i] = (byte)i; + } + + values[32] = (byte)'"'; + values[33] = (byte)'\\'; + return SearchValues.Create(values); + } + + private static SearchValues CreateEscapedChars() + { + Span values = stackalloc char[34]; + + for (var i = 0; i < 32; i++) + { + values[i] = (char)i; + } + + values[32] = '"'; + values[33] = '\\'; + return SearchValues.Create(values); + } +#else + private static int IndexOfEscaped(ReadOnlySpan value) + { + for (var i = 0; i < value.Length; i++) + { + var current = value[i]; + + if (current < 0x20 || current is (byte)'"' or (byte)'\\') + { + return i; + } + } + + return -1; + } + + private static int IndexOfEscaped(ReadOnlySpan value) + { + for (var i = 0; i < value.Length; i++) + { + var current = value[i]; + + if (current < 0x20 || current is '"' or '\\') + { + return i; + } + } + + return -1; + } +#endif +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableDefinitionNode.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableDefinitionNode.cs new file mode 100644 index 00000000000..0f128a52aab --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableDefinitionNode.cs @@ -0,0 +1,198 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Language; + +/// +/// Provides a view over a variable definition in a packed UTF-8 syntax tree. +/// +public readonly struct Utf8VariableDefinitionNode : IUtf8SyntaxNode +{ + private readonly Utf8OperationDocument _document; + private readonly int _cursor; + + internal Utf8VariableDefinitionNode(Utf8OperationDocument document, int cursor) + { + // document is usually not null, but the Current property on the enumerators + // (when initialized as default) can physically pass null. + _document = document; + _cursor = cursor; + Debug.Assert(document.GetRow(cursor).Kind is Utf8SyntaxKind.VariableDefinition); + } + + /// + /// Gets the variable name without the leading dollar sign. + /// + internal string Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetString(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the UTF-8 encoded variable name without the leading dollar sign. + /// + public ReadOnlySpan Utf8Name + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + return _document.GetSource(nameRow.Location, nameRow.SizeOrLength); + } + } + + /// + /// Gets the document-scoped ordinal of this variable. Ordinals identify distinct variable + /// names and are assigned by first occurrence in document order. + /// + public int Ordinal + { + get + { + CheckValidInstance(); + var nameRow = _document.GetRow(_cursor + 1); + var name = _document.GetSource(nameRow.Location, nameRow.SizeOrLength); + var count = _document.VariableCount; + + for (var ordinal = 0; ordinal < count; ordinal++) + { + if (name.SequenceEqual(_document.GetVariableName(ordinal))) + { + return ordinal; + } + } + + throw new InvalidOperationException( + "The variable definition is not present in the document's variable directory."); + } + } + + /// + /// Writes this variable definition's GraphQL source text to the specified buffer writer, + /// substituting variable names through . + /// + /// + /// The buffer writer that receives the UTF-8 encoded output. + /// + /// + /// , the default, to write compact single-line output that drops + /// comments and keeps only the whitespace that is required to separate two tokens; + /// to preserve the formatting of the source document verbatim, + /// including its whitespace and comments. + /// + /// + /// , the default, to write plain GraphQL source text; + /// to write a JSON string value that holds the GraphQL source text, + /// including the enclosing quotation marks. + /// + /// + /// The ordinal-indexed variable name substitutions to apply, or the default value to keep + /// every original name. + /// + public void Format( + IBufferWriter writer, + bool indented = false, + bool formatAsJsonStringValue = false, + Utf8VariableNameMap variables = default) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Format( + _document, _cursor, writer, indented, formatAsJsonStringValue, variables); + } + + /// + /// Writes this variable definition's GraphQL source text to the specified syntax writer + /// without the delimiters of a JSON string value. + /// + /// + /// The syntax writer that receives the UTF-8 encoded output. + /// + /// + /// to write compact single-line output that drops comments and keeps + /// only the whitespace that is required to separate two tokens; to + /// preserve the formatting of the source document verbatim. + /// + internal void Format(Utf8SyntaxWriter writer, bool indented) + { + CheckValidInstance(); + Utf8SyntaxFormatter.Write(_document, _cursor, writer, default, indented); + } + + private void CheckValidInstance() + { + if (_document is null) + { + throw new InvalidOperationException(); + } + } +} + +/// +/// Provides pattern-based enumeration over variable definitions without collection interfaces. +/// +public readonly struct Utf8VariableDefinitionEnumerable +{ + private readonly Utf8OperationDocument? _document; + private readonly int _start; + + internal Utf8VariableDefinitionEnumerable( + Utf8OperationDocument document, + int start) + { + _document = document; + _start = start; + } + + /// + /// Gets an enumerator over the variable definitions. + /// + public Enumerator GetEnumerator() => new(_document, _start); + + /// + /// Enumerates variable definitions without implementing enumerator interfaces. + /// + public struct Enumerator + { + private readonly Utf8OperationDocument? _document; + private int _next; + private int _current; + + internal Enumerator(Utf8OperationDocument? document, int start) + { + _document = document; + _next = start; + _current = -1; + } + + /// + /// Gets the current variable definition. + /// + public Utf8VariableDefinitionNode Current + => _document is null || _current < 0 + ? default + : new Utf8VariableDefinitionNode(_document, _current); + + /// + /// Advances to the next variable definition. + /// + public bool MoveNext() + { + if (_document is not null + && _next < _document.RowCount + && _document.GetRow(_next).Kind is Utf8SyntaxKind.VariableDefinition) + { + _current = _next; + _next = checked(_next + _document.GetRow(_next).NumberOfRows); + return true; + } + + _current = -1; + return false; + } + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableNameMap.cs b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableNameMap.cs new file mode 100644 index 00000000000..2d7f2a0ba1a --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8.SyntaxTree/Utf8VariableNameMap.cs @@ -0,0 +1,64 @@ +namespace HotChocolate.Language; + +/// +/// Represents ordinal-indexed variable name substitutions applied when formatting a packed UTF-8 +/// syntax node. Each entry replaces the name of the variable with the matching document-scoped +/// ordinal. Entries are the replacement names without the leading dollar sign; the dollar sign +/// stays part of the verbatim source. The default value applies no substitutions. +/// +public readonly struct Utf8VariableNameMap +{ + private readonly ReadOnlyMemory[]? _names; + + /// + /// Initializes a new instance of the struct over the + /// specified replacement names. The array is held, not copied; the caller must not mutate it + /// while formatting. The array is indexed by the document-scoped variable ordinal, and each + /// entry is a replacement name without the leading dollar sign. An out-of-range or empty + /// entry keeps the original variable name. + /// + /// + /// The replacement names indexed by variable ordinal, without the leading dollar sign. + /// + public Utf8VariableNameMap(ReadOnlyMemory[] names) + { + _names = names; + } + + /// + /// Gets a value indicating whether this map contains no substitutions. + /// + public bool IsEmpty => _names is null || _names.Length == 0; + + /// + /// Tries to get the replacement name for the variable identified by + /// . + /// + /// + /// The document-scoped variable ordinal. + /// + /// + /// When this method returns , the replacement name without the leading + /// dollar sign; otherwise, an empty value. + /// + /// + /// when a replacement name exists; otherwise, + /// to keep the original name. + /// + internal bool TryGetReplacement(int ordinal, out ReadOnlyMemory name) + { + var names = _names; + if (names is not null && (uint)ordinal < (uint)names.Length) + { + var candidate = names[ordinal]; + if (!candidate.IsEmpty) + { + name = candidate; + return true; + } + } + + name = default; + return false; + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8/HotChocolate.Language.Utf8.csproj b/src/HotChocolate/Language/src/Language.Utf8/HotChocolate.Language.Utf8.csproj index fa37aeb9247..0fd5b13eb00 100644 --- a/src/HotChocolate/Language/src/Language.Utf8/HotChocolate.Language.Utf8.csproj +++ b/src/HotChocolate/Language/src/Language.Utf8/HotChocolate.Language.Utf8.csproj @@ -25,6 +25,8 @@ + + diff --git a/src/HotChocolate/Language/src/Language.Utf8/Utf8GraphQLOperationParser.cs b/src/HotChocolate/Language/src/Language.Utf8/Utf8GraphQLOperationParser.cs new file mode 100644 index 00000000000..3bda5b7d262 --- /dev/null +++ b/src/HotChocolate/Language/src/Language.Utf8/Utf8GraphQLOperationParser.cs @@ -0,0 +1,1008 @@ +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using HotChocolate.Buffers; +using static HotChocolate.Language.Properties.LangUtf8Resources; +using DbRow = HotChocolate.Language.Utf8OperationDocument.DbRow; +using MetaDb = HotChocolate.Language.Utf8OperationDocument.MetaDb; +using VariableTable = HotChocolate.Language.Utf8OperationDocument.VariableTable; + +namespace HotChocolate.Language; + +/// +/// Parses executable GraphQL documents into a packed, immutable UTF-8 syntax tree. +/// +public ref struct Utf8GraphQLOperationParser +{ + // A type level records the offset of its opening bracket, the exclusive end of its closing + // bracket and the exclusive end of the non-null marker that follows it, if there is one. + private const int TypeLevelSize = 3; + + // The row count is capped by the row layout, which spans a node in 27 bits. + private const int MaxMetadataLength = DbRow.MaxNumberOfRows * DbRow.Size; + + private readonly ReadOnlySpan _source; + private readonly ChunkedArrayWriter _metadata; + private readonly bool _allowFragmentVariables; + private readonly int _maxAllowedNodes; + private readonly int _maxAllowedFields; + private readonly int _maxAllowedDirectives; + private readonly int _maxAllowedRecursionDepth; + private Utf8GraphQLReader _reader; + private byte[]? _variableSites; + private byte[]? _variableDirectory; + private int[]? _typeLevels; + private int _siteCount; + private int _variableCount; + private int _parsedNodes; + private int _parsedFields; + private int _recursionDepth; + private int _previousEnd; + private int _openRows; + + private Utf8GraphQLOperationParser( + ReadOnlySpan sourceText, + ChunkedArrayWriter metadata, + ParserOptions? options) + { + options ??= ParserOptions.Default; + _source = sourceText; + _metadata = metadata; + _allowFragmentVariables = options.Experimental.AllowFragmentVariables; + _maxAllowedNodes = options.MaxAllowedNodes; + _maxAllowedFields = options.MaxAllowedFields; + _maxAllowedDirectives = options.MaxAllowedDirectives; + _maxAllowedRecursionDepth = options.MaxAllowedRecursionDepth; + _reader = new Utf8GraphQLReader(sourceText, options.MaxAllowedTokens); + _variableSites = null; + _variableDirectory = null; + _typeLevels = null; + _siteCount = 0; + _variableCount = 0; + _parsedNodes = 0; + _parsedFields = 0; + _recursionDepth = 0; + _previousEnd = 0; + _openRows = 0; + } + + private void Parse() + { + CountNode(); + MoveNext(); + + while (_reader.Kind is not TokenKind.EndOfFile) + { + var sourceStart = _reader.Start; + + if (_reader.Kind is TokenKind.String or TokenKind.BlockString) + { + CountNode(); + ValidateString(); + MoveNext(); + } + + if (_reader.Kind is TokenKind.LeftBrace) + { + ParseOperationDefinition(OperationType.Query, sourceStart, shorthand: true); + continue; + } + + if (IsKeyword(GraphQLKeywords.Query)) + { + ParseOperationDefinition(OperationType.Query, sourceStart, shorthand: false); + continue; + } + + if (IsKeyword(GraphQLKeywords.Mutation)) + { + ParseOperationDefinition(OperationType.Mutation, sourceStart, shorthand: false); + continue; + } + + if (IsKeyword(GraphQLKeywords.Subscription)) + { + ParseOperationDefinition(OperationType.Subscription, sourceStart, shorthand: false); + continue; + } + + if (IsKeyword(GraphQLKeywords.Fragment)) + { + ParseFragmentDefinition(sourceStart); + continue; + } + + throw Error("Only executable operation and fragment definitions are supported."); + } + + if (_openRows != 0) + { + throw new InvalidOperationException("The packed syntax metadata is incomplete."); + } + } + + private void ParseOperationDefinition( + OperationType operation, + int sourceStart, + bool shorthand) + { + var kind = operation switch + { + OperationType.Mutation => Utf8SyntaxKind.OperationMutation, + OperationType.Subscription => Utf8SyntaxKind.OperationSubscription, + _ => Utf8SyntaxKind.OperationQuery + }; + var cursor = AppendPlaceholder(); + + if (!shorthand) + { + MoveNext(); + + if (_reader.Kind is TokenKind.Name) + { + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + } + } + + ParseVariableDefinitions(); + ParseDirectives(isConstant: false); + var sourceEnd = ParseSelectionSet(); + + Patch(cursor, new DbRow(kind, sourceStart, sourceEnd - sourceStart, RowCount - cursor)); + } + + private void ParseFragmentDefinition(int sourceStart) + { + var cursor = AppendPlaceholder(); + MoveNext(); + ReadFragmentName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + + if (_allowFragmentVariables) + { + ParseVariableDefinitions(); + } + + ExpectKeyword(GraphQLKeywords.On); + // The classic parser counts the type condition as a NamedType node. The removed + // early type-condition placeholder used to supply that count, so restore it here. + CountNode(); + ReadName(out var typeStart, out var typeLength); + AppendRow(new DbRow(Utf8SyntaxKind.TypeCondition, typeStart, typeLength, 1)); + ParseDirectives(isConstant: false); + var sourceEnd = ParseSelectionSet(); + + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.FragmentDefinition, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + } + + private void ParseVariableDefinitions() + { + if (_reader.Kind is not TokenKind.LeftParenthesis) + { + return; + } + + MoveNext(); + + while (_reader.Kind is not TokenKind.RightParenthesis) + { + if (_reader.Kind is TokenKind.EndOfFile) + { + throw Error("Expected a closing parenthesis."); + } + + var sourceStart = _reader.Start; + if (_reader.Kind is TokenKind.String or TokenKind.BlockString) + { + CountNode(); + ValidateString(); + MoveNext(); + } + + var cursor = AppendPlaceholder(); + CountNode(); + Expect(TokenKind.Dollar); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + RecordVariableSite(nameStart, nameLength); + Expect(TokenKind.Colon); + ParseTypeReference(); + + if (_reader.Kind is TokenKind.Equal) + { + MoveNext(); + ParseValue(isConstant: true); + } + + ParseDirectives(isConstant: true); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.VariableDefinition, + sourceStart, + _previousEnd - sourceStart, + RowCount - cursor)); + } + + MoveNext(); + } + + private int ParseSelectionSet() + { + EnterDepth(); + try + { + var sourceStart = _reader.Start; + Expect(TokenKind.LeftBrace); + var cursor = AppendPlaceholder(); + + while (_reader.Kind is not TokenKind.RightBrace) + { + if (_reader.Kind is TokenKind.EndOfFile) + { + throw Error("Expected a closing brace."); + } + + ParseSelection(); + } + + var sourceEnd = _reader.End; + MoveNext(); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.SelectionSet, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + return sourceEnd; + } + finally + { + ExitDepth(); + } + } + + private void ParseSelection() + { + if (_reader.Kind is TokenKind.Spread) + { + ParseFragmentSelection(); + } + else + { + ParseField(); + } + } + + private void ParseField() + { + if (++_parsedFields > _maxAllowedFields) + { + throw Error($"The maximum allowed number of fields ({_maxAllowedFields}) was exceeded."); + } + + var sourceStart = _reader.Start; + var cursor = AppendPlaceholder(); + ReadName(out var firstStart, out var firstLength); + + if (_reader.Kind is TokenKind.Colon) + { + // The first name is the alias; in source order the alias token precedes the name. + AppendRow(new DbRow(Utf8SyntaxKind.Alias, firstStart, firstLength, 1)); + MoveNext(); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + } + else + { + AppendRow(new DbRow(Utf8SyntaxKind.Name, firstStart, firstLength, 1)); + } + + ParseArguments(isConstant: false); + ParseDirectives(isConstant: false); + + var sourceEnd = _previousEnd; + if (_reader.Kind is TokenKind.LeftBrace) + { + sourceEnd = ParseSelectionSet(); + } + + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.Field, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + } + + private void ParseFragmentSelection() + { + var sourceStart = _reader.Start; + var cursor = AppendPlaceholder(); + MoveNext(); + + if (_reader.Kind is TokenKind.Name && !IsKeyword(GraphQLKeywords.On)) + { + ReadFragmentName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + ParseDirectives(isConstant: false); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.FragmentSpread, + sourceStart, + _previousEnd - sourceStart, + RowCount - cursor)); + return; + } + + if (IsKeyword(GraphQLKeywords.On)) + { + MoveNext(); + CountNode(); + ReadName(out var typeStart, out var typeLength); + AppendRow(new DbRow(Utf8SyntaxKind.TypeCondition, typeStart, typeLength, 1)); + } + + ParseDirectives(isConstant: false); + var sourceEnd = ParseSelectionSet(); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.InlineFragment, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + } + + private void ParseArguments(bool isConstant) + { + if (_reader.Kind is not TokenKind.LeftParenthesis) + { + return; + } + + MoveNext(); + while (_reader.Kind is not TokenKind.RightParenthesis) + { + CountNode(); + var sourceStart = _reader.Start; + var cursor = AppendUncountedPlaceholder(); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + Expect(TokenKind.Colon); + ParseValue(isConstant); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.Argument, + sourceStart, + _previousEnd - sourceStart, + RowCount - cursor)); + } + MoveNext(); + } + + private void ParseDirectives(bool isConstant) + { + var count = 0; + while (_reader.Kind is TokenKind.At) + { + if (++count > _maxAllowedDirectives) + { + throw Error( + $"The maximum allowed number of directives ({_maxAllowedDirectives}) was exceeded."); + } + + CountNode(); + var sourceStart = _reader.Start; + var cursor = AppendUncountedPlaceholder(); + MoveNext(); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + ParseArguments(isConstant); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.Directive, + sourceStart, + _previousEnd - sourceStart, + RowCount - cursor)); + } + } + + /// + /// Parses a type reference and appends its rows in document order. A type reference is a + /// run of list wrappers around a named type, and each wrapper can be marked non-null only + /// after its contents have been read, so the type is read first and the rows are appended + /// from the outermost wrapper inwards. + /// + private void ParseTypeReference() + { + // Every list wrapper enters the depth in the same frame, so the run is unwound with a + // single assignment instead of one ExitDepth call per wrapper. + var depth = _recursionDepth; + try + { + var levels = 0; + var nonNullCount = 0; + + while (true) + { + EnterDepth(); + CountNode(); + + if (_reader.Kind is not TokenKind.LeftBracket) + { + break; + } + + PushTypeLevel(levels++, _reader.Start); + MoveNext(); + } + + ReadName(out var nameStart, out var nameLength); + var nameEnd = 0; + + if (_reader.Kind is TokenKind.Bang) + { + CountNode(); + nonNullCount++; + nameEnd = _reader.End; + MoveNext(); + } + + for (var level = levels - 1; level >= 0; level--) + { + var closeEnd = _reader.End; + Expect(TokenKind.RightBracket); + var bangEnd = 0; + + if (_reader.Kind is TokenKind.Bang) + { + CountNode(); + nonNullCount++; + bangEnd = _reader.End; + MoveNext(); + } + + CloseTypeLevel(level, closeEnd, bangEnd); + } + + AppendTypeRows(levels, nonNullCount, nameStart, nameLength, nameEnd); + } + finally + { + _recursionDepth = depth; + } + } + + private readonly void AppendTypeRows( + int levels, + int nonNullCount, + int nameStart, + int nameLength, + int nameEnd) + { + // A non-null marker always ends past the start of the source text, so a zero end marks + // the absence of the marker: nameEnd for the named type, bangEnd for a list wrapper. + var remaining = levels + nonNullCount + 1; + + for (var level = 0; level < levels; level++) + { + ReadTypeLevel(level, out var start, out var closeEnd, out var bangEnd); + + if (bangEnd != 0) + { + AppendRow( + new DbRow(Utf8SyntaxKind.NonNullType, start, bangEnd - start, remaining--)); + } + + AppendRow(new DbRow(Utf8SyntaxKind.ListType, start, closeEnd - start, remaining--)); + } + + if (nameEnd != 0) + { + AppendRow( + new DbRow( + Utf8SyntaxKind.NonNullType, + nameStart, + nameEnd - nameStart, + remaining--)); + } + + AppendRow(new DbRow(Utf8SyntaxKind.NamedType, nameStart, nameLength, 1)); + } + + private void PushTypeLevel(int level, int start) + { + var required = (level + 1) * TypeLevelSize; + + if (_typeLevels is null || _typeLevels.Length < required) + { + var next = ArrayPool.Shared.Rent(required); + + if (_typeLevels is not null) + { + _typeLevels.AsSpan().CopyTo(next); + ArrayPool.Shared.Return(_typeLevels); + } + + _typeLevels = next; + } + + _typeLevels[level * TypeLevelSize] = start; + } + + private readonly void CloseTypeLevel(int level, int closeEnd, int bangEnd) + { + var offset = level * TypeLevelSize; + _typeLevels![offset + 1] = closeEnd; + _typeLevels[offset + 2] = bangEnd; + } + + private readonly void ReadTypeLevel(int level, out int start, out int closeEnd, out int bangEnd) + { + var offset = level * TypeLevelSize; + start = _typeLevels![offset]; + closeEnd = _typeLevels[offset + 1]; + bangEnd = _typeLevels[offset + 2]; + } + + private void ParseValue(bool isConstant) + { + EnterDepth(); + CountNode(); + try + { + switch (_reader.Kind) + { + case TokenKind.Integer: + AppendValueRow(Utf8SyntaxKind.IntValue); + MoveNext(); + return; + + case TokenKind.Float: + AppendValueRow(Utf8SyntaxKind.FloatValue); + MoveNext(); + return; + + case TokenKind.Name: + AppendValueRow(Utf8SyntaxKind.EnumValue); + MoveNext(); + return; + + case TokenKind.String: + case TokenKind.BlockString: + ValidateString(); + AppendValueRow(Utf8SyntaxKind.StringValue); + MoveNext(); + return; + + case TokenKind.Dollar when !isConstant: + MoveNext(); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Variable, nameStart, nameLength, 1)); + RecordVariableSite(nameStart, nameLength); + return; + + case TokenKind.LeftBracket: + ParseListValue(isConstant); + return; + + case TokenKind.LeftBrace: + ParseObjectValue(isConstant); + return; + + default: + throw Error("Expected a value literal."); + } + } + finally + { + ExitDepth(); + } + } + + private void ParseListValue(bool isConstant) + { + var sourceStart = _reader.Start; + var cursor = AppendUncountedPlaceholder(); + MoveNext(); + + while (_reader.Kind is not TokenKind.RightBracket) + { + ParseValue(isConstant); + } + + var sourceEnd = _reader.End; + MoveNext(); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.ListValue, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + } + + private void ParseObjectValue(bool isConstant) + { + var sourceStart = _reader.Start; + var cursor = AppendUncountedPlaceholder(); + MoveNext(); + + while (_reader.Kind is not TokenKind.RightBrace) + { + CountNode(); + var fieldStart = _reader.Start; + var fieldCursor = AppendUncountedPlaceholder(); + ReadName(out var nameStart, out var nameLength); + AppendRow(new DbRow(Utf8SyntaxKind.Name, nameStart, nameLength, 1)); + Expect(TokenKind.Colon); + ParseValue(isConstant); + Patch( + fieldCursor, + new DbRow( + Utf8SyntaxKind.ObjectField, + fieldStart, + _previousEnd - fieldStart, + RowCount - fieldCursor)); + } + + var sourceEnd = _reader.End; + MoveNext(); + Patch( + cursor, + new DbRow( + Utf8SyntaxKind.ObjectValue, + sourceStart, + sourceEnd - sourceStart, + RowCount - cursor)); + } + + private void AppendValueRow(Utf8SyntaxKind kind) + => AppendRow(new DbRow(kind, _reader.Start, _reader.Position - _reader.Start, 1)); + + private void ReadFragmentName(out int start, out int length) + { + if (IsKeyword(GraphQLKeywords.On)) + { + throw Error("A fragment name cannot be `on`."); + } + + ReadName(out start, out length); + } + + private void ReadName(out int start, out int length) + { + if (_reader.Kind is not TokenKind.Name) + { + throw Error("Expected a name."); + } + + CountNode(); + start = _reader.Start; + length = _reader.End - _reader.Start; + MoveNext(); + } + + private void ExpectKeyword(ReadOnlySpan keyword) + { + if (!IsKeyword(keyword)) + { + throw Error("Expected a keyword."); + } + + MoveNext(); + } + + private bool IsKeyword(ReadOnlySpan keyword) + => _reader.Kind is TokenKind.Name && _reader.Value.SequenceEqual(keyword); + + private void Expect(TokenKind kind) + { + if (_reader.Kind != kind) + { + throw Error($"Expected {kind}, found {_reader.Kind}."); + } + + MoveNext(); + } + + private void MoveNext() + { + _previousEnd = _reader.Position; + _reader.MoveNext(); + } + + private void ValidateString() + => Utf8Helper.Validate(_reader.Value, _reader.Kind is TokenKind.BlockString); + + private void RecordVariableSite(int nameStart, int nameLength) + { + var ordinal = ResolveOrdinal(nameStart, nameLength); + + var required = checked((_siteCount + 1) * 8); + if (_variableSites is null || _variableSites.Length < required) + { + GrowVariableBuffer(ref _variableSites, required); + } + + var offset = _siteCount * 8; + ref var start = ref MemoryMarshal.GetReference(_variableSites.AsSpan(offset)); + Unsafe.WriteUnaligned(ref start, nameStart); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref start, 4), (ushort)ordinal); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref start, 6), (ushort)0); + _siteCount++; + } + + private int ResolveOrdinal(int nameStart, int nameLength) + { + var name = _source.Slice(nameStart, nameLength); + + for (var i = 0; i < _variableCount; i++) + { + ref var entry = ref MemoryMarshal.GetReference(_variableDirectory!.AsSpan(i * 8)); + var existingStart = Unsafe.ReadUnaligned(ref entry); + var existingLength = Unsafe.ReadUnaligned(ref Unsafe.Add(ref entry, 4)); + + if (name.SequenceEqual(_source.Slice(existingStart, existingLength))) + { + return i; + } + } + + if (_variableCount > ushort.MaxValue) + { + throw Error( + $"The maximum allowed number of distinct variables ({ushort.MaxValue + 1}) was exceeded."); + } + + var required = checked((_variableCount + 1) * 8); + if (_variableDirectory is null || _variableDirectory.Length < required) + { + GrowVariableBuffer(ref _variableDirectory, required); + } + + ref var slot = ref MemoryMarshal.GetReference(_variableDirectory!.AsSpan(_variableCount * 8)); + Unsafe.WriteUnaligned(ref slot, nameStart); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref slot, 4), nameLength); + return _variableCount++; + } + + private static void GrowVariableBuffer(ref byte[]? buffer, int required) + { + var next = ArrayPool.Shared.Rent(required); + + if (buffer is not null) + { + buffer.AsSpan().CopyTo(next); + ArrayPool.Shared.Return(buffer); + } + + buffer = next; + } + + private readonly VariableTable CreateVariableTable(bool pooled) + { + if (_siteCount == 0) + { + return VariableTable.Empty; + } + + var siteBytes = _siteCount * 8; + var directoryBytes = _variableCount * 8; + var length = siteBytes + directoryBytes; + var buffer = pooled + ? ArrayPool.Shared.Rent(length) + : new byte[length]; + + _variableSites.AsSpan(0, siteBytes).CopyTo(buffer); + _variableDirectory.AsSpan(0, directoryBytes).CopyTo(buffer.AsSpan(siteBytes)); + return VariableTable.Create(buffer, _siteCount, _variableCount, pooled); + } + + private void ReturnScratchBuffers() + { + if (_variableSites is not null) + { + ArrayPool.Shared.Return(_variableSites); + _variableSites = null; + } + + if (_variableDirectory is not null) + { + ArrayPool.Shared.Return(_variableDirectory); + _variableDirectory = null; + } + + if (_typeLevels is not null) + { + ArrayPool.Shared.Return(_typeLevels); + _typeLevels = null; + } + } + + private int AppendPlaceholder() + { + CountNode(); + return AppendUncountedPlaceholder(); + } + + /// + /// Reserves a row for a node whose syntax-node count is already accounted for by the + /// construct that is being parsed. + /// + private int AppendUncountedPlaceholder() + { + var metadataLength = _metadata.Length; + AssertCanAppendRow(metadataLength); + var cursor = metadataLength / DbRow.Size; + _metadata.GetSpan(DbRow.Size); + _metadata.Advance(DbRow.Size); + _openRows++; + return cursor; + } + + private readonly void AppendRow(in DbRow row) + { + AssertCanAppendRow(_metadata.Length); + var buffer = _metadata.GetSpan(DbRow.Size); + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(buffer), row); + _metadata.Advance(DbRow.Size); + } + + internal static void AssertCanAppendRow(int metadataLength) + { + if ((uint)metadataLength > MaxMetadataLength - DbRow.Size) + { + throw new OverflowException( + "The packed syntax metadata exceeded its maximum of " + + $"{DbRow.MaxNumberOfRows} rows."); + } + } + + internal static int GetNextMetadataLength(int metadataLength) + { + AssertCanAppendRow(metadataLength); + return metadataLength + DbRow.Size; + } + + private void Patch(int cursor, DbRow row) + { + Span buffer = stackalloc byte[DbRow.Size]; + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(buffer), row); + _metadata.WriteAt(checked(cursor * DbRow.Size), buffer); + _openRows--; + } + + private readonly int RowCount => _metadata.Length / DbRow.Size; + + private void CountNode() + { + if (++_parsedNodes > _maxAllowedNodes) + { + throw Error( + $"The maximum allowed number of syntax nodes ({_maxAllowedNodes}) was exceeded."); + } + } + + private void EnterDepth() + { + if (++_recursionDepth > _maxAllowedRecursionDepth) + { + throw Error( + $"The maximum allowed recursion depth ({_maxAllowedRecursionDepth}) was exceeded."); + } + } + + private void ExitDepth() => _recursionDepth--; + + private readonly SyntaxException Error(string message) => new(_reader, message); + + /// + /// Parses an executable GraphQL document into a packed UTF-8 syntax tree. The returned + /// document adopts as its source; the caller must not + /// mutate the array afterwards. The document requires no disposal. + /// + /// + /// The UTF-8 encoded GraphQL source text that becomes the document's source. + /// + /// + /// The parser options, or to use the defaults. + /// + /// + /// The parsed document. + /// + /// + /// is . + /// + /// + /// is empty. + /// + public static Utf8OperationDocument Parse( + byte[] sourceText, + ParserOptions? options = null) + { + if (sourceText is null) + { + throw new ArgumentNullException(nameof(sourceText)); + } + + if (sourceText.Length == 0) + { + throw new ArgumentException(GraphQLData_Empty, nameof(sourceText)); + } + + return Parse(new ReadOnlyMemorySegment(sourceText), options); + } + + /// + /// Parses an executable GraphQL document into a packed UTF-8 syntax tree. The returned + /// document is a view over ; the segment's owner must + /// outlive the document. + /// + /// + /// The GraphQL source text that the document views. + /// + /// + /// The parser options, or to use the defaults. + /// + /// + /// When , the packed metadata is stored in a pooled buffer and the + /// document must be disposed to return it. When , the metadata is + /// stored in an exactly sized buffer and disposal is optional. + /// + /// + /// The parsed document. + /// + /// + /// is empty. + /// + public static Utf8OperationDocument Parse( + ReadOnlyMemorySegment sourceText, + ParserOptions? options = null, + bool pooledMetaDb = false) + { + if (sourceText.IsEmpty) + { + throw new ArgumentException(GraphQLData_Empty, nameof(sourceText)); + } + + using var writer = new ChunkedArrayWriter(JsonMemoryKind.Metadata); + var parser = new Utf8GraphQLOperationParser(sourceText.Span, writer, options); + try + { + parser.Parse(); + + return new Utf8OperationDocument( + sourceText, + CreateMetaDb(writer, pooledMetaDb), + parser.CreateVariableTable(pooledMetaDb)); + } + finally + { + parser.ReturnScratchBuffers(); + } + } + + private static MetaDb CreateMetaDb(ChunkedArrayWriter writer, bool pooled) + { + var length = writer.Length; + var buffer = pooled + ? ArrayPool.Shared.Rent(length) + : new byte[length]; + writer.CopyTo(buffer, 0, length); + return MetaDb.Create(buffer, length, pooled); + } +} diff --git a/src/HotChocolate/Language/src/Language.Utf8/Utf8Helper.cs b/src/HotChocolate/Language/src/Language.Utf8/Utf8Helper.cs index 7aff0db9d7f..dafcbc8ee60 100644 --- a/src/HotChocolate/Language/src/Language.Utf8/Utf8Helper.cs +++ b/src/HotChocolate/Language/src/Language.Utf8/Utf8Helper.cs @@ -10,6 +10,95 @@ namespace HotChocolate.Language; internal static class Utf8Helper { + public static void Validate(ReadOnlySpan escapedString, bool isBlockString) + { + var position = 0; + var highSurrogate = -1; + + while (position < escapedString.Length) + { + var nextBackslash = escapedString.Slice(position).IndexOf(GraphQLCharacters.Backslash); + if (nextBackslash < 0) + { + break; + } + + position += nextBackslash; + if (++position >= escapedString.Length) + { + throw new Utf8EncodingException( + string.Format(Utf8Helper_InvalidEscapeChar, '\\')); + } + + var code = escapedString[position++]; + if (isBlockString && code == GraphQLCharacters.Quote) + { + if (position + 1 >= escapedString.Length + || escapedString[position] != GraphQLCharacters.Quote + || escapedString[position + 1] != GraphQLCharacters.Quote) + { + throw new Utf8EncodingException(Utf8Helper_InvalidQuoteEscapeCount); + } + + position += 2; + continue; + } + + if (code == GraphQLCharacters.U) + { + if (position + 3 >= escapedString.Length) + { + throw new Utf8EncodingException( + string.Format(Utf8Helper_InvalidEscapeChar, 'u')); + } + + var unicodeDecimal = UnescapeUtf8Hex( + escapedString[position], + escapedString[position + 1], + escapedString[position + 2], + escapedString[position + 3]); + position += 4; + + if (unicodeDecimal is >= 0xD800 and <= 0xDBFF) + { + if (highSurrogate >= 0) + { + throw new Utf8EncodingException("Unexpected high surrogate."); + } + + highSurrogate = unicodeDecimal; + } + else if (unicodeDecimal is >= 0xDC00 and <= 0xDFFF) + { + if (highSurrogate < 0) + { + throw new Utf8EncodingException("Unexpected low surrogate."); + } + + highSurrogate = -1; + } + else if (highSurrogate >= 0) + { + throw new Utf8EncodingException( + "High surrogate not followed by low surrogate."); + } + + continue; + } + + if (!code.IsValidEscapeCharacter()) + { + throw new Utf8EncodingException( + string.Format(Utf8Helper_InvalidEscapeChar, (char)code)); + } + } + + if (highSurrogate >= 0) + { + throw new Utf8EncodingException("High surrogate not followed by low surrogate."); + } + } + public static void Unescape( in ReadOnlySpan escapedString, ref Span unescapedString, @@ -163,6 +252,11 @@ public static void Unescape( } } + if (highSurrogate >= 0) + { + throw new Utf8EncodingException("High surrogate not followed by low surrogate."); + } + if (unescapedString.Length > writePos) { unescapedString = unescapedString.Slice(0, writePos); @@ -287,7 +381,20 @@ private static void ProcessEscapeSequenceCold( [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int UnescapeUtf8Hex(byte a, byte b, byte c, byte d) - => (HexToDecimal(a) << 12) | (HexToDecimal(b) << 8) | (HexToDecimal(c) << 4) | HexToDecimal(d); + { + var x1 = HexToDecimal(a); + var x2 = HexToDecimal(b); + var x3 = HexToDecimal(c); + var x4 = HexToDecimal(d); + + if ((x1 | x2 | x3 | x4) > 0xF) + { + throw new Utf8EncodingException( + string.Format(Utf8Helper_InvalidEscapeChar, 'u')); + } + + return (x1 << 12) | (x2 << 8) | (x3 << 4) | x4; + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void UnescapeUtf8Hex( diff --git a/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8GraphQLOperationParserTests.cs b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8GraphQLOperationParserTests.cs new file mode 100644 index 00000000000..132f7a67c4b --- /dev/null +++ b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8GraphQLOperationParserTests.cs @@ -0,0 +1,1202 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using HotChocolate.Buffers; + +namespace HotChocolate.Language; + +public class Utf8GraphQLOperationParserTests +{ + [Fact] + public void ParseOperationDocument_Should_ExposePackedExecutableStructure_When_DocumentIsComplex() + { + // arrange + const string source = """ + query Search($term: String! = "hot" @tag) @operation { + result: search(term: $term) { + title + ...Card + ... on Product @include(if: true) { price } + ... @defer { id } + } + } + fragment Card($size: Int) on Item @fragment { id } + """; + + // act + var document = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes(source), + new ParserOptions(allowFragmentVariables: true)); + + // assert + Assert.Equal( + """ + operation Query Search + variable term + field result:search + field title + spread Card + inline Product + field price + inline + field id + fragment Card on Item + variable size + field id + + """, + Describe(document)); + } + + [Fact] + public void ParseOperationDocument_Should_PreserveOffsets_When_SourceHasBomCommentsAndUtf8Strings() + { + // arrange + var query = Encoding.UTF8.GetBytes("query Q { first(text: \"Grüße\") # 日本語\n second }"); + var bom = Encoding.UTF8.GetPreamble(); + var source = new byte[bom.Length + query.Length]; + bom.CopyTo(source, 0); + query.CopyTo(source, bom.Length); + + // act + var operation = First( + Utf8GraphQLOperationParser.Parse(source).GetOperations()); + var selections = operation.SelectionSet.GetSelections().GetEnumerator(); + selections.MoveNext(); + var first = selections.Current.GetField(); + selections.MoveNext(); + var second = selections.Current.GetField(); + + // assert + Assert.Equal("first", Encoding.UTF8.GetString(first.Utf8Name)); + Assert.Equal("second", Encoding.UTF8.GetString(second.Utf8Name)); + } + + [Fact] + public void ParseOperationDocument_Should_CrossMetadataChunkBoundary_When_DocumentHasManyFields() + { + // arrange + var source = new StringBuilder("{"); + for (var i = 0; i < 3300; i++) + { + source.Append(" f").Append(i); + } + source.Append(" }"); + + // act + var operation = First( + Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes(source.ToString()), + new ParserOptions(maxAllowedFields: 4000)).GetOperations()); + var fields = operation.SelectionSet.GetSelections().GetEnumerator(); + var count = 0; + var last = string.Empty; + while (fields.MoveNext()) + { + count++; + last = fields.Current.GetField().Name; + } + + // assert + Assert.Equal(3300, count); + Assert.Equal("f3299", last); + } + + [Fact] + public void ParseOperationDocument_Should_EnforceFieldLimit_When_LimitIsExceeded() + { + // act + var exception = Record.Exception( + () => Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("{ first second }"), + new ParserOptions(maxAllowedFields: 1))); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void SelectionNode_Should_UseConsistentDefaultAndWrongKindBehavior() + { + // arrange + var selection = First( + First( + Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes("{ field }")) + .GetOperations()) + .SelectionSet + .GetSelections()); + var defaultSelection = default(Utf8SelectionNode); + + // act + var wrongKind = Record.Exception(() => selection.GetFragmentSpread()); + var found = defaultSelection.TryGetField(out var field); + + // assert + Assert.Equal(Utf8SelectionKind.None, defaultSelection.Kind); + Assert.IsType(wrongKind); + Assert.False(found); + Assert.Equal(default, field); + } + + [Theory] + [InlineData("{ field }")] + [InlineData("query { field }")] + public void ParseOperationDocument_Should_ExposeAnonymousQuery_When_NameIsOmitted(string source) + { + // act + var operation = First( + Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)).GetOperations()); + + // assert + Assert.Equal(OperationType.Query, operation.Operation); + Assert.False(operation.HasName); + Assert.Null(operation.Name); + Assert.True(operation.Utf8Name.IsEmpty); + } + + [Fact] + public void ParseOperationDocument_Should_RejectSchemaDefinition_When_DocumentIsNotExecutable() + { + // act + var exception = Record.Exception( + () => Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("type Query { field: String }"))); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void ParseOperationDocument_Should_HonorFragmentVariableOption_When_VariablesAreDeclared() + { + // arrange + const string source = "fragment F($id: ID!) on Node { id }"; + + // act + var disabled = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source))); + var enabled = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes(source), + new ParserOptions(allowFragmentVariables: true)); + var fragment = First(enabled.GetFragments()); + var variables = fragment.GetVariableDefinitions().GetEnumerator(); + + // assert + Assert.IsType(disabled); + Assert.True(variables.MoveNext()); + Assert.Equal("id", variables.Current.Name); + Assert.False(variables.MoveNext()); + } + + [Fact] + public void ParseOperationDocument_Should_RetainOnlyExactSourceArray() + { + // arrange + const string source = "{ one { two } ...F } fragment F on Type { three }"; + + // act + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + var arrayFields = typeof(Utf8OperationDocument) + .GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic) + .Where(t => t.FieldType.IsArray) + .Select(t => t.FieldType) + .ToArray(); + + // assert + Assert.Equal(Encoding.UTF8.GetByteCount(source), document.SourceLength); + Assert.Equal(15 * Utf8OperationDocument.DbRow.Size, document.MetadataLength); + Assert.Equal([typeof(byte[])], arrayFields); + } + + [Theory] + [InlineData("query Q($id: [ID!]! = [\"a\", \"b\"]) @one { node(id: $id) @two { id } }")] + [InlineData("{ field(arg: { one: [1, $value] }) @one }")] + [InlineData("fragment F on Item { value } query Q { ...F ... on Item { nested } }")] + public void ParseOperationDocument_Should_MatchClassicNodeLimit_When_LimitIsExact(string source) + { + // arrange + var sourceBytes = Encoding.UTF8.GetBytes(source); + var classicParser = new Utf8GraphQLParser(sourceBytes); + classicParser.Parse(); + var exactNodeCount = classicParser.ParsedSyntaxNodes; + var exact = new ParserOptions(maxAllowedNodes: exactNodeCount); + var below = new ParserOptions(maxAllowedNodes: exactNodeCount - 1); + + // act + var classicExact = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, exact)); + var packedExact = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, exact)); + var classicBelow = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, below)); + var packedBelow = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, below)); + + // assert + Assert.Null(classicExact); + Assert.Null(packedExact); + Assert.IsType(classicBelow); + Assert.IsType(packedBelow); + } + + [Fact] + public void ParseOperationDocument_Should_MatchClassicTokenLimit_When_LimitIsExact() + { + // arrange + const string source = "query Q($id: ID!) { node(id: $id) { id } }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + var reader = new Utf8GraphQLReader(sourceBytes); + var exactTokenCount = reader.Count(); + var exact = new ParserOptions(maxAllowedTokens: exactTokenCount); + var below = new ParserOptions(maxAllowedTokens: exactTokenCount - 1); + + // act + var classicExact = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, exact)); + var packedExact = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, exact)); + var classicBelow = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, below)); + var packedBelow = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, below)); + + // assert + Assert.Null(classicExact); + Assert.Null(packedExact); + Assert.IsType(classicBelow); + Assert.IsType(packedBelow); + } + + [Fact] + public void ParseOperationDocument_Should_MatchClassicDirectiveLimit_When_LimitIsExact() + { + // arrange + const string source = "{ field @one @two }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + var exact = new ParserOptions(maxAllowedDirectives: 2); + var below = new ParserOptions(maxAllowedDirectives: 1); + + // act + var classicExact = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, exact)); + var packedExact = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, exact)); + var classicBelow = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, below)); + var packedBelow = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, below)); + + // assert + Assert.Null(classicExact); + Assert.Null(packedExact); + Assert.IsType(classicBelow); + Assert.IsType(packedBelow); + } + + [Fact] + public void ParseOperationDocument_Should_MatchClassicTypeDepthLimit_When_LimitIsExact() + { + // arrange + const string source = "query Q($value: [[[[[Int]]]]]) { field }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + var exact = new ParserOptions(maxAllowedRecursionDepth: 6); + var below = new ParserOptions(maxAllowedRecursionDepth: 5); + + // act + var classicExact = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, exact)); + var packedExact = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, exact)); + var classicBelow = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes, below)); + var packedBelow = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes, below)); + + // assert + Assert.Null(classicExact); + Assert.Null(packedExact); + Assert.IsType(classicBelow); + Assert.IsType(packedBelow); + } + + [Theory] + [InlineData("{ field(arg: \"\\u12G4\") }")] + [InlineData("{ field(arg: \"\\uD800\") }")] + public void ParseOperationDocument_Should_RejectInvalidStringEscapeLikeClassicParser(string source) + { + // arrange + var sourceBytes = Encoding.UTF8.GetBytes(source); + + // act + var classic = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes)); + var packed = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes)); + + // assert + Assert.IsType(classic); + Assert.IsType(packed); + } + + [Theory] + [InlineData("\"\\u12G4\" query Q { field }")] + [InlineData("\"\\uD800\" query Q { field }")] + public void ParseOperationDocument_Should_RejectInvalidDescriptionEscapeLikeClassicParser( + string source) + { + // arrange + var sourceBytes = Encoding.UTF8.GetBytes(source); + + // act + var classic = Record.Exception(() => Utf8GraphQLParser.Parse(sourceBytes)); + var packed = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(sourceBytes)); + + // assert + Assert.IsType(classic); + Assert.IsType(packed); + } + + [Theory] + [InlineData("query Q($value: String = \"abc\") { field }", "\"abc\"")] + [InlineData("query Q($value: String = \"\"\"abc\"\"\") { field }", "\"\"\"abc\"\"\"")] + public void ParseOperationDocument_Should_PreserveExclusiveRawEnd_When_DefaultIsString( + string source, + string value) + { + // act + // rows: [OperationQuery][Name Q][VariableDefinition][Name value]... + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + var variable = document.GetRow(2); + + // assert + Assert.Equal(source.IndexOf(value, StringComparison.Ordinal) + value.Length, variable.SourceEnd); + } + + [Fact] + public void Enumerables_Should_FindDefinitions_When_FragmentPrecedesOperation() + { + // act + var document = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("fragment F on Item { value } query Q { ...F }")); + + // assert + Assert.Equal("F", First(document.GetFragments()).Name); + Assert.Equal("Q", First(document.GetOperations()).Name); + } + + [Fact] + public void SelectionEnumerable_Should_AdvanceToSibling_When_PreviousFieldHasSubtree() + { + // arrange + var operation = First( + Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes("{ parent { child } sibling }")) + .GetOperations()); + + // act + var selections = operation.SelectionSet.GetSelections().GetEnumerator(); + selections.MoveNext(); + var parent = selections.Current.GetField(); + selections.MoveNext(); + var sibling = selections.Current.GetField(); + + // assert + Assert.Equal("child", First(parent.SelectionSet.GetSelections()).GetField().Name); + Assert.Equal("sibling", sibling.Name); + Assert.False(selections.MoveNext()); + } + + [Fact] + public void DefaultViews_Should_ThrowInvalidOperation_When_SelectionSetAccessed() + { + // act + var operationSelection = Record.Exception( + () => _ = default(Utf8OperationDefinitionNode).SelectionSet); + var fragmentSelection = Record.Exception( + () => _ = default(Utf8FragmentDefinitionNode).SelectionSet); + var inlineSelection = Record.Exception( + () => _ = default(Utf8InlineFragmentNode).SelectionSet); + var fieldSelection = Record.Exception( + () => _ = default(Utf8FieldNode).SelectionSet); + var selectionSet = Record.Exception( + () => default(Utf8SelectionSetNode).GetSelections()); + + // assert + Assert.IsType(operationSelection); + Assert.IsType(fragmentSelection); + Assert.IsType(inlineSelection); + Assert.IsType(fieldSelection); + Assert.IsType(selectionSet); + } + + [Fact] + public void DefaultViews_Should_ThrowInvalidOperation_When_NameAccessed() + { + // act + var variable = Record.Exception( + () => _ = default(Utf8VariableDefinitionNode).Name); + var spread = Record.Exception( + () => _ = default(Utf8FragmentSpreadNode).Name); + + // assert + Assert.IsType(variable); + Assert.IsType(spread); + } + + [Fact] + public void DefaultDefinitionEnumerables_Should_BeEmpty_When_DocumentIsDefault() + { + // act + var operations = default(Utf8OperationDefinitionEnumerable).GetEnumerator(); + var fragments = default(Utf8FragmentDefinitionEnumerable).GetEnumerator(); + + // assert + Assert.False(operations.MoveNext()); + Assert.False(fragments.MoveNext()); + Assert.Equal(default, operations.Current); + Assert.Equal(default, fragments.Current); + } + + [Fact] + public void DefaultMemberEnumerables_Should_BeEmpty_When_ContainerIsDefault() + { + // act + var variables = default(Utf8VariableDefinitionEnumerable).GetEnumerator(); + var selections = default(Utf8SelectionEnumerable).GetEnumerator(); + + // assert + Assert.False(variables.MoveNext()); + Assert.False(selections.MoveNext()); + Assert.Equal(default, variables.Current); + Assert.Equal(Utf8SelectionKind.None, selections.Current.Kind); + } + + [Theory] + [InlineData(0, Utf8OperationDocument.DbRow.Size)] + [InlineData(1_610_612_712, 1_610_612_724)] + public void GetNextMetadataLength_Should_AdvanceOneRow_When_LengthIsWithinLimit( + int length, + int expected) + { + // act + var next = Utf8GraphQLOperationParser.GetNextMetadataLength(length); + + // assert + Assert.Equal(expected, next); + } + + [Theory] + [InlineData(-1)] + [InlineData(1_610_612_713)] + [InlineData(int.MaxValue)] + public void GetNextMetadataLength_Should_Throw_When_NextRowWouldOverflow(int length) + { + // act + var exception = Record.Exception( + () => Utf8GraphQLOperationParser.GetNextMetadataLength(length)); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void ParseOperationDocument_Should_ResolveAliasAndName_When_CommentsSurroundColon() + { + // arrange + const string source = "{ alias # c\n : # c\n name }"; + + // act + var operation = First(Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)).GetOperations()); + var field = First(operation.SelectionSet.GetSelections()).GetField(); + + // assert + Assert.True(field.HasAlias); + Assert.Equal("alias", field.Alias); + Assert.Equal("name", field.Name); + } + + [Fact] + public void ParseOperationDocument_Should_ResolveName_When_CommentSeparatesKeywordAndName() + { + // arrange + const string source = "query # c\n Foo { a }"; + + // act + var operation = First(Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)).GetOperations()); + + // assert + Assert.True(operation.HasName); + Assert.Equal("Foo", operation.Name); + Assert.Equal(OperationType.Query, operation.Operation); + } + + [Fact] + public void ParseOperationDocument_Should_ResolveTypeCondition_When_CommentsSurroundOn() + { + // arrange + const string source = "fragment Frag # c\n on # c\n Item { id }"; + + // act + var fragment = First(Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)).GetFragments()); + + // assert + Assert.Equal("Frag", fragment.Name); + Assert.Equal("Item", fragment.TypeCondition); + } + + [Fact] + public void ParseOperationDocument_Should_NavigatePastVariables_When_FragmentDeclaresVariables() + { + // arrange + const string source = "fragment F($a: Int, $b: String) on Item { id }"; + + // act + var fragment = First( + Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes(source), + new ParserOptions(allowFragmentVariables: true)).GetFragments()); + var variableNames = new StringBuilder(); + foreach (var variable in fragment.GetVariableDefinitions()) + { + variableNames.Append(variable.Name).Append(';'); + } + var field = First(fragment.SelectionSet.GetSelections()).GetField(); + + // assert + Assert.Equal("a;b;", variableNames.ToString()); + Assert.Equal("Item", fragment.TypeCondition); + Assert.Equal("id", field.Name); + } + + [Fact] + public void DbRow_Should_PreserveValues_When_KindSetsSignBit() + { + // arrange + // FragmentSpread (8) sets the top bit of the kind nybble, locking the unsigned-shift read. + var row = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.FragmentSpread, + location: 7, + sizeOrLength: 4, + numberOfRows: 2); + + // act + var result = RoundTrip(row); + + // assert + Assert.Equal(Utf8SyntaxKind.FragmentSpread, result.Kind); + Assert.Equal(7, result.Location); + Assert.Equal(11, result.SourceEnd); + Assert.Equal(2, result.NumberOfRows); + } + + [Fact] + public void DbRow_Should_PreserveValues_When_KindIsNameLeaf() + { + // arrange + // Name (11) also sets the top bit of the kind nybble. + var row = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.Name, + location: 3, + sizeOrLength: 5, + numberOfRows: 1); + + // act + var result = RoundTrip(row); + + // assert + Assert.Equal(Utf8SyntaxKind.Name, result.Kind); + Assert.Equal(3, result.Location); + Assert.Equal(5, result.SizeOrLength); + Assert.Equal(1, result.NumberOfRows); + } + + [Fact] + public void DbRow_Should_PreserveValues_When_KindExceedsFourBits() + { + // arrange + // Kinds from 16 upwards need the fifth kind bit, which locks the shift and the mask. + var objectValue = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.ObjectValue, + location: 9, + sizeOrLength: 6, + numberOfRows: 3); + var nonNullType = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.NonNullType, + location: 2, + sizeOrLength: 4, + numberOfRows: 2); + + // act + var objectValueResult = RoundTrip(objectValue); + var nonNullTypeResult = RoundTrip(nonNullType); + + // assert + Assert.Equal(Utf8SyntaxKind.ObjectValue, objectValueResult.Kind); + Assert.Equal(3, objectValueResult.NumberOfRows); + Assert.Equal(Utf8SyntaxKind.NonNullType, nonNullTypeResult.Kind); + Assert.Equal(2, nonNullTypeResult.NumberOfRows); + } + + [Fact] + public void DbRow_Should_PreserveValues_When_LocationAndLengthAreMaxInt() + { + // arrange + var row = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.SelectionSet, + location: int.MaxValue, + sizeOrLength: int.MaxValue, + numberOfRows: 0x07FFFFFF); + + // act + var result = RoundTrip(row); + + // assert + Assert.Equal(int.MaxValue, result.Location); + Assert.Equal(int.MaxValue, result.SizeOrLength); + Assert.Equal(0x07FFFFFF, result.NumberOfRows); + } + + [Fact] + public void DbRow_Should_PreserveValues_When_KindIsMaxAndNumberOfRowsIsMax() + { + // arrange + var row = new Utf8OperationDocument.DbRow( + Utf8SyntaxKind.NonNullType, + location: 0, + sizeOrLength: 0, + numberOfRows: 0x07FFFFFF); + + // act + var result = RoundTrip(row); + + // assert + Assert.Equal(Utf8SyntaxKind.NonNullType, result.Kind); + Assert.Equal(0x07FFFFFF, result.NumberOfRows); + } + + [Fact] + public void Parse_Should_ExposeSameTree_When_SourceIsOffsetSegment() + { + // arrange + const string source = "query Q { hero: name } fragment F on Person { id }"; + var text = Encoding.UTF8.GetBytes(source); + var buffer = new byte[8 + text.Length + 5]; + buffer.AsSpan().Fill((byte)'#'); + text.CopyTo(buffer, 8); + var segment = new ReadOnlyMemorySegment(new ArrayMemoryOwner(buffer), 8, text.Length); + + // act + var document = Utf8GraphQLOperationParser.Parse(segment); + var operation = First(document.GetOperations()); + var field = First(operation.SelectionSet.GetSelections()).GetField(); + var fragment = First(document.GetFragments()); + + // assert + Assert.Equal("Q", operation.Name); + Assert.Equal("hero", field.Alias); + Assert.Equal("name", field.Name); + Assert.Equal("Person", fragment.TypeCondition); + } + + [Fact] + public void Parse_Should_ReturnEquivalentDocument_When_MetaDbIsPooled() + { + // arrange + const string source = "query Q { hero: name { id } } fragment F on Person { id }"; + var segment = new ReadOnlyMemorySegment(Encoding.UTF8.GetBytes(source)); + + // act + var exact = Utf8GraphQLOperationParser.Parse(segment); + var pooled = Utf8GraphQLOperationParser.Parse(segment, pooledMetaDb: true); + var equivalent = Describe(exact) == Describe(pooled); + pooled.Dispose(); + + // assert + Assert.True(equivalent); + } + + [Fact] + public void Dispose_Should_BlockRowAccess_When_MetaDbIsPooled() + { + // arrange + var document = Utf8GraphQLOperationParser.Parse( + new ReadOnlyMemorySegment(Encoding.UTF8.GetBytes("query Q { field }")), + pooledMetaDb: true); + var operation = First(document.GetOperations()); + document.Dispose(); + + // act + var exception = Record.Exception(() => _ = operation.Name); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void Parse_Should_AdoptArrayInPlace_When_SourceIsByteArray() + { + // arrange + var source = Encoding.UTF8.GetBytes("query Q { field }"); + + // act + var document = Utf8GraphQLOperationParser.Parse(source); + var operation = First(document.GetOperations()); + var name = operation.Name; + source[Array.IndexOf(source, (byte)'Q')] = (byte)'Z'; + var mutatedName = Encoding.UTF8.GetString(operation.Utf8Name); + var dispose = Record.Exception(document.Dispose); + + // assert + Assert.Equal("Q", name); + Assert.Equal("Z", mutatedName); + Assert.Null(dispose); + } + + [Fact] + public void Dispose_Should_BeIdempotent_When_CalledTwice() + { + // arrange + var document = Utf8GraphQLOperationParser.Parse( + new ReadOnlyMemorySegment(Encoding.UTF8.GetBytes("{ field }")), + pooledMetaDb: true); + + // act + document.Dispose(); + var second = Record.Exception(document.Dispose); + + // assert + Assert.Null(second); + } + + [Fact] + public void Parse_Should_Throw_When_SegmentIsEmpty() + { + // act + var exception = Record.Exception( + () => Utf8GraphQLOperationParser.Parse(default(ReadOnlyMemorySegment))); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void Parse_Should_RecordVariableSites_When_VariablesAppearInArgumentsAndDirectives() + { + // arrange + const string source = + "query Foo($a: Int! = 1 @x(y: 2)) " + + "{ field(a: $a, w: { inner: [$a, $b] }) @dir(if: $b) { child(c: $a) } }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + + // act + var document = Utf8GraphQLOperationParser.Parse(sourceBytes); + var sites = DescribeSites(document, sourceBytes); + + // assert + Assert.Equal(2, document.VariableCount); + sites.MatchInlineSnapshot( + """ + 0 @11 'a' + 0 @45 'a' + 0 @62 'a' + 1 @66 'b' + 1 @82 'b' + 0 @97 'a' + """); + } + + [Fact] + public void Parse_Should_ShareOrdinal_When_TwoOperationsUseSameVariableName() + { + // arrange + const string source = "query A($a: Int) { f(x: $a) } query B($a: Int) { g(y: $a) }"; + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + // act + var ordinals = new int[document.VariableSiteCount]; + for (var i = 0; i < ordinals.Length; i++) + { + ordinals[i] = document.GetVariableSiteOrdinal(i); + } + + // assert + Assert.Equal(1, document.VariableCount); + Assert.Equal([0, 0, 0, 0], ordinals); + } + + [Fact] + public void Parse_Should_ReturnEmptyTable_When_DocumentHasNoVariables() + { + // act + var document = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("query Q { field { child } }")); + + // assert + Assert.Equal(0, document.VariableSiteCount); + Assert.Equal(0, document.VariableCount); + } + + [Fact] + public void Parse_Should_RecordDefinitionSite_When_TriviaSeparatesDollarAndName() + { + // arrange + const string source = "query ($ #c\n a: Int) { f(x: $a) }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + + // act + var document = Utf8GraphQLOperationParser.Parse(sourceBytes); + var definitionSite = document.GetVariableSitePosition(0); + + // assert + Assert.Equal((byte)'a', sourceBytes[definitionSite]); + Assert.Equal(source.IndexOf("a: Int", StringComparison.Ordinal), definitionSite); + } + + [Fact] + public void Parse_Should_RecordFragmentVariableSites_When_FragmentVariablesAllowed() + { + // arrange + const string source = "fragment F($a: Int) on Item { f(x: $a) }"; + var sourceBytes = Encoding.UTF8.GetBytes(source); + + // act + var document = Utf8GraphQLOperationParser.Parse( + sourceBytes, + new ParserOptions(allowFragmentVariables: true)); + + // assert + Assert.Equal(1, document.VariableCount); + Assert.Equal("a", Encoding.UTF8.GetString(document.GetVariableName(0))); + Assert.Equal(2, document.VariableSiteCount); + } + + [Fact] + public void Dispose_Should_BlockVariableTableAccess_When_MetaDbIsPooled() + { + // arrange + var document = Utf8GraphQLOperationParser.Parse( + new ReadOnlyMemorySegment(Encoding.UTF8.GetBytes("query Q($a: Int) { f(x: $a) }")), + pooledMetaDb: true); + document.Dispose(); + + // act + var exception = Record.Exception(() => document.GetVariableSitePosition(0)); + + // assert + Assert.IsType(exception); + } + + [Fact] + public void ParseOperationDocument_Should_EmitAliasThenName_When_FieldIsAliased() + { + // act + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes("{ hero: name }")); + + // assert + DescribeRows(document).MatchInlineSnapshot( + """ + OperationQuery (5) + SelectionSet (4) + Field (3) + Alias 'hero' + Name 'name' + """); + } + + [Fact] + public void ParseOperationDocument_Should_OrderRows_When_FragmentDeclaresVariables() + { + // arrange + const string source = "fragment F($a: Int, $b: String) on Item { id }"; + + // act + var document = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes(source), + new ParserOptions(allowFragmentVariables: true)); + + // assert + DescribeRows(document).MatchInlineSnapshot( + """ + FragmentDefinition (12) + Name 'F' + VariableDefinition (3) + Name 'a' + NamedType 'Int' + VariableDefinition (3) + Name 'b' + NamedType 'String' + TypeCondition 'Item' + SelectionSet (3) + Field (2) + Name 'id' + """); + } + + [Fact] + public void ParseOperationDocument_Should_EmitValueRows_When_ArgumentsCarryEveryValueKind() + { + // arrange + const string source = + """{ f(a: $v, b: 1, c: 1.5, d: "s", e: ENUM, g: [1, null], h: { i: true }) }"""; + + // act + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + // assert + DescribeRows(document).MatchInlineSnapshot( + """ + OperationQuery (30) + SelectionSet (29) + Field (28) + Name 'f' + Argument (3) + Name 'a' + Variable 'v' + Argument (3) + Name 'b' + IntValue '1' + Argument (3) + Name 'c' + FloatValue '1.5' + Argument (3) + Name 'd' + StringValue '"s"' + Argument (3) + Name 'e' + EnumValue 'ENUM' + Argument (5) + Name 'g' + ListValue (3) + IntValue '1' + EnumValue 'null' + Argument (6) + Name 'h' + ObjectValue (4) + ObjectField (3) + Name 'i' + EnumValue 'true' + """); + } + + [Fact] + public void ParseOperationDocument_Should_EmitTypeRows_When_TypeIsNestedAndNonNull() + { + // arrange + const string source = "query Q($a: [[Int!]]! = null @tag) { f }"; + + // act + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + // assert + DescribeRows(document).MatchInlineSnapshot( + """ + OperationQuery (15) + Name 'Q' + VariableDefinition (10) + Name 'a' + NonNullType (5) + ListType (4) + ListType (3) + NonNullType (2) + NamedType 'Int' + EnumValue 'null' + Directive (2) + Name 'tag' + SelectionSet (3) + Field (2) + Name 'f' + """); + } + + [Fact] + public void ParseOperationDocument_Should_DiscoverNamePresence_When_NamedVsShorthand() + { + // act + var named = First( + Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("query Q { field }")).GetOperations()); + var shorthand = First( + Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("{ field }")).GetOperations()); + + // assert + Assert.True(named.HasName); + Assert.Equal("Q", Encoding.UTF8.GetString(named.Utf8Name)); + Assert.False(shorthand.HasName); + Assert.True(shorthand.Utf8Name.IsEmpty); + } + + [Fact] + public void Parse_Should_ReturnVariableNames_When_DocumentHasMultipleVariables() + { + // arrange + const string source = "query Q($alpha: Int, $beta: String) { f(a: $alpha, b: $beta) }"; + + // act + var document = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + // assert + Assert.Equal(2, document.VariableCount); + Assert.Equal("alpha", Encoding.UTF8.GetString(document.GetVariableName(0))); + Assert.Equal("beta", Encoding.UTF8.GetString(document.GetVariableName(1))); + } + + private static string DescribeRows(Utf8OperationDocument document) + { + var builder = new StringBuilder(); + for (var i = 0; i < document.RowCount; i++) + { + var row = document.GetRow(i); + if (i > 0) + { + builder.AppendLine(); + } + + builder.Append(row.Kind); + if (IsToken(row.Kind)) + { + builder + .Append(" '") + .Append(document.GetString(row.Location, row.SizeOrLength)) + .Append('\''); + } + else + { + builder.Append(" (").Append(row.NumberOfRows).Append(')'); + } + } + + return builder.ToString(); + } + + private static bool IsToken(Utf8SyntaxKind kind) + => kind is Utf8SyntaxKind.Name + or Utf8SyntaxKind.Alias + or Utf8SyntaxKind.TypeCondition + or Utf8SyntaxKind.Variable + or Utf8SyntaxKind.IntValue + or Utf8SyntaxKind.FloatValue + or Utf8SyntaxKind.StringValue + or Utf8SyntaxKind.EnumValue + or Utf8SyntaxKind.NamedType; + + private static string DescribeSites(Utf8OperationDocument document, byte[] source) + { + var builder = new StringBuilder(); + for (var i = 0; i < document.VariableSiteCount; i++) + { + var position = document.GetVariableSitePosition(i); + if (i > 0) + { + builder.AppendLine(); + } + builder + .Append(document.GetVariableSiteOrdinal(i)) + .Append(" @") + .Append(position) + .Append(" '") + .Append((char)source[position]) + .Append('\''); + } + + return builder.ToString(); + } + + private static Utf8OperationDocument.DbRow RoundTrip(Utf8OperationDocument.DbRow row) + { + Span buffer = stackalloc byte[Utf8OperationDocument.DbRow.Size]; + Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(buffer), row); + return MemoryMarshal.Read(buffer); + } + + private static Utf8OperationDefinitionNode First(Utf8OperationDefinitionEnumerable enumerable) + { + var enumerator = enumerable.GetEnumerator(); + Assert.True(enumerator.MoveNext()); + return enumerator.Current; + } + + private static Utf8SelectionNode First(Utf8SelectionEnumerable enumerable) + { + var enumerator = enumerable.GetEnumerator(); + Assert.True(enumerator.MoveNext()); + return enumerator.Current; + } + + private static Utf8FragmentDefinitionNode First(Utf8FragmentDefinitionEnumerable enumerable) + { + var enumerator = enumerable.GetEnumerator(); + Assert.True(enumerator.MoveNext()); + return enumerator.Current; + } + + private static string Describe(Utf8OperationDocument document) + { + var description = new StringBuilder(); + foreach (var operation in document.GetOperations()) + { + description + .Append("operation ") + .Append(operation.Operation) + .Append(' ') + .Append(operation.Name) + .AppendLine(); + foreach (var variable in operation.GetVariableDefinitions()) + { + description.Append(" variable ").AppendLine(variable.Name); + } + Describe(operation.SelectionSet, description, 1); + } + + foreach (var fragment in document.GetFragments()) + { + description + .Append("fragment ") + .Append(fragment.Name) + .Append(" on ") + .AppendLine(fragment.TypeCondition); + foreach (var variable in fragment.GetVariableDefinitions()) + { + description.Append(" variable ").AppendLine(variable.Name); + } + Describe(fragment.SelectionSet, description, 1); + } + + return description.ToString(); + } + + private static void Describe( + Utf8SelectionSetNode selectionSet, + StringBuilder description, + int depth) + { + foreach (var selection in selectionSet.GetSelections()) + { + description.Append(' ', depth * 2); + switch (selection.Kind) + { + case Utf8SelectionKind.Field: + var field = selection.GetField(); + description.Append("field "); + if (field.HasAlias) + { + description.Append(field.Alias).Append(':'); + } + description.AppendLine(field.Name); + if (field.HasSelectionSet) + { + Describe(field.SelectionSet, description, depth + 1); + } + break; + + case Utf8SelectionKind.FragmentSpread: + description + .Append("spread ") + .AppendLine(selection.GetFragmentSpread().Name); + break; + + case Utf8SelectionKind.InlineFragment: + var inlineFragment = selection.GetInlineFragment(); + description.Append("inline"); + if (inlineFragment.HasTypeCondition) + { + description.Append(' ').Append(inlineFragment.TypeCondition); + } + description.AppendLine(); + Describe(inlineFragment.SelectionSet, description, depth + 1); + break; + } + } + } +} diff --git a/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8OperationDocumentBuilderTests.cs b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8OperationDocumentBuilderTests.cs new file mode 100644 index 00000000000..4784a6aea5e --- /dev/null +++ b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8OperationDocumentBuilderTests.cs @@ -0,0 +1,518 @@ +using System.Buffers; +using System.Text; +using System.Text.Json; + +namespace HotChocolate.Language; + +public class Utf8OperationDocumentBuilderTests +{ + [Fact] + public void Complete_Should_EmitBatchedOperation_When_TwoItemsShareOneDocument() + { + // arrange + var document = Parse( + "query($id: ID!, $first: Int) { productById(id: $id) { name(first: $first) } }"); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .SetName("Foo") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + "query Foo($first:Int, $_0_id:ID!, $_1_id:ID!) { " + + "_0_productById:productById(id:$_0_id){name(first:$first)} " + + "_1_productById:productById(id:$_1_id){name(first:$first)} }"); + } + + [Fact] + public void Complete_Should_Roundtrip_When_OutputParsedAgain() + { + // arrange + var document = Parse( + "query($id: ID!, $first: Int) { productById(id: $id) { name(first: $first) } }"); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + Utf8OperationDocumentBuilder.New(writer) + .SetName("Foo") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // act + var reparsed = Utf8GraphQLOperationParser.Parse(writer.WrittenSpan.ToArray()); + var operation = FirstOperation(reparsed); + + // assert + Assert.Equal("Foo", Encoding.UTF8.GetString(operation.Utf8Name)); + Assert.Equal(2, CountSelections(operation)); + } + + [Fact] + public void Complete_Should_EmitCompactOperation_When_SourceDocumentIsIndented() + { + // arrange + var document = Parse( + """ + query ( + $id: ID! + $first: Int + ) { + # the lookup + productById(id: $id) { + name(first: $first) + } + } + """); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .SetName("Batch") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + "query Batch($first:Int, $_0_id:ID!, $_1_id:ID!) { " + + "_0_productById:productById(id:$_0_id){name(first:$first)} " + + "_1_productById:productById(id:$_1_id){name(first:$first)} }"); + } + + [Fact] + public void Complete_Should_Roundtrip_When_SourceDocumentIsIndented() + { + // arrange + var document = Parse( + """ + query ( + $id: ID! + $first: Int + ) { + # the lookup + productById(id: $id) { + name(first: $first) + } + } + """); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + Utf8OperationDocumentBuilder.New(writer) + .SetName("Batch") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // act + var reparsed = Utf8GraphQLOperationParser.Parse(writer.WrittenSpan.ToArray()); + var operation = FirstOperation(reparsed); + + // assert + Assert.Equal("Batch", Encoding.UTF8.GetString(operation.Utf8Name)); + Assert.Equal(2, CountSelections(operation)); + } + + [Fact] + public void Complete_Should_EmitAnonymousQueryWithParentheses_When_NameNotSetAndItemHasVariables() + { + // arrange + var document = Parse("query($id: ID!) { a(id: $id) }"); + var field = FirstField(document); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot("query($_0_id:ID!) { _0_a:a(id:$_0_id) }"); + } + + [Fact] + public void Complete_Should_OmitParentheses_When_DocumentHasNoVariables() + { + // arrange + var document = Parse("{ productById { name } }"); + var field = FirstField(document); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot("query { _0_productById:productById{name} }"); + } + + [Fact] + public void Complete_Should_RenamePerIndex_When_ItemsComeFromDifferentDocuments() + { + // arrange + var documentA = Parse("query($id: ID!) { a(id: $id) }"); + var documentB = Parse("query($id: ID!) { b(id: $id) }"); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(FirstField(documentA)) + .AddRootSelection(FirstField(documentB)) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + "query($_0_id:ID!, $_1_id:ID!) { _0_a:a(id:$_0_id) _1_b:b(id:$_1_id) }"); + } + + [Fact] + public void AddRootSelection_Should_DropDescription_When_DefinitionIsRenamed() + { + // arrange + // A description is not part of the variable definition the rows describe, so the + // canonical output of a renamed definition carries the definition only. + var document = Parse("query(\"the id\" $id: ID!) { productById(id: $id) { name } }"); + var field = FirstField(document); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + "query($_0_id:ID!) { _0_productById:productById(id:$_0_id){name} }"); + } + + [Fact] + public void AddRootSelection_Should_EmitTypeAndDefault_When_DefinitionIsRenamed() + { + // arrange + var document = Parse( + "query($ids: [ID!]! = [\"a\"] @tag) { productsByIds(ids: $ids) { name } }"); + var field = FirstField(document); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + "query($_0_ids:[ID!]!=[\"a\"]@tag) { " + + "_0_productsByIds:productsByIds(ids:$_0_ids){name} }"); + } + + [Fact] + public void Complete_Should_Roundtrip_When_RenamedDefinitionHasTypeAndDefault() + { + // arrange + var document = Parse( + "query($ids: [ID!]! = [\"a\"] @tag) { productsByIds(ids: $ids) { name } }"); + var writer = new ArrayBufferWriter(); + Utf8OperationDocumentBuilder.New(writer) + .AddRootSelection(FirstField(document)) + .Complete(); + + // act + var reparsed = Utf8GraphQLOperationParser.Parse(writer.WrittenSpan.ToArray()); + var operation = FirstOperation(reparsed); + var definition = new ArrayBufferWriter(); + VariableDefinition(reparsed, "_0_ids").Format(definition); + + // assert + Assert.Equal(1, CountSelections(operation)); + Text(definition).MatchInlineSnapshot( + """ + $_0_ids:[ID!]!=["a"]@tag + """); + } + + [Fact] + public void SetName_Should_Throw_When_CalledAfterAddRootSelection() + { + // arrange + var document = Parse("query { a { b } }"); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()) + .AddRootSelection(FirstField(document)); + + // act + void Act() => writer.SetName("Foo"); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void AddSharedVariable_Should_Throw_When_CalledAfterAddRootSelection() + { + // arrange + var document = Parse("query($id: ID!) { a(id: $id) }"); + var definition = VariableDefinition(document, "id"); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()) + .AddRootSelection(FirstField(document)); + + // act + void Act() => writer.AddSharedVariable(definition); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void AddRootSelection_Should_Throw_When_CalledAfterComplete() + { + // arrange + var document = Parse("query { a { b } }"); + var field = FirstField(document); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()) + .AddRootSelection(field); + writer.Complete(); + + // act + void Act() => writer.AddRootSelection(field); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void Complete_Should_Throw_When_CalledTwice() + { + // arrange + var document = Parse("query { a { b } }"); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()) + .AddRootSelection(FirstField(document)); + writer.Complete(); + + // act + void Act() => writer.Complete(); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void Complete_Should_Throw_When_NoRootSelections() + { + // arrange + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()) + .SetName("Foo"); + + // act + void Act() => writer.Complete(); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void AddRootSelection_Should_Throw_When_SelectionHasFragmentSpread() + { + // arrange + var document = Parse( + "query { productById { ...Frag } } fragment Frag on Product { name }"); + var field = FirstField(document); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()); + + // act + void Act() => writer.AddRootSelection(field); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void AddRootSelection_Should_Throw_When_SelectionHasAlias() + { + // arrange + var document = Parse("query($id: ID!) { alias: productById(id: $id) { name } }"); + var field = FirstField(document); + var writer = Utf8OperationDocumentBuilder.New(new ArrayBufferWriter()); + + // act + void Act() => writer.AddRootSelection(field); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void AddRootSelection_Should_LeaveOutputEmpty_When_SelectionHasAlias() + { + // arrange + var document = Parse("query($id: ID!) { alias: productById(id: $id) { name } }"); + var buffer = new ArrayBufferWriter(); + var writer = Utf8OperationDocumentBuilder.New(buffer, formatAsJsonStringValue: true); + + // act + void Act() => writer.AddRootSelection(FirstField(document)); + + // assert + Assert.Throws(Act); + Assert.Equal(0, buffer.WrittenCount); + } + + [Fact] + public void Complete_Should_UsePooledOrdinalSet_When_DocumentHasMoreThan64Variables() + { + // arrange + var document = Parse(GenerateManyVariableDocument(70)); + var field = FirstField(document); + var shared = VariableDefinition(document, "v0"); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer) + .AddSharedVariable(shared) + .AddRootSelection(field) + .Complete(); + + // assert + var text = Text(writer); + Assert.Contains("$v0:Int", text); + Assert.Contains("$_0_v65", text); + } + + private static string GenerateManyVariableDocument(int count) + { + var definitions = new StringBuilder(); + var arguments = new StringBuilder(); + + for (var i = 0; i < count; i++) + { + if (i > 0) + { + definitions.Append(", "); + arguments.Append(", "); + } + + definitions.Append($"$v{i}: Int"); + arguments.Append($"a{i}: $v{i}"); + } + + return $"query({definitions}) {{ f({arguments}) }}"; + } + + [Fact] + public void Complete_Should_EmitJsonStringLiteral_When_FormatAsJsonStringValue() + { + // arrange + var document = Parse( + """ + query($id: ID!, $first: Int) { + productById(id: $id, tag: "a\"b") { name(first: $first) } + } + """); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + + // act + Utf8OperationDocumentBuilder.New(writer, formatAsJsonStringValue: true) + .SetName("Foo") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // assert + Text(writer).MatchInlineSnapshot( + """ + "query Foo($first:Int, $_0_id:ID!, $_1_id:ID!) { _0_productById:productById(id:$_0_id,tag:\"a\\\"b\"){name(first:$first)} _1_productById:productById(id:$_1_id,tag:\"a\\\"b\"){name(first:$first)} }" + """); + } + + [Fact] + public void Complete_Should_RoundtripDecodedOperation_When_FormatAsJsonStringValue() + { + // arrange + var document = Parse( + """ + query($id: ID!, $first: Int) { + productById(id: $id, tag: "a\"b") { name(first: $first) } + } + """); + var field = FirstField(document); + var firstDefinition = VariableDefinition(document, "first"); + var writer = new ArrayBufferWriter(); + Utf8OperationDocumentBuilder.New(writer, formatAsJsonStringValue: true) + .SetName("Foo") + .AddSharedVariable(firstDefinition) + .AddRootSelection(field) + .AddRootSelection(field) + .Complete(); + + // act + using var json = JsonDocument.Parse(writer.WrittenMemory); + var decoded = json.RootElement.GetString()!; + var reparsed = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(decoded)); + var operation = FirstOperation(reparsed); + + // assert + Assert.Equal("Foo", Encoding.UTF8.GetString(operation.Utf8Name)); + Assert.Equal(2, CountSelections(operation)); + } + + private static Utf8OperationDocument Parse(string source) + => Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + private static string Text(ArrayBufferWriter writer) + => Encoding.UTF8.GetString(writer.WrittenSpan); + + private static Utf8OperationDefinitionNode FirstOperation(Utf8OperationDocument document) + { + var operations = document.GetOperations().GetEnumerator(); + Assert.True(operations.MoveNext()); + return operations.Current; + } + + private static Utf8FieldNode FirstField(Utf8OperationDocument document) + { + var selections = FirstOperation(document).SelectionSet.GetSelections().GetEnumerator(); + Assert.True(selections.MoveNext()); + return selections.Current.GetField(); + } + + private static Utf8VariableDefinitionNode VariableDefinition( + Utf8OperationDocument document, + string name) + { + foreach (var definition in FirstOperation(document).GetVariableDefinitions()) + { + if (Encoding.UTF8.GetString(definition.Utf8Name) == name) + { + return definition; + } + } + + throw new InvalidOperationException($"The variable '{name}' was not found."); + } + + private static int CountSelections(Utf8OperationDefinitionNode operation) + { + var count = 0; + foreach (var _ in operation.SelectionSet.GetSelections()) + { + count++; + } + + return count; + } +} diff --git a/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxFormatterTests.cs b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxFormatterTests.cs new file mode 100644 index 00000000000..08226ec0b47 --- /dev/null +++ b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxFormatterTests.cs @@ -0,0 +1,801 @@ +using System.Buffers; +using System.Text; +using System.Text.Json; +using HotChocolate.Buffers; + +namespace HotChocolate.Language; + +public class Utf8SyntaxFormatterTests +{ + private const string IndentedSource = + """ + # leading comment + query Foo($a: Int!, $b: String) { + # a comment + field(arg: $a, other: $b) @skip(if: $a) { + nested { + id + } + } + } + """; + + private const string AdjacentTokenSource = + """ + query Foo { + a(list: [1 -2, 3.5, -4]) @x @y { + ...F + ... on Thing { id } + } + } + + fragment F on Thing { + id + } + """; + + private const string KitchenSinkSource = + """" + query Q($a: [ID!]! = ["x"], $b: Int = 1 @onVariable) @onOperation { + alias: f(x: $a, y: { z: [1, -2, 3.5, null] }, t: """ + text + """) @onField { + ...F @onSpread + ... on Thing @onInline { id } + ... { id } + } + } + + fragment F on Thing @onFragment { + id(unit: SECONDS) + } + """"; + + [Fact] + public void Format_Should_RoundtripSource_When_MapIsEmpty() + { + // arrange + var source = Encoding.UTF8.GetBytes("query Foo($a: Int!) { abc(a: $a) { b } }"); + var document = Utf8GraphQLOperationParser.Parse(source); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: true); + + // assert + Assert.Equal(source, writer.WrittenSpan.ToArray()); + } + + [Fact] + public void Format_Should_SubstituteVariableNames_When_MapProvided() + { + // arrange + var document = Parse("query Foo($a: Int!) { abc(a: $a) { b } }"); + var map = new Utf8VariableNameMap([Bytes("_0_a")]); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: true, variables: map); + + // assert + Text(writer).MatchInlineSnapshot("query Foo($_0_a: Int!) { abc(a: $_0_a) { b } }"); + } + + [Fact] + public void Format_Should_SubstituteNestedSites_When_VariablesInInputObjectsAndDirectives() + { + // arrange + var document = Parse( + """ + query Q($a: Int!, $b: String!) { + f(filter: { ids: [$a, 2], name: $b }) @skip(if: $a) { + # keep me + id + } + } + """); + var map = new Utf8VariableNameMap([Bytes("alpha"), Bytes("beta")]); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: true, variables: map); + + // assert + Text(writer).MatchInlineSnapshot( + """ + query Q($alpha: Int!, $beta: String!) { + f(filter: { ids: [$alpha, 2], name: $beta }) @skip(if: $alpha) { + # keep me + id + } + } + """); + } + + [Fact] + public void Format_Should_KeepOriginalName_When_MapEntryMissingOrEmpty() + { + // arrange + var document = Parse("query Q($a: Int, $b: Int, $c: Int) { f(x: $a, y: $b, z: $c) }"); + var map = new Utf8VariableNameMap([Bytes("A"), ReadOnlyMemory.Empty]); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: true, variables: map); + + // assert + Text(writer).MatchInlineSnapshot( + "query Q($A: Int, $b: Int, $c: Int) { f(x: $A, y: $b, z: $c) }"); + } + + [Fact] + public void Format_Should_EmitSubtreeOnly_When_CalledOnFieldView() + { + // arrange + var document = Parse("query Foo($a: Int!) { r: abc(a: $a) { b } }"); + var field = FirstField(document); + var map = new Utf8VariableNameMap([Bytes("_0_a")]); + var writer = new ArrayBufferWriter(); + + // act + field.Format(writer, indented: true, variables: map); + + // assert + Text(writer).MatchInlineSnapshot("r: abc(a: $_0_a) { b }"); + } + + [Fact] + public void SelectionSet_Should_SkipArgumentValues_When_ArgumentsCarryObjectFields() + { + // arrange + // An object value contributes rows to the same sibling run as the selection set, so the + // lookup has to hop over each argument instead of descending into its value. + var withoutSelectionSet = FirstField(Parse("{ a(x: { y: 1 }) @d(z: [{ w: 2 }]) }")); + var withSelectionSet = FirstField(Parse("{ b(x: { y: 1 }) { c } }")); + var writer = new ArrayBufferWriter(); + + // act + withSelectionSet.SelectionSet.Format(writer, indented: false); + + // assert + Assert.False(withoutSelectionSet.HasSelectionSet); + Text(writer).MatchInlineSnapshot("{c}"); + } + + [Fact] + public void Format_Should_WorkThroughInterface_When_NodeIsBoxed() + { + // arrange + var document = Parse("query Foo($a: Int!) { abc(a: $a) { b } }"); + var field = FirstField(document); + var map = new Utf8VariableNameMap([Bytes("_0_a")]); + + // act + var documentDirect = new ArrayBufferWriter(); + var documentBoxed = new ArrayBufferWriter(); + document.Format(documentDirect, indented: true, variables: map); + ((IUtf8SyntaxNode)document).Format(documentBoxed, indented: true, variables: map); + var fieldDirect = new ArrayBufferWriter(); + var fieldBoxed = new ArrayBufferWriter(); + field.Format(fieldDirect, indented: true, variables: map); + ((IUtf8SyntaxNode)field).Format(fieldBoxed, indented: true, variables: map); + + // assert + Assert.Equal(documentDirect.WrittenSpan.ToArray(), documentBoxed.WrittenSpan.ToArray()); + Assert.Equal(fieldDirect.WrittenSpan.ToArray(), fieldBoxed.WrittenSpan.ToArray()); + } + + [Fact] + public void Format_Should_Throw_When_DocumentIsDisposed() + { + // arrange + var document = Utf8GraphQLOperationParser.Parse( + new ReadOnlyMemorySegment(Encoding.UTF8.GetBytes("query Foo($a: Int!) { abc(a: $a) { b } }")), + pooledMetaDb: true); + var map = new Utf8VariableNameMap([Bytes("_0_a")]); + var writer = new ArrayBufferWriter(); + document.Dispose(); + + // act + void Act() => document.Format(writer, indented: true, variables: map); + + // assert + Assert.Throws(Act); + } + + [Fact] + public void Ordinal_Should_MatchDeclarationIndex_When_SingleOperation() + { + // arrange + var document = Parse("query Q($a: Int, $b: Int, $c: Int) { f(x: $a, y: $b, z: $c) }"); + var variables = VariableDefinitions(FirstOperation(document)); + + // act + var ordinals = new[] { variables[0].Ordinal, variables[1].Ordinal, variables[2].Ordinal }; + + // assert + Assert.Equal([0, 1, 2], ordinals); + } + + [Fact] + public void Ordinal_Should_ReflectFirstOccurrence_When_FragmentPrecedesOperation() + { + // arrange + // $b first occurs in fragment F, so it is assigned ordinal 0 even though the operation + // declares $a before $b. + var document = Parse( + "fragment F on Foo { g(x: $b) } query Q($a: Int, $b: Int) { ...F f(x: $a) }"); + var variables = VariableDefinitions(FirstOperation(document)); + + // act + var ordinals = new[] { variables[0].Ordinal, variables[1].Ordinal }; + + // assert + Assert.Equal([1, 0], ordinals); + } + + [Fact] + public void Format_Should_ReproduceSource_When_IndentedIsTrue() + { + // arrange + var source = Encoding.UTF8.GetBytes(IndentedSource); + var document = Utf8GraphQLOperationParser.Parse(source); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: true); + + // assert + Assert.Equal(source, writer.WrittenSpan.ToArray()); + } + + [Fact] + public void Format_Should_CollapseWhitespaceAndComments_When_IndentedIsFalse() + { + // act + var compact = FormatCompactAndReparse(Parse(IndentedSource)); + + // assert + compact.MatchInlineSnapshot( + "query Foo($a:Int!,$b:String){field(arg:$a,other:$b)@skip(if:$a){nested{id}}}"); + } + + [Fact] + public void Format_Should_KeepDocumentStructure_When_CompactOutputIsReparsed() + { + // arrange + var document = Parse(IndentedSource); + var writer = new ArrayBufferWriter(); + document.Format(writer, indented: false); + + // act + var reparsed = Utf8GraphQLOperationParser.Parse(writer.WrittenSpan.ToArray()); + var operation = FirstOperation(reparsed); + + // assert + Assert.Equal("Foo", Encoding.UTF8.GetString(operation.Utf8Name)); + Assert.Equal(2, VariableDefinitions(operation).Count); + Assert.Equal("field", Encoding.UTF8.GetString(FirstField(reparsed).Utf8Name)); + } + + [Fact] + public void Format_Should_PreserveStringLiterals_When_IndentedIsFalse() + { + // arrange + var document = Parse( + """" + query Q { + f( + a: "hello world" + b: "he said \"hi\"" + c: """ + block + text + """ + ) + } + """"); + + // act + var compact = FormatCompactAndReparse(document); + + // assert + compact.MatchInlineSnapshot( + """" + query Q{f(a:"hello world",b:"he said \"hi\"",c:""" + block + text + """)} + """"); + } + + [Fact] + public void Format_Should_SeparateAdjacentTokens_When_IndentedIsFalse() + { + // act + var compact = FormatCompactAndReparse(Parse(AdjacentTokenSource)); + + // assert + compact.MatchInlineSnapshot( + "query Foo{a(list:[1,-2,3.5,-4])@x@y{...F ...on Thing{id}}} " + + "fragment F on Thing{id}"); + } + + [Fact] + public void Format_Should_KeepDefinitionNames_When_AdjacentTokenOutputIsReparsed() + { + // arrange + var document = Parse(AdjacentTokenSource); + var writer = new ArrayBufferWriter(); + document.Format(writer, indented: false); + + // act + var reparsed = Utf8GraphQLOperationParser.Parse(writer.WrittenSpan.ToArray()); + + // assert + Assert.Equal("Foo", Encoding.UTF8.GetString(FirstOperation(reparsed).Utf8Name)); + Assert.Equal("F", Encoding.UTF8.GetString(FirstFragment(reparsed).Utf8Name)); + } + + [Fact] + public void Format_Should_EmitEveryValueKind_When_IndentedIsFalse() + { + // arrange + var document = Parse( + """ + query Q($v: Int) { + f( + a: $v + b: 1 + c: -1.5e3 + d: "he said \"hi\"" + e: ENUM + g: true + h: false + i: null + j: [1, [2], { m: $v }] + k: { n: { o: [] } } + ) + } + """); + + // act + var compact = FormatCompactAndReparse(document); + + // assert + compact.MatchInlineSnapshot( + """ + query Q($v:Int){f(a:$v,b:1,c:-1.5e3,d:"he said \"hi\"",e:ENUM,g:true,h:false,i:null,j:[1,[2],{m:$v}],k:{n:{o:[]}})} + """); + } + + [Fact] + public void Format_Should_EmitDirectives_When_EveryConstructIsDecorated() + { + // arrange + var document = Parse( + """ + query Q($a: Int @onVariable) @onOperation { + f(x: $a) @onField { + ...F @onSpread + ... on Thing @onInline { id } + } + } + + fragment F on Thing @onFragment { id } + """); + + // act + var compact = FormatCompactAndReparse(document); + + // assert + compact.MatchInlineSnapshot( + "query Q($a:Int@onVariable)@onOperation{f(x:$a)@onField{...F@onSpread " + + "...on Thing@onInline{id}}} fragment F on Thing@onFragment{id}"); + } + + [Fact] + public void Format_Should_EmitTypesAndDefaults_When_VariablesUseListAndNonNullTypes() + { + // arrange + var document = Parse( + """ + query Q($a: [ID!]! = ["x"], $b: Int = 3, $c: [[Boolean]] = null, $d: String) { + f + } + """); + + // act + var compact = FormatCompactAndReparse(document); + + // assert + compact.MatchInlineSnapshot( + """ + query Q($a:[ID!]!=["x"],$b:Int=3,$c:[[Boolean]]=null,$d:String){f} + """); + } + + [Fact] + public void Format_Should_EmitTypeCondition_When_FragmentDeclaresVariables() + { + // arrange + var document = Utf8GraphQLOperationParser.Parse( + Encoding.UTF8.GetBytes("fragment F($a: Int = 1) on Thing { id(x: $a) }"), + new ParserOptions(allowFragmentVariables: true)); + + // act + var writer = new ArrayBufferWriter(); + document.Format(writer, indented: false); + var reparsed = Utf8GraphQLOperationParser.Parse( + writer.WrittenSpan.ToArray(), + new ParserOptions(allowFragmentVariables: true)); + + // assert + Assert.Equal("Thing", Encoding.UTF8.GetString(FirstFragment(reparsed).Utf8TypeCondition)); + Text(writer).MatchInlineSnapshot("fragment F($a:Int=1)on Thing{id(x:$a)}"); + } + + [Fact] + public void Format_Should_EmitKeyword_When_OperationIsShorthandOrMutation() + { + // arrange + var shorthand = Parse("{ a }"); + var mutation = Parse("mutation { a } subscription { b }"); + + // act + var shorthandCompact = FormatCompactAndReparse(shorthand); + var mutationCompact = FormatCompactAndReparse(mutation); + + // assert + Assert.Equal("query{a}", shorthandCompact); + Assert.Equal("mutation{a} subscription{b}", mutationCompact); + } + + [Fact] + public void Format_Should_SubstituteVariableNames_When_IndentedIsFalseAndSourceIsMultiLine() + { + // arrange + var document = Parse( + """ + query Q($a: Int!, $b: String) { + f(x: $a) { + g(y: $b, z: $a) + } + } + """); + var map = new Utf8VariableNameMap([Bytes("alpha"), Bytes("beta")]); + + // act + var compact = FormatCompactAndReparse(document, map); + + // assert + compact.MatchInlineSnapshot( + "query Q($alpha:Int!,$beta:String){f(x:$alpha){g(y:$beta,z:$alpha)}}"); + } + + [Fact] + public void Format_Should_SubstituteNestedSites_When_IndentedIsFalse() + { + // arrange + var document = Parse( + """ + query Q($a: Int, $b: Int = 2) { + f(x: { y: [$a, { z: $b }] }) @d(if: $a) + } + """); + var map = new Utf8VariableNameMap([Bytes("alpha"), Bytes("beta")]); + + // act + var compact = FormatCompactAndReparse(document, map); + + // assert + compact.MatchInlineSnapshot( + "query Q($alpha:Int,$beta:Int=2){f(x:{y:[$alpha,{z:$beta}]})@d(if:$alpha)}"); + } + + [Fact] + public void Format_Should_PrefixUnsharedVariableNames_When_SourceIsMultiLine() + { + // arrange + var document = Parse( + """ + query Q($id: ID!, $first: Int) { + productById(id: $id) { + name(first: $first) + } + } + """); + var field = FirstField(document); + Span words = stackalloc ulong[1]; + var shared = new SharedOrdinalSet(words); + shared.Add(Ordinal(document, "first")); + var writer = new ArrayBufferWriter(); + + // act + field.Format(new Utf8SyntaxWriter(writer, escape: false), "_0_"u8, shared); + + // assert + ReparseSelection(Text(writer)).MatchInlineSnapshot( + "productById(id:$_0_id){name(first:$first)}"); + } + + [Fact] + public void Format_Should_SubstituteVariableNames_When_CommentsSeparateEveryToken() + { + // arrange + var document = Parse( + """ + query # c1 + Foo # c2 + ( # c3 + $ # c4 + a # c5 + : # c6 + Int # c7 + ) # c8 + { # c9 + alias # c10 + : # c11 + field # c12 + ( # c13 + arg # c14 + : # c15 + $ # c16 + a # c17 + ) # c18 + } # c19 + """); + var map = new Utf8VariableNameMap([Bytes("alpha")]); + + // act + var compact = FormatCompactAndReparse(document, map); + + // assert + compact.MatchInlineSnapshot("query Foo($alpha:Int){alias:field(arg:$alpha)}"); + } + + [Fact] + public void Format_Should_EmitJsonStringLiteral_When_FormatAsJsonStringValue() + { + // arrange + var document = Parse( + """ + query Q { + f(a: "he said \"hi\"", b: "c:\\tmp", c: "größe") + } + """); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: false, formatAsJsonStringValue: true); + + // assert + Text(writer).MatchInlineSnapshot( + """ + "query Q{f(a:\"he said \\\"hi\\\"\",b:\"c:\\\\tmp\",c:\"größe\")}" + """); + } + + [Fact] + public void Format_Should_WrapOutputInQuotesOnce_When_NodeIsMinimal() + { + // arrange + var document = Parse("{ a }"); + var field = FirstField(document); + var writer = new ArrayBufferWriter(); + + // act + field.Format(writer, indented: false, formatAsJsonStringValue: true); + + // assert + Text(writer).MatchInlineSnapshot(""" + "a" + """); + } + + [Fact] + public void Format_Should_EscapeControlCharacters_When_LiteralsCarryTabAndNewline() + { + // arrange + var document = Parse( + "query Q { f(a: \"x\ty\", b: \"\"\"\nline1\nline2\"\"\") }"); + var writer = new ArrayBufferWriter(); + + // act + document.Format(writer, indented: false, formatAsJsonStringValue: true); + + // assert + Text(writer).MatchInlineSnapshot( + """ + "query Q{f(a:\"x\ty\",b:\"\"\"\nline1\nline2\"\"\")}" + """); + } + + [Fact] + public void Format_Should_DecodeToPlainOutput_When_CompactJsonStringValueIsParsed() + { + // arrange + var document = Parse( + """ + query Q($a: Int!) { + f(a: $a, b: "he said \"hi\"", c: "c:\\tmp") { id } + } + """); + + // act + var decoded = FormatAndDecode(document, indented: false, variables: default); + + // assert + Assert.Equal(FormatAsText(document, indented: false, variables: default), decoded); + } + + [Fact] + public void Format_Should_DecodeToPlainOutput_When_VerbatimJsonStringValueIsParsed() + { + // arrange + var document = Parse( + """ + query Q($a: Int!) { + # a comment + f(a: $a, b: "he said \"hi\"") { id } + } + """); + + // act + var decoded = FormatAndDecode(document, indented: true, variables: default); + + // assert + Assert.Equal(FormatAsText(document, indented: true, variables: default), decoded); + } + + [Fact] + public void Format_Should_DecodeToPlainOutput_When_SubstitutedJsonStringValueIsParsed() + { + // arrange + var document = Parse( + """ + query Q($a: Int!) { + f(a: $a, b: "he said \"hi\"") { id } + } + """); + var map = new Utf8VariableNameMap([Bytes("_0_a")]); + + // act + var decoded = FormatAndDecode(document, indented: false, variables: map); + + // assert + Assert.Equal(FormatAsText(document, indented: false, variables: map), decoded); + } + + [Fact] + public void Format_Should_DecodeToPlainOutput_When_DocumentUsesEveryConstruct() + { + // arrange + var document = Parse(KitchenSinkSource); + + // act + var decoded = FormatAndDecode(document, indented: false, variables: default); + var reparsed = Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(decoded)); + + // assert + Assert.Equal(FormatAsText(document, indented: false, variables: default), decoded); + Assert.Equal("Q", Encoding.UTF8.GetString(FirstOperation(reparsed).Utf8Name)); + Assert.Equal("F", Encoding.UTF8.GetString(FirstFragment(reparsed).Utf8Name)); + } + + [Fact] + public void Format_Should_EmitEveryConstruct_When_IndentedIsFalse() + { + // act + var compact = FormatCompactAndReparse(Parse(KitchenSinkSource)); + + // assert + compact.MatchInlineSnapshot( + """" + query Q($a:[ID!]!=["x"],$b:Int=1@onVariable)@onOperation{alias:f(x:$a,y:{z:[1,-2,3.5,null]},t:""" + text + """)@onField{...F@onSpread ...on Thing@onInline{id} ...{id}}} fragment F on Thing@onFragment{id(unit:SECONDS)} + """"); + } + + /// + /// Parses the emitted selection inside a minimal operation so that a canonical snapshot of a + /// selection is anchored to a valid GraphQL document, and returns the emitted text. + /// + private static string ReparseSelection(string selection) + { + Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes($"{{{selection}}}")); + return selection; + } + + /// + /// Formats the document in canonical form, parses the output again so that every canonical + /// snapshot is anchored to a valid GraphQL document, and returns the emitted text. + /// + private static string FormatCompactAndReparse( + Utf8OperationDocument document, + Utf8VariableNameMap variables = default) + { + var writer = new ArrayBufferWriter(); + document.Format(writer, indented: false, variables: variables); + var text = writer.WrittenSpan.ToArray(); + Utf8GraphQLOperationParser.Parse(text); + return Encoding.UTF8.GetString(text); + } + + private static string FormatAsText( + Utf8OperationDocument document, + bool indented, + Utf8VariableNameMap variables) + { + var writer = new ArrayBufferWriter(); + document.Format(writer, indented, variables: variables); + return Text(writer); + } + + private static string FormatAndDecode( + Utf8OperationDocument document, + bool indented, + Utf8VariableNameMap variables) + { + var writer = new ArrayBufferWriter(); + document.Format(writer, indented, formatAsJsonStringValue: true, variables); + using var json = JsonDocument.Parse(writer.WrittenMemory); + return json.RootElement.GetString()!; + } + + private static Utf8OperationDocument Parse(string source) + => Utf8GraphQLOperationParser.Parse(Encoding.UTF8.GetBytes(source)); + + private static ReadOnlyMemory Bytes(string value) + => Encoding.UTF8.GetBytes(value); + + private static string Text(ArrayBufferWriter writer) + => Encoding.UTF8.GetString(writer.WrittenSpan); + + private static Utf8OperationDefinitionNode FirstOperation(Utf8OperationDocument document) + { + var operations = document.GetOperations().GetEnumerator(); + Assert.True(operations.MoveNext()); + return operations.Current; + } + + private static Utf8FragmentDefinitionNode FirstFragment(Utf8OperationDocument document) + { + var fragments = document.GetFragments().GetEnumerator(); + Assert.True(fragments.MoveNext()); + return fragments.Current; + } + + private static Utf8FieldNode FirstField(Utf8OperationDocument document) + { + var selections = FirstOperation(document).SelectionSet.GetSelections().GetEnumerator(); + Assert.True(selections.MoveNext()); + return selections.Current.GetField(); + } + + private static int Ordinal(Utf8OperationDocument document, string name) + { + foreach (var definition in FirstOperation(document).GetVariableDefinitions()) + { + if (Encoding.UTF8.GetString(definition.Utf8Name) == name) + { + return definition.Ordinal; + } + } + + throw new InvalidOperationException($"The variable '{name}' was not found."); + } + + private static List VariableDefinitions( + Utf8OperationDefinitionNode operation) + { + var list = new List(); + foreach (var variable in operation.GetVariableDefinitions()) + { + list.Add(variable); + } + + return list; + } +} diff --git a/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxWriterTests.cs b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxWriterTests.cs new file mode 100644 index 00000000000..8953be865ec --- /dev/null +++ b/src/HotChocolate/Language/test/Language.Tests/Parser/Utf8SyntaxWriterTests.cs @@ -0,0 +1,66 @@ +using System.Buffers; +using System.Text; + +namespace HotChocolate.Language; + +public class Utf8SyntaxWriterTests +{ + [Fact] + public void Write_Should_EmitUnicodeEscapes_When_ValueCarriesOtherControlCharacters() + { + // arrange + var buffer = new ArrayBufferWriter(); + var writer = new Utf8SyntaxWriter(buffer, escape: true); + + // act + writer.Write([0x01, (byte)'a', 0x1F]); + + // assert + Text(buffer).MatchInlineSnapshot("""\u0001a\u001F"""); + } + + [Fact] + public void Write_Should_EmitTwoByteEscapes_When_ValueCarriesNamedControlCharacters() + { + // arrange + var buffer = new ArrayBufferWriter(); + var writer = new Utf8SyntaxWriter(buffer, escape: true); + + // act + writer.Write("\b\f\n\r\t\"\\"u8); + + // assert + Text(buffer).MatchInlineSnapshot("""\b\f\n\r\t\"\\"""); + } + + [Fact] + public void Write_Should_EmitValueUnchanged_When_WriterDoesNotEscape() + { + // arrange + var buffer = new ArrayBufferWriter(); + var writer = new Utf8SyntaxWriter(buffer, escape: false); + + // act + writer.Write("a\"b\\c"u8); + + // assert + Text(buffer).MatchInlineSnapshot("""a"b\c"""); + } + + [Fact] + public void Write_Should_EscapeEncodedText_When_ValueIsString() + { + // arrange + var buffer = new ArrayBufferWriter(); + var writer = new Utf8SyntaxWriter(buffer, escape: true); + + // act + writer.Write("größe \" ü \\ "); + + // assert + Text(buffer).MatchInlineSnapshot("""größe \" ü \\ """); + } + + private static string Text(ArrayBufferWriter writer) + => Encoding.UTF8.GetString(writer.WrittenSpan); +} diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/ArrayMemoryOwner.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/ArrayMemoryOwner.cs index fa5dce1e44e..83e6acc7260 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/ArrayMemoryOwner.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/ArrayMemoryOwner.cs @@ -1,63 +1,35 @@ using System.Buffers; +using System.Runtime.InteropServices; namespace HotChocolate.Buffers; /// -/// A memory owner for a byte array. +/// A memory owner over memory whose lifetime is managed elsewhere. /// public sealed class ArrayMemoryOwner : IMemoryOwner { - private readonly byte[] _buffer; - private readonly int _start; - private readonly int _length; - - public ArrayMemoryOwner(byte[] buffer) + private readonly ReadOnlyMemory _memory; + + /// + /// Initializes a new instance of . + /// + /// + /// The memory that is exposed by this owner. + /// + public ArrayMemoryOwner(ReadOnlyMemory memory) { -#if NET8_0_OR_GREATER - ArgumentNullException.ThrowIfNull(buffer); -#else - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } -#endif - - _buffer = buffer; - _start = 0; - _length = buffer.Length; - } - - public ArrayMemoryOwner(byte[] buffer, int start, int length) - { -#if NET8_0_OR_GREATER - ArgumentNullException.ThrowIfNull(buffer); - ArgumentOutOfRangeException.ThrowIfLessThan(start, 0); - ArgumentOutOfRangeException.ThrowIfLessThan(length, 0); -#else - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if (start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - - if (length < 0) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } -#endif - - _buffer = buffer; - _start = start; - _length = length; + _memory = memory; } - public Memory Memory => _buffer.AsMemory().Slice(_start, _length); + /// + /// Gets the memory that is exposed by this owner. + /// + public Memory Memory => MemoryMarshal.AsMemory(_memory); + /// + /// Does nothing as the memory is not owned by this instance. + /// public void Dispose() { - // do nothing } } diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/ChunkedArrayWriter.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/ChunkedArrayWriter.cs index 53d61ff703e..d975154a4e2 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/ChunkedArrayWriter.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/ChunkedArrayWriter.cs @@ -52,6 +52,50 @@ public int Position /// public int Length => Position; + internal bool IsDisposed => _disposed; + + /// + /// Overwrites an already advanced segment without changing the current write position. + /// Handles segments that span chunk boundaries. + /// + public void WriteAt(int location, ReadOnlySpan source) + { +#if NETSTANDARD2_0 + if (_disposed) + { + throw new ObjectDisposedException(typeof(ChunkedArrayWriter).FullName!); + } +#else + ObjectDisposedException.ThrowIf(_disposed, this); +#endif + + if ((uint)location > (uint)Length) + { + throw new ArgumentOutOfRangeException(nameof(location)); + } + + if (source.Length > Length - location) + { + throw new ArgumentException( + "The source does not fit within the advanced range.", + nameof(source)); + } + + var remaining = source; + var chunkIndex = location >> BufferShift; + var offsetInChunk = location & BufferMask; + + while (!remaining.IsEmpty) + { + var length = Math.Min(remaining.Length, BufferSize - offsetInChunk); + remaining.Slice(0, length).CopyTo( + _chunks[chunkIndex].AsSpan(offsetInChunk, length)); + remaining = remaining.Slice(length); + chunkIndex++; + offsetInChunk = 0; + } + } + /// public Span GetSpan(int sizeHint = 0) { @@ -166,6 +210,29 @@ public ReadOnlySpan Read(ref int start, ref int length) return _chunks[chunkIndex].AsSpan(offsetInChunk, available); } + /// + /// Reads as much data as possible from the chunk at the given location, mirroring + /// for callers that hand the data to an API that takes memory. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlyMemory ReadMemory(ref int start, ref int length) + { + var chunkIndex = start >> BufferShift; + var offsetInChunk = start & BufferMask; + var available = BufferSize - offsetInChunk; + + if (available >= length) + { + var memory = _chunks[chunkIndex].AsMemory(offsetInChunk, length); + length = 0; + return memory; + } + + start = (chunkIndex + 1) << BufferShift; + length -= available; + return _chunks[chunkIndex].AsMemory(offsetInChunk, available); + } + /// /// Compares an external span against a written segment at the specified location. /// Handles segments that span chunk boundaries. diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj b/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj index 0e7bc8b6256..899a7d169f0 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj @@ -18,6 +18,8 @@ + + diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/ReadOnlyMemorySegment.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/ReadOnlyMemorySegment.cs index 69553b65dd4..a841d11c7a9 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/ReadOnlyMemorySegment.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/ReadOnlyMemorySegment.cs @@ -5,11 +5,13 @@ namespace HotChocolate.Buffers; /// -/// A segment of memory that is owned by a . +/// A segment of memory that is either owned by a +/// or refers to memory whose lifetime is managed elsewhere. /// public readonly struct ReadOnlyMemorySegment { - private readonly IMemoryOwner _owner; + private readonly IMemoryOwner? _owner; + private readonly ReadOnlyMemory _memory; private readonly int _start; private readonly int _length; @@ -47,7 +49,9 @@ public ReadOnlyMemorySegment(IMemoryOwner owner, int start, int length) throw new ArgumentOutOfRangeException(nameof(length)); } #endif - + // we have start and length here so that we can lazily slice the memory. + // this allows us in combination with the Utf8MemoryBuilder to create + // a memory segment before the memory is actually written to. _owner = owner; _start = start; _length = length; @@ -56,55 +60,19 @@ public ReadOnlyMemorySegment(IMemoryOwner owner, int start, int length) /// /// Initializes a new instance of . /// - /// - /// The buffer to create the memory segment from. - /// - public ReadOnlyMemorySegment(byte[] buffer) - : this(buffer, 0, buffer.Length) - { - } - - /// - /// Initializes a new instance of . - /// - /// - /// The buffer to create the memory segment from. + /// + /// The memory the segment refers to. /// - /// - /// The start index of the memory segment. - /// - /// - /// The length of the memory segment. - /// - public ReadOnlyMemorySegment(byte[] buffer, int start, int length) + public ReadOnlyMemorySegment(ReadOnlyMemory memory) { -#if NET8_0_OR_GREATER - ArgumentNullException.ThrowIfNull(buffer); - ArgumentOutOfRangeException.ThrowIfLessThan(start, 0); - ArgumentOutOfRangeException.ThrowIfLessThan(length, 0); -#else - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - if (start < 0) - { - throw new ArgumentOutOfRangeException(nameof(start)); - } - if (length < 0) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } -#endif - _owner = new ArrayMemoryOwner(buffer, start, length); - _start = start; - _length = length; + _memory = memory; + _length = memory.Length; } /// - /// Gets a value indicating whether the memory segment is empty. + /// Gets a value indicating whether the segment has no backing memory. /// - public bool IsEmpty => _owner is null; + public bool IsEmpty => _owner is null && _memory.Equals(default); /// /// Gets the length of the memory segment. @@ -120,7 +88,7 @@ public ReadOnlyMemory Memory { return _owner is not null ? _owner.Memory.Slice(_start, _length) - : Array.Empty(); + : _memory; } } @@ -133,7 +101,7 @@ public ReadOnlySpan Span { return _owner is not null ? _owner.Memory.Span.Slice(_start, _length) - : []; + : _memory.Span; } } } diff --git a/src/HotChocolate/Utilities/test/Utilities.Tests/ChunkedArrayWriterTests.cs b/src/HotChocolate/Utilities/test/Utilities.Tests/ChunkedArrayWriterTests.cs index 02a07457cd2..8008eca6c3e 100644 --- a/src/HotChocolate/Utilities/test/Utilities.Tests/ChunkedArrayWriterTests.cs +++ b/src/HotChocolate/Utilities/test/Utilities.Tests/ChunkedArrayWriterTests.cs @@ -4,6 +4,99 @@ namespace HotChocolate.Utilities; public class ChunkedArrayWriterTests { + [Theory] + [InlineData(JsonMemory.BufferSize - 20, 40)] + [InlineData(JsonMemory.BufferSize, 40)] + [InlineData(JsonMemory.BufferSize - 20, JsonMemory.BufferSize + 40)] + public void WriteAt_Should_OverwriteAdvancedBytes_When_RangeCrossesChunks( + int location, + int patchLength) + { + // Arrange + using var writer = new ChunkedArrayWriter(); + var length = location + patchLength + 17; + var expected = new byte[length]; + WritePattern(expected, seed: 11); + expected.CopyTo(writer.GetSpan(length)); + writer.Advance(length); + + var patch = new byte[patchLength]; + WritePattern(patch, seed: 41); + patch.CopyTo(expected.AsSpan(location)); + var position = writer.Position; + + // Act + writer.WriteAt(location, patch); + var actual = new byte[length]; + writer.CopyTo(actual, 0, actual.Length); + + // Assert + Assert.Equal(position, writer.Position); + Assert.Equal(expected, actual); + } + + [Fact] + public void WriteAt_Should_AllowEmptyPatch_When_LocationEqualsLength() + { + // Arrange + using var writer = new ChunkedArrayWriter(); + writer.Advance(7); + + // Act + writer.WriteAt(writer.Length, ReadOnlySpan.Empty); + + // Assert + Assert.Equal(7, writer.Position); + } + + [Fact] + public void WriteAt_Should_RejectRange_When_RangeWasNotAdvanced() + { + // Arrange + using var writer = new ChunkedArrayWriter(); + writer.Advance(8); + + // Act + var negative = Record.Exception(() => writer.WriteAt(-1, [1])); + var pastEnd = Record.Exception(() => writer.WriteAt(9, [])); + var overlapsEnd = Record.Exception(() => writer.WriteAt(7, [1, 2])); + + // Assert + Assert.IsType(negative); + Assert.IsType(pastEnd); + Assert.IsType(overlapsEnd); + } + + [Fact] + public void WriteAt_Should_UseCurrentAdvancedRange_When_WriterWasReset() + { + // Arrange + using var writer = new ChunkedArrayWriter(); + writer.Advance(16); + writer.Reset(); + + // Act + var exception = Record.Exception(() => writer.WriteAt(0, [1])); + + // Assert + Assert.IsType(exception); + } + + [Fact] + public void WriteAt_Should_RejectPatch_When_WriterIsDisposed() + { + // Arrange + var writer = new ChunkedArrayWriter(); + writer.Advance(1); + writer.Dispose(); + + // Act + var exception = Record.Exception(() => writer.WriteAt(0, [1])); + + // Assert + Assert.IsType(exception); + } + [Fact] public void GetSpan_Should_RoundTripScratchBytes_When_RequestSpansChunksAndScratchGrows() { diff --git a/src/HotChocolate/Utilities/test/Utilities.Tests/ReadOnlyMemorySegmentTests.cs b/src/HotChocolate/Utilities/test/Utilities.Tests/ReadOnlyMemorySegmentTests.cs new file mode 100644 index 00000000000..5174767b500 --- /dev/null +++ b/src/HotChocolate/Utilities/test/Utilities.Tests/ReadOnlyMemorySegmentTests.cs @@ -0,0 +1,82 @@ +namespace HotChocolate.Buffers; + +public class ReadOnlyMemorySegmentTests +{ + [Fact] + public void Span_Should_ReturnCarvedBytes_When_StartIsNonZero() + { + // arrange + var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + + // act + var segment = new ReadOnlyMemorySegment(buffer.AsMemory(3, 4)); + + // assert + Assert.Equal(4, segment.Length); + Assert.Equal([4, 5, 6, 7], segment.Span.ToArray()); + Assert.Equal([4, 5, 6, 7], segment.Memory.ToArray()); + } + + [Fact] + public void Span_Should_ReturnCarvedBytes_When_SegmentEndsAtBufferEnd() + { + // arrange + var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + + // act + var segment = new ReadOnlyMemorySegment(buffer.AsMemory(5, 3)); + + // assert + Assert.Equal(3, segment.Length); + Assert.Equal([6, 7, 8], segment.Span.ToArray()); + Assert.Equal([6, 7, 8], segment.Memory.ToArray()); + } + + [Fact] + public void Span_Should_ReturnSameBytesAsMemoryCtor_When_ConstructedFromMemoryOwner() + { + // arrange + var buffer = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + var owner = new ArrayMemoryOwner(buffer); + + // act + var fromOwner = new ReadOnlyMemorySegment(owner, 3, 4); + var fromMemory = new ReadOnlyMemorySegment(buffer.AsMemory(3, 4)); + + // assert + Assert.Equal(fromMemory.Length, fromOwner.Length); + Assert.Equal(fromMemory.Span.ToArray(), fromOwner.Span.ToArray()); + Assert.Equal(fromMemory.Memory.ToArray(), fromOwner.Memory.ToArray()); + } + + [Fact] + public void IsEmpty_Should_BeTrue_When_SegmentIsDefault() + { + // arrange + ReadOnlyMemorySegment segment = default; + + // act + var isEmpty = segment.IsEmpty; + + // assert + Assert.True(isEmpty); + Assert.Equal(0, segment.Length); + Assert.Empty(segment.Span.ToArray()); + Assert.True(segment.Memory.IsEmpty); + } + + [Fact] + public void IsEmpty_Should_BeFalse_When_SegmentCarvesZeroBytesFromBuffer() + { + // arrange + var buffer = new byte[] { 1, 2, 3, 4 }; + + // act + var segment = new ReadOnlyMemorySegment(buffer.AsMemory(2, 0)); + + // assert + Assert.False(segment.IsEmpty); + Assert.Equal(0, segment.Length); + Assert.Empty(segment.Span.ToArray()); + } +}