From 2fc66dc530c407dad94a005d2dc50bbd4e6484a6 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 19 Nov 2025 23:09:56 +0100 Subject: [PATCH 01/42] Cleanup constants and helpers --- .../Text/Json/JsonConstants.cs | 81 ------------------- .../Fusion.Execution/Text/Json/JsonHelpers.cs | 22 ----- .../src/Json/HotChocolate.Text.Json.csproj | 4 - 3 files changed, 107 deletions(-) diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs index 7fd0b4379d4..71dafe31735 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs @@ -13,48 +13,22 @@ internal static class JsonConstants public const byte LineFeed = (byte)'\n'; public const byte Tab = (byte)'\t'; public const byte Comma = (byte)','; - public const byte KeyValueSeparator = (byte)':'; public const byte Quote = (byte)'"'; public const byte BackSlash = (byte)'\\'; public const byte Slash = (byte)'/'; public const byte BackSpace = (byte)'\b'; public const byte FormFeed = (byte)'\f'; - public const byte Asterisk = (byte)'*'; public const byte Colon = (byte)':'; - public const byte Period = (byte)'.'; - public const byte Plus = (byte)'+'; - public const byte Hyphen = (byte)'-'; - public const byte UtcOffsetToken = (byte)'Z'; - public const byte TimePrefix = (byte)'T'; - public const byte NewLineLineFeed = (byte)'\n'; - // \u2028 and \u2029 are considered respectively line and paragraph separators - // UTF-8 representation for them is E2, 80, A8/A9 - public const byte StartingByteOfNonStandardSeparator = 0xE2; - public static ReadOnlySpan Data => "data"u8; public static ReadOnlySpan Errors => "errors"u8; public static ReadOnlySpan Extensions => "extensions"u8; - public static ReadOnlySpan Utf8Bom => [0xEF, 0xBB, 0xBF]; public static ReadOnlySpan TrueValue => "true"u8; public static ReadOnlySpan FalseValue => "false"u8; public static ReadOnlySpan NullValue => "null"u8; - public static ReadOnlySpan NaNValue => "NaN"u8; - public static ReadOnlySpan PositiveInfinityValue => "Infinity"u8; - public static ReadOnlySpan NegativeInfinityValue => "-Infinity"u8; - public const int MaximumFloatingPointConstantLength = 9; - - // Used to search for the end of a number - public static ReadOnlySpan Delimiters => ",}] \n\r\t/"u8; - - // Explicitly skipping ReverseSolidus since that is handled separately - public static ReadOnlySpan EscapableChars => "\"nrt/ubf"u8; - - public const int RemoveFlagsBitMask = 0x7FFFFFFF; - // In the worst case, an ASCII character represented as a single utf-8 byte could expand 6x when escaped. // For example: '+' becomes '\u0043' // Escaping surrogate pairs (represented by 3 or 4 utf-8 bytes) would expand to 12 bytes (which is still <= 6x). @@ -66,65 +40,10 @@ internal static class JsonConstants // All other UTF-16 characters can be represented by either 1 or 2 UTF-8 bytes. public const int MaxExpansionFactorWhileTranscoding = 3; - // When transcoding from UTF8 -> UTF16, the byte count threshold where we rent from the array pool before performing a normal alloc. - public const long ArrayPoolMaxSizeBeforeUsingNormalAlloc = -#if NET - 1024 * 1024 * 1024; // ArrayPool limit increased in .NET 6 -#else - 1024 * 1024; -#endif - - // The maximum number of characters allowed when writing raw UTF-16 JSON. This is the maximum length that we can guarantee can - // be safely transcoded to UTF-8 and fit within an integer-length span, given the max expansion factor of a single character (3). - public const int MaxUtf16RawValueLength = int.MaxValue / MaxExpansionFactorWhileTranscoding; - - public const int MaxEscapedTokenSize = 1_000_000_000; // Max size for already escaped value. - public const int MaxUnescapedTokenSize = MaxEscapedTokenSize / MaxExpansionFactorWhileEscaping; // 166_666_666 bytes - public const int MaxCharacterTokenSize = MaxEscapedTokenSize / MaxExpansionFactorWhileEscaping; // 166_666_666 characters - - public const int MaximumFormatBooleanLength = 5; - public const int MaximumFormatInt64Length = 20; // 19 + sign (i.e. -9223372036854775808) - public const int MaximumFormatUInt32Length = 10; // i.e. 4294967295 - public const int MaximumFormatUInt64Length = 20; // i.e. 18446744073709551615 - public const int MaximumFormatDoubleLength = 128; // default (i.e. 'G'), using 128 (rather than say 32) to be future-proof. - public const int MaximumFormatSingleLength = 128; // default (i.e. 'G'), using 128 (rather than say 32) to be future-proof. - public const int MaximumFormatDecimalLength = 31; // default (i.e. 'G') - public const int MaximumFormatGuidLength = 36; // default (i.e. 'D'), 8 + 4 + 4 + 4 + 12 + 4 for the hyphens (e.g. 094ffa0a-0442-494d-b452-04003fa755cc) - public const int MaximumEscapedGuidLength = MaxExpansionFactorWhileEscaping * MaximumFormatGuidLength; - public const int MaximumFormatDateTimeLength = 27; // StandardFormat 'O', e.g. 2017-06-12T05:30:45.7680000 - public const int MaximumFormatDateTimeOffsetLength = 33; // StandardFormat 'O', e.g. 2017-06-12T05:30:45.7680000-07:00 - public const int MaxDateTimeUtcOffsetHours = 14; // The UTC offset portion of a TimeSpan or DateTime can be no more than 14 hours and no less than -14 hours. - public const int DateTimeNumFractionDigits = 7; // TimeSpan and DateTime formats allow exactly up to many digits for specifying the fraction after the seconds. - public const int MaxDateTimeFraction = 9_999_999; // The largest fraction expressible by TimeSpan and DateTime formats - public const int DateTimeParseNumFractionDigits = 16; // The maximum number of fraction digits the Json DateTime parser allows - public const int MaximumDateTimeOffsetParseLength = MaximumFormatDateTimeOffsetLength - + (DateTimeParseNumFractionDigits - DateTimeNumFractionDigits); // Like StandardFormat 'O' for DateTimeOffset, but allowing 9 additional (up to 16) fraction digits. - public const int MinimumDateTimeParseLength = 10; // YYYY-MM-DD - public const int MaximumEscapedDateTimeOffsetParseLength = MaxExpansionFactorWhileEscaping * MaximumDateTimeOffsetParseLength; - - public const int MaximumLiteralLength = 5; // Must be able to fit null, true, & false. - - // Encoding Helpers - public const char HighSurrogateStart = '\ud800'; - public const char HighSurrogateEnd = '\udbff'; - public const char LowSurrogateStart = '\udc00'; - public const char LowSurrogateEnd = '\udfff'; - public const int UnicodePlane01StartValue = 0x10000; public const int HighSurrogateStartValue = 0xD800; public const int HighSurrogateEndValue = 0xDBFF; public const int LowSurrogateStartValue = 0xDC00; public const int LowSurrogateEndValue = 0xDFFF; public const int BitShiftBy10 = 0x400; - - // The maximum number of parameters a constructor can have where it can be considered - // for a path on deserialization where we don't box the constructor arguments. - public const int UnboxedParameterCountThreshold = 4; - - // Two space characters is the default indentation. - public const char DefaultIndentCharacter = ' '; - public const char TabIndentCharacter = '\t'; - public const int DefaultIndentSize = 2; - public const int MinimumIndentSize = 0; - public const int MaximumIndentSize = 127; // If this value is changed, the impact on the options masking used in the JsonWriterOptions struct must be checked carefully. } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs index 6de1d7c5347..f8d9b5a8b12 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs @@ -4,13 +4,6 @@ namespace HotChocolate.Fusion.Text.Json; internal static class JsonHelpers { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsValidDateTimeOffsetParseLength(int length) - => IsInRangeInclusive( - length, - JsonConstants.MinimumDateTimeParseLength, - JsonConstants.MaximumEscapedDateTimeOffsetParseLength); - /// /// Returns if is between /// and , inclusive. @@ -18,19 +11,4 @@ public static bool IsValidDateTimeOffsetParseLength(int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsInRangeInclusive(uint value, uint lowerBound, uint upperBound) => (value - lowerBound) <= (upperBound - lowerBound); - - /// - /// Returns if is between - /// and , inclusive. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsInRangeInclusive(int value, int lowerBound, int upperBound) - => (uint)(value - lowerBound) <= (uint)(upperBound - lowerBound); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsValidUnescapedDateTimeOffsetParseLength(int length) - => IsInRangeInclusive( - length, - JsonConstants.MinimumDateTimeParseLength, - JsonConstants.MaximumDateTimeOffsetParseLength); } diff --git a/src/HotChocolate/Json/src/Json/HotChocolate.Text.Json.csproj b/src/HotChocolate/Json/src/Json/HotChocolate.Text.Json.csproj index c66c31fec8c..3366abcbd96 100644 --- a/src/HotChocolate/Json/src/Json/HotChocolate.Text.Json.csproj +++ b/src/HotChocolate/Json/src/Json/HotChocolate.Text.Json.csproj @@ -6,8 +6,4 @@ preview - - - - From e133a9b8436dadf123e94858cf8d1c285a25f750 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 20 Nov 2025 08:54:55 +0100 Subject: [PATCH 02/42] Copied metadb to the core --- .../Core/src/Types/HotChocolate.Types.csproj | 38 +++++ .../src/Types/Text/Json/ElementTokenType.cs | 21 +++ .../Types/Text/Json/ResultDocument.DbRow.cs | 157 ++++++++++++++++++ .../Json/CompositeResultDocument.DbRow.cs | 52 ++++-- .../Text/Json/JsonConstants.cs | 4 + .../Fusion.Execution/Text/Json/JsonHelpers.cs | 4 + 6 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ElementTokenType.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index c97a2503d2a..efa4a1d2e5a 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -67,6 +67,40 @@ + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonHelpers.cs + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonConstants.cs + + + + Text\Json\JsonConstants.cs + + @@ -152,4 +186,8 @@ + + + + diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ElementTokenType.cs b/src/HotChocolate/Core/src/Types/Text/Json/ElementTokenType.cs new file mode 100644 index 00000000000..095f8521b55 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ElementTokenType.cs @@ -0,0 +1,21 @@ +namespace HotChocolate.Text.Json; + +internal enum ElementTokenType : byte +{ + None = 0, + StartObject = 1, + EndObject = 2, + StartArray = 3, + EndArray = 4, + PropertyName = 5, + // Retained for compatibility, we do not actually need this. + Comment = 6, + String = 7, + Number = 8, + True = 9, + False = 10, + Null = 11, + // A reference in case a property or array element point + // to an array or an object + Reference = 12 +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs new file mode 100644 index 00000000000..701c7734e40 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs @@ -0,0 +1,157 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + [StructLayout(LayoutKind.Sequential)] + internal readonly struct DbRow + { + public const int Size = 20; + public const int UnknownSize = -1; + + // 27 bits for location + 2 bits OpRefType + 3 reserved bits + private readonly int _locationAndOpRefType; + + // Sign bit for HasComplexChildren + 31 bits for size/length + private readonly int _sizeOrLengthUnion; + + // 4 bits TokenType + 27 bits NumberOfRows + 1 reserved bit + private readonly int _numberOfRowsTypeAndReserved; + + // 15 bits SourceDocumentId + 17 bits (high 17 bits of ParentRow) + private readonly int _sourceAndParentHigh; + + // 15 bits OperationReferenceId + 6 bits Flags + 11 bits (low bits of ParentRow) + private readonly int _selectionSetFlagsAndParentLow; + + public DbRow( + ElementTokenType tokenType, + int location, + int sizeOrLength = 0, + int sourceDocumentId = 0, + int parentRow = 0, + int operationReferenceId = 0, + OperationReferenceType operationReferenceType = OperationReferenceType.None, + int numberOfRows = 0, + ElementFlags flags = ElementFlags.None) + { + Debug.Assert((byte)tokenType < 16); + Debug.Assert(location is >= 0 and <= 0x07FFFFFF); // 27 bits + Debug.Assert(sizeOrLength >= UnknownSize); + Debug.Assert(sourceDocumentId is >= 0 and <= 0x7FFF); // 15 bits + Debug.Assert(parentRow is >= 0 and <= 0x0FFFFFFF); // 28 bits + Debug.Assert(operationReferenceId is >= 0 and <= 0x7FFF); // 15 bits + Debug.Assert(numberOfRows is >= 0 and <= 0x07FFFFFF); // 27 bits + Debug.Assert((byte)flags <= 63); // 6 bits (0x3F) + Debug.Assert((byte)operationReferenceType <= 3); // 2 bits + Debug.Assert(Unsafe.SizeOf() == Size); + + _locationAndOpRefType = location | ((int)operationReferenceType << 27); + _sizeOrLengthUnion = sizeOrLength; + _numberOfRowsTypeAndReserved = ((int)tokenType << 28) | (numberOfRows & 0x07FFFFFF); + _sourceAndParentHigh = sourceDocumentId | ((parentRow >> 11) << 15); + _selectionSetFlagsAndParentLow = operationReferenceId | ((int)flags << 15) | ((parentRow & 0x7FF) << 21); + } + + /// + /// Element token type (includes Reference for composition). + /// + /// + /// 4 bits = possible values + /// + public ElementTokenType TokenType => (ElementTokenType)(unchecked((uint)_numberOfRowsTypeAndReserved) >> 28); + + /// + /// Operation reference type indicating the type of GraphQL operation element. + /// + /// + /// 2 bits = 4 possible values + /// + public OperationReferenceType OperationReferenceType + => (OperationReferenceType)((_locationAndOpRefType >> 27) & 0x03); + + /// + /// Byte offset in source data OR metaDb row index for references. + /// + /// + /// 2 bits = 4 possible values + /// + public int Location => _locationAndOpRefType & 0x07FFFFFF; + + /// + /// Length of data in JSON payload, number of elements if array or number of properties in an object. + /// + /// + /// 27 bits = 134M limit + /// + public int SizeOrLength => _sizeOrLengthUnion & int.MaxValue; + + /// + /// String/PropertyName: Unescaping required. + /// + public bool HasComplexChildren => _sizeOrLengthUnion < 0; + + /// + /// Specifies if a size for the item has ben set. + /// + public bool IsUnknownSize => _sizeOrLengthUnion == UnknownSize; + + /// + /// Number of metadb rows this element spans. + /// + /// + /// 27 bits = 134M rows + /// + public int NumberOfRows => _numberOfRowsTypeAndReserved & 0x07FFFFFF; + + /// + /// Index of parent element in metadb for navigation and null propagation. + /// + /// + /// 28 bits = 268M rows + /// + public int ParentRow + => ((int)((uint)_sourceAndParentHigh >> 15) << 11) | ((_selectionSetFlagsAndParentLow >> 21) & 0x7FF); + + /// + /// Reference to GraphQL selection set or selection metadata. + /// 15 bits = 32K selections + /// + public int OperationReferenceId => _selectionSetFlagsAndParentLow & 0x7FFF; + + /// + /// Element metadata flags. + /// + /// + /// 6 bits = 64 combinations + /// + public ElementFlags Flags => (ElementFlags)((_selectionSetFlagsAndParentLow >> 15) & 0x3F); + + /// + /// True for primitive JSON values (strings, numbers, booleans, null). + /// + public bool IsSimpleValue => TokenType is >= ElementTokenType.PropertyName and <= ElementTokenType.Null; + } + + internal enum OperationReferenceType : byte + { + None = 0, + SelectionSet = 1, + Selection = 2 + } + + [Flags] + internal enum ElementFlags : byte + { + None = 0, + Invalidated = 1, + SourceResult = 2, + IsNullable = 4, + IsRoot = 8, + IsInternal = 16, + IsExcluded = 32 + } +} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs index 08fdf7eeff7..42785ef9614 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs @@ -57,67 +57,87 @@ public DbRow( } /// - /// Byte offset in source data OR metaDb row index for references. - /// 27 bits = 134M limit (increased from 26 bits / 67M limit) + /// Element token type (includes Reference for composition). /// - public int Location => _locationAndOpRefType & 0x07FFFFFF; + /// + /// 4 bits = possible values + /// + public ElementTokenType TokenType => (ElementTokenType)(unchecked((uint)_numberOfRowsTypeAndReserved) >> 28); /// /// Operation reference type indicating the type of GraphQL operation element. - /// 2 bits = 4 possible values /// + /// + /// 2 bits = 4 possible values + /// public OperationReferenceType OperationReferenceType => (OperationReferenceType)((_locationAndOpRefType >> 27) & 0x03); + /// + /// Byte offset in source data OR metaDb row index for references + /// + /// + /// 27 bits = 134M limit + /// + public int Location => _locationAndOpRefType & 0x07FFFFFF; + /// /// Length of data in JSON payload, number of elements if array or number of properties in an object. - /// 31 bits = 2GB limit /// + /// + /// 31 bits = 2GB limit + /// public int SizeOrLength => _sizeOrLengthUnion & int.MaxValue; /// /// String/PropertyName: Unescaping required. - /// Array: Contains complex children. /// public bool HasComplexChildren => _sizeOrLengthUnion < 0; - public bool IsUnknownSize => _sizeOrLengthUnion == UnknownSize; - /// - /// Element token type (includes Reference for composition). - /// 4 bits = 16 types + /// Specifies if a size for the item has ben set. /// - public ElementTokenType TokenType => (ElementTokenType)(unchecked((uint)_numberOfRowsTypeAndReserved) >> 28); + public bool IsUnknownSize => _sizeOrLengthUnion == UnknownSize; /// /// Number of metadb rows this element spans. - /// 27 bits = 134M rows /// + /// + /// 27 bits = 134M rows + /// public int NumberOfRows => _numberOfRowsTypeAndReserved & 0x07FFFFFF; /// /// Which source JSON document contains the data. - /// 15 bits = 32K documents /// + /// + /// 15 bits = 32K documents + /// public int SourceDocumentId => _sourceAndParentHigh & 0x7FFF; /// /// Index of parent element in metadb for navigation and null propagation. - /// 28 bits = 268M rows (reconstructed from high+low bits) /// + /// + /// 28 bits = 268M rows + /// public int ParentRow => ((int)((uint)_sourceAndParentHigh >> 15) << 11) | ((_selectionSetFlagsAndParentLow >> 21) & 0x7FF); /// /// Reference to GraphQL selection set or selection metadata. - /// 15 bits = 32K selections /// + /// + /// 15 bits = 32K selections + /// public int OperationReferenceId => _selectionSetFlagsAndParentLow & 0x7FFF; /// /// Element metadata flags. - /// 6 bits = 64 combinations /// + /// + /// 6 bits = 64 combinations + /// public ElementFlags Flags => (ElementFlags)((_selectionSetFlagsAndParentLow >> 15) & 0x3F); /// diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs index 71dafe31735..108aa42d801 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs @@ -1,4 +1,8 @@ +#if Fusion namespace HotChocolate.Fusion.Text.Json; +#else +namespace HotChocolate.Text.Json; +#endif internal static class JsonConstants { diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs index f8d9b5a8b12..e824b996bab 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs @@ -1,6 +1,10 @@ using System.Runtime.CompilerServices; +#if Fusion namespace HotChocolate.Fusion.Text.Json; +#else +namespace HotChocolate.Text.Json; +#endif internal static class JsonHelpers { From baac8d853206507d02d9985e9e3b2e1288ee60e2 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 20 Nov 2025 09:17:13 +0100 Subject: [PATCH 03/42] Added metabd --- .../Core/src/Types/HotChocolate.Types.csproj | 6 +- .../Json/CompositeResultDocument.MetaDb.cs | 383 ++++++++++++++++++ .../Types/Text/Json/ResultDocument.Cursor.cs | 171 ++++++++ .../Text/Json/JsonConstants.cs | 2 +- .../Fusion.Execution/Text/Json/JsonHelpers.cs | 2 +- .../Text/Json/MetaDbEventSource.cs | 6 + 6 files changed, 565 insertions(+), 5 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Cursor.cs diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index efa4a1d2e5a..ebf81309726 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -67,7 +67,7 @@ - + Text\Json\JsonConstants.cs @@ -77,8 +77,8 @@ Text\Json\JsonHelpers.cs - - Text\Json\JsonConstants.cs + + Text\Json\MetaDbEventSource.cs diff --git a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs b/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs new file mode 100644 index 00000000000..5f6561ac0ec --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs @@ -0,0 +1,383 @@ +using System.Buffers; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using static HotChocolate.Text.Json.MetaDbEventSource; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + internal struct MetaDb : IDisposable + { + private const int TokenTypeOffset = 8; + private static readonly ArrayPool s_arrayPool = ArrayPool.Shared; + + private byte[][] _chunks; + private Cursor _next; + private bool _disposed; + + internal static MetaDb CreateForEstimatedRows(int estimatedRows) + { + var chunksNeeded = Math.Max(4, (estimatedRows / Cursor.RowsPerChunk) + 1); + var chunks = s_arrayPool.Rent(chunksNeeded); + var log = Log; + + log.MetaDbCreated(2, estimatedRows, 1); + + // Rent the first chunk now to avoid branching on first append + chunks[0] = MetaDbMemory.Rent(); + log.ChunkAllocated(2, 0); + + for (var i = 1; i < chunks.Length; i++) + { + chunks[i] = []; + } + + return new MetaDb + { + _chunks = chunks, + _next = Cursor.Zero + }; + } + + public Cursor NextCursor => _next; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Cursor Append( + ElementTokenType tokenType, + int location = 0, + int sizeOrLength = 0, + int sourceDocumentId = 0, + int parentRow = 0, + int operationReferenceId = 0, + OperationReferenceType operationReferenceType = OperationReferenceType.None, + int numberOfRows = 0, + ElementFlags flags = ElementFlags.None) + { + var log = Log; + var next = _next; + var chunkIndex = next.Chunk; + var byteOffset = next.ByteOffset; + + var chunks = _chunks.AsSpan(); + var chunksLength = chunks.Length; + + if (byteOffset + DbRow.Size > Cursor.ChunkBytes) + { + chunkIndex++; + byteOffset = 0; + next = Cursor.FromByteOffset(chunkIndex, byteOffset); + } + + // make sure we have enough space for the chunk referenced by the chunkIndex. + if (chunkIndex >= chunksLength) + { + // if we do not have enough space we will double the size we have for + // chunks of memory. + var nextChunksLength = chunksLength * 2; + var newChunks = s_arrayPool.Rent(nextChunksLength); + log.ChunksExpanded(2, chunksLength, nextChunksLength); + + // copy chunks to new buffer + Array.Copy(_chunks, newChunks, chunksLength); + + for (var i = chunksLength; i < nextChunksLength; i++) + { + newChunks[i] = []; + } + + // clear and return old chunks buffer + chunks.Clear(); + s_arrayPool.Return(_chunks); + + // assign new chunks buffer + _chunks = newChunks; + chunks = newChunks.AsSpan(); + } + + var chunk = chunks[chunkIndex]; + + // if the chunk is empty we did not yet rent any memory for it + if (chunk.Length == 0) + { + chunk = chunks[chunkIndex] = MetaDbMemory.Rent(); + log.ChunkAllocated(2, chunkIndex); + } + + var row = new DbRow( + tokenType, + location, + sizeOrLength, + sourceDocumentId, + parentRow, + operationReferenceId, + operationReferenceType, + numberOfRows, + flags); + + ref var dest = ref MemoryMarshal.GetArrayDataReference(chunk); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref dest, byteOffset), row); + + // Advance write head by one row + _next = next + 1; + return next; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Replace( + Cursor cursor, + ElementTokenType tokenType, + int location = 0, + int sizeOrLength = 0, + int sourceDocumentId = 0, + int parentRow = 0, + int operationReferenceId = 0, + OperationReferenceType operationReferenceType = OperationReferenceType.None, + int numberOfRows = 0, + ElementFlags flags = ElementFlags.None) + { + AssertValidCursor(cursor); + + var row = new DbRow( + tokenType, + location, + sizeOrLength, + sourceDocumentId, + parentRow, + operationReferenceId, + operationReferenceType, + numberOfRows, + flags); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + MemoryMarshal.Write(span, in row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal DbRow Get(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + return MemoryMarshal.Read(span); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal (Cursor, ElementTokenType) GetStartCursor(Cursor cursor) + { + AssertValidCursor(cursor); + + var chunks = _chunks.AsSpan(); + var span = chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + var union = MemoryMarshal.Read(span[TokenTypeOffset..]); + var tokenType = (ElementTokenType)(union >> 28); + + if (tokenType is ElementTokenType.Reference) + { + var index = MemoryMarshal.Read(span) & 0x07FFFFFF; + cursor = Cursor.FromIndex(index); + span = chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset); + union = MemoryMarshal.Read(span); + tokenType = (ElementTokenType)(union >> 28); + } + + return (cursor, tokenType); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int GetLocation(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + var locationAndOpRefType = MemoryMarshal.Read(span); + return locationAndOpRefType & 0x07FFFFFF; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Cursor GetLocationCursor(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + var locationAndOpRefType = MemoryMarshal.Read(span); + return Cursor.FromIndex(locationAndOpRefType & 0x07FFFFFF); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int GetParent(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + var sourceAndParentHigh = MemoryMarshal.Read(span[12..]); + var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span[16..]); + + return (sourceAndParentHigh >>> 15 << 11) + | ((selectionSetFlagsAndParentLow >> 21) & 0x7FF); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Cursor GetParentCursor(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); + + var sourceAndParentHigh = MemoryMarshal.Read(span[12..]); + var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span[16..]); + + var index = (sourceAndParentHigh >>> 15 << 11) + | ((selectionSetFlagsAndParentLow >> 21) & 0x7FF); + + return Cursor.FromIndex(index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int GetNumberOfRows(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset); + + var value = MemoryMarshal.Read(span); + return value & 0x0FFFFFFF; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ElementFlags GetFlags(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 16); + + var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span); + return (ElementFlags)((selectionSetFlagsAndParentLow >> 15) & 0x3F); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetFlags(Cursor cursor, ElementFlags flags) + { + AssertValidCursor(cursor); + Debug.Assert((byte)flags <= 63, "Flags value exceeds 6-bit limit"); + + var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 16); + var currentValue = MemoryMarshal.Read(fieldSpan); + + var clearedValue = currentValue & 0xFFE07FFF; // ~(0x3F << 15) + var newValue = (int)(clearedValue | (uint)((int)flags << 15)); + + MemoryMarshal.Write(fieldSpan, newValue); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal int GetSizeOrLength(Cursor cursor) + { + AssertValidCursor(cursor); + + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); + var value = MemoryMarshal.Read(span); + + return value & int.MaxValue; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetSizeOrLength(Cursor cursor, int sizeOrLength) + { + AssertValidCursor(cursor); + Debug.Assert(sizeOrLength >= 0 && sizeOrLength <= int.MaxValue, "SizeOrLength value exceeds 31-bit limit"); + + var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); + var currentValue = MemoryMarshal.Read(fieldSpan); + + // Keep only the sign bit (HasComplexChildren) + var clearedValue = currentValue & unchecked((int)0x80000000); + var newValue = clearedValue | (sizeOrLength & int.MaxValue); + + MemoryMarshal.Write(fieldSpan, newValue); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void SetNumberOfRows(Cursor cursor, int numberOfRows) + { + AssertValidCursor(cursor); + Debug.Assert(numberOfRows >= 0 && numberOfRows <= 0x0FFFFFFF, "NumberOfRows value exceeds 28-bit limit"); + + var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset); + var currentValue = MemoryMarshal.Read(fieldSpan); + + // Keep only the top 4 bits (token type) + var clearedValue = currentValue & unchecked((int)0xF0000000); + var newValue = clearedValue | (numberOfRows & 0x0FFFFFFF); + + MemoryMarshal.Write(fieldSpan, newValue); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ElementTokenType GetElementTokenType(Cursor cursor, bool resolveReferences = true) + { + AssertValidCursor(cursor); + + var union = MemoryMarshal.Read(_chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset)); + var tokenType = (ElementTokenType)(union >> 28); + + if (resolveReferences && tokenType == ElementTokenType.Reference) + { + var idx = GetLocation(cursor); + var resolved = Cursor.FromIndex(idx); + union = MemoryMarshal.Read(_chunks[resolved.Chunk].AsSpan(resolved.ByteOffset + TokenTypeOffset)); + tokenType = (ElementTokenType)(union >> 28); + } + + return tokenType; + } + + [Conditional("DEBUG")] + private void AssertValidCursor(Cursor cursor) + { + Debug.Assert(cursor.Chunk >= 0, "Negative chunk"); + Debug.Assert(cursor.Chunk < _chunks.Length, "Chunk index out of bounds"); + Debug.Assert(_chunks[cursor.Chunk].Length > 0, "Accessing unallocated chunk"); + + var maxExclusive = _next.Chunk * Cursor.RowsPerChunk + _next.Row; + var absoluteIndex = (cursor.Chunk * Cursor.RowsPerChunk) + cursor.Row; + + Debug.Assert(absoluteIndex >= 0 && absoluteIndex < maxExclusive, + $"Cursor points to row {absoluteIndex}, but only {maxExclusive} rows are valid."); + Debug.Assert(cursor.ByteOffset + DbRow.Size <= MetaDbMemory.BufferSize, "Cursor byte offset out of bounds"); + } + + public void Dispose() + { + if (!_disposed) + { + var cursor = _next; + var chunksLength = cursor.Chunk + 1; + var chunks = _chunks.AsSpan(0, chunksLength); + Log.MetaDbDisposed(2, chunksLength, cursor.Row); + + foreach (var chunk in chunks) + { + if (chunk.Length == 0) + { + break; + } + + MetaDbMemory.Return(chunk); + } + + chunks.Clear(); + s_arrayPool.Return(_chunks); + + _chunks = []; + _disposed = true; + } + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Cursor.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Cursor.cs new file mode 100644 index 00000000000..4e8ee11677b --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Cursor.cs @@ -0,0 +1,171 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + /// + /// Comparable MetaDb cursor (chunk, row) + /// + [StructLayout(LayoutKind.Sequential, Size = 4)] + internal readonly struct Cursor : IEquatable, IComparable + { + public const int ChunkBytes = 1 << 17; + public const int RowsPerChunk = ChunkBytes / DbRow.Size; + public const int MaxChunks = 4096; + + private const int RowBits = 14; + private const int ChunkBits = 12; + private const int ChunkShift = RowBits; + + private const uint RowMask = (1u << RowBits) - 1u; + private const uint ChunkMask = (1u << ChunkBits) - 1u; + + private readonly uint _value; + + public static readonly Cursor Zero = From(0, 0); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Cursor(uint value) => _value = value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor From(int chunkIndex, int rowWithinChunk) + { + Debug.Assert((uint)chunkIndex < MaxChunks); + Debug.Assert((uint)rowWithinChunk < RowsPerChunk); + return new Cursor(((uint)chunkIndex << ChunkShift) | (uint)rowWithinChunk); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor FromIndex(int rowIndex) + { + Debug.Assert(rowIndex >= 0); + var chunk = rowIndex / RowsPerChunk; + var row = rowIndex - (chunk * RowsPerChunk); + return From(chunk, row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor FromByteOffset(int chunkIndex, int byteOffset) + { + Debug.Assert(byteOffset % DbRow.Size == 0, "byteOffset must be row-aligned."); + return From(chunkIndex, byteOffset / DbRow.Size); + } + + public uint Value => _value; + + public int Chunk + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (int)((_value >> ChunkShift) & ChunkMask); + } + + public int Row + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (int)(_value & RowMask); + } + + public int ByteOffset + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Row * DbRow.Size; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cursor AddRows(int delta) + { + if (delta == 0) + { + return this; + } + + var row = Row + delta; + var chunk = Chunk; + + if (row >= RowsPerChunk) + { + var carry = row / RowsPerChunk; + row -= carry * RowsPerChunk; + chunk += carry; + } + else if (row < 0) + { + var borrow = (-row + RowsPerChunk - 1) / RowsPerChunk; + row += borrow * RowsPerChunk; + chunk -= borrow; + } + + if (chunk < 0) + { + Debug.Fail("Cursor underflow"); + chunk = 0; + row = 0; + } + else if (chunk >= MaxChunks) + { + Debug.Fail("Cursor overflow"); + chunk = MaxChunks - 1; + row = RowsPerChunk - 1; + } + + return From(chunk, row); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cursor WithChunk(int chunk) => From(chunk, Row); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Cursor WithRow(int row) => From(Chunk, row); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ToIndex() => (Chunk * RowsPerChunk) + Row; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ToTotalBytes() => (Chunk * ChunkBytes) + ByteOffset; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(Cursor other) => _value == other._value; + + public override bool Equals(object? obj) => obj is Cursor c && Equals(c); + + public override int GetHashCode() => (int)_value; + + public override string ToString() => $"chunk={Chunk}, row={Row} (0x{_value:X8})"; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int CompareTo(Cursor other) => _value.CompareTo(other._value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(Cursor a, Cursor b) => a._value == b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(Cursor a, Cursor b) => a._value != b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <(Cursor a, Cursor b) => a._value < b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >(Cursor a, Cursor b) => a._value > b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator <=(Cursor a, Cursor b) => a._value <= b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator >=(Cursor a, Cursor b) => a._value >= b._value; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor operator +(Cursor x, int delta) => x.AddRows(delta); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor operator -(Cursor x, int delta) => x.AddRows(-delta); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor operator ++(Cursor x) => x.AddRows(1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Cursor operator --(Cursor x) => x.AddRows(-1); + } +} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs index 108aa42d801..9201cc9fc5d 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonConstants.cs @@ -1,4 +1,4 @@ -#if Fusion +#if FUSION namespace HotChocolate.Fusion.Text.Json; #else namespace HotChocolate.Text.Json; diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs index e824b996bab..4a281fc2966 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonHelpers.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -#if Fusion +#if FUSION namespace HotChocolate.Fusion.Text.Json; #else namespace HotChocolate.Text.Json; diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbEventSource.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbEventSource.cs index 8135fd7c4f7..9394f2d213d 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbEventSource.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbEventSource.cs @@ -1,8 +1,14 @@ using System.Diagnostics.Tracing; +#if FUSION namespace HotChocolate.Fusion.Text.Json; [EventSource(Name = "HotChocolate-Fusion-MetaDb")] +#else +namespace HotChocolate.Text.Json; + +[EventSource(Name = "HotChocolate-MetaDb")] +#endif internal sealed class MetaDbEventSource : EventSource { public static readonly MetaDbEventSource Log = new(); From 269436beda8f2b6bd2191fcdb743975ba409f7e1 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 26 Nov 2025 19:47:43 +0100 Subject: [PATCH 04/42] Merge Types Fetching and Execution --- src/All.slnx | 2 - .../CookieCrumble.HotChocolate.csproj | 1 - .../HotChocolate.Adapters.Mcp.csproj | 1 - .../src/Transport.Http/GraphQLHttpResponse.cs | 8 +- .../JsonLines/JsonLinesReader.cs | 3 +- .../src/Transport.Http/Sse/SseEventParser.cs | 2 +- .../src/Transport.Http/Sse/SseReader.cs | 7 +- .../src/Caching/HotChocolate.Caching.csproj | 1 - src/HotChocolate/Core/HotChocolate.Core.slnx | 2 - .../HotChocolate.Authorization.csproj | 2 +- .../Core/src/Core/HotChocolate.Core.csproj | 2 - .../HotChocolate.Execution.Projections.csproj | 2 +- .../Execution/HotChocolate.Execution.csproj | 247 -------- .../src/Fetching/HotChocolate.Fetching.csproj | 40 -- .../HotChocolate.Types.Errors.csproj | 2 +- .../Types.Json/HotChocolate.Types.Json.csproj | 1 - .../HotChocolate.Types.Mutations.csproj | 2 +- ...HotChocolate.Types.OffsetPagination.csproj | 1 - .../HotChocolate.Types.Queries.csproj | 2 +- .../Execution/Caching/DefaultDocumentCache.cs | 0 .../Caching/DefaultPreparedOperationCache.cs | 0 .../Caching/IPreparedOperationCache.cs | 0 .../Configuration/ConfigurationContext.cs | 0 .../ConfigureRequestExecutorSetup.cs | 0 .../DefaultRequestExecutorBuilder.cs | 0 .../IConfigureRequestExecutorSetup.cs | 0 .../Execution/Configuration/ITypeModule.cs | 0 ...OnConfigureRequestExecutorOptionsAction.cs | 0 .../OnConfigureSchemaBuilderAction.cs | 0 .../OnConfigureSchemaServices.cs | 0 .../OnRequestExecutorCreatedAction.cs | 0 .../OnRequestExecutorEvictedAction.cs | 0 .../Configuration/RequestExecutorSetup.cs | 0 .../RootServiceProviderAccessor.cs | 0 .../DefaultRequestContextAccessor.cs | 0 .../Execution/DefaultRequestExecutor.cs | 0 .../DeferredWorkStateOwnerFactory.cs | 0 .../DependencyInjection/Factories/IFactory.cs | 0 .../Factories/OperationContextFactory.cs | 0 .../Factories/OperationContextOwnerFactory.cs | 0 .../Factories/PooledServiceFactory.cs | 0 ...ternalSchemaServiceCollectionExtensions.cs | 0 .../InternalServiceCollectionExtensions.cs | 0 ...RequestExecutorBuilderExtensions.Caches.cs | 0 ...uestExecutorBuilderExtensions.Composite.cs | 0 ...estExecutorBuilderExtensions.DataLoader.cs | 0 ...stExecutorBuilderExtensions.ErrorFilter.cs | 0 ...equestExecutorBuilderExtensions.Hashing.cs | 0 ...tExecutorBuilderExtensions.IdSerializer.cs | 0 ...stExecutorBuilderExtensions.InputParser.cs | 0 ...ecutorBuilderExtensions.Instrumentation.cs | 0 ...uestExecutorBuilderExtensions.Optimizer.cs | 0 ...questExecutorBuilderExtensions.Services.cs | 0 ...cutorBuilderExtensions.TransactionScope.cs | 0 ...xecutorBuilderExtensions.TypeConversion.cs | 0 ...ExecutorBuilderExtensions.TypeDiscovery.cs | 0 ...estExecutorBuilderExtensions.UseRequest.cs | 0 ...estExecutorBuilderExtensions.Validation.cs | 0 .../RequestExecutorBuilderExtensions.cs | 0 ...uestExecutorServiceCollectionExtensions.cs | 0 ...equestExecutorServiceProviderExtensions.cs | 0 ...estExecutorBuilderExtensions.Convention.cs | 0 ...questExecutorBuilderExtensions.Document.cs | 0 ...estExecutorBuilderExtensions.Middleware.cs | 0 ...RequestExecutorBuilderExtensions.Paging.cs | 0 ...aRequestExecutorBuilderExtensions.Relay.cs | 0 ...uestExecutorBuilderExtensions.Resolvers.cs | 0 ...ecutorBuilderExtensions.TypeInterceptor.cs | 0 ...stExecutorBuilderExtensions.TypeModules.cs | 0 ...aRequestExecutorBuilderExtensions.Types.cs | 0 .../SchemaRequestExecutorBuilderExtensions.cs | 0 .../src/{ => Types}/Execution/ErrorHelper.cs | 0 .../Errors/FuncErrorFilterWrapper.cs | 0 ...xecutionObjectFieldDescriptorExtensions.cs | 0 .../ExecutionRequestExecutorExtensions.cs | 0 .../Extensions/ExecutionResultExtensions.cs | 0 .../Extensions/ExecutionSchemaExtensions.cs | 0 ...colateExecutionRequestContextExtensions.cs | 0 .../Extensions/OperationContextExtensions.cs | 0 .../Execution/IRequestContextAccessor.cs | 0 .../Execution/IRequestContextEnricher.cs | 0 .../AggregateExecutionDiagnosticEvents.cs | 0 .../ExecutionDiagnosticEventListener.cs | 0 .../IExecutionDiagnosticEventListener.cs | 0 .../IExecutionDiagnosticEvents.cs | 0 .../NoopExecutionDiagnosticEvents.cs | 0 .../Internal/ArgumentCoercionHelper.cs | 0 .../Internal/MiddlewareContextMarshal.cs | 0 .../Execution/Internal/SchemaFileExporter.cs | 0 .../{ => Types}/Execution/NeedsFormatting.cs | 0 .../Options/IErrorHandlerOptionsAccessor.cs | 0 .../IPersistedOperationOptionsAccessor.cs | 0 .../IRequestExecutorOptionsAccessor.cs | 0 .../Options/IRequestTimeoutOptionsAccessor.cs | 0 .../Options/NodeIdSerializerOptions.cs | 0 .../Options/RequestExecutorOptions.cs | 0 .../Execution/Options/RequestParserOptions.cs | 0 .../Execution/Options/ResultBufferOptions.cs | 0 .../Execution/Options/TracingPreference.cs | 0 .../Pipeline/OperationCacheMiddleware.cs | 0 .../Pipeline/OperationExecutionMiddleware.cs | 0 .../Execution/Pipeline/OperationInfo.cs | 0 .../Pipeline/OperationResolverMiddleware.cs | 0 .../OperationVariableCoercionMiddleware.cs | 0 .../Execution/Pipeline/PipelineTools.cs | 0 .../Execution/Pipeline/Pipelines.md | 0 .../Pipeline/RequestClassMiddlewareFactory.cs | 0 .../Execution/Pipeline/TimeoutMiddleware.cs | 0 .../Processing/ArgumentNonNullValidator.cs | 0 .../Processing/AsyncManualResetEvent.cs | 0 .../Execution/Processing/DefaultActivator.cs | 0 .../Processing/DefaultTransactionScope.cs | 0 .../DefaultTransactionScopeHandler.cs | 0 .../Processing/DeferredExecutionTask.cs | 0 .../Processing/DeferredExecutionTaskResult.cs | 0 .../Execution/Processing/DeferredFragment.cs | 0 .../Execution/Processing/DeferredStream.cs | 0 .../Processing/DeferredWorkScheduler.cs | 0 .../Execution/Processing/DeferredWorkState.cs | 0 .../Processing/DeferredWorkStateOwner.cs | 0 .../Processing/EmptySelectionCollection.cs | 0 .../Execution/Processing/Fragment.cs | 0 .../Processing/IOperationCompilerOptimizer.cs | 0 .../Processing/IOperationOptimizer.cs | 0 .../Processing/ISelectionSetOptimizer.cs | 0 .../Execution/Processing/ISubscription.cs | 0 .../Execution/Processing/ITaskStatistics.cs | 0 .../Execution/Processing/ITransactionScope.cs | 0 .../Processing/ITransactionScopeHandler.cs | 0 .../Execution/Processing/IncludeCondition.cs | 0 .../Processing/MiddlewareContext.Arguments.cs | 0 .../Processing/MiddlewareContext.Global.cs | 0 .../Processing/MiddlewareContext.Pooling.cs | 0 .../Processing/MiddlewareContext.Pure.cs | 0 .../Processing/MiddlewareContext.Selection.cs | 0 .../Processing/MiddlewareContext.State.cs | 0 .../Processing/NoOpTransactionScope.cs | 0 .../Processing/NoOpTransactionScopeHandler.cs | 0 .../Processing/NoopBatchDispatcher.cs | 0 .../Execution/Processing/Operation.cs | 0 .../OperationCompiler.ArgumentValues.cs | 0 .../OperationCompiler.BacklogItem.cs | 0 .../OperationCompiler.CompilerContext.cs | 0 .../OperationCompiler.Optimizers.cs | 0 .../OperationCompiler.SelectionSetInfo.cs | 0 .../Execution/Processing/OperationCompiler.cs | 0 .../Processing/OperationCompilerMetrics.cs | 0 .../OperationCompilerOptimizerHelper.cs | 0 .../Processing/OperationCompilerOptimizers.cs | 0 .../Processing/OperationCompilerPool.cs | 0 .../Processing/OperationContext.Execution.cs | 0 .../OperationContext.IExecutionTaskContext.cs | 0 .../Processing/OperationContext.Operation.cs | 0 .../Processing/OperationContext.Pooling.cs | 0 .../Processing/OperationContext.Services.cs | 0 .../Processing/OperationContext.Utilities.cs | 0 .../Execution/Processing/OperationContext.cs | 0 .../Processing/OperationContextOwner.cs | 0 .../Processing/OperationOptimizerContext.cs | 0 .../Execution/Processing/OperationPrinter.cs | 0 .../Processing/OperationResolverHelper.cs | 0 .../Execution/Processing/PathHelper.cs | 0 .../Execution/Processing/QueryExecutor.cs | 0 .../Execution/Processing/Result/ListResult.cs | 0 .../Processing/Result/ListResultPool.cs | 0 .../Processing/Result/ObjectFieldResult.cs | 0 .../Processing/Result/ObjectResult.cs | 0 .../Result/ObjectResultExtensions.cs | 0 .../Processing/Result/ObjectResultPool.cs | 0 .../Processing/Result/ResultBucket.cs | 0 .../Result/ResultBuilder.NonNullHandling.cs | 0 .../Result/ResultBuilder.ObjectResult.cs | 0 .../Result/ResultBuilder.Pooling.cs | 0 .../Processing/Result/ResultBuilder.cs | 0 .../Execution/Processing/Result/ResultData.cs | 0 .../Processing/Result/ResultMemoryOwner.cs | 0 .../Execution/Processing/Result/ResultPool.cs | 0 .../Processing/Result/ResultPoolDefaults.cs | 0 .../Execution/Processing/RootValueResolver.cs | 0 .../Execution/Processing/Selection.cs | 0 .../Processing/SelectionCollection.cs | 0 .../Processing/SelectionIncludeCondition.cs | 0 .../Processing/SelectionInclusionKind.cs | 0 .../Execution/Processing/SelectionPath.cs | 0 .../Execution/Processing/SelectionSet.cs | 0 .../SelectionSetOptimizerContext.cs | 0 .../Execution/Processing/SelectionVariants.cs | 0 .../SubscriptionExecutor.Subscription.cs | 0 .../Processing/SubscriptionExecutor.cs | 0 .../Processing/Tasks/ExecutionTaskPool.cs | 0 .../Tasks/ExecutionTaskPoolPolicy.cs | 0 .../Tasks/ResolverTask.CompleteValue.cs | 0 .../Processing/Tasks/ResolverTask.Execute.cs | 0 .../Processing/Tasks/ResolverTask.Pooling.cs | 0 .../Processing/Tasks/ResolverTask.cs | 0 .../Processing/Tasks/ResolverTaskFactory.cs | 0 .../Tasks/ResolverTaskPoolPolicy.cs | 0 .../Processing/Tasks/StreamHelper.cs | 0 .../Processing/ValueCompletion.Leaf.cs | 0 .../Processing/ValueCompletion.List.cs | 0 .../Processing/ValueCompletion.Object.cs | 0 .../Execution/Processing/ValueCompletion.cs | 0 .../Processing/ValueCompletionContext.cs | 0 .../Processing/VariableCoercionHelper.cs | 0 .../Execution/Processing/VariableRewriter.cs | 0 .../Processing/VariableValueCollection.cs | 0 .../Processing/VariableValueOrLiteral.cs | 0 .../Execution/Processing/WorkQueue.cs | 0 .../Processing/WorkScheduler.Execute.cs | 0 .../Processing/WorkScheduler.Pooling.cs | 0 .../Execution/Processing/WorkScheduler.cs | 0 .../RequestExecutorManager.Events.cs | 0 .../Execution/RequestExecutorManager.Hooks.cs | 0 .../RequestExecutorManager.Warmup.cs | 0 .../Execution/RequestExecutorManager.cs | 0 .../Requirements/FieldRequirementsMetadata.cs | 0 .../Execution/Requirements/PropertyNode.cs | 0 .../Requirements/PropertyTreeBuilder.cs | 0 .../RequirementsTypeInterceptor.cs | 0 .../Execution/Requirements/TypeContainer.cs | 0 .../Execution/Requirements/TypeNode.cs | 0 .../src/{ => Types}/Execution/SchemaName.cs | 0 .../src/{ => Types}/Execution/ThrowHelper.cs | 0 .../src/{ => Types}/Execution/Timestamp.cs | 0 .../Fetching/AdHocBatchDataLoader.cs | 0 .../Fetching/AdHocCacheDataLoader.cs | 0 .../Fetching/AdHocGroupedDataLoader.cs | 0 .../Fetching/AsyncAutoResetEvent.cs | 0 .../Attributes/UseDataLoaderAttribute.cs | 0 .../Fetching/BatchDispatchEventArgs.cs | 0 .../Fetching/BatchDispatchEventType.cs | 0 .../BatchDispatcher.ExecutorSession.cs | 0 .../BatchDispatcher.IBatchScheduler.cs | 0 .../{ => Types}/Fetching/BatchDispatcher.cs | 0 .../Fetching/BatchDispatcherOptions.cs | 0 .../Fetching/BatchDispatcherResult.cs | 0 .../Fetching/DataLoaderDefaults.cs | 0 .../DataLoaderParameterExpressionBuilder.cs | 0 .../DataLoaderRootFieldTypeInterceptor.cs | 0 .../Fetching/DataLoaderScopeHolder.cs | 0 .../Fetching/ExecutionDataLoaderScope.cs | 0 .../ExecutionDataLoaderScopeFactory.cs | 0 .../DataLoaderResolverContextExtensions.cs | 0 .../DataLoaderServiceProviderExtensions.cs | 0 .../Extensions/GetDataLoaderAttribute.cs | 0 .../ObjectFieldDataLoaderExtensions.cs | 0 .../src/{ => Types}/Fetching/FetchBatch.cs | 0 .../src/{ => Types}/Fetching/FetchCache.cs | 0 .../src/{ => Types}/Fetching/FetchGroup.cs | 0 .../{ => Types}/Fetching/IBatchDispatcher.cs | 0 .../Fetching/IDataLoaderScopeFactory.cs | 0 .../Fetching/RegisterDataLoaderException.cs | 0 .../Fetching/SkipDataLoaderCacheAttribute.cs | 0 .../Fetching/Utilities/ThrowHelper.cs | 0 .../Core/src/Types/HotChocolate.Types.csproj | 58 +- .../Internal/IParameterExpressionBuilder.cs | 2 +- .../Properties/FetchingResources.Designer.cs | 30 +- .../Properties/FetchingResources.resx | 0 .../Properties/Resources.Designer.cs | 0 .../Properties/Resources.resx | 0 ...ent.MetaDb.cs => ResultDocument.MetaDb.cs} | 11 +- .../src/Types/Text/Json/ResultDocument.cs | 598 ++++++++++++++++++ .../HotChocolate.Execution.Tests.csproj | 2 +- .../HotChocolate.Fetching.Tests.csproj | 1 - .../HotChocolate.Types.NodaTime.Tests.csproj | 1 - .../HotChocolate.Types.Scalars.Tests.csproj | 1 - .../HotChocolate.CostAnalysis.csproj | 1 - .../Data/src/Data/HotChocolate.Data.csproj | 2 +- .../HotChocolate.Diagnostics.csproj | 2 +- .../HotChocolate.Fusion.Execution.csproj | 1 - .../Json/CompositeResultDocument.DbRow.cs | 2 +- .../Json/CompositeResultDocument.MetaDb.cs | 11 +- .../Fusion.Execution/Text/Json/JsonMemory.cs | 54 -- .../Text/Json/MetaDbMemory.cs | 17 - .../Text/Json/SourceResultDocument.MetaDb.cs | 9 +- .../Text/Json/SourceResultDocument.Parse.cs | 5 +- .../Text/Json/SourceResultDocument.cs | 3 +- .../Text/Json/SourceResultDocumentBuilder.cs | 6 +- .../src/Data/HotChocolate.Data.MongoDb.csproj | 2 +- .../Types/HotChocolate.Types.MongoDb.csproj | 1 - .../Types/HotChocolate.Types.Spatial.csproj | 1 - .../Utilities.Buffers}/FixedSizeArrayPool.cs | 19 +- .../FixedSizeArrayPoolEventSource.cs | 4 +- .../FixedSizeArrayPoolKinds.cs | 6 + .../HotChocolate.Utilities.Buffers.csproj | 5 + .../src/Utilities.Buffers/JsonMemory.cs | 102 +++ .../JsonMemoryEventSource.cs | 47 ++ .../src/Utilities.Buffers/JsonMemoryKind.cs | 7 + .../Properties/BuffersResources.Designer.cs | 6 + .../Properties/BuffersResources.resx | 3 + 290 files changed, 889 insertions(+), 459 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Execution/HotChocolate.Execution.csproj delete mode 100644 src/HotChocolate/Core/src/Fetching/HotChocolate.Fetching.csproj rename src/HotChocolate/Core/src/{ => Types}/Execution/Caching/DefaultDocumentCache.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Caching/DefaultPreparedOperationCache.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Caching/IPreparedOperationCache.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/ConfigurationContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/ConfigureRequestExecutorSetup.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/DefaultRequestExecutorBuilder.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/IConfigureRequestExecutorSetup.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/ITypeModule.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/OnConfigureRequestExecutorOptionsAction.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/OnConfigureSchemaBuilderAction.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/OnConfigureSchemaServices.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/OnRequestExecutorCreatedAction.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/OnRequestExecutorEvictedAction.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/RequestExecutorSetup.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Configuration/RootServiceProviderAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DefaultRequestContextAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DefaultRequestExecutor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/Factories/IFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/Factories/OperationContextFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/Factories/OperationContextOwnerFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/Factories/PooledServiceFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/InternalSchemaServiceCollectionExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Caches.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.DataLoader.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.ErrorFilter.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Hashing.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.IdSerializer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.InputParser.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Instrumentation.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Optimizer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Services.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TransactionScope.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeConversion.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeDiscovery.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.UseRequest.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Validation.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Document.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Middleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Paging.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Relay.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Resolvers.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeInterceptor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeModules.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Types.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/ErrorHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Errors/FuncErrorFilterWrapper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/ExecutionObjectFieldDescriptorExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/ExecutionRequestExecutorExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/ExecutionResultExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/ExecutionSchemaExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Extensions/OperationContextExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/IRequestContextAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/IRequestContextEnricher.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Instrumentation/AggregateExecutionDiagnosticEvents.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Instrumentation/ExecutionDiagnosticEventListener.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Instrumentation/IExecutionDiagnosticEventListener.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Instrumentation/IExecutionDiagnosticEvents.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Instrumentation/NoopExecutionDiagnosticEvents.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Internal/ArgumentCoercionHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Internal/MiddlewareContextMarshal.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Internal/SchemaFileExporter.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/NeedsFormatting.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/IErrorHandlerOptionsAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/IPersistedOperationOptionsAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/IRequestExecutorOptionsAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/IRequestTimeoutOptionsAccessor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/NodeIdSerializerOptions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/RequestExecutorOptions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/RequestParserOptions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/ResultBufferOptions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Options/TracingPreference.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/OperationCacheMiddleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/OperationExecutionMiddleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/OperationInfo.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/OperationResolverMiddleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/OperationVariableCoercionMiddleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/PipelineTools.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/Pipelines.md (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/RequestClassMiddlewareFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Pipeline/TimeoutMiddleware.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ArgumentNonNullValidator.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/AsyncManualResetEvent.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DefaultActivator.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DefaultTransactionScope.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DefaultTransactionScopeHandler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredExecutionTask.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredExecutionTaskResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredFragment.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredStream.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredWorkScheduler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredWorkState.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/DeferredWorkStateOwner.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/EmptySelectionCollection.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Fragment.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/IOperationCompilerOptimizer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/IOperationOptimizer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ISelectionSetOptimizer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ISubscription.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ITaskStatistics.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ITransactionScope.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ITransactionScopeHandler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/IncludeCondition.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.Arguments.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.Global.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.Pooling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.Pure.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.Selection.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/MiddlewareContext.State.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/NoOpTransactionScope.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/NoOpTransactionScopeHandler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/NoopBatchDispatcher.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Operation.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.ArgumentValues.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.BacklogItem.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.CompilerContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.Optimizers.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.SelectionSetInfo.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompiler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompilerMetrics.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompilerOptimizerHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompilerOptimizers.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationCompilerPool.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.Execution.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.IExecutionTaskContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.Operation.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.Pooling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.Services.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.Utilities.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationContextOwner.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationOptimizerContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationPrinter.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/OperationResolverHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/PathHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/QueryExecutor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ListResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ListResultPool.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ObjectFieldResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ObjectResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ObjectResultExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ObjectResultPool.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultBucket.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultBuilder.ObjectResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultBuilder.Pooling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultBuilder.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultData.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultMemoryOwner.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultPool.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Result/ResultPoolDefaults.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/RootValueResolver.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Selection.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionCollection.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionIncludeCondition.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionInclusionKind.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionPath.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionSet.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionSetOptimizerContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SelectionVariants.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SubscriptionExecutor.Subscription.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/SubscriptionExecutor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ExecutionTaskPool.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ExecutionTaskPoolPolicy.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTask.Execute.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTask.Pooling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTask.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTaskFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/ResolverTaskPoolPolicy.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/Tasks/StreamHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ValueCompletion.Leaf.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ValueCompletion.List.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ValueCompletion.Object.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ValueCompletion.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/ValueCompletionContext.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/VariableCoercionHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/VariableRewriter.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/VariableValueCollection.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/VariableValueOrLiteral.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/WorkQueue.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/WorkScheduler.Execute.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/WorkScheduler.Pooling.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Processing/WorkScheduler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/RequestExecutorManager.Events.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/RequestExecutorManager.Hooks.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/RequestExecutorManager.Warmup.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/RequestExecutorManager.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/FieldRequirementsMetadata.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/PropertyNode.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/PropertyTreeBuilder.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/RequirementsTypeInterceptor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/TypeContainer.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Requirements/TypeNode.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/SchemaName.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/ThrowHelper.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Execution/Timestamp.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/AdHocBatchDataLoader.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/AdHocCacheDataLoader.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/AdHocGroupedDataLoader.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/AsyncAutoResetEvent.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Attributes/UseDataLoaderAttribute.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatchEventArgs.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatchEventType.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatcher.ExecutorSession.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatcher.IBatchScheduler.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatcher.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatcherOptions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/BatchDispatcherResult.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/DataLoaderDefaults.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/DataLoaderParameterExpressionBuilder.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/DataLoaderRootFieldTypeInterceptor.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/DataLoaderScopeHolder.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/ExecutionDataLoaderScope.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/ExecutionDataLoaderScopeFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Extensions/DataLoaderResolverContextExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Extensions/DataLoaderServiceProviderExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Extensions/GetDataLoaderAttribute.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Extensions/ObjectFieldDataLoaderExtensions.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/FetchBatch.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/FetchCache.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/FetchGroup.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/IBatchDispatcher.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/IDataLoaderScopeFactory.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/RegisterDataLoaderException.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/SkipDataLoaderCacheAttribute.cs (100%) rename src/HotChocolate/Core/src/{ => Types}/Fetching/Utilities/ThrowHelper.cs (100%) rename src/HotChocolate/Core/src/{Fetching => Types}/Properties/FetchingResources.Designer.cs (96%) rename src/HotChocolate/Core/src/{Fetching => Types}/Properties/FetchingResources.resx (100%) rename src/HotChocolate/Core/src/{Execution => Types}/Properties/Resources.Designer.cs (100%) rename src/HotChocolate/Core/src/{Execution => Types}/Properties/Resources.resx (100%) rename src/HotChocolate/Core/src/Types/Text/Json/{CompositeResultDocument.MetaDb.cs => ResultDocument.MetaDb.cs} (96%) create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs delete mode 100644 src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonMemory.cs delete mode 100644 src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbMemory.cs rename src/HotChocolate/{Fusion-vnext/src/Fusion.Execution/Buffers => Utilities/src/Utilities.Buffers}/FixedSizeArrayPool.cs (90%) rename src/HotChocolate/{Fusion-vnext/src/Fusion.Execution/Buffers => Utilities/src/Utilities.Buffers}/FixedSizeArrayPoolEventSource.cs (95%) create mode 100644 src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolKinds.cs create mode 100644 src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemory.cs create mode 100644 src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryEventSource.cs create mode 100644 src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryKind.cs diff --git a/src/All.slnx b/src/All.slnx index 5620c0e8200..d6a71a909b4 100644 --- a/src/All.slnx +++ b/src/All.slnx @@ -90,9 +90,7 @@ - - diff --git a/src/CookieCrumble/src/CookieCrumble.HotChocolate/CookieCrumble.HotChocolate.csproj b/src/CookieCrumble/src/CookieCrumble.HotChocolate/CookieCrumble.HotChocolate.csproj index d177e47f486..a674bb77188 100644 --- a/src/CookieCrumble/src/CookieCrumble.HotChocolate/CookieCrumble.HotChocolate.csproj +++ b/src/CookieCrumble/src/CookieCrumble.HotChocolate/CookieCrumble.HotChocolate.csproj @@ -10,7 +10,6 @@ - diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp/HotChocolate.Adapters.Mcp.csproj b/src/HotChocolate/Adapters/src/Adapters.Mcp/HotChocolate.Adapters.Mcp.csproj index 119b51ea708..6d167c021a3 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp/HotChocolate.Adapters.Mcp.csproj +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp/HotChocolate.Adapters.Mcp.csproj @@ -6,7 +6,6 @@ - diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs index 4c57bac7179..2281101d5b2 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs @@ -1,3 +1,5 @@ + +using HotChocolate.Buffers; #if FUSION using System.Buffers; using System.Net; @@ -160,7 +162,7 @@ private async ValueTask ReadAsResultInternalAsync(string? charS #if FUSION // we try and read the first chunk into a single chunk. var reader = PipeReader.Create(stream, s_options); - var currentChunk = JsonMemory.Rent(); + var currentChunk = JsonMemory.Rent(JsonMemoryKind.Json); var currentChunkPosition = 0; var chunkIndex = 0; var chunks = ArrayPool.Shared.Rent(64); @@ -215,7 +217,7 @@ private async ValueTask ReadAsResultInternalAsync(string? charS } chunks[chunkIndex++] = currentChunk; - currentChunk = JsonMemory.Rent(); + currentChunk = JsonMemory.Rent(JsonMemoryKind.Json); currentChunkPosition = 0; } } @@ -253,7 +255,7 @@ private async ValueTask ReadAsResultInternalAsync(string? charS } chunks[chunkIndex++] = currentChunk; - currentChunk = JsonMemory.Rent(); + currentChunk = JsonMemory.Rent(JsonMemoryKind.Json); currentChunkPosition = 0; } } diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/JsonLines/JsonLinesReader.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/JsonLines/JsonLinesReader.cs index b8bfef41735..f9896ac4442 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/JsonLines/JsonLinesReader.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/JsonLines/JsonLinesReader.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.IO.Pipelines; using System.Runtime.CompilerServices; +using HotChocolate.Buffers; using HotChocolate.Fusion.Text.Json; #else using System.Buffers; @@ -103,7 +104,7 @@ private static SourceResultDocument ParseDocument(ReadOnlySequence lineBuf // Ceiling division to make sure we end up with the right amount of chunks. var chunksNeeded = (requiredSize + JsonMemory.BufferSize - 1) / JsonMemory.BufferSize; - var chunks = JsonMemory.RentRange(chunksNeeded); + var chunks = JsonMemory.RentRange(JsonMemoryKind.Json, chunksNeeded); var chunkIndex = 0; var chunkPosition = 0; diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseEventParser.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseEventParser.cs index 47d0ba8e6a3..2866a300500 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseEventParser.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseEventParser.cs @@ -2,7 +2,7 @@ using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; -using HotChocolate.Fusion.Text.Json; +using HotChocolate.Buffers; #else using System.Runtime.CompilerServices; diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseReader.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseReader.cs index f7de7d41d38..3348a1e1100 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseReader.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/Sse/SseReader.cs @@ -2,6 +2,7 @@ using System.Buffers; using System.IO.Pipelines; using System.Runtime.CompilerServices; +using HotChocolate.Buffers; using HotChocolate.Fusion.Text.Json; #else using System.Buffers; @@ -107,7 +108,7 @@ public async IAsyncEnumerator GetAsyncEnumerator( case SseEventType.Complete: reader.AdvanceTo(buffer.GetPosition(1, position.Value)); #if FUSION - JsonMemory.Return(eventBuffers); + JsonMemory.Return(JsonMemoryKind.Json, eventBuffers); eventBuffers.Clear(); #endif yield break; @@ -162,7 +163,7 @@ public async IAsyncEnumerator GetAsyncEnumerator( await reader.CompleteAsync().ConfigureAwait(false); #if FUSION // we return whatever is in here. - JsonMemory.Return(eventBuffers); + JsonMemory.Return(JsonMemoryKind.Json, eventBuffers); #endif } } @@ -232,7 +233,7 @@ private static void WriteBytesToChunks(List chunks, ref int currentPosit if (chunks.Count == 0 || currentPosition >= JsonMemory.BufferSize) { currentPosition = 0; - chunks.Add(JsonMemory.Rent()); + chunks.Add(JsonMemory.Rent(JsonMemoryKind.Json)); } var currentChunk = chunks[^1]; diff --git a/src/HotChocolate/Caching/src/Caching/HotChocolate.Caching.csproj b/src/HotChocolate/Caching/src/Caching/HotChocolate.Caching.csproj index 19568782fb1..76d0623f5d7 100644 --- a/src/HotChocolate/Caching/src/Caching/HotChocolate.Caching.csproj +++ b/src/HotChocolate/Caching/src/Caching/HotChocolate.Caching.csproj @@ -18,7 +18,6 @@ - diff --git a/src/HotChocolate/Core/HotChocolate.Core.slnx b/src/HotChocolate/Core/HotChocolate.Core.slnx index 874b0c44d4f..2f8095bec3b 100644 --- a/src/HotChocolate/Core/HotChocolate.Core.slnx +++ b/src/HotChocolate/Core/HotChocolate.Core.slnx @@ -7,9 +7,7 @@ - - diff --git a/src/HotChocolate/Core/src/Authorization/HotChocolate.Authorization.csproj b/src/HotChocolate/Core/src/Authorization/HotChocolate.Authorization.csproj index 36369fa8d90..c4fea1db81e 100644 --- a/src/HotChocolate/Core/src/Authorization/HotChocolate.Authorization.csproj +++ b/src/HotChocolate/Core/src/Authorization/HotChocolate.Authorization.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/HotChocolate/Core/src/Core/HotChocolate.Core.csproj b/src/HotChocolate/Core/src/Core/HotChocolate.Core.csproj index 8c5f1883691..21d8f857b7b 100644 --- a/src/HotChocolate/Core/src/Core/HotChocolate.Core.csproj +++ b/src/HotChocolate/Core/src/Core/HotChocolate.Core.csproj @@ -18,8 +18,6 @@ - - diff --git a/src/HotChocolate/Core/src/Execution.Projections/HotChocolate.Execution.Projections.csproj b/src/HotChocolate/Core/src/Execution.Projections/HotChocolate.Execution.Projections.csproj index 74997ec1546..8e5a544034f 100644 --- a/src/HotChocolate/Core/src/Execution.Projections/HotChocolate.Execution.Projections.csproj +++ b/src/HotChocolate/Core/src/Execution.Projections/HotChocolate.Execution.Projections.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/HotChocolate/Core/src/Execution/HotChocolate.Execution.csproj b/src/HotChocolate/Core/src/Execution/HotChocolate.Execution.csproj deleted file mode 100644 index a30275088fc..00000000000 --- a/src/HotChocolate/Core/src/Execution/HotChocolate.Execution.csproj +++ /dev/null @@ -1,247 +0,0 @@ - - - - true - - - - HotChocolate.Execution - HotChocolate.Execution - HotChocolate.Execution - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Resources.resx - - - OperationCompiler.cs - - - OperationCompiler.cs - - - OperationCompiler.cs - - - OperationCompiler.cs - - - OperationContext.cs - - - OperationContext.cs - - - OperationCompiler.cs - - - MiddlewareContext.Global.cs - - - MiddlewareContext.Global.cs - - - MiddlewareContext.Global.cs - - - MiddlewareContext.Global.cs - - - MiddlewareContext.Global.cs - - - ResolverTask.cs - - - WorkScheduler.cs - - - WorkScheduler.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - SchemaRequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - ValueCompletion.cs - - - ValueCompletion.cs - - - ValueCompletion.cs - - - ResultBuilder.cs - - - ResultBuilder.cs - - - ResultBuilder.cs - - - ResolverTask.cs - - - ResolverTask.cs - - - OperationContext.cs - - - OperationContext.cs - - - OperationContext.cs - - - OperationContext.cs - - - JsonResultFormatter.cs - - - SubscriptionExecutor.cs - - - RequestExecutorResolver.cs - - - ValueCompletion.cs - - - BatchExecutor.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorManager.cs - - - RequestExecutorManager.cs - - - RequestExecutorManager.cs - - - RequestExecutorBuilderExtensions.cs - - - RequestExecutorBuilderExtensions.cs - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - diff --git a/src/HotChocolate/Core/src/Fetching/HotChocolate.Fetching.csproj b/src/HotChocolate/Core/src/Fetching/HotChocolate.Fetching.csproj deleted file mode 100644 index 27229d59adc..00000000000 --- a/src/HotChocolate/Core/src/Fetching/HotChocolate.Fetching.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - HotChocolate.Fetching - HotChocolate.Fetching - HotChocolate.Fetching - HC8001;$(NoWarn) - - - - - - - - - - - - - - ResXFileCodeGenerator - FetchingResources.Designer.cs - - - - - - True - True - FetchingResources.resx - - - BatchDispatcher.cs - - - BatchDispatcher.cs - - - - diff --git a/src/HotChocolate/Core/src/Types.Errors/HotChocolate.Types.Errors.csproj b/src/HotChocolate/Core/src/Types.Errors/HotChocolate.Types.Errors.csproj index 04de55ffd98..4bdc4169e1f 100644 --- a/src/HotChocolate/Core/src/Types.Errors/HotChocolate.Types.Errors.csproj +++ b/src/HotChocolate/Core/src/Types.Errors/HotChocolate.Types.Errors.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/HotChocolate/Core/src/Types.Json/HotChocolate.Types.Json.csproj b/src/HotChocolate/Core/src/Types.Json/HotChocolate.Types.Json.csproj index a2ff17d8626..cafc753595e 100644 --- a/src/HotChocolate/Core/src/Types.Json/HotChocolate.Types.Json.csproj +++ b/src/HotChocolate/Core/src/Types.Json/HotChocolate.Types.Json.csproj @@ -13,7 +13,6 @@ - diff --git a/src/HotChocolate/Core/src/Types.Mutations/HotChocolate.Types.Mutations.csproj b/src/HotChocolate/Core/src/Types.Mutations/HotChocolate.Types.Mutations.csproj index 8faf45d5e11..bb59ec657e4 100644 --- a/src/HotChocolate/Core/src/Types.Mutations/HotChocolate.Types.Mutations.csproj +++ b/src/HotChocolate/Core/src/Types.Mutations/HotChocolate.Types.Mutations.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/HotChocolate/Core/src/Types.OffsetPagination/HotChocolate.Types.OffsetPagination.csproj b/src/HotChocolate/Core/src/Types.OffsetPagination/HotChocolate.Types.OffsetPagination.csproj index 3561ed6ead9..489e7d6cf91 100644 --- a/src/HotChocolate/Core/src/Types.OffsetPagination/HotChocolate.Types.OffsetPagination.csproj +++ b/src/HotChocolate/Core/src/Types.OffsetPagination/HotChocolate.Types.OffsetPagination.csproj @@ -13,7 +13,6 @@ - diff --git a/src/HotChocolate/Core/src/Types.Queries/HotChocolate.Types.Queries.csproj b/src/HotChocolate/Core/src/Types.Queries/HotChocolate.Types.Queries.csproj index 1a42342fada..2ec4deeeec7 100644 --- a/src/HotChocolate/Core/src/Types.Queries/HotChocolate.Types.Queries.csproj +++ b/src/HotChocolate/Core/src/Types.Queries/HotChocolate.Types.Queries.csproj @@ -25,7 +25,7 @@ - + diff --git a/src/HotChocolate/Core/src/Execution/Caching/DefaultDocumentCache.cs b/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultDocumentCache.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Caching/DefaultDocumentCache.cs rename to src/HotChocolate/Core/src/Types/Execution/Caching/DefaultDocumentCache.cs diff --git a/src/HotChocolate/Core/src/Execution/Caching/DefaultPreparedOperationCache.cs b/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Caching/DefaultPreparedOperationCache.cs rename to src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs diff --git a/src/HotChocolate/Core/src/Execution/Caching/IPreparedOperationCache.cs b/src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Caching/IPreparedOperationCache.cs rename to src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/ConfigurationContext.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/ConfigurationContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/ConfigurationContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/ConfigurationContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/ConfigureRequestExecutorSetup.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/ConfigureRequestExecutorSetup.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/ConfigureRequestExecutorSetup.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/ConfigureRequestExecutorSetup.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/DefaultRequestExecutorBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/DefaultRequestExecutorBuilder.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/DefaultRequestExecutorBuilder.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/DefaultRequestExecutorBuilder.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/IConfigureRequestExecutorSetup.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/IConfigureRequestExecutorSetup.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/IConfigureRequestExecutorSetup.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/IConfigureRequestExecutorSetup.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/ITypeModule.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/ITypeModule.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/ITypeModule.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/ITypeModule.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/OnConfigureRequestExecutorOptionsAction.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureRequestExecutorOptionsAction.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/OnConfigureRequestExecutorOptionsAction.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureRequestExecutorOptionsAction.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/OnConfigureSchemaBuilderAction.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureSchemaBuilderAction.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/OnConfigureSchemaBuilderAction.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureSchemaBuilderAction.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/OnConfigureSchemaServices.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureSchemaServices.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/OnConfigureSchemaServices.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/OnConfigureSchemaServices.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/OnRequestExecutorCreatedAction.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/OnRequestExecutorCreatedAction.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/OnRequestExecutorCreatedAction.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/OnRequestExecutorCreatedAction.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/OnRequestExecutorEvictedAction.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/OnRequestExecutorEvictedAction.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/OnRequestExecutorEvictedAction.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/OnRequestExecutorEvictedAction.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/RequestExecutorSetup.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/RequestExecutorSetup.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/RequestExecutorSetup.cs diff --git a/src/HotChocolate/Core/src/Execution/Configuration/RootServiceProviderAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/Configuration/RootServiceProviderAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Configuration/RootServiceProviderAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/Configuration/RootServiceProviderAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/DefaultRequestContextAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/DefaultRequestContextAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DefaultRequestContextAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/DefaultRequestContextAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/DefaultRequestExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DefaultRequestExecutor.cs rename to src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/IFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/IFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/IFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/IFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/OperationContextFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/OperationContextFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/OperationContextOwnerFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextOwnerFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/OperationContextOwnerFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextOwnerFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/PooledServiceFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/PooledServiceFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/Factories/PooledServiceFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/PooledServiceFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/InternalSchemaServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalSchemaServiceCollectionExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/InternalSchemaServiceCollectionExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalSchemaServiceCollectionExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Caches.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Caches.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Caches.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Caches.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Composite.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.DataLoader.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.DataLoader.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.DataLoader.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.DataLoader.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.ErrorFilter.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.ErrorFilter.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.ErrorFilter.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.ErrorFilter.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Hashing.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Hashing.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Hashing.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Hashing.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.IdSerializer.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.IdSerializer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.IdSerializer.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.IdSerializer.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.InputParser.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.InputParser.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.InputParser.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.InputParser.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Instrumentation.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Instrumentation.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Instrumentation.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Instrumentation.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Optimizer.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Optimizer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Optimizer.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Optimizer.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Services.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Services.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Services.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Services.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TransactionScope.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TransactionScope.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TransactionScope.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TransactionScope.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeConversion.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeConversion.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeConversion.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeConversion.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeDiscovery.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeDiscovery.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeDiscovery.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.TypeDiscovery.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.UseRequest.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.UseRequest.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.UseRequest.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.UseRequest.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Validation.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Validation.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Validation.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.Validation.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Document.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Document.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Document.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Document.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Middleware.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Middleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Middleware.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Middleware.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Paging.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Paging.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Paging.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Paging.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Relay.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Relay.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Relay.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Relay.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Resolvers.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Resolvers.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Resolvers.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Resolvers.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeInterceptor.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeInterceptor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeInterceptor.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeInterceptor.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeModules.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeModules.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeModules.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.TypeModules.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Types.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Types.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Types.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Types.cs diff --git a/src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/ErrorHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Errors/FuncErrorFilterWrapper.cs b/src/HotChocolate/Core/src/Types/Execution/Errors/FuncErrorFilterWrapper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Errors/FuncErrorFilterWrapper.cs rename to src/HotChocolate/Core/src/Types/Execution/Errors/FuncErrorFilterWrapper.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionObjectFieldDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionObjectFieldDescriptorExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/ExecutionObjectFieldDescriptorExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionObjectFieldDescriptorExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionRequestExecutorExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/ExecutionRequestExecutorExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionRequestExecutorExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/ExecutionResultExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/ExecutionSchemaExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/ExecutionSchemaExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Extensions/OperationContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Extensions/OperationContextExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/IRequestContextAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/IRequestContextAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/IRequestContextAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/IRequestContextAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/IRequestContextEnricher.cs b/src/HotChocolate/Core/src/Types/Execution/IRequestContextEnricher.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/IRequestContextEnricher.cs rename to src/HotChocolate/Core/src/Types/Execution/IRequestContextEnricher.cs diff --git a/src/HotChocolate/Core/src/Execution/Instrumentation/AggregateExecutionDiagnosticEvents.cs b/src/HotChocolate/Core/src/Types/Execution/Instrumentation/AggregateExecutionDiagnosticEvents.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Instrumentation/AggregateExecutionDiagnosticEvents.cs rename to src/HotChocolate/Core/src/Types/Execution/Instrumentation/AggregateExecutionDiagnosticEvents.cs diff --git a/src/HotChocolate/Core/src/Execution/Instrumentation/ExecutionDiagnosticEventListener.cs b/src/HotChocolate/Core/src/Types/Execution/Instrumentation/ExecutionDiagnosticEventListener.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Instrumentation/ExecutionDiagnosticEventListener.cs rename to src/HotChocolate/Core/src/Types/Execution/Instrumentation/ExecutionDiagnosticEventListener.cs diff --git a/src/HotChocolate/Core/src/Execution/Instrumentation/IExecutionDiagnosticEventListener.cs b/src/HotChocolate/Core/src/Types/Execution/Instrumentation/IExecutionDiagnosticEventListener.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Instrumentation/IExecutionDiagnosticEventListener.cs rename to src/HotChocolate/Core/src/Types/Execution/Instrumentation/IExecutionDiagnosticEventListener.cs diff --git a/src/HotChocolate/Core/src/Execution/Instrumentation/IExecutionDiagnosticEvents.cs b/src/HotChocolate/Core/src/Types/Execution/Instrumentation/IExecutionDiagnosticEvents.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Instrumentation/IExecutionDiagnosticEvents.cs rename to src/HotChocolate/Core/src/Types/Execution/Instrumentation/IExecutionDiagnosticEvents.cs diff --git a/src/HotChocolate/Core/src/Execution/Instrumentation/NoopExecutionDiagnosticEvents.cs b/src/HotChocolate/Core/src/Types/Execution/Instrumentation/NoopExecutionDiagnosticEvents.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Instrumentation/NoopExecutionDiagnosticEvents.cs rename to src/HotChocolate/Core/src/Types/Execution/Instrumentation/NoopExecutionDiagnosticEvents.cs diff --git a/src/HotChocolate/Core/src/Execution/Internal/ArgumentCoercionHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Internal/ArgumentCoercionHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Internal/MiddlewareContextMarshal.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Internal/MiddlewareContextMarshal.cs rename to src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs diff --git a/src/HotChocolate/Core/src/Execution/Internal/SchemaFileExporter.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Internal/SchemaFileExporter.cs rename to src/HotChocolate/Core/src/Types/Execution/Internal/SchemaFileExporter.cs diff --git a/src/HotChocolate/Core/src/Execution/NeedsFormatting.cs b/src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/NeedsFormatting.cs rename to src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/IErrorHandlerOptionsAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/Options/IErrorHandlerOptionsAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/IErrorHandlerOptionsAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/IErrorHandlerOptionsAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/IPersistedOperationOptionsAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/Options/IPersistedOperationOptionsAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/IPersistedOperationOptionsAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/IPersistedOperationOptionsAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/IRequestExecutorOptionsAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/Options/IRequestExecutorOptionsAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/IRequestExecutorOptionsAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/IRequestExecutorOptionsAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/IRequestTimeoutOptionsAccessor.cs b/src/HotChocolate/Core/src/Types/Execution/Options/IRequestTimeoutOptionsAccessor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/IRequestTimeoutOptionsAccessor.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/IRequestTimeoutOptionsAccessor.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/NodeIdSerializerOptions.cs b/src/HotChocolate/Core/src/Types/Execution/Options/NodeIdSerializerOptions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/NodeIdSerializerOptions.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/NodeIdSerializerOptions.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/RequestExecutorOptions.cs b/src/HotChocolate/Core/src/Types/Execution/Options/RequestExecutorOptions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/RequestExecutorOptions.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/RequestExecutorOptions.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/RequestParserOptions.cs b/src/HotChocolate/Core/src/Types/Execution/Options/RequestParserOptions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/RequestParserOptions.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/RequestParserOptions.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/ResultBufferOptions.cs b/src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/ResultBufferOptions.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs diff --git a/src/HotChocolate/Core/src/Execution/Options/TracingPreference.cs b/src/HotChocolate/Core/src/Types/Execution/Options/TracingPreference.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Options/TracingPreference.cs rename to src/HotChocolate/Core/src/Types/Execution/Options/TracingPreference.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/OperationCacheMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/OperationCacheMiddleware.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/OperationExecutionMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/OperationExecutionMiddleware.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/OperationInfo.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/OperationInfo.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/OperationResolverMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/OperationResolverMiddleware.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/OperationVariableCoercionMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationVariableCoercionMiddleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/OperationVariableCoercionMiddleware.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationVariableCoercionMiddleware.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/PipelineTools.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/PipelineTools.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/PipelineTools.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/PipelineTools.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/Pipelines.md b/src/HotChocolate/Core/src/Types/Execution/Pipeline/Pipelines.md similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/Pipelines.md rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/Pipelines.md diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/RequestClassMiddlewareFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/RequestClassMiddlewareFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/RequestClassMiddlewareFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/RequestClassMiddlewareFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/Pipeline/TimeoutMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/TimeoutMiddleware.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Pipeline/TimeoutMiddleware.cs rename to src/HotChocolate/Core/src/Types/Execution/Pipeline/TimeoutMiddleware.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentNonNullValidator.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ArgumentNonNullValidator.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentNonNullValidator.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/AsyncManualResetEvent.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/AsyncManualResetEvent.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/AsyncManualResetEvent.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/AsyncManualResetEvent.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DefaultActivator.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DefaultActivator.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DefaultActivator.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DefaultActivator.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DefaultTransactionScope.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DefaultTransactionScope.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DefaultTransactionScope.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DefaultTransactionScope.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DefaultTransactionScopeHandler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DefaultTransactionScopeHandler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DefaultTransactionScopeHandler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DefaultTransactionScopeHandler.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredExecutionTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredExecutionTask.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredExecutionTaskResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredExecutionTaskResult.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredFragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredFragment.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredStream.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredStream.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredWorkScheduler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredWorkScheduler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredWorkState.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredWorkState.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/DeferredWorkStateOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/DeferredWorkStateOwner.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/EmptySelectionCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/EmptySelectionCollection.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/EmptySelectionCollection.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/EmptySelectionCollection.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Fragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Fragment.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/IOperationCompilerOptimizer.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOperationCompilerOptimizer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/IOperationCompilerOptimizer.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/IOperationCompilerOptimizer.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/IOperationOptimizer.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOperationOptimizer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/IOperationOptimizer.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/IOperationOptimizer.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ISelectionSetOptimizer.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSetOptimizer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ISelectionSetOptimizer.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSetOptimizer.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ISubscription.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISubscription.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ISubscription.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ISubscription.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ITaskStatistics.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ITaskStatistics.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ITaskStatistics.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ITaskStatistics.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ITransactionScope.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ITransactionScope.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ITransactionScope.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ITransactionScope.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ITransactionScopeHandler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ITransactionScopeHandler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ITransactionScopeHandler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ITransactionScopeHandler.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/IncludeCondition.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/IncludeCondition.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Arguments.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Arguments.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Global.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Pooling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Pure.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Pure.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.Selection.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.State.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/MiddlewareContext.State.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/NoOpTransactionScope.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/NoOpTransactionScope.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/NoOpTransactionScope.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/NoOpTransactionScope.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/NoOpTransactionScopeHandler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/NoOpTransactionScopeHandler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/NoOpTransactionScopeHandler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/NoOpTransactionScopeHandler.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/NoopBatchDispatcher.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/NoopBatchDispatcher.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/NoopBatchDispatcher.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/NoopBatchDispatcher.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Operation.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.ArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.ArgumentValues.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.ArgumentValues.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.ArgumentValues.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.BacklogItem.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.BacklogItem.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.CompilerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompilerContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.CompilerContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompilerContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.Optimizers.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.Optimizers.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.SelectionSetInfo.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.SelectionSetInfo.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompiler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompilerMetrics.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerMetrics.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompilerMetrics.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerMetrics.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompilerOptimizerHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompilerOptimizerHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompilerOptimizers.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompilerOptimizers.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationCompilerPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationCompilerPool.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.Execution.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.IExecutionTaskContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.IExecutionTaskContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.Operation.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.Pooling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.Services.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Services.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.Services.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Services.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.Utilities.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Utilities.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.Utilities.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Utilities.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationContextOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationContextOwner.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationOptimizerContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationPrinter.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationPrinter.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/OperationResolverHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResolverHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/OperationResolverHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/OperationResolverHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/PathHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/PathHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/QueryExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/QueryExecutor.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ListResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ListResult.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ListResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ListResultPool.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ObjectFieldResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ObjectFieldResult.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResult.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResultExtensions.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ObjectResultPool.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultBucket.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultBucket.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.ObjectResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.ObjectResult.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.Pooling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultBuilder.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultData.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultData.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultMemoryOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultMemoryOwner.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultPool.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Result/ResultPoolDefaults.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Result/ResultPoolDefaults.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/RootValueResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/RootValueResolver.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Selection.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionCollection.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionIncludeCondition.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionIncludeCondition.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionIncludeCondition.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionIncludeCondition.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionInclusionKind.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionInclusionKind.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionInclusionKind.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionInclusionKind.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionPath.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionPath.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionPath.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionPath.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionSet.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionSetOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionSetOptimizerContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SelectionVariants.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SelectionVariants.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SubscriptionExecutor.Subscription.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SubscriptionExecutor.Subscription.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/SubscriptionExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/SubscriptionExecutor.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ExecutionTaskPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ExecutionTaskPool.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ExecutionTaskPool.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ExecutionTaskPool.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ExecutionTaskPoolPolicy.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ExecutionTaskPoolPolicy.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ExecutionTaskPoolPolicy.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ExecutionTaskPoolPolicy.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.Execute.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.Execute.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.Pooling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTask.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTaskFactory.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTaskPoolPolicy.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskPoolPolicy.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/ResolverTaskPoolPolicy.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskPoolPolicy.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/Tasks/StreamHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/StreamHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/Tasks/StreamHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/StreamHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.Leaf.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.Leaf.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.List.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.List.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.Object.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ValueCompletion.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/ValueCompletionContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletionContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/ValueCompletionContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletionContext.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/VariableCoercionHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableCoercionHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/VariableCoercionHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/VariableCoercionHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/VariableRewriter.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableRewriter.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/VariableRewriter.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/VariableRewriter.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/VariableValueCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueCollection.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/VariableValueCollection.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueCollection.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/VariableValueOrLiteral.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/VariableValueOrLiteral.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/WorkQueue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkQueue.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/WorkQueue.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/WorkQueue.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.Execute.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Execute.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.Execute.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Execute.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.Pooling.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs diff --git a/src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Processing/WorkScheduler.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.cs diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutorManager.Events.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Events.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/RequestExecutorManager.Events.cs rename to src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Events.cs diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutorManager.Hooks.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Hooks.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/RequestExecutorManager.Hooks.cs rename to src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Hooks.cs diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutorManager.Warmup.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Warmup.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/RequestExecutorManager.Warmup.cs rename to src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.Warmup.cs diff --git a/src/HotChocolate/Core/src/Execution/RequestExecutorManager.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/RequestExecutorManager.cs rename to src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/FieldRequirementsMetadata.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/FieldRequirementsMetadata.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/FieldRequirementsMetadata.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/FieldRequirementsMetadata.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/PropertyNode.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/PropertyNode.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/PropertyNode.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/PropertyNode.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/PropertyTreeBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/PropertyTreeBuilder.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/PropertyTreeBuilder.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/PropertyTreeBuilder.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/RequirementsTypeInterceptor.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/RequirementsTypeInterceptor.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/RequirementsTypeInterceptor.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/RequirementsTypeInterceptor.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/TypeContainer.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/TypeContainer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/TypeContainer.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/TypeContainer.cs diff --git a/src/HotChocolate/Core/src/Execution/Requirements/TypeNode.cs b/src/HotChocolate/Core/src/Types/Execution/Requirements/TypeNode.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Requirements/TypeNode.cs rename to src/HotChocolate/Core/src/Types/Execution/Requirements/TypeNode.cs diff --git a/src/HotChocolate/Core/src/Execution/SchemaName.cs b/src/HotChocolate/Core/src/Types/Execution/SchemaName.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/SchemaName.cs rename to src/HotChocolate/Core/src/Types/Execution/SchemaName.cs diff --git a/src/HotChocolate/Core/src/Execution/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/ThrowHelper.cs rename to src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs diff --git a/src/HotChocolate/Core/src/Execution/Timestamp.cs b/src/HotChocolate/Core/src/Types/Execution/Timestamp.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Timestamp.cs rename to src/HotChocolate/Core/src/Types/Execution/Timestamp.cs diff --git a/src/HotChocolate/Core/src/Fetching/AdHocBatchDataLoader.cs b/src/HotChocolate/Core/src/Types/Fetching/AdHocBatchDataLoader.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/AdHocBatchDataLoader.cs rename to src/HotChocolate/Core/src/Types/Fetching/AdHocBatchDataLoader.cs diff --git a/src/HotChocolate/Core/src/Fetching/AdHocCacheDataLoader.cs b/src/HotChocolate/Core/src/Types/Fetching/AdHocCacheDataLoader.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/AdHocCacheDataLoader.cs rename to src/HotChocolate/Core/src/Types/Fetching/AdHocCacheDataLoader.cs diff --git a/src/HotChocolate/Core/src/Fetching/AdHocGroupedDataLoader.cs b/src/HotChocolate/Core/src/Types/Fetching/AdHocGroupedDataLoader.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/AdHocGroupedDataLoader.cs rename to src/HotChocolate/Core/src/Types/Fetching/AdHocGroupedDataLoader.cs diff --git a/src/HotChocolate/Core/src/Fetching/AsyncAutoResetEvent.cs b/src/HotChocolate/Core/src/Types/Fetching/AsyncAutoResetEvent.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/AsyncAutoResetEvent.cs rename to src/HotChocolate/Core/src/Types/Fetching/AsyncAutoResetEvent.cs diff --git a/src/HotChocolate/Core/src/Fetching/Attributes/UseDataLoaderAttribute.cs b/src/HotChocolate/Core/src/Types/Fetching/Attributes/UseDataLoaderAttribute.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Attributes/UseDataLoaderAttribute.cs rename to src/HotChocolate/Core/src/Types/Fetching/Attributes/UseDataLoaderAttribute.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatchEventArgs.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatchEventArgs.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatchEventArgs.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatchEventArgs.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatchEventType.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatchEventType.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatchEventType.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatchEventType.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatcher.ExecutorSession.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.ExecutorSession.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatcher.ExecutorSession.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.ExecutorSession.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatcher.IBatchScheduler.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.IBatchScheduler.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatcher.IBatchScheduler.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.IBatchScheduler.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatcher.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatcher.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatcher.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatcherOptions.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherOptions.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatcherOptions.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherOptions.cs diff --git a/src/HotChocolate/Core/src/Fetching/BatchDispatcherResult.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/BatchDispatcherResult.cs rename to src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs diff --git a/src/HotChocolate/Core/src/Fetching/DataLoaderDefaults.cs b/src/HotChocolate/Core/src/Types/Fetching/DataLoaderDefaults.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/DataLoaderDefaults.cs rename to src/HotChocolate/Core/src/Types/Fetching/DataLoaderDefaults.cs diff --git a/src/HotChocolate/Core/src/Fetching/DataLoaderParameterExpressionBuilder.cs b/src/HotChocolate/Core/src/Types/Fetching/DataLoaderParameterExpressionBuilder.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/DataLoaderParameterExpressionBuilder.cs rename to src/HotChocolate/Core/src/Types/Fetching/DataLoaderParameterExpressionBuilder.cs diff --git a/src/HotChocolate/Core/src/Fetching/DataLoaderRootFieldTypeInterceptor.cs b/src/HotChocolate/Core/src/Types/Fetching/DataLoaderRootFieldTypeInterceptor.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/DataLoaderRootFieldTypeInterceptor.cs rename to src/HotChocolate/Core/src/Types/Fetching/DataLoaderRootFieldTypeInterceptor.cs diff --git a/src/HotChocolate/Core/src/Fetching/DataLoaderScopeHolder.cs b/src/HotChocolate/Core/src/Types/Fetching/DataLoaderScopeHolder.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/DataLoaderScopeHolder.cs rename to src/HotChocolate/Core/src/Types/Fetching/DataLoaderScopeHolder.cs diff --git a/src/HotChocolate/Core/src/Fetching/ExecutionDataLoaderScope.cs b/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/ExecutionDataLoaderScope.cs rename to src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs diff --git a/src/HotChocolate/Core/src/Fetching/ExecutionDataLoaderScopeFactory.cs b/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScopeFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/ExecutionDataLoaderScopeFactory.cs rename to src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScopeFactory.cs diff --git a/src/HotChocolate/Core/src/Fetching/Extensions/DataLoaderResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Extensions/DataLoaderResolverContextExtensions.cs rename to src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs diff --git a/src/HotChocolate/Core/src/Fetching/Extensions/DataLoaderServiceProviderExtensions.cs b/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderServiceProviderExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Extensions/DataLoaderServiceProviderExtensions.cs rename to src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderServiceProviderExtensions.cs diff --git a/src/HotChocolate/Core/src/Fetching/Extensions/GetDataLoaderAttribute.cs b/src/HotChocolate/Core/src/Types/Fetching/Extensions/GetDataLoaderAttribute.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Extensions/GetDataLoaderAttribute.cs rename to src/HotChocolate/Core/src/Types/Fetching/Extensions/GetDataLoaderAttribute.cs diff --git a/src/HotChocolate/Core/src/Fetching/Extensions/ObjectFieldDataLoaderExtensions.cs b/src/HotChocolate/Core/src/Types/Fetching/Extensions/ObjectFieldDataLoaderExtensions.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Extensions/ObjectFieldDataLoaderExtensions.cs rename to src/HotChocolate/Core/src/Types/Fetching/Extensions/ObjectFieldDataLoaderExtensions.cs diff --git a/src/HotChocolate/Core/src/Fetching/FetchBatch.cs b/src/HotChocolate/Core/src/Types/Fetching/FetchBatch.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/FetchBatch.cs rename to src/HotChocolate/Core/src/Types/Fetching/FetchBatch.cs diff --git a/src/HotChocolate/Core/src/Fetching/FetchCache.cs b/src/HotChocolate/Core/src/Types/Fetching/FetchCache.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/FetchCache.cs rename to src/HotChocolate/Core/src/Types/Fetching/FetchCache.cs diff --git a/src/HotChocolate/Core/src/Fetching/FetchGroup.cs b/src/HotChocolate/Core/src/Types/Fetching/FetchGroup.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/FetchGroup.cs rename to src/HotChocolate/Core/src/Types/Fetching/FetchGroup.cs diff --git a/src/HotChocolate/Core/src/Fetching/IBatchDispatcher.cs b/src/HotChocolate/Core/src/Types/Fetching/IBatchDispatcher.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/IBatchDispatcher.cs rename to src/HotChocolate/Core/src/Types/Fetching/IBatchDispatcher.cs diff --git a/src/HotChocolate/Core/src/Fetching/IDataLoaderScopeFactory.cs b/src/HotChocolate/Core/src/Types/Fetching/IDataLoaderScopeFactory.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/IDataLoaderScopeFactory.cs rename to src/HotChocolate/Core/src/Types/Fetching/IDataLoaderScopeFactory.cs diff --git a/src/HotChocolate/Core/src/Fetching/RegisterDataLoaderException.cs b/src/HotChocolate/Core/src/Types/Fetching/RegisterDataLoaderException.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/RegisterDataLoaderException.cs rename to src/HotChocolate/Core/src/Types/Fetching/RegisterDataLoaderException.cs diff --git a/src/HotChocolate/Core/src/Fetching/SkipDataLoaderCacheAttribute.cs b/src/HotChocolate/Core/src/Types/Fetching/SkipDataLoaderCacheAttribute.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/SkipDataLoaderCacheAttribute.cs rename to src/HotChocolate/Core/src/Types/Fetching/SkipDataLoaderCacheAttribute.cs diff --git a/src/HotChocolate/Core/src/Fetching/Utilities/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Utilities/ThrowHelper.cs rename to src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index ebf81309726..bf2bed99fa2 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -34,7 +34,6 @@ - @@ -54,13 +53,26 @@ + + + + + + + + + + + + + @@ -81,24 +93,16 @@ Text\Json\MetaDbEventSource.cs - - Text\Json\JsonConstants.cs - - - - Text\Json\JsonConstants.cs - - - - Text\Json\JsonConstants.cs + + ResultDocument.cs - - Text\Json\JsonConstants.cs + + ResultDocument.cs - - Text\Json\JsonConstants.cs + + ResultDocument.cs @@ -169,25 +173,33 @@ DescriptorContext.cs - - True - True - TypeResources.resx - InterfaceType.cs + + True + True + TypeResources.resx + + ResXFileCodeGenerator TypeResources.Designer.cs - - - + + True + True + Resources.resx + + + + ResXFileCodeGenerator + Resources.Designer.cs + diff --git a/src/HotChocolate/Core/src/Types/Internal/IParameterExpressionBuilder.cs b/src/HotChocolate/Core/src/Types/Internal/IParameterExpressionBuilder.cs index 432f3ce243b..8c0e873c448 100644 --- a/src/HotChocolate/Core/src/Types/Internal/IParameterExpressionBuilder.cs +++ b/src/HotChocolate/Core/src/Types/Internal/IParameterExpressionBuilder.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Internal; /// -/// This interface represents an expression builder to resolver resolver parameter values. +/// This interface represents an expression builder to resolver parameter values. /// public interface IParameterExpressionBuilder { diff --git a/src/HotChocolate/Core/src/Fetching/Properties/FetchingResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs similarity index 96% rename from src/HotChocolate/Core/src/Fetching/Properties/FetchingResources.Designer.cs rename to src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs index ce30a8ad324..83d091f7900 100644 --- a/src/HotChocolate/Core/src/Fetching/Properties/FetchingResources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs @@ -9,21 +9,21 @@ namespace HotChocolate.Fetching.Properties { using System; - - + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class FetchingResources { - + private static System.Resources.ResourceManager resourceMan; - + private static System.Globalization.CultureInfo resourceCulture; - + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal FetchingResources() { } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Resources.ResourceManager ResourceManager { get { @@ -34,7 +34,7 @@ internal static System.Resources.ResourceManager ResourceManager { return resourceMan; } } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Globalization.CultureInfo Culture { get { @@ -44,49 +44,49 @@ internal static System.Globalization.CultureInfo Culture { resourceCulture = value; } } - + internal static string DataLoaderRegistry_KeyNullOrEmpty { get { return ResourceManager.GetString("DataLoaderRegistry_KeyNullOrEmpty", resourceCulture); } } - + internal static string DefaultDataLoaderRegistry_GetOrRegister { get { return ResourceManager.GetString("DefaultDataLoaderRegistry_GetOrRegister", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_RegistryIsNull { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_RegistryIsNull", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_UnableToRegister { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_UnableToRegister", resourceCulture); } } - + internal static string ThrowHelper_DataLoader_InvalidType { get { return ResourceManager.GetString("ThrowHelper_DataLoader_InvalidType", resourceCulture); } } - + internal static string BatchDispatcherResult_NoExceptions { get { return ResourceManager.GetString("BatchDispatcherResult_NoExceptions", resourceCulture); diff --git a/src/HotChocolate/Core/src/Fetching/Properties/FetchingResources.resx b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx similarity index 100% rename from src/HotChocolate/Core/src/Fetching/Properties/FetchingResources.resx rename to src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs similarity index 100% rename from src/HotChocolate/Core/src/Execution/Properties/Resources.Designer.cs rename to src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs diff --git a/src/HotChocolate/Core/src/Execution/Properties/Resources.resx b/src/HotChocolate/Core/src/Types/Properties/Resources.resx similarity index 100% rename from src/HotChocolate/Core/src/Execution/Properties/Resources.resx rename to src/HotChocolate/Core/src/Types/Properties/Resources.resx diff --git a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs similarity index 96% rename from src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs rename to src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs index 5f6561ac0ec..46af3d2c6b3 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultDocument.MetaDb.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using HotChocolate.Buffers; using static HotChocolate.Text.Json.MetaDbEventSource; namespace HotChocolate.Text.Json; @@ -26,7 +27,7 @@ internal static MetaDb CreateForEstimatedRows(int estimatedRows) log.MetaDbCreated(2, estimatedRows, 1); // Rent the first chunk now to avoid branching on first append - chunks[0] = MetaDbMemory.Rent(); + chunks[0] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(2, 0); for (var i = 1; i < chunks.Length; i++) @@ -101,7 +102,7 @@ internal Cursor Append( // if the chunk is empty we did not yet rent any memory for it if (chunk.Length == 0) { - chunk = chunks[chunkIndex] = MetaDbMemory.Rent(); + chunk = chunks[chunkIndex] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(2, chunkIndex); } @@ -291,7 +292,7 @@ internal int GetSizeOrLength(Cursor cursor) internal void SetSizeOrLength(Cursor cursor, int sizeOrLength) { AssertValidCursor(cursor); - Debug.Assert(sizeOrLength >= 0 && sizeOrLength <= int.MaxValue, "SizeOrLength value exceeds 31-bit limit"); + Debug.Assert(sizeOrLength >= 0, "SizeOrLength value exceeds 31-bit limit"); var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); var currentValue = MemoryMarshal.Read(fieldSpan); @@ -350,7 +351,7 @@ private void AssertValidCursor(Cursor cursor) Debug.Assert(absoluteIndex >= 0 && absoluteIndex < maxExclusive, $"Cursor points to row {absoluteIndex}, but only {maxExclusive} rows are valid."); - Debug.Assert(cursor.ByteOffset + DbRow.Size <= MetaDbMemory.BufferSize, "Cursor byte offset out of bounds"); + Debug.Assert(cursor.ByteOffset + DbRow.Size <= JsonMemory.BufferSize, "Cursor byte offset out of bounds"); } public void Dispose() @@ -369,7 +370,7 @@ public void Dispose() break; } - MetaDbMemory.Return(chunk); + JsonMemory.Return(JsonMemoryKind.Metadata, chunk); } chunks.Clear(); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs new file mode 100644 index 00000000000..ab09873c494 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -0,0 +1,598 @@ +using System.Buffers; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text; +using HotChocolate.Execution.Processing; +using HotChocolate.Types; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument : IDisposable +{ + private static readonly Encoding s_utf8Encoding = Encoding.UTF8; + private readonly IOperation _operation; + private readonly ulong _includeFlags; + private List? _errors; + private Dictionary? _extensions; + internal MetaDb _metaDb; + private bool _disposed; + + public ResultDocument(IOperation operation, ulong includeFlags) + { + _metaDb = MetaDb.CreateForEstimatedRows(Cursor.RowsPerChunk * 8); + _operation = operation; + _includeFlags = includeFlags; + + Data = CreateObject(Cursor.Zero, operation.RootSelectionSet); + } + + public CompositeResultElement Data { get; } + + public List? Errors + { + get => _errors; + internal set => _errors = value; + } + + public Dictionary? Extensions + { + get => _extensions; + internal set => _extensions = value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ElementTokenType GetElementTokenType(Cursor cursor) + => _metaDb.GetElementTokenType(cursor); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal IOperation GetOperation() + => _operation; + + internal ISelectionSet? GetSelectionSet(Cursor cursor) + { + var row = _metaDb.Get(cursor); + + if (row.OperationReferenceType is not OperationReferenceType.SelectionSet) + { + return null; + } + + return _operation.GetSelectionSetById(row.OperationReferenceId); + } + + internal ISelection? GetSelection(Cursor cursor) + { + if (cursor == Cursor.Zero) + { + return null; + } + + // If the cursor points at a value, step back to the PropertyName row. + var row = _metaDb.Get(cursor); + + if (row.TokenType is not ElementTokenType.PropertyName) + { + cursor = cursor.AddRows(-1); + row = _metaDb.Get(cursor); + + if (row.TokenType is not ElementTokenType.PropertyName) + { + return null; + } + } + + if (row.OperationReferenceType is not OperationReferenceType.Selection) + { + return null; + } + + return _operation.GetSelectionById(row.OperationReferenceId); + } + + internal CompositeResultElement GetArrayIndexElement(Cursor current, int arrayIndex) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var (start, tokenType) = _metaDb.GetStartCursor(current); + + CheckExpectedType(ElementTokenType.StartArray, tokenType); + + var len = _metaDb.GetNumberOfRows(start); + + if ((uint)arrayIndex >= (uint)len) + { + throw new IndexOutOfRangeException(); + } + + // first element is at +1 after StartArray + return new CompositeResultElement(this, start.AddRows(arrayIndex + 1)); + } + + internal int GetArrayLength(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + (current, var tokenType) = _metaDb.GetStartCursor(current); + + CheckExpectedType(ElementTokenType.StartArray, tokenType); + + return _metaDb.GetSizeOrLength(current); + } + + internal int GetPropertyCount(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + (current, var tokenType) = _metaDb.GetStartCursor(current); + + CheckExpectedType(ElementTokenType.StartObject, tokenType); + + return _metaDb.GetSizeOrLength(current); + } + + internal Path CreatePath(Cursor current) + { + // Stop at root via IsRoot flag. + if ((_metaDb.GetFlags(current) & ElementFlags.IsRoot) == ElementFlags.IsRoot) + { + return Path.Root; + } + + Span chain = stackalloc Cursor[64]; + var c = current; + var written = 0; + + do + { + chain[written++] = c; + + var parentIndex = _metaDb.GetParent(c); + if (parentIndex <= 0) + { + break; + } + + c = Cursor.FromIndex(parentIndex); + + if (written >= 64) + { + throw new InvalidOperationException("The path is to deep."); + } + } while (true); + + var path = Path.Root; + var parentTokenType = ElementTokenType.StartObject; + + chain = chain[..written]; + + for (var i = chain.Length - 1; i >= 0; i--) + { + c = chain[i]; + var tokenType = _metaDb.GetElementTokenType(c, resolveReferences: false); + + if (tokenType == ElementTokenType.PropertyName) + { + path = path.Append(GetSelection(c)!.ResponseName); + i--; // skip over the actual value + } + else if (chain.Length - 1 > i) + { + var parentCursor = chain[i + 1]; + + if (parentTokenType is ElementTokenType.StartArray) + { + // arrayIndex = abs(child) - (abs(parent) + 1) + var absChild = c.Chunk * Cursor.RowsPerChunk + c.Row; + var absParent = parentCursor.Chunk * Cursor.RowsPerChunk + parentCursor.Row; + var arrayIndex = absChild - (absParent + 1); + path = path.Append(arrayIndex); + } + } + + parentTokenType = tokenType; + } + + return path; + } + + internal CompositeResultElement GetParent(Cursor current) + { + // The null cursor represents the data object, which is the utmost root. + // If we have reached that we simply return an undefined element + if (current == Cursor.Zero) + { + return default; + } + + var parent = _metaDb.GetParentCursor(current); + + // if the parent element is a property name then we must get the parent of that, + // as property name and value represent the same element. + if (_metaDb.GetElementTokenType(parent) is ElementTokenType.PropertyName) + { + parent = _metaDb.GetParentCursor(parent); + } + + // if we have not yet reached the root and the element type of the parent is an object or an array + // then we need to get still the parent of this row as we want to get the logical parent + // which is the value level of the property or the element in an array. + if (parent != Cursor.Zero + && _metaDb.GetElementTokenType(parent) is ElementTokenType.StartObject or ElementTokenType.StartArray) + { + parent = _metaDb.GetParentCursor(parent); + + // in this case the parent must be a reference, otherwise we would have + // found an inconsistency in the database. + Debug.Assert(_metaDb.GetElementTokenType(parent, resolveReferences: false) == ElementTokenType.Reference); + } + + return new CompositeResultElement(this, parent); + } + + internal bool IsInvalidated(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var tokenType = _metaDb.GetElementTokenType(current, resolveReferences: false); + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + } + + if (tokenType is ElementTokenType.Reference) + { + current = _metaDb.GetLocationCursor(current); + tokenType = _metaDb.GetElementTokenType(current); + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + } + } + + return false; + } + + internal bool IsNullOrInvalidated(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var tokenType = _metaDb.GetElementTokenType(current); + + if (tokenType is ElementTokenType.Null) + { + return true; + } + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + } + + if (tokenType is ElementTokenType.Reference) + { + current = _metaDb.GetLocationCursor(current); + tokenType = _metaDb.GetElementTokenType(current); + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + } + } + + return false; + } + + internal bool IsInternalProperty(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + // The flag sits on the property row (one before value) + var propertyCursor = current.AddRows(-1); + var flags = _metaDb.GetFlags(propertyCursor); + return (flags & ElementFlags.IsInternal) == ElementFlags.IsInternal; + } + + internal void Invalidate(Cursor current) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var tokenType = _metaDb.GetElementTokenType(current, resolveReferences: false); + + if (tokenType is ElementTokenType.None) + { + return; + } + + if (tokenType is ElementTokenType.StartArray) + { + return; + } + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + _metaDb.SetFlags(current, flags | ElementFlags.Invalidated); + return; + } + + if (tokenType is ElementTokenType.Reference) + { + current = _metaDb.GetLocationCursor(current); + tokenType = _metaDb.GetElementTokenType(current); + + if (tokenType is ElementTokenType.StartObject) + { + var flags = _metaDb.GetFlags(current); + _metaDb.SetFlags(current, flags | ElementFlags.Invalidated); + } + + return; + } + + Debug.Fail("Only objects can be invalidated."); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteRawValueTo(IBufferWriter writer, DbRow row, int indentLevel, bool indented) + { + if ((row.Flags & ElementFlags.SourceResult) == ElementFlags.SourceResult) + { + var document = _sources[row.SourceDocumentId]; + + if (row.TokenType is ElementTokenType.StartObject or ElementTokenType.StartArray) + { + // Reconstruct the source cursor from stored Location (Chunk) and SizeOrLength (Row) + var sourceCursor = SourceResultDocument.Cursor.From(row.Location, row.SizeOrLength); + var formatter = new SourceResultDocument.RawJsonFormatter(document, writer, indentLevel, indented); + formatter.WriteValue(sourceCursor); + return; + } + + // For simple values, write directly using location and size + document.WriteRawValueTo(writer, row.Location, row.SizeOrLength); + return; + } + + throw new NotSupportedException(); + } + + private ReadOnlySpan ReadRawValue(DbRow row) + { + if (row.TokenType == ElementTokenType.Null) + { + return JsonConstants.NullValue; + } + + if (row.TokenType == ElementTokenType.True) + { + return JsonConstants.TrueValue; + } + + if (row.TokenType == ElementTokenType.False) + { + return JsonConstants.FalseValue; + } + + if (row.TokenType == ElementTokenType.PropertyName) + { + return _operation.GetSelectionById(row.OperationReferenceId).Utf8ResponseName; + } + + if ((row.Flags & ElementFlags.SourceResult) == ElementFlags.SourceResult) + { + var document = _sources[row.SourceDocumentId]; + return document.ReadRawValue(row.Location, row.SizeOrLength); + } + + throw new NotSupportedException(); + } + + internal CompositeResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) + { + var startObjectCursor = WriteStartObject(parent, selectionSet.Id); + + var selectionCount = 0; + foreach (var selection in selectionSet.Selections) + { + WriteEmptyProperty(startObjectCursor, selection); + selectionCount++; + } + + WriteEndObject(startObjectCursor, selectionCount); + + return new CompositeResultElement(this, startObjectCursor); + } + + internal CompositeResultElement CreateArray(Cursor parent, int length) + { + var cursor = WriteStartArray(parent, length); + + for (var i = 0; i < length; i++) + { + WriteEmptyValue(cursor); + } + + WriteEndArray(); + + return new CompositeResultElement(this, cursor); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AssignCompositeValue(CompositeResultElement target, CompositeResultElement value) + { + _metaDb.Replace( + cursor: target.Cursor, + tokenType: ElementTokenType.Reference, + location: value.Cursor.ToIndex(), + parentRow: _metaDb.GetParent(target.Cursor)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AssignSourceValue(CompositeResultElement target, SourceResultElement source) + { + var value = source.GetValuePointer(); + var parent = source._parent; + + if (parent.Id == -1) + { + Debug.Assert(!_sources.Contains(parent), "The source document is marked as unbound but is already registered."); + parent.Id = _sources.Count; + _sources.Add(parent); + } + + Debug.Assert(_sources.Contains(parent), "Expected the source document of the source element to be registered."); + + var tokenType = source.TokenType.ToElementTokenType(); + + if (tokenType is ElementTokenType.StartObject or ElementTokenType.StartArray) + { + var sourceCursor = source._cursor; + + _metaDb.Replace( + cursor: target.Cursor, + tokenType: source.TokenType.ToElementTokenType(), + location: sourceCursor.Chunk, + sizeOrLength: sourceCursor.Row, + sourceDocumentId: parent.Id, + parentRow: _metaDb.GetParent(target.Cursor), + flags: ElementFlags.SourceResult); + return; + } + + _metaDb.Replace( + cursor: target.Cursor, + tokenType: source.TokenType.ToElementTokenType(), + location: value.Location, + sizeOrLength: value.Size, + sourceDocumentId: parent.Id, + parentRow: _metaDb.GetParent(target.Cursor), + flags: ElementFlags.SourceResult); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AssignNullValue(CompositeResultElement target) + { + _metaDb.Replace( + cursor: target.Cursor, + tokenType: ElementTokenType.Null, + parentRow: _metaDb.GetParent(target.Cursor)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Cursor WriteStartObject(Cursor parent, int selectionSetId = 0) + { + var flags = ElementFlags.None; + var parentRow = ToIndex(parent); + + if (parentRow < 0) + { + parentRow = 0; + flags = ElementFlags.IsRoot; + } + + return _metaDb.Append( + ElementTokenType.StartObject, + parentRow: parentRow, + operationReferenceId: selectionSetId, + operationReferenceType: OperationReferenceType.SelectionSet, + flags: flags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteEndObject(Cursor startObjectCursor, int length) + { + _metaDb.Append(ElementTokenType.EndObject); + + _metaDb.SetNumberOfRows(startObjectCursor, (length * 2) + 1); + _metaDb.SetSizeOrLength(startObjectCursor, length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Cursor WriteStartArray(Cursor parent, int length = 0) + { + var flags = ElementFlags.None; + var parentRow = ToIndex(parent); + + if (parentRow < 0) + { + parentRow = 0; + flags = ElementFlags.IsRoot; + } + + return _metaDb.Append( + ElementTokenType.StartArray, + sizeOrLength: length, + parentRow: parentRow, + numberOfRows: length + 1, + flags: flags); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteEndArray() => _metaDb.Append(ElementTokenType.EndArray); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteEmptyProperty(Cursor parent, ISelection selection) + { + var flags = ElementFlags.None; + + if (selection.IsInternal) + { + flags = ElementFlags.IsInternal; + } + + if (!selection.IsIncluded(_includeFlags)) + { + flags |= ElementFlags.IsExcluded; + } + + if (selection.Type.Kind is not TypeKind.NonNull) + { + flags |= ElementFlags.IsNullable; + } + + var prop = _metaDb.Append( + ElementTokenType.PropertyName, + parentRow: ToIndex(parent), + operationReferenceId: selection.Id, + operationReferenceType: OperationReferenceType.Selection, + flags: flags); + + _metaDb.Append( + ElementTokenType.None, + parentRow: ToIndex(prop)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteEmptyValue(Cursor parent) + { + _metaDb.Append( + ElementTokenType.None, + parentRow: ToIndex(parent)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int ToIndex(Cursor c) => (c.Chunk * Cursor.RowsPerChunk) + c.Row; + + private static void CheckExpectedType(ElementTokenType expected, ElementTokenType actual) + { + if (expected != actual) + { + throw new ArgumentOutOfRangeException($"Expected {expected} but found {actual}."); + } + } + + public void Dispose() + { + if (!_disposed) + { + _metaDb.Dispose(); + _disposed = true; + } + } +} diff --git a/src/HotChocolate/Core/test/Execution.Tests/HotChocolate.Execution.Tests.csproj b/src/HotChocolate/Core/test/Execution.Tests/HotChocolate.Execution.Tests.csproj index 17b7c9c5d0d..0f46058c97a 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/HotChocolate.Execution.Tests.csproj +++ b/src/HotChocolate/Core/test/Execution.Tests/HotChocolate.Execution.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/HotChocolate/Core/test/Fetching.Tests/HotChocolate.Fetching.Tests.csproj b/src/HotChocolate/Core/test/Fetching.Tests/HotChocolate.Fetching.Tests.csproj index cd72005885c..e7cb45365b6 100644 --- a/src/HotChocolate/Core/test/Fetching.Tests/HotChocolate.Fetching.Tests.csproj +++ b/src/HotChocolate/Core/test/Fetching.Tests/HotChocolate.Fetching.Tests.csproj @@ -8,7 +8,6 @@ - diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/HotChocolate.Types.NodaTime.Tests.csproj b/src/HotChocolate/Core/test/Types.NodaTime.Tests/HotChocolate.Types.NodaTime.Tests.csproj index d7cdb3cafe4..f773538a6ff 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/HotChocolate.Types.NodaTime.Tests.csproj +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/HotChocolate.Types.NodaTime.Tests.csproj @@ -6,7 +6,6 @@ - diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/HotChocolate.Types.Scalars.Tests.csproj b/src/HotChocolate/Core/test/Types.Scalars.Tests/HotChocolate.Types.Scalars.Tests.csproj index b314284c42c..2d157d98a23 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/HotChocolate.Types.Scalars.Tests.csproj +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/HotChocolate.Types.Scalars.Tests.csproj @@ -6,7 +6,6 @@ - diff --git a/src/HotChocolate/CostAnalysis/src/CostAnalysis/HotChocolate.CostAnalysis.csproj b/src/HotChocolate/CostAnalysis/src/CostAnalysis/HotChocolate.CostAnalysis.csproj index c3bd3025c3f..a6baf2a2152 100644 --- a/src/HotChocolate/CostAnalysis/src/CostAnalysis/HotChocolate.CostAnalysis.csproj +++ b/src/HotChocolate/CostAnalysis/src/CostAnalysis/HotChocolate.CostAnalysis.csproj @@ -6,7 +6,6 @@ - diff --git a/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj b/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj index c6d4fbb16bf..f5f21fbc643 100644 --- a/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj +++ b/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/HotChocolate.Diagnostics.csproj b/src/HotChocolate/Diagnostics/src/Diagnostics/HotChocolate.Diagnostics.csproj index 886bfa3e70d..49885604251 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/HotChocolate.Diagnostics.csproj +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/HotChocolate.Diagnostics.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj index 1ff85c15c78..784fba4a269 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/HotChocolate.Fusion.Execution.csproj @@ -90,7 +90,6 @@ Transport\Http\Sse\SseReader.cs - SourceResultElement.cs diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs index 42785ef9614..0a84bde497f 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.DbRow.cs @@ -15,7 +15,7 @@ internal readonly struct DbRow // 27 bits for location + 2 bits OpRefType + 3 reserved bits private readonly int _locationAndOpRefType; - // Sign bit for HasComplexChildren + 31 bits for size/length + // A Sign bit for HasComplexChildren + 31 bits for size/length private readonly int _sizeOrLengthUnion; // 4 bits TokenType + 27 bits NumberOfRows + 1 reserved bit diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.MetaDb.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.MetaDb.cs index 5d2d0d0d9c8..bda078eb5bf 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.MetaDb.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.MetaDb.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using HotChocolate.Buffers; using static HotChocolate.Fusion.Text.Json.MetaDbEventSource; namespace HotChocolate.Fusion.Text.Json; @@ -26,7 +27,7 @@ internal static MetaDb CreateForEstimatedRows(int estimatedRows) log.MetaDbCreated(2, estimatedRows, 1); // Rent the first chunk now to avoid branching on first append - chunks[0] = MetaDbMemory.Rent(); + chunks[0] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(2, 0); for (var i = 1; i < chunks.Length; i++) @@ -101,7 +102,7 @@ internal Cursor Append( // if the chunk is empty we did not yet rent any memory for it if (chunk.Length == 0) { - chunk = chunks[chunkIndex] = MetaDbMemory.Rent(); + chunk = chunks[chunkIndex] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(2, chunkIndex); } @@ -291,7 +292,7 @@ internal int GetSizeOrLength(Cursor cursor) internal void SetSizeOrLength(Cursor cursor, int sizeOrLength) { AssertValidCursor(cursor); - Debug.Assert(sizeOrLength >= 0 && sizeOrLength <= int.MaxValue, "SizeOrLength value exceeds 31-bit limit"); + Debug.Assert(sizeOrLength >= 0, "SizeOrLength value exceeds 31-bit limit"); var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); var currentValue = MemoryMarshal.Read(fieldSpan); @@ -350,7 +351,7 @@ private void AssertValidCursor(Cursor cursor) Debug.Assert(absoluteIndex >= 0 && absoluteIndex < maxExclusive, $"Cursor points to row {absoluteIndex}, but only {maxExclusive} rows are valid."); - Debug.Assert(cursor.ByteOffset + DbRow.Size <= MetaDbMemory.BufferSize, "Cursor byte offset out of bounds"); + Debug.Assert(cursor.ByteOffset + DbRow.Size <= JsonMemory.BufferSize, "Cursor byte offset out of bounds"); } public void Dispose() @@ -369,7 +370,7 @@ public void Dispose() break; } - MetaDbMemory.Return(chunk); + JsonMemory.Return(JsonMemoryKind.Metadata, chunk); } chunks.Clear(); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonMemory.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonMemory.cs deleted file mode 100644 index e11f24de5ff..00000000000 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonMemory.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Buffers; -using System.Runtime.InteropServices; -using HotChocolate.Fusion.Buffers; - -namespace HotChocolate.Fusion.Text.Json; - -/// -/// Manages the memory for storing JSON data. -/// -public static class JsonMemory -{ - public const int BufferSize = 1 << 17; - - private static readonly FixedSizeArrayPool s_pool = new(1, BufferSize, 128 * 6, preAllocate: true); - private static readonly ArrayPool s_chunkPool = ArrayPool.Shared; - - public static byte[] Rent() - => s_pool.Rent(); - - public static byte[][] RentRange(int requiredChunks) - { - var chunks = s_chunkPool.Rent(requiredChunks); - - for (var i = 0; i < requiredChunks; i++) - { - chunks[i] = s_pool.Rent(); - } - - return chunks; - } - - public static void Return(byte[] chunk) - => s_pool.Return(chunk); - - public static void Return(List chunks) - { - ArgumentNullException.ThrowIfNull(chunks); - - foreach (var chunk in CollectionsMarshal.AsSpan(chunks)) - { - s_pool.Return(chunk); - } - } - - public static void Return(byte[][] chunks, int usedChunks) - { - ArgumentNullException.ThrowIfNull(chunks); - - foreach (var chunk in chunks.AsSpan(0, usedChunks)) - { - s_pool.Return(chunk); - } - } -} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbMemory.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbMemory.cs deleted file mode 100644 index 20c4232e4dd..00000000000 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/MetaDbMemory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using HotChocolate.Fusion.Buffers; - -namespace HotChocolate.Fusion.Text.Json; - -public static class MetaDbMemory -{ - public const int BufferSize = 1 << 17; - public const int RowsPerChunk = 6552; - - private static readonly FixedSizeArrayPool s_pool = new(2, BufferSize, 128 * 6, preAllocate: true); - - public static byte[] Rent() - => s_pool.Rent(); - - public static void Return(byte[] chunk) - => s_pool.Return(chunk); -} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.MetaDb.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.MetaDb.cs index 0e5b4815f52..08fc5aadc6e 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.MetaDb.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.MetaDb.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.Json; +using HotChocolate.Buffers; using static HotChocolate.Fusion.Text.Json.MetaDbEventSource; namespace HotChocolate.Fusion.Text.Json; @@ -23,7 +24,7 @@ internal struct MetaDb : IDisposable static MetaDb() { Debug.Assert( - MetaDbMemory.BufferSize >= Cursor.ChunkBytes, + JsonMemory.BufferSize >= Cursor.ChunkBytes, "MetaDb.BufferSize must match Cursor.ChunkBytes for index math to align."); } @@ -36,7 +37,7 @@ internal static MetaDb CreateForEstimatedRows(int estimatedRows) log.MetaDbCreated(1, estimatedRows, 1); // Rent the first chunk now to avoid branching on first append - chunks[0] = MetaDbMemory.Rent(); + chunks[0] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(1, 0); for (var i = 1; i < chunks.Length; i++) @@ -101,7 +102,7 @@ internal Cursor Append( // if the chunk is empty we did not yet rent any memory for it if (chunk.Length == 0) { - chunk = chunks[chunkIndex] = MetaDbMemory.Rent(); + chunk = chunks[chunkIndex] = JsonMemory.Rent(JsonMemoryKind.Metadata); log.ChunkAllocated(1, chunkIndex); } @@ -215,7 +216,7 @@ public void Dispose() break; } - MetaDbMemory.Return(chunk); + JsonMemory.Return(JsonMemoryKind.Metadata, chunk); } chunks.Clear(); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.Parse.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.Parse.cs index f7af9525d73..6c3fbf84af7 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.Parse.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.Parse.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text.Json; +using HotChocolate.Buffers; namespace HotChocolate.Fusion.Text.Json; @@ -62,7 +63,7 @@ internal static SourceResultDocument ParseSingleSegment( { foreach (var chunk in dataChunksSpan) { - JsonMemory.Return(chunk); + JsonMemory.Return(JsonMemoryKind.Json, chunk); } dataChunksSpan.Clear(); @@ -121,7 +122,7 @@ internal static SourceResultDocument ParseMultipleSegments( { foreach (var chunk in dataChunksSpan) { - JsonMemory.Return(chunk); + JsonMemory.Return(JsonMemoryKind.Json, chunk); } dataChunksSpan.Clear(); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.cs index 31bce68fb06..b51dc541331 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocument.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; +using HotChocolate.Buffers; namespace HotChocolate.Fusion.Text.Json; @@ -228,7 +229,7 @@ public void Dispose() { if (_pooledMemory) { - JsonMemory.Return(_dataChunks, _usedChunks); + JsonMemory.Return(JsonMemoryKind.Json, _dataChunks, _usedChunks); if (_dataChunks.Length > 1) { diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocumentBuilder.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocumentBuilder.cs index 2c5c1b28a13..57a69863033 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocumentBuilder.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/SourceResultDocumentBuilder.cs @@ -116,7 +116,7 @@ public SourceResultDocument Build() } // Rent the first chunk - chunks[0] = JsonMemory.Rent(); + chunks[0] = JsonMemory.Rent(JsonMemoryKind.Json); var currentChunkIndex = 0; var currentChunkOffset = 0; @@ -132,7 +132,7 @@ public SourceResultDocument Build() } catch { - JsonMemory.Return(chunks, currentChunkIndex + 1); + JsonMemory.Return(JsonMemoryKind.Json, chunks, currentChunkIndex + 1); ArrayPool.Shared.Return(chunks); throw; } @@ -334,7 +334,7 @@ private static void EnsureChunkCapacity( { Debug.Fail("foo"); - chunks[currentChunkIndex] = JsonMemory.Rent(); + chunks[currentChunkIndex] = JsonMemory.Rent(JsonMemoryKind.Json); } } diff --git a/src/HotChocolate/MongoDb/src/Data/HotChocolate.Data.MongoDb.csproj b/src/HotChocolate/MongoDb/src/Data/HotChocolate.Data.MongoDb.csproj index 35ad9d7e70c..5a8c1cfd60f 100644 --- a/src/HotChocolate/MongoDb/src/Data/HotChocolate.Data.MongoDb.csproj +++ b/src/HotChocolate/MongoDb/src/Data/HotChocolate.Data.MongoDb.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj b/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj index def8e832c74..3be34f6d613 100644 --- a/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj +++ b/src/HotChocolate/MongoDb/src/Types/HotChocolate.Types.MongoDb.csproj @@ -9,7 +9,6 @@ - diff --git a/src/HotChocolate/Spatial/src/Types/HotChocolate.Types.Spatial.csproj b/src/HotChocolate/Spatial/src/Types/HotChocolate.Types.Spatial.csproj index 505cf7f2374..52a2228e685 100644 --- a/src/HotChocolate/Spatial/src/Types/HotChocolate.Types.Spatial.csproj +++ b/src/HotChocolate/Spatial/src/Types/HotChocolate.Types.Spatial.csproj @@ -12,7 +12,6 @@ - diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPool.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPool.cs similarity index 90% rename from src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPool.cs rename to src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPool.cs index 46b3c20f5a1..a8e4df61cba 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPool.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPool.cs @@ -1,8 +1,8 @@ using System.Diagnostics; -using static HotChocolate.Fusion.Buffers.FixedSizeArrayPoolEventSource; -using static HotChocolate.Fusion.Properties.FusionExecutionResources; +using static HotChocolate.Buffers.FixedSizeArrayPoolEventSource; +using static HotChocolate.Buffers.Properties.BuffersResources; -namespace HotChocolate.Fusion.Buffers; +namespace HotChocolate.Buffers; internal sealed class FixedSizeArrayPool { @@ -45,7 +45,14 @@ public byte[] Rent() public void Return(byte[] array) { +#if NET8_0_OR_GREATER ArgumentNullException.ThrowIfNull(array); +#else + if(array is null) + { + throw new ArgumentNullException(nameof(array)); + } +#endif if (array.Length != _arraySize) { @@ -149,7 +156,11 @@ internal Bucket(int poolId, int bufferLength, int numberOfBuffers, bool preAlloc internal bool Return(byte[] array) { - Debug.Assert(array.Length == _bufferLength); + // if the returned array has not the expected size we will reject it without throwing an error. + if (array.Length != _bufferLength) + { + return false; + } var returned = false; var lockTaken = false; diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPoolEventSource.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolEventSource.cs similarity index 95% rename from src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPoolEventSource.cs rename to src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolEventSource.cs index 0f550556dd3..d219a9e4e2b 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Buffers/FixedSizeArrayPoolEventSource.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolEventSource.cs @@ -1,8 +1,8 @@ using System.Diagnostics.Tracing; -namespace HotChocolate.Fusion.Buffers; +namespace HotChocolate.Buffers; -[EventSource(Name = "HotChocolate-Fusion-FixedSizeArrayPool")] +[EventSource(Name = "HotChocolate-Buffers-FixedSizeArrayPool")] internal sealed class FixedSizeArrayPoolEventSource : EventSource { public static readonly FixedSizeArrayPoolEventSource Log = new(); diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolKinds.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolKinds.cs new file mode 100644 index 00000000000..2f28bf87fb9 --- /dev/null +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/FixedSizeArrayPoolKinds.cs @@ -0,0 +1,6 @@ +namespace HotChocolate.Buffers; + +internal static class FixedSizeArrayPoolKinds +{ + public const int JsonMemory = 1; +} 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 c8dbaec6ad7..d6931ad087f 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj @@ -16,6 +16,11 @@ true + + + + + diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemory.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemory.cs new file mode 100644 index 00000000000..9b21a6fd4d5 --- /dev/null +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemory.cs @@ -0,0 +1,102 @@ +using System.Buffers; +#if NET8_0_OR_GREATER +using System.Runtime.InteropServices; +#endif +using static HotChocolate.Buffers.JsonMemoryEventSource; + +namespace HotChocolate.Buffers; + +/// +/// Manages the memory for storing JSON data. +/// +internal static class JsonMemory +{ + public const int BufferSize = 1 << 17; + + private static FixedSizeArrayPool s_pool = new(FixedSizeArrayPoolKinds.JsonMemory, BufferSize, 128); + private static readonly ArrayPool s_chunkPool = ArrayPool.Shared; + + public static void Reconfigure(Func factory) + { +#if NET8_0_OR_GREATER + ArgumentNullException.ThrowIfNull(factory); +#else + if(factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } +#endif + + s_pool = factory() ?? throw new InvalidOperationException("The factory must create a valid pool."); + Log.ReconfiguredPool(); + } + + public static byte[] Rent(JsonMemoryKind kind) + { + var buffer = s_pool.Rent(); + Log.BufferRented(kind, bufferCount: 1); + return buffer; + } + + public static byte[][] RentRange(JsonMemoryKind kind, int requiredChunks) + { + var chunks = s_chunkPool.Rent(requiredChunks); + + for (var i = 0; i < requiredChunks; i++) + { + chunks[i] = s_pool.Rent(); + } + + Log.BufferReturned(kind, requiredChunks); + return chunks; + } + + public static void Return(JsonMemoryKind kind, byte[] chunk) + { + s_pool.Return(chunk); + Log.BufferReturned(kind, 1); + } + + public static void Return(JsonMemoryKind kind, byte[][] chunks, int usedChunks) + { +#if NET8_0_OR_GREATER + ArgumentNullException.ThrowIfNull(chunks); +#else + if (chunks is null) + { + throw new ArgumentNullException(nameof(chunks)); + } +#endif + + foreach (var chunk in chunks.AsSpan(0, usedChunks)) + { + s_pool.Return(chunk); + } + + Log.BufferReturned(kind, usedChunks); + } + + public static void Return(JsonMemoryKind kind, List chunks) + { +#if NET8_0_OR_GREATER + ArgumentNullException.ThrowIfNull(chunks); + + foreach (var chunk in CollectionsMarshal.AsSpan(chunks)) + { + s_pool.Return(chunk); + } +#else + if (chunks is null) + { + throw new ArgumentNullException(nameof(chunks)); + } + + foreach (var chunk in chunks) + { + s_pool.Return(chunk); + } +#endif + + Log.BufferReturned(kind, chunks.Count); + } +} diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryEventSource.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryEventSource.cs new file mode 100644 index 00000000000..58799402b72 --- /dev/null +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryEventSource.cs @@ -0,0 +1,47 @@ +using System.Diagnostics.Tracing; + +namespace HotChocolate.Buffers; + +[EventSource(Name = "HotChocolate-Buffers-JsonMemory")] +internal sealed class JsonMemoryEventSource : EventSource +{ + public static readonly JsonMemoryEventSource Log = new(); + + private JsonMemoryEventSource() { } + + [Event( + eventId: 1, + Level = EventLevel.Informational, + Message = "Pool reconfigured.")] + public void ReconfiguredPool() + { + if (IsEnabled(EventLevel.Verbose, EventKeywords.None)) + { + WriteEvent(1); + } + } + + [Event( + eventId: 2, + Level = EventLevel.Verbose, + Message = "Buffer rented (Kind={0}, BufferCount={1})")] + public void BufferRented(JsonMemoryKind kind, int bufferCount) + { + if (IsEnabled(EventLevel.Verbose, EventKeywords.None)) + { + WriteEvent(2, kind, bufferCount); + } + } + + [Event( + eventId: 3, + Level = EventLevel.Verbose, + Message = "Buffer returned (Kind={0}, BufferCount={1})")] + public void BufferReturned(JsonMemoryKind kind, int bufferCount) + { + if (IsEnabled(EventLevel.Verbose, EventKeywords.None)) + { + WriteEvent(3, kind, bufferCount); + } + } +} diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryKind.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryKind.cs new file mode 100644 index 00000000000..d4016d2f620 --- /dev/null +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/JsonMemoryKind.cs @@ -0,0 +1,7 @@ +namespace HotChocolate.Buffers; + +internal enum JsonMemoryKind +{ + Metadata = 1, + Json = 2 +} diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.Designer.cs b/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.Designer.cs index 6388029e0e7..a02fc93a0b6 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.Designer.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.Designer.cs @@ -50,5 +50,11 @@ internal static string ArrayWriter_Advance_BufferOverflow { return ResourceManager.GetString("ArrayWriter_Advance_BufferOverflow", resourceCulture); } } + + internal static string FixedSizeArrayPool_Return_InvalidArraySize { + get { + return ResourceManager.GetString("FixedSizeArrayPool_Return_InvalidArraySize", resourceCulture); + } + } } } diff --git a/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.resx b/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.resx index 5449972ccdc..05fdeb25e4c 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.resx +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/Properties/BuffersResources.resx @@ -21,4 +21,7 @@ Cannot advance past the end of the buffer. + + Buffer size {0} does not match expected chunk size {1} + From 2505534f880a8b0ef58361e463836ab21469c980 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 26 Nov 2025 19:53:44 +0100 Subject: [PATCH 05/42] Deprectaion notice --- .../hotchocolate/v16/migrating/migrate-from-15-to-16.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/website/src/docs/hotchocolate/v16/migrating/migrate-from-15-to-16.md b/website/src/docs/hotchocolate/v16/migrating/migrate-from-15-to-16.md index 68d903f035e..ef350da0e9d 100644 --- a/website/src/docs/hotchocolate/v16/migrating/migrate-from-15-to-16.md +++ b/website/src/docs/hotchocolate/v16/migrating/migrate-from-15-to-16.md @@ -278,6 +278,12 @@ If you need the old behavior, use can still use the non-generic `ID`-attribute a Previously the `TryConfigure` or `OnConfigure` methods carried a non-nullable parameter of the member the descriptor attribute was annotated to. With the new source generator we moved away from pure reflection based APIs. This means that when you use the source generator +## Merged Assemblies HotChocolate.Types, HotChocolate.Execution, HotChocolate.Fetching + +With Hot Chocolate 16 we introduced a lot more abstractions, meaning we pulled out abstractions of the type system or the execution into separate libraries. But at the same time we simplified the implementation of the type system and the execution by moving the implementations of HotChocolate.Execution and HotChocolate.Fetching into HotChocolate.Types. This allowed us to simplify the implementation and make it more efficient. + +So, if you were referencing HotChocolate.Execution or HotChocolate.Fetching directly make sure to remove references to these libraries and replace them with HotChocolate.Types. + # Deprecations Things that will continue to function this release, but we encourage you to move away from. From a7a87ca0815e5ae81a25cb40d15b003e3184c324 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 27 Nov 2025 10:25:25 +0100 Subject: [PATCH 06/42] wip --- src/All.slnx | 1 - src/HotChocolate/Core/HotChocolate.Core.slnx | 1 - .../src/Types.Shared/WellKnownDirectives.cs | 13 - .../Core/src/Types.Shared/WellKnownTypes.cs | 20 - .../Processing/IOptionalSelection.cs | 2 +- .../Types/Execution/Processing/Operation.cs | 10 + .../Core/src/Types/HotChocolate.Types.csproj | 44 +- .../Properties/TextJsonResources.Designer.cs | 90 +++ .../Types/Properties/TextJsonResources.resx | 42 ++ .../Core/src/Types/SchemaBuilder.Setup.cs | 1 - .../Core/src/Types/SchemaPrinter.cs | 1 - .../Text/Json/CompositeResultProperty.cs | 123 +++ .../Types/Text/Json/ResultDocument.Text.cs | 205 +++++ .../Json/ResultDocument.TryGetProperty.cs | 251 ++++++ .../Text/Json/ResultDocument.TryGetValue.cs | 226 ++++++ .../Types/Text/Json/ResultDocument.WriteTo.cs | 313 ++++++++ .../src/Types/Text/Json/ResultDocument.cs | 60 +- .../Json/ResultElement.ArrayEnumerator.cs | 100 +++ .../Json/ResultElement.ObjectEnumerator.cs | 127 ++++ .../Core/src/Types/Text/Json/ResultElement.cs | 713 ++++++++++++++++++ .../Text/Json/JsonReaderHelper.cs | 7 + .../Fusion.Execution/Text/Json/ThrowHelper.cs | 7 + .../src/Primitives/Types}/BuiltInTypes.cs | 42 +- .../Types/IntrospectionTypeNames.cs | 15 + ...otChocolate.Utilities.Introspection.csproj | 2 +- .../IntrospectionClient.cs | 1 + .../IntrospectionFormatter.cs | 6 +- 27 files changed, 2325 insertions(+), 98 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Types.Shared/WellKnownDirectives.cs delete mode 100644 src/HotChocolate/Core/src/Types.Shared/WellKnownTypes.cs create mode 100644 src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs create mode 100644 src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Text.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetValue.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ArrayEnumerator.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs create mode 100644 src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs rename src/HotChocolate/{Core/src/Types.Shared => Primitives/src/Primitives/Types}/BuiltInTypes.cs (60%) create mode 100644 src/HotChocolate/Primitives/src/Primitives/Types/IntrospectionTypeNames.cs diff --git a/src/All.slnx b/src/All.slnx index d6a71a909b4..a0dedb768b2 100644 --- a/src/All.slnx +++ b/src/All.slnx @@ -110,7 +110,6 @@ - diff --git a/src/HotChocolate/Core/HotChocolate.Core.slnx b/src/HotChocolate/Core/HotChocolate.Core.slnx index 2f8095bec3b..64c576bc86a 100644 --- a/src/HotChocolate/Core/HotChocolate.Core.slnx +++ b/src/HotChocolate/Core/HotChocolate.Core.slnx @@ -27,7 +27,6 @@ - diff --git a/src/HotChocolate/Core/src/Types.Shared/WellKnownDirectives.cs b/src/HotChocolate/Core/src/Types.Shared/WellKnownDirectives.cs deleted file mode 100644 index 62a1fecea18..00000000000 --- a/src/HotChocolate/Core/src/Types.Shared/WellKnownDirectives.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace HotChocolate.Utilities.Introspection; - -internal static class WellKnownDirectives -{ - public const string Skip = "skip"; - public const string Include = "include"; - public const string Defer = "defer"; - public const string Stream = "stream"; - public const string Deprecated = "deprecated"; - public const string SpecifiedBy = "specifiedBy"; - public const string DeprecationReasonArgument = "reason"; - public const string OneOf = "oneOf"; -} diff --git a/src/HotChocolate/Core/src/Types.Shared/WellKnownTypes.cs b/src/HotChocolate/Core/src/Types.Shared/WellKnownTypes.cs deleted file mode 100644 index 3749d2bfa4f..00000000000 --- a/src/HotChocolate/Core/src/Types.Shared/WellKnownTypes.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace HotChocolate.Utilities.Introspection; - -internal static class WellKnownTypes -{ -#pragma warning disable IDE1006, InconsistentNaming - public const string __Directive = "__Directive"; - public const string __DirectiveLocation = "__DirectiveLocation"; - public const string __EnumValue = "__EnumValue"; - public const string __Field = "__Field"; - public const string __InputValue = "__InputValue"; - public const string __Schema = "__Schema"; - public const string __Type = "__Type"; - public const string __TypeKind = "__TypeKind"; -#pragma warning restore IDE1006, InconsistentNaming - public const string String = "String"; - public const string Boolean = "Boolean"; - public const string Float = "Float"; - public const string ID = "ID"; - public const string Int = "Int"; -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs index 8345292c0d3..fb6839101d4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs @@ -27,5 +27,5 @@ public interface IOptionalSelection /// /// True, if this selection shall be included into the request execution. /// - bool IsIncluded(long includeFlags, bool allowInternals = false); + bool IsIncluded(ulong includeFlags, bool allowInternals = false); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index df2bf92e50e..0c2e3384b3f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -200,6 +200,16 @@ internal void Seal( } } + public SelectionSet GetSelectionSetById(int selectionSetId) + { + + } + + public Selection GetSelectionById(int selectionSetId) + { + + } + public IEnumerator GetEnumerator() { foreach (var selectionVariant in _selectionVariants) diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index bf2bed99fa2..ae9e6fe3046 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -77,7 +77,6 @@ - @@ -89,10 +88,18 @@ Text\Json\JsonHelpers.cs + + Text\Json\JsonReaderHelper.cs + + Text\Json\MetaDbEventSource.cs + + Text\Json\ThrowHelper.cs + + ResultDocument.cs @@ -104,6 +111,36 @@ ResultDocument.cs + + + ResultDocument.cs + + + + ResultDocument.cs + + + + ResultDocument.cs + + + + ResultDocument.cs + + + + ResultElement.cs + + + + ResultElement.cs + + + + True + True + TextJsonResources.resx + @@ -200,6 +237,11 @@ ResXFileCodeGenerator Resources.Designer.cs + + + ResXFileCodeGenerator + TextJsonResources.Designer.cs + diff --git a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs new file mode 100644 index 00000000000..47f922f9119 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace HotChocolate.Properties { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TextJsonResources { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TextJsonResources() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("HotChocolate.Properties.TextJsonResources", typeof(TextJsonResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static string CompositeResultElement_GetBoolean_JsonElementHasWrongType { + get { + return ResourceManager.GetString("CompositeResultElement_GetBoolean_JsonElementHasWrongType", resourceCulture); + } + } + + internal static string SourceResultElement_GetBoolean_JsonElementHasWrongType { + get { + return ResourceManager.GetString("SourceResultElement_GetBoolean_JsonElementHasWrongType", resourceCulture); + } + } + + internal static string Rethrowable { + get { + return ResourceManager.GetString("Rethrowable", resourceCulture); + } + } + + internal static string JsonReaderHelper_TranscodeHelper_CannotTranscodeInvalidUtf8 { + get { + return ResourceManager.GetString("JsonReaderHelper_TranscodeHelper_CannotTranscodeInvalidUtf8", resourceCulture); + } + } + + internal static string ThrowHelper_ReadInvalidUTF16 { + get { + return ResourceManager.GetString("ThrowHelper_ReadInvalidUTF16", resourceCulture); + } + } + + internal static string ThrowHelper_ReadIncompleteUTF16 { + get { + return ResourceManager.GetString("ThrowHelper_ReadIncompleteUTF16", resourceCulture); + } + } + + internal static string FixedSizeArrayPool_Return_InvalidArraySize { + get { + return ResourceManager.GetString("FixedSizeArrayPool_Return_InvalidArraySize", resourceCulture); + } + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx new file mode 100644 index 00000000000..9375281edf6 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx @@ -0,0 +1,42 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The requested operation requires an element of type '{0}', but the target element has type '{1}'. + + + The requested operation requires an element of type '{0}', but the target element has type '{1}'. + + + HotChocolate.Text.Json.Rethrowable + + + Cannot transcode invalid UTF-8 JSON text to UTF-16 string. + + + Cannot read invalid UTF-16 JSON text as string. Invalid surrogate value: '{0}'. + + + Cannot read incomplete UTF-16 JSON text as string with missing low surrogate. + + + Buffer size {0} does not match expected chunk size {1} + + diff --git a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs index c274967f213..de9f72c32a7 100644 --- a/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs +++ b/src/HotChocolate/Core/src/Types/SchemaBuilder.Setup.cs @@ -12,7 +12,6 @@ using HotChocolate.Types.Pagination; using HotChocolate.Types.Relay; using HotChocolate.Utilities; -using HotChocolate.Utilities.Introspection; using Microsoft.Extensions.DependencyInjection.Extensions; namespace HotChocolate; diff --git a/src/HotChocolate/Core/src/Types/SchemaPrinter.cs b/src/HotChocolate/Core/src/Types/SchemaPrinter.cs index c0e50daa958..4e4449efb4d 100644 --- a/src/HotChocolate/Core/src/Types/SchemaPrinter.cs +++ b/src/HotChocolate/Core/src/Types/SchemaPrinter.cs @@ -4,7 +4,6 @@ using HotChocolate.Language.Utilities; using HotChocolate.Types; using HotChocolate.Utilities; -using HotChocolate.Utilities.Introspection; namespace HotChocolate; diff --git a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs new file mode 100644 index 00000000000..d34e5576f8c --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs @@ -0,0 +1,123 @@ +using System.Diagnostics; +using System.Text.Json; +using HotChocolate.Fusion.Execution.Nodes; + +namespace HotChocolate.Fusion.Text.Json; + +/// +/// Represents a single property for a JSON object. +/// +[DebuggerDisplay("{DebuggerDisplay,nq}")] +public readonly struct CompositeResultProperty +{ + internal CompositeResultProperty(CompositeResultElement value) + { + Value = value; + } + + /// + /// The value of this property. + /// + public CompositeResultElement Value { get; } + + /// + /// The name of this property. + /// This allocates a new string instance for each call. + /// + public string Name => Value.GetPropertyName(); + + public Selection? Selection => Value.Selection; + + public Selection GetRequiredSelection() => Value.AssertSelection(); + + /// + /// Compares to the name of this property. + /// + /// The text to compare against. + /// + /// if the name of this property matches , + /// otherwise. + /// + /// + /// This value's is not . + /// + /// + /// This method is functionally equal to doing an ordinal comparison of and + /// , but can avoid creating the string instance. + /// + public bool NameEquals(string? text) + { + return NameEquals(text.AsSpan()); + } + + /// + /// Compares the text represented by to the name of this property. + /// + /// The UTF-8 encoded text to compare against. + /// + /// if the name of this property has the same UTF-8 encoding as + /// , otherwise. + /// + /// + /// This value's is not . + /// + /// + /// This method is functionally equal to doing an ordinal comparison of and + /// , but can avoid creating the string instance. + /// + public bool NameEquals(ReadOnlySpan utf8Text) + { + return Value.TextEqualsHelper(utf8Text, isPropertyName: true, shouldUnescape: true); + } + + /// + /// Compares to the name of this property. + /// + /// The text to compare against. + /// + /// if the name of this property matches , + /// otherwise. + /// + /// + /// This value's is not . + /// + /// + /// This method is functionally equal to doing an ordinal comparison of and + /// , but can avoid creating the string instance. + /// + public bool NameEquals(ReadOnlySpan text) + { + return Value.TextEqualsHelper(text, isPropertyName: true); + } + + internal bool EscapedNameEquals(ReadOnlySpan utf8Text) + { + return Value.TextEqualsHelper(utf8Text, isPropertyName: true, shouldUnescape: false); + } + + internal ReadOnlySpan NameSpan => Value.GetPropertyNameRaw(); + + /// + /// Provides a representation of the property for + /// debugging purposes. + /// + /// + /// A string containing the un-interpreted value of the property, beginning + /// at the declaring open-quote and ending at the last character that is part of + /// the value. + /// + public override string ToString() + { + return Value.GetPropertyRawText(); + } + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string DebuggerDisplay + => Value.ValueKind == JsonValueKind.Undefined ? "" : $"\"{ToString()}\""; + + public void Deconstruct(out Selection selection, out CompositeResultElement value) + { + selection = GetRequiredSelection(); + value = Value; + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Text.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Text.cs new file mode 100644 index 00000000000..510e4dc3d01 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.Text.cs @@ -0,0 +1,205 @@ +using System.Buffers; +using System.Diagnostics; +using System.Text.Unicode; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + internal string? GetString(Cursor cursor, ElementTokenType expectedType) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + var tokenType = row.TokenType; + + if (tokenType == ElementTokenType.Null) + { + return null; + } + + CheckExpectedType(expectedType, tokenType); + + var segment = ReadRawValue(row); + + if (tokenType is ElementTokenType.String) + { + segment = segment[1..^1]; + } + + return row.HasComplexChildren + ? JsonReaderHelper.GetUnescapedString(segment) + : JsonReaderHelper.TranscodeHelper(segment); + } + + internal string GetRequiredString(Cursor cursor, ElementTokenType expectedType) + { + var value = GetString(cursor, expectedType); + + if (value is null) + { + throw new InvalidOperationException("The element value is null."); + } + + return value; + } + + internal string GetNameOfPropertyValue(Cursor valueCursor) + { + // The property name is one row before the property value + return GetString(valueCursor + (-1), ElementTokenType.PropertyName)!; + } + + internal ReadOnlySpan GetPropertyNameRaw(Cursor valueCursor) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + // The property name is stored one row before the value + var nameCursor = valueCursor + (-1); + var row = _metaDb.Get(nameCursor); + Debug.Assert(row.TokenType is ElementTokenType.PropertyName); + + return ReadRawValue(row); + } + + internal string GetRawValueAsString(Cursor cursor) + { + var segment = GetRawValue(cursor, includeQuotes: true); + return JsonReaderHelper.TranscodeHelper(segment); + } + + internal ReadOnlySpan GetRawValue(Cursor cursor, bool includeQuotes) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + + if (row.IsSimpleValue) + { + if (!includeQuotes && row.TokenType == ElementTokenType.String) + { + // Skip opening/closing quotes + return ReadRawValue(row)[1..^1]; + } + + return ReadRawValue(row); + } + + // TODO: this is more complex with the new design, we gonna tackle this later. + // var endCursor = GetEndCursor(cursor, includeEndElement: false); + // var start = row.Location; + // var endRow = _metaDb.Get(endCursor); + // return _utf8Json.Slice(start, endRow.Location - start + endRow.SizeOrLength); + throw new NotImplementedException(); + } + + internal string GetPropertyRawValueAsString(Cursor valueCursor) + { + var segment = GetPropertyRawValue(valueCursor); + return JsonReaderHelper.TranscodeHelper(segment); + } + + private ReadOnlySpan GetPropertyRawValue(Cursor valueCursor) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + // The property name is stored one row before the value + Debug.Assert(_metaDb.GetElementTokenType(valueCursor - 1) == ElementTokenType.PropertyName); + + var row = _metaDb.Get(valueCursor); + + if (row.IsSimpleValue) + { + return ReadRawValue(row); + } + + // var endCursor = GetEndCursor(valueCursor, includeEndElement: false); + // var endRow = _metaDb.Get(endCursor); + // return _utf8Json.Slice(start, end - start); + throw new NotSupportedException("Properties are expected to be simple values."); + } + + internal bool TextEquals(Cursor cursor, ReadOnlySpan otherText, bool isPropertyName) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + byte[]? otherUtf8TextArray = null; + + var length = checked(otherText.Length * JsonConstants.MaxExpansionFactorWhileTranscoding); + var otherUtf8Text = length <= JsonConstants.StackallocByteThreshold + ? stackalloc byte[JsonConstants.StackallocByteThreshold] + : (otherUtf8TextArray = ArrayPool.Shared.Rent(length)); + + var status = Utf8.FromUtf16( + otherText, otherUtf8Text, out var charsRead, out var written, + replaceInvalidSequences: false, isFinalBlock: true); + + Debug.Assert(status is OperationStatus.Done or + OperationStatus.DestinationTooSmall or + OperationStatus.InvalidData); + Debug.Assert(charsRead == otherText.Length || status is not OperationStatus.Done); + + bool result; + if (status == OperationStatus.InvalidData) + { + result = false; + } + else + { + Debug.Assert(status == OperationStatus.Done); + result = TextEquals(cursor, otherUtf8Text[..written], isPropertyName, shouldUnescape: true); + } + + if (otherUtf8TextArray != null) + { + otherUtf8Text[..written].Clear(); + ArrayPool.Shared.Return(otherUtf8TextArray); + } + + return result; + } + + internal bool TextEquals(Cursor cursor, ReadOnlySpan otherUtf8Text, bool isPropertyName, bool shouldUnescape) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var matchCursor = isPropertyName ? cursor + (-1) : cursor; + var row = _metaDb.Get(matchCursor); + + CheckExpectedType( + isPropertyName ? ElementTokenType.PropertyName : ElementTokenType.String, + row.TokenType); + + var segment = ReadRawValue(row); + + if (!isPropertyName) + { + segment = segment[1..^1]; + } + + if (otherUtf8Text.Length > segment.Length || (!shouldUnescape && otherUtf8Text.Length != segment.Length)) + { + return false; + } + + if (row.HasComplexChildren && shouldUnescape) + { + if (otherUtf8Text.Length < segment.Length / JsonConstants.MaxExpansionFactorWhileEscaping) + { + return false; + } + + var idx = segment.IndexOf(JsonConstants.BackSlash); + Debug.Assert(idx != -1); + + if (!otherUtf8Text.StartsWith(segment[..idx])) + { + return false; + } + + return JsonReaderHelper.UnescapeAndCompare(segment[idx..], otherUtf8Text[idx..]); + } + + return segment.SequenceEqual(otherUtf8Text); + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs new file mode 100644 index 00000000000..9fc7679a472 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs @@ -0,0 +1,251 @@ +using System.Buffers; +using System.Diagnostics; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + internal bool TryGetNamedPropertyValue( + Cursor startCursor, + string propertyName, + out CompositeResultElement value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + (startCursor, var tokenType) = _metaDb.GetStartCursor(startCursor); + CheckExpectedType(ElementTokenType.StartObject, tokenType); + + var numberOfRows = _metaDb.GetNumberOfRows(startCursor); + + // Only one row means it was EndObject. + if (numberOfRows == 1) + { + value = default; + return false; + } + + var row = _metaDb.Get(startCursor); + if (row.OperationReferenceType is OperationReferenceType.SelectionSet) + { + var selectionSet = _operation.GetSelectionSetById(row.OperationReferenceId); + if (selectionSet.TryGetSelection(propertyName, out var selection)) + { + var propertyIndex = selection.Id - selectionSet.Id - 1; + var propertyRowIndex = (propertyIndex * 2) + 1; + var propertyCursor = startCursor + propertyRowIndex; + Debug.Assert(_metaDb.GetElementTokenType(propertyCursor) is ElementTokenType.PropertyName); + Debug.Assert(_metaDb.Get(propertyCursor).OperationReferenceId == selection.Id); + value = new CompositeResultElement(this, propertyCursor + 1); + return true; + } + } + + var maxBytes = s_utf8Encoding.GetMaxByteCount(propertyName.Length); + var endCursor = startCursor + (numberOfRows - 1); + + if (maxBytes < JsonConstants.StackallocByteThreshold) + { + Span utf8Name = stackalloc byte[JsonConstants.StackallocByteThreshold]; + var len = s_utf8Encoding.GetBytes(propertyName, utf8Name); + utf8Name = utf8Name[..len]; + + return TryGetNamedPropertyValue( + startCursor + 1, + endCursor, + utf8Name, + out value); + } + + // Unescaping the property name will make the string shorter (or the same) + // So the first viable candidate is one whose length in bytes matches, or + // exceeds, our length in chars. + // + // The maximal escaping seems to be 6 -> 1 ("\u0030" => "0"), but just transcode + // and switch once one viable long property is found. + + var minBytes = propertyName.Length; + var candidate = endCursor; + + while (candidate > startCursor) + { + var passed = candidate; + + row = _metaDb.Get(candidate); + Debug.Assert(row.TokenType != ElementTokenType.PropertyName); + + candidate--; + row = _metaDb.Get(candidate); + Debug.Assert(row.TokenType == ElementTokenType.PropertyName); + + if (row.SizeOrLength >= minBytes) + { + var tmpUtf8 = ArrayPool.Shared.Rent(maxBytes); + Span utf8Name = default; + + try + { + var len = s_utf8Encoding.GetBytes(propertyName, tmpUtf8); + utf8Name = tmpUtf8.AsSpan(0, len); + + return TryGetNamedPropertyValue( + startCursor, + passed + 1, + utf8Name, + out value); + } + finally + { + // While property names aren't usually a secret, they also usually + // aren't long enough to end up in the rented buffer transcode path. + // + // On the basis that this is user data, go ahead and clear it. + utf8Name.Clear(); + ArrayPool.Shared.Return(tmpUtf8); + } + } + + // Move to the previous value + candidate--; + } + + // None of the property names were within the range that the UTF-8 encoding would have been. + value = default; + return false; + } + + internal bool TryGetNamedPropertyValue( + Cursor startCursor, + ReadOnlySpan propertyName, + out CompositeResultElement value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + (startCursor, var tokenType) = _metaDb.GetStartCursor(startCursor); + CheckExpectedType(ElementTokenType.StartObject, tokenType); + + var numberOfRows = _metaDb.GetNumberOfRows(startCursor); + + // Only one row means it was EndObject. + if (numberOfRows == 1) + { + value = default; + return false; + } + + var row = _metaDb.Get(startCursor); + if (row.OperationReferenceType is OperationReferenceType.SelectionSet) + { + var selectionSet = _operation.GetSelectionSetById(row.OperationReferenceId); + if (selectionSet.TryGetSelection(propertyName, out var selection)) + { + var propertyIndex = selection.Id - selectionSet.Id - 1; + var propertyRowIndex = (propertyIndex * 2) + 1; + var propertyCursor = startCursor + propertyRowIndex; + Debug.Assert(_metaDb.GetElementTokenType(propertyCursor) is ElementTokenType.PropertyName); + Debug.Assert(_metaDb.Get(propertyCursor).OperationReferenceId == selection.Id); + value = new CompositeResultElement(this, propertyCursor + 1); + return true; + } + } + + var endCursor = startCursor + (numberOfRows - 1); + + return TryGetNamedPropertyValue( + startCursor + 1, + endCursor, + propertyName, + out value); + } + + private bool TryGetNamedPropertyValue( + Cursor startCursor, + Cursor endCursor, + ReadOnlySpan propertyName, + out CompositeResultElement value) + { + Span utf8UnescapedStack = stackalloc byte[JsonConstants.StackallocByteThreshold]; + var cursor = endCursor; + + while (cursor > startCursor) + { + var row = _metaDb.Get(cursor); + Debug.Assert(row.TokenType != ElementTokenType.PropertyName); + cursor--; + + row = _metaDb.Get(cursor); + Debug.Assert(row.TokenType == ElementTokenType.PropertyName); + var currentPropertyName = ReadRawValue(row); + + if (row.HasComplexChildren) + { + // An escaped property name will be longer than an unescaped candidate, so only unescape + // when the lengths are compatible. + if (currentPropertyName.Length > propertyName.Length) + { + var idx = currentPropertyName.IndexOf(JsonConstants.BackSlash); + Debug.Assert(idx >= 0); + + // If everything up to where the property name has a backslash matches, keep going. + if (propertyName.Length > idx + && currentPropertyName[..idx].SequenceEqual(propertyName[..idx])) + { + var remaining = currentPropertyName.Length - idx; + var written = 0; + byte[]? rented = null; + + try + { + var utf8Unescaped = remaining <= utf8UnescapedStack.Length + ? utf8UnescapedStack + : (rented = ArrayPool.Shared.Rent(remaining)); + + // Only unescape the part we haven't processed. + JsonReaderHelper.Unescape(currentPropertyName[idx..], utf8Unescaped, 0, out written); + + // If the unescaped remainder matches the input remainder, it's a match. + if (utf8Unescaped[..written].SequenceEqual(propertyName[idx..])) + { + // If the property name is a match, the answer is the next element. + value = new CompositeResultElement(this, cursor + 1); + return true; + } + } + finally + { + if (rented != null) + { + rented.AsSpan(0, written).Clear(); + ArrayPool.Shared.Return(rented); + } + } + } + } + } + else if (currentPropertyName.SequenceEqual(propertyName)) + { + // If the property name is a match, the answer is the next element. + value = new CompositeResultElement(this, cursor + 1); + return true; + } + + // Move to the previous value + cursor--; + } + + value = default; + return false; + } + + internal Cursor GetStartCursor(Cursor cursor) + { + ObjectDisposedException.ThrowIf(_disposed, this); + (cursor, _) = _metaDb.GetStartCursor(cursor); + return cursor; + } + + internal Cursor GetEndCursor(Cursor cursor) + { + ObjectDisposedException.ThrowIf(_disposed, this); + return cursor + _metaDb.GetNumberOfRows(cursor); + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetValue.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetValue.cs new file mode 100644 index 00000000000..2794eb02500 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetValue.cs @@ -0,0 +1,226 @@ +using System.Buffers.Text; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument +{ + internal bool TryGetValue(Cursor cursor, out sbyte value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out sbyte tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out byte value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out byte tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out short value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out short tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out ushort value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out ushort tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out int value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out int tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out uint value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out uint tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out long value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out long tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out ulong value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out ulong tmp, out var consumed) + && consumed == rawValue.Length) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out double value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out double tmp, out var bytesConsumed) + && rawValue.Length == bytesConsumed) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out float value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out float tmp, out var bytesConsumed) + && rawValue.Length == bytesConsumed) + { + value = tmp; + return true; + } + + value = 0; + return false; + } + + internal bool TryGetValue(Cursor cursor, out decimal value) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + var row = _metaDb.Get(cursor); + CheckExpectedType(ElementTokenType.Number, row.TokenType); + + var rawValue = ReadRawValue(row); + + if (Utf8Parser.TryParse(rawValue, out decimal tmp, out var bytesConsumed) + && rawValue.Length == bytesConsumed) + { + value = tmp; + return true; + } + + value = 0; + return false; + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs new file mode 100644 index 00000000000..c5c86bd324a --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -0,0 +1,313 @@ +using System.Buffers; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Text.Json; +using HotChocolate.Execution; + +namespace HotChocolate.Text.Json; + +public sealed partial class ResultDocument : IRawJsonFormatter +{ + public void WriteTo(IBufferWriter writer, bool indented = false) + { + var formatter = new RawJsonFormatter(this, writer, indented); + formatter.Write(); + } + + internal ref struct RawJsonFormatter(ResultDocument document, IBufferWriter writer, bool indented) + { + private int _indentLevel = 0; + + public void Write() + { + WriteByte(JsonConstants.OpenBrace); + + if (indented) + { + WriteNewLine(); + _indentLevel++; + } + + if (document._errors?.Count > 0) + { + if (indented) + { + WriteIndent(); + } + + WriteByte(JsonConstants.Quote); + writer.Write(JsonConstants.Errors); + WriteByte(JsonConstants.Quote); + WriteByte(JsonConstants.Colon); + + if (indented) + { + WriteByte(JsonConstants.Space); + } + + var options = new JsonWriterOptions { Indented = indented }; + using var jsonWriter = new Utf8JsonWriter(writer, options); + JsonValueFormatter.WriteErrors( + jsonWriter, + document._errors, + new JsonSerializerOptions(JsonSerializerDefaults.Web), + default); + jsonWriter.Flush(); + + WriteByte(JsonConstants.Comma); + } + + // Write "data": + var root = Cursor.Zero; + var row = document._metaDb.Get(root); + + if (indented) + { + WriteIndent(); + } + + WriteByte(JsonConstants.Quote); + writer.Write(JsonConstants.Data); + WriteByte(JsonConstants.Quote); + WriteByte(JsonConstants.Colon); + + if (indented) + { + WriteByte(JsonConstants.Space); + } + + if (row.TokenType is ElementTokenType.Null + || (ElementFlags.Invalidated & row.Flags) == ElementFlags.Invalidated) + { + writer.Write(JsonConstants.NullValue); + } + else + { + WriteObject(root, row); + } + + if (document.Extensions?.Count > 0) + { + WriteByte(JsonConstants.Comma); + + if (indented) + { + WriteIndent(); + } + + WriteByte(JsonConstants.Quote); + writer.Write(JsonConstants.Extensions); + WriteByte(JsonConstants.Quote); + WriteByte(JsonConstants.Colon); + + if (indented) + { + WriteByte(JsonConstants.Space); + } + + var options = new JsonWriterOptions { Indented = indented }; + using var jsonWriter = new Utf8JsonWriter(writer, options); + JsonValueFormatter.WriteDictionary( + jsonWriter, + document.Extensions, + new JsonSerializerOptions(JsonSerializerDefaults.Web), + default); + jsonWriter.Flush(); + } + + if (indented) + { + _indentLevel--; + WriteNewLine(); + WriteIndent(); + } + + WriteByte(JsonConstants.CloseBrace); + } + + public void WriteValue(Cursor cursor, DbRow row) + { + var tokenType = row.TokenType; + + // Inline reference resolution + if (tokenType is ElementTokenType.Reference) + { + cursor = document._metaDb.GetLocationCursor(cursor); + row = document._metaDb.Get(cursor); + tokenType = row.TokenType; + } + + Debug.Assert(tokenType is not ElementTokenType.Reference); + Debug.Assert(tokenType is not ElementTokenType.EndObject); + Debug.Assert(tokenType is not ElementTokenType.EndArray); + + switch (tokenType) + { + case ElementTokenType.StartObject + when (ElementFlags.SourceResult & row.Flags) != ElementFlags.SourceResult: + WriteObject(cursor, row); + break; + + case ElementTokenType.StartArray + when (ElementFlags.SourceResult & row.Flags) != ElementFlags.SourceResult: + WriteArray(cursor, row); + break; + + case ElementTokenType.None: + case ElementTokenType.Null: + writer.Write(JsonConstants.NullValue); + break; + + case ElementTokenType.True: + writer.Write(JsonConstants.TrueValue); + break; + + case ElementTokenType.False: + writer.Write(JsonConstants.FalseValue); + break; + + default: + document.WriteRawValueTo(writer, row, _indentLevel, indented); + break; + } + } + + private void WriteObject(Cursor start, DbRow startRow) + { + Debug.Assert(startRow.TokenType is ElementTokenType.StartObject); + + var current = start + 1; + var end = start + startRow.NumberOfRows; + + WriteByte(JsonConstants.OpenBrace); + + if (indented && current < end) + { + _indentLevel++; + } + + var first = true; + while (current < end) + { + var row = document._metaDb.Get(current); + Debug.Assert(row.TokenType is ElementTokenType.PropertyName); + + if ((ElementFlags.IsInternal & row.Flags) == ElementFlags.IsInternal + || (ElementFlags.IsExcluded & row.Flags) == ElementFlags.IsExcluded) + { + // skip name+value + current += 2; + continue; + } + + if (!first) + { + WriteByte(JsonConstants.Comma); + } + first = false; + + if (indented) + { + WriteNewLine(); + WriteIndent(); + } + + // property name (quoted) + WriteByte(JsonConstants.Quote); + writer.Write(document.ReadRawValue(row)); + WriteByte(JsonConstants.Quote); + WriteByte(JsonConstants.Colon); + + if (indented) + { + WriteByte(JsonConstants.Space); + } + + // property value + current++; + row = document._metaDb.Get(current); + WriteValue(current, row); + + // next property (move past value) + current++; + } + + if (indented && !first) + { + _indentLevel--; + WriteNewLine(); + WriteIndent(); + } + + WriteByte(JsonConstants.CloseBrace); + } + + private void WriteArray(Cursor start, DbRow startRow) + { + Debug.Assert(startRow.TokenType is ElementTokenType.StartArray); + + var current = start + 1; + var end = start + startRow.NumberOfRows; + + WriteByte(JsonConstants.OpenBracket); + + if (indented && current < end) + { + _indentLevel++; + } + + var first = true; + while (current < end) + { + if (!first) + { + WriteByte(JsonConstants.Comma); + } + first = false; + + if (indented) + { + WriteNewLine(); + WriteIndent(); + } + + var row = document._metaDb.Get(current); + WriteValue(current, row); + + current++; + } + + if (indented && end > start + 1) + { + _indentLevel--; + WriteNewLine(); + WriteIndent(); + } + + WriteByte(JsonConstants.CloseBracket); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private readonly void WriteNewLine() => WriteByte(JsonConstants.NewLineLineFeed); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private readonly void WriteIndent() + { + var indentSize = _indentLevel * 2; + if (indentSize > 0) + { + var span = writer.GetSpan(indentSize); + span[..indentSize].Fill(JsonConstants.Space); + writer.Advance(indentSize); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private readonly void WriteByte(byte value) + { + var span = writer.GetSpan(1); + span[0] = value; + writer.Advance(1); + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index ab09873c494..c34fedfd4ca 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -10,14 +10,13 @@ namespace HotChocolate.Text.Json; public sealed partial class ResultDocument : IDisposable { private static readonly Encoding s_utf8Encoding = Encoding.UTF8; - private readonly IOperation _operation; + private readonly Operation _operation; private readonly ulong _includeFlags; private List? _errors; - private Dictionary? _extensions; internal MetaDb _metaDb; private bool _disposed; - public ResultDocument(IOperation operation, ulong includeFlags) + internal ResultDocument(Operation operation, ulong includeFlags) { _metaDb = MetaDb.CreateForEstimatedRows(Cursor.RowsPerChunk * 8); _operation = operation; @@ -26,41 +25,35 @@ public ResultDocument(IOperation operation, ulong includeFlags) Data = CreateObject(Cursor.Zero, operation.RootSelectionSet); } - public CompositeResultElement Data { get; } + public ResultElement Data { get; } + // we need extra methods to add stuff public List? Errors { get => _errors; internal set => _errors = value; } - public Dictionary? Extensions - { - get => _extensions; - internal set => _extensions = value; - } + public Dictionary? Extensions { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ElementTokenType GetElementTokenType(Cursor cursor) => _metaDb.GetElementTokenType(cursor); [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal IOperation GetOperation() + internal Operation GetOperation() => _operation; - internal ISelectionSet? GetSelectionSet(Cursor cursor) + internal SelectionSet? GetSelectionSet(Cursor cursor) { var row = _metaDb.Get(cursor); - if (row.OperationReferenceType is not OperationReferenceType.SelectionSet) - { - return null; - } - - return _operation.GetSelectionSetById(row.OperationReferenceId); + return row.OperationReferenceType is OperationReferenceType.SelectionSet + ? _operation.GetSelectionSetById(row.OperationReferenceId) + : null; } - internal ISelection? GetSelection(Cursor cursor) + internal Selection? GetSelection(Cursor cursor) { if (cursor == Cursor.Zero) { @@ -81,15 +74,12 @@ internal IOperation GetOperation() } } - if (row.OperationReferenceType is not OperationReferenceType.Selection) - { - return null; - } - - return _operation.GetSelectionById(row.OperationReferenceId); + return row.OperationReferenceType is OperationReferenceType.Selection + ? _operation.GetSelectionById(row.OperationReferenceId) + : null; } - internal CompositeResultElement GetArrayIndexElement(Cursor current, int arrayIndex) + internal ResultElement GetArrayIndexElement(Cursor current, int arrayIndex) { ObjectDisposedException.ThrowIf(_disposed, this); @@ -105,7 +95,7 @@ internal CompositeResultElement GetArrayIndexElement(Cursor current, int arrayIn } // first element is at +1 after StartArray - return new CompositeResultElement(this, start.AddRows(arrayIndex + 1)); + return new ResultElement(this, start.AddRows(arrayIndex + 1)); } internal int GetArrayLength(Cursor current) @@ -195,7 +185,7 @@ internal Path CreatePath(Cursor current) return path; } - internal CompositeResultElement GetParent(Cursor current) + internal ResultElement GetParent(Cursor current) { // The null cursor represents the data object, which is the utmost root. // If we have reached that we simply return an undefined element @@ -226,7 +216,7 @@ internal CompositeResultElement GetParent(Cursor current) Debug.Assert(_metaDb.GetElementTokenType(parent, resolveReferences: false) == ElementTokenType.Reference); } - return new CompositeResultElement(this, parent); + return new ResultElement(this, parent); } internal bool IsInvalidated(Cursor current) @@ -393,7 +383,7 @@ private ReadOnlySpan ReadRawValue(DbRow row) throw new NotSupportedException(); } - internal CompositeResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) + internal ResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) { var startObjectCursor = WriteStartObject(parent, selectionSet.Id); @@ -406,10 +396,10 @@ internal CompositeResultElement CreateObject(Cursor parent, ISelectionSet select WriteEndObject(startObjectCursor, selectionCount); - return new CompositeResultElement(this, startObjectCursor); + return new ResultElement(this, startObjectCursor); } - internal CompositeResultElement CreateArray(Cursor parent, int length) + internal ResultElement CreateArray(Cursor parent, int length) { var cursor = WriteStartArray(parent, length); @@ -420,11 +410,11 @@ internal CompositeResultElement CreateArray(Cursor parent, int length) WriteEndArray(); - return new CompositeResultElement(this, cursor); + return new ResultElement(this, cursor); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AssignCompositeValue(CompositeResultElement target, CompositeResultElement value) + internal void AssignCompositeValue(ResultElement target, ResultElement value) { _metaDb.Replace( cursor: target.Cursor, @@ -434,7 +424,7 @@ internal void AssignCompositeValue(CompositeResultElement target, CompositeResul } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AssignSourceValue(CompositeResultElement target, SourceResultElement source) + internal void AssignSourceValue(ResultElement target, ResultElement source) { var value = source.GetValuePointer(); var parent = source._parent; @@ -476,7 +466,7 @@ internal void AssignSourceValue(CompositeResultElement target, SourceResultEleme } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AssignNullValue(CompositeResultElement target) + internal void AssignNullValue(ResultElement target) { _metaDb.Replace( cursor: target.Cursor, diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ArrayEnumerator.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ArrayEnumerator.cs new file mode 100644 index 00000000000..b7a04e9ec98 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ArrayEnumerator.cs @@ -0,0 +1,100 @@ +using System.Collections; +using System.Diagnostics; + +namespace HotChocolate.Text.Json; + +public readonly partial struct ResultElement +{ + /// + /// An enumerable and enumerator for the contents of a JSON array. + /// + [DebuggerDisplay("{Current,nq}")] + public struct ArrayEnumerator : IEnumerable, IEnumerator + { + private readonly ResultDocument _document; + private readonly ResultDocument.Cursor _start; + private readonly ResultDocument.Cursor _end; + private ResultDocument.Cursor _cursor; + + internal ArrayEnumerator(ResultElement target) + { + _document = target._parent; + (_start, var tokenType) = _document._metaDb.GetStartCursor(target._cursor); + Debug.Assert(tokenType is ElementTokenType.StartArray); + _end = _start + _document._metaDb.GetNumberOfRows(_start); + _cursor = _start; + } + + /// + public ResultElement Current + { + get + { + var cursor = _cursor; + if (cursor == _start || cursor >= _end) + { + return default; + } + + return new ResultElement(_document, cursor); + } + } + + /// + object IEnumerator.Current => Current; + + /// + /// Returns an enumerator that iterates through the array. + /// + public ArrayEnumerator GetEnumerator() + { + var enumerator = this; + enumerator._cursor = enumerator._start; + return enumerator; + } + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public bool MoveNext() + { + var start = _start; + var end = _end; + + if (_cursor == start) + { + var first = start + 1; + if (first < end) + { + _cursor = first; + return true; + } + + _cursor = end; + return false; + } + + var next = _cursor + 1; + if (next < end) + { + _cursor = next; + return true; + } + + _cursor = end; + return false; + } + + /// + public void Reset() => _cursor = _start; + + /// + public void Dispose() => _cursor = _end; + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs new file mode 100644 index 00000000000..58d8d5d163b --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs @@ -0,0 +1,127 @@ +using System.Collections; +using System.Diagnostics; +using static HotChocolate.Fusion.Text.Json.CompositeResultDocument; + +namespace HotChocolate.Text.Json; + +public readonly partial struct ResultElement +{ + /// + /// An enumerable and enumerator for the properties of a JSON object. + /// + [DebuggerDisplay("{Current,nq}")] + public struct ObjectEnumerator : IEnumerable, IEnumerator + { + private readonly CompositeResultDocument _document; + private readonly Cursor _start; + private readonly Cursor _end; + private Cursor _cursor; + + internal ObjectEnumerator(CompositeResultElement target) + { + _document = target._parent; + (_start, var tokenType) = _document._metaDb.GetStartCursor(target._cursor); + Debug.Assert(tokenType is ElementTokenType.StartObject); + _end = _start + _document._metaDb.GetNumberOfRows(_start); + _cursor = _start; + } + + /// + public CompositeResultProperty Current + { + get + { + if (_cursor == _start || _cursor >= _end) + { + return default; + } + + return new CompositeResultProperty(new CompositeResultElement(_document, _cursor + 1)); + } + } + + /// + /// Returns an enumerator that iterates the properties of an object. + /// + /// + /// An value that can be used to iterate + /// through the object. + /// + /// + /// The enumerator will enumerate the properties in the order they are + /// declared, and when an object has multiple definitions of a single + /// property they will all individually be returned (each in the order + /// they appear in the content). + /// + public ObjectEnumerator GetEnumerator() + { + var enumerator = this; + enumerator._cursor = enumerator._start; + return enumerator; + } + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + /// + public void Dispose() + { + _cursor = _end; + } + + /// + public void Reset() + { + _cursor = _start; + } + + /// + object IEnumerator.Current => Current; + + /// + public bool MoveNext() + { + while (MoveNextInternal()) + { + var flags = _document._metaDb.GetFlags(_cursor); + if ((ElementFlags.IsExcluded & flags) is not ElementFlags.IsExcluded) + { + return true; + } + } + + return false; + } + + private bool MoveNextInternal() + { + if (_cursor == _start) + { + var first = _start + 1; + if (first < _end) + { + _cursor = first; + return true; + } + + _cursor = _end; + return false; + } + + var next = _cursor += 2; + if (next < _end) + { + _cursor = next; + return true; + } + + _cursor = _end; + return false; + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs new file mode 100644 index 00000000000..94b91ddb9bf --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -0,0 +1,713 @@ +using System.Buffers; +using System.Diagnostics; +using System.Text.Json; +using HotChocolate.Execution; +using HotChocolate.Execution.Processing; +using HotChocolate.Types; +using static HotChocolate.Properties.TextJsonResources; + +#pragma warning disable CS1574, CS1584, CS1581, CS1580 + +namespace HotChocolate.Text.Json; + +public readonly partial struct ResultElement : IRawJsonFormatter +{ + private readonly ResultDocument _parent; + private readonly ResultDocument.Cursor _cursor; + + internal ResultElement(ResultDocument parent, ResultDocument.Cursor cursor) + { + // parent is usually not null, but the Current property + // on the enumerators (when initialized as `default`) can + // get here with a null. + _parent = parent; + _cursor = cursor; + } + + public void WriteTo(IBufferWriter writer, bool indented = false) + { + var formatter = new ResultDocument.RawJsonFormatter(_parent, writer, indented); + + var row = _parent._metaDb.Get(_cursor); + formatter.WriteValue(_cursor, row); + } + + /// + /// Gets the internal meta-db cursor. + /// + internal ResultDocument.Cursor Cursor => _cursor; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ElementTokenType TokenType => _parent?.GetElementTokenType(_cursor) ?? ElementTokenType.None; + + /// + /// The that the value is. + /// + /// + /// The parent has been disposed. + /// + public JsonValueKind ValueKind => TokenType.ToValueKind(); + + /// + /// Get the value at a specified index when the current value is a + /// . + /// + /// + /// This value's is not . + /// + /// + /// is not in the range [0, ()). + /// + /// + /// The parent has been disposed. + /// + public ResultElement this[int index] + { + get + { + CheckValidInstance(); + + return _parent.GetArrayIndexElement(_cursor, index); + } + } + + public IOperation Operation + { + get + { + CheckValidInstance(); + + return _parent.GetOperation(); + } + } + + public ISelectionSet? SelectionSet + { + get + { + CheckValidInstance(); + + return _parent.GetSelectionSet(_cursor); + } + } + + public ISelection? Selection + { + get + { + CheckValidInstance(); + + if (_cursor == ResultDocument.Cursor.Zero) + { + return null; + } + + // note: the selection is stored on the property not on the value. + return _parent.GetSelection(_cursor - 1); + } + } + + public IType? Type + { + get + { + if (_cursor == ResultDocument.Cursor.Zero) + { + return null; + } + + var selection = Selection; + + if (selection is not null) + { + return selection.Type; + } + + var type = Parent.Type; + + if (type?.IsListType() == true) + { + return type.ElementType(); + } + + return null; + } + } + + public bool IsInvalidated + { + get + { + CheckValidInstance(); + + return _parent.IsInvalidated(_cursor); + } + } + + public bool IsNullOrInvalidated + { + get + { + if (_parent is null) + { + return true; + } + + return _parent.IsNullOrInvalidated(_cursor); + } + } + + public Path Path + { + get + { + CheckValidInstance(); + + return _parent.CreatePath(_cursor); + } + } + + public ResultElement Parent + { + get + { + CheckValidInstance(); + + return _parent.GetParent(_cursor); + } + } + + public bool IsNullable + { + get + { + CheckValidInstance(); + + if (_cursor == ResultDocument.Cursor.Zero) + { + return false; + } + + return Type?.IsNullableType() ?? true; + } + } + + public bool IsInternal + { + get + { + CheckValidInstance(); + + return _parent.IsInternalProperty(_cursor); + } + } + + public ISelectionSet AssertSelectionSet() + { + var selectionSet = SelectionSet; + + if (selectionSet is null) + { + throw new InvalidOperationException("The selection set is null.") { Source = Rethrowable }; + } + + return selectionSet; + } + + public ISelection AssertSelection() + { + var selection = Selection; + + if (selection is null) + { + throw new InvalidOperationException("The selection set is null.") { Source = Rethrowable }; + } + + return selection; + } + + public IType AssertType() + { + var type = Type; + + if (type is null) + { + throw new InvalidOperationException("The type is null.") { Source = Rethrowable }; + } + + return type; + } + + public void Invalidate() + { + CheckValidInstance(); + + _parent.Invalidate(_cursor); + } + + /// + /// Get the number of values contained within the current array value. + /// + public int GetArrayLength() + { + CheckValidInstance(); + + return _parent.GetArrayLength(_cursor); + } + + /// + /// Get the number of properties contained within the current object value. + /// + public int GetPropertyCount() + { + CheckValidInstance(); + + return _parent.GetPropertyCount(_cursor); + } + + public ResultElement GetProperty(string propertyName) + { + ArgumentNullException.ThrowIfNull(propertyName); + + if (TryGetProperty(propertyName, out var property)) + { + return property; + } + + throw new KeyNotFoundException(); + } + + public ResultElement GetProperty(ReadOnlySpan utf8PropertyName) + { + if (TryGetProperty(utf8PropertyName, out var property)) + { + return property; + } + + throw new KeyNotFoundException(); + } + + public bool TryGetProperty(string propertyName, out ResultElement value) + { + ArgumentNullException.ThrowIfNull(propertyName); + + return _parent.TryGetNamedPropertyValue(_cursor, propertyName, out value); + } + + public bool TryGetProperty(ReadOnlySpan utf8PropertyName, out ResultElement value) + { + CheckValidInstance(); + + return _parent.TryGetNamedPropertyValue(_cursor, utf8PropertyName, out value); + } + + public bool GetBoolean() + { + var type = TokenType; + + return type switch + { + ElementTokenType.True => true, + ElementTokenType.False => false, + _ => ThrowJsonElementWrongTypeException(type) + }; + + static bool ThrowJsonElementWrongTypeException(ElementTokenType actualType) + { + throw new InvalidOperationException(string.Format( + ResultElement_GetBoolean_JsonElementHasWrongType, + nameof(Boolean), + actualType.ToValueKind())) + { + Source = Rethrowable + }; + } + } + + public string? GetString() + { + CheckValidInstance(); + + return _parent.GetString(_cursor, ElementTokenType.String); + } + + public string AssertString() + { + CheckValidInstance(); + + return _parent.GetRequiredString(_cursor, ElementTokenType.String); + } + + public bool TryGetSByte(out sbyte value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public sbyte GetSByte() => TryGetSByte(out var value) ? value : throw new FormatException(); + + public bool TryGetByte(out byte value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public byte GetByte() + { + if (TryGetByte(out var value)) + { + return value; + } + + throw new FormatException(); + } + + public bool TryGetInt16(out short value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public short GetInt16() + { + if (TryGetInt16(out var value)) + { + return value; + } + + throw new FormatException(); + } + + public bool TryGetUInt16(out ushort value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public ushort GetUInt16() + { + if (TryGetUInt16(out var value)) + { + return value; + } + + throw new FormatException(); + } + + public bool TryGetInt32(out int value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public int GetInt32() + { + if (!TryGetInt32(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetUInt32(out uint value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public uint GetUInt32() + { + if (!TryGetUInt32(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetInt64(out long value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public long GetInt64() + { + if (!TryGetInt64(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetUInt64(out ulong value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public ulong GetUInt64() + { + if (!TryGetUInt64(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetDouble(out double value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public double GetDouble() + { + if (!TryGetDouble(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetSingle(out float value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public float GetSingle() + { + if (!TryGetSingle(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + public bool TryGetDecimal(out decimal value) + { + CheckValidInstance(); + + return _parent.TryGetValue(_cursor, out value); + } + + public decimal GetDecimal() + { + if (!TryGetDecimal(out var value)) + { + ThrowHelper.FormatException(); + } + + return value; + } + + internal string GetPropertyName() + { + CheckValidInstance(); + + return _parent.GetNameOfPropertyValue(_cursor); + } + + internal ReadOnlySpan GetPropertyNameRaw() + { + CheckValidInstance(); + + return _parent.GetPropertyNameRaw(_cursor); + } + + public string GetRawText() + { + CheckValidInstance(); + + return _parent.GetRawValueAsString(_cursor); + } + + internal ReadOnlySpan GetRawValue(bool includeQuotes = true) + { + CheckValidInstance(); + + return _parent.GetRawValue(_cursor, includeQuotes: true); + } + + public bool ValueEquals(string? text) + { + if (TokenType == ElementTokenType.Null) + { + return text == null; + } + + return TextEqualsHelper(text.AsSpan(), isPropertyName: false); + } + + public bool ValueEquals(ReadOnlySpan utf8Text) + { + if (TokenType == ElementTokenType.Null) + { +#pragma warning disable CA2265 + return utf8Text[..0] == default; +#pragma warning restore CA2265 + } + + return TextEqualsHelper(utf8Text, isPropertyName: false, shouldUnescape: true); + } + + public bool ValueEquals(ReadOnlySpan text) + { + if (TokenType == ElementTokenType.Null) + { +#pragma warning disable CA2265 + return text[..0] == default; +#pragma warning restore CA2265 + } + + return TextEqualsHelper(text, isPropertyName: false); + } + + internal bool TextEqualsHelper(ReadOnlySpan utf8Text, bool isPropertyName, bool shouldUnescape) + { + CheckValidInstance(); + + return _parent.TextEquals(_cursor, utf8Text, isPropertyName, shouldUnescape); + } + + internal bool TextEqualsHelper(ReadOnlySpan text, bool isPropertyName) + { + CheckValidInstance(); + + return _parent.TextEquals(_cursor, text, isPropertyName); + } + + internal string GetPropertyRawText() + { + CheckValidInstance(); + + return _parent.GetPropertyRawValueAsString(_cursor); + } + + public ArrayEnumerator EnumerateArray() + { + CheckValidInstance(); + + var tokenType = TokenType; + + if (tokenType != ElementTokenType.StartArray) + { + throw new InvalidOperationException(string.Format( + "The requested operation requires an element of type '{0}', but the target element has type '{1}'.", + ElementTokenType.StartArray, + tokenType)) + { + Source = Rethrowable + }; + } + + return new ArrayEnumerator(this); + } + + public ObjectEnumerator EnumerateObject() + { + CheckValidInstance(); + + var tokenType = TokenType; + + if (tokenType is not ElementTokenType.StartObject) + { + throw new InvalidOperationException(string.Format( + "The requested operation requires an element of type '{0}', but the target element has type '{1}'.", + ElementTokenType.StartObject, + tokenType)); + } + + return new ObjectEnumerator(this); + } + + internal void SetObjectValue(SelectionSet selectionSet) + { + CheckValidInstance(); + + ArgumentNullException.ThrowIfNull(selectionSet); + + var obj = _parent.CreateObject(_cursor, selectionSet: selectionSet); + _parent.AssignCompositeValue(this, obj); + } + + internal void SetArrayValue(int length) + { + CheckValidInstance(); + + ArgumentOutOfRangeException.ThrowIfNegative(length); + + var arr = _parent.CreateArray(_cursor, length); + _parent.AssignCompositeValue(this, arr); + } + + internal void SetLeafValue(SourceResultElement source) + { + CheckValidInstance(); + + _parent.AssignSourceValue(this, source); + } + + internal void SetNullValue() + { + CheckValidInstance(); + + _parent.AssignNullValue(this); + } + + public override string ToString() + { + switch (TokenType) + { + case ElementTokenType.None: + case ElementTokenType.Null: + return string.Empty; + + case ElementTokenType.True: + return bool.TrueString; + + case ElementTokenType.False: + return bool.FalseString; + + case ElementTokenType.Number: + case ElementTokenType.StartArray: + case ElementTokenType.StartObject: + Debug.Assert(_parent != null); + return _parent.GetRawValueAsString(_cursor); + + case ElementTokenType.String: + return GetString()!; + + case ElementTokenType.Comment: + case ElementTokenType.EndArray: + case ElementTokenType.EndObject: + default: + Debug.Fail($"No handler for {nameof(JsonTokenType)}.{TokenType}"); + return string.Empty; + } + } + + private void CheckValidInstance() + { + if (_parent == null) + { + throw new InvalidOperationException(); + } + } +} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs index 8f3d1a55222..100366d0af1 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs @@ -4,9 +4,16 @@ using System.Runtime.CompilerServices; using System.Text; using System.Text.Json; + +#if FUSION using static HotChocolate.Fusion.Properties.FusionExecutionResources; namespace HotChocolate.Fusion.Text.Json; +#else +using static HotChocolate.Properties.TypeResources; + +namespace HotChocolate.Text.Json; +#endif internal static class JsonReaderHelper { diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/ThrowHelper.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/ThrowHelper.cs index 992c9511d9d..5461a82bcee 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/ThrowHelper.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/ThrowHelper.cs @@ -1,7 +1,14 @@ using System.Diagnostics.CodeAnalysis; + +#if FUSION using static HotChocolate.Fusion.Properties.FusionExecutionResources; namespace HotChocolate.Fusion.Text.Json; +#else +using static HotChocolate.Properties.TextJsonResources; + +namespace HotChocolate.Text.Json; +#endif internal static class ThrowHelper { diff --git a/src/HotChocolate/Core/src/Types.Shared/BuiltInTypes.cs b/src/HotChocolate/Primitives/src/Primitives/Types/BuiltInTypes.cs similarity index 60% rename from src/HotChocolate/Core/src/Types.Shared/BuiltInTypes.cs rename to src/HotChocolate/Primitives/src/Primitives/Types/BuiltInTypes.cs index ba792c03e00..16d5e401aca 100644 --- a/src/HotChocolate/Core/src/Types.Shared/BuiltInTypes.cs +++ b/src/HotChocolate/Primitives/src/Primitives/Types/BuiltInTypes.cs @@ -1,35 +1,35 @@ using HotChocolate.Language; -namespace HotChocolate.Utilities.Introspection; +namespace HotChocolate.Types; public static class BuiltInTypes { private static readonly HashSet s_typeNames = [ - WellKnownTypes.__Directive, - WellKnownTypes.__DirectiveLocation, - WellKnownTypes.__EnumValue, - WellKnownTypes.__Field, - WellKnownTypes.__InputValue, - WellKnownTypes.__Schema, - WellKnownTypes.__Type, - WellKnownTypes.__TypeKind, - WellKnownTypes.String, - WellKnownTypes.Boolean, - WellKnownTypes.Float, - WellKnownTypes.ID, - WellKnownTypes.Int + IntrospectionTypeNames.__Directive, + IntrospectionTypeNames.__DirectiveLocation, + IntrospectionTypeNames.__EnumValue, + IntrospectionTypeNames.__Field, + IntrospectionTypeNames.__InputValue, + IntrospectionTypeNames.__Schema, + IntrospectionTypeNames.__Type, + IntrospectionTypeNames.__TypeKind, + SpecScalarNames.String.Name, + SpecScalarNames.Boolean.Name, + SpecScalarNames.Float.Name, + SpecScalarNames.ID.Name, + SpecScalarNames.Int.Name ]; private static readonly HashSet s_directiveNames = [ - WellKnownDirectives.Skip, - WellKnownDirectives.Include, - WellKnownDirectives.Deprecated, - WellKnownDirectives.Defer, - WellKnownDirectives.Stream, - WellKnownDirectives.SpecifiedBy, - WellKnownDirectives.OneOf + DirectiveNames.Skip.Name, + DirectiveNames.Include.Name, + DirectiveNames.Deprecated.Name, + DirectiveNames.Defer.Name, + DirectiveNames.Stream.Name, + DirectiveNames.SpecifiedBy.Name, + DirectiveNames.OneOf.Name ]; public static bool IsBuiltInType(string name) diff --git a/src/HotChocolate/Primitives/src/Primitives/Types/IntrospectionTypeNames.cs b/src/HotChocolate/Primitives/src/Primitives/Types/IntrospectionTypeNames.cs new file mode 100644 index 00000000000..9057e806224 --- /dev/null +++ b/src/HotChocolate/Primitives/src/Primitives/Types/IntrospectionTypeNames.cs @@ -0,0 +1,15 @@ +namespace HotChocolate.Types; + +public static class IntrospectionTypeNames +{ + // ReSharper disable InconsistentNaming + public const string __Directive = nameof(__Directive); + public const string __DirectiveLocation = nameof(__DirectiveLocation); + public const string __EnumValue = nameof(__EnumValue); + public const string __Field = nameof(__Field); + public const string __InputValue = nameof(__InputValue); + public const string __Schema = nameof(__Schema); + public const string __Type = nameof(__Type); + public const string __TypeKind = nameof(__TypeKind); + // ReSharper restore InconsistentNaming +} diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/HotChocolate.Utilities.Introspection.csproj b/src/HotChocolate/Utilities/src/Utilities.Introspection/HotChocolate.Utilities.Introspection.csproj index a014d417a25..bef5c3c11aa 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/HotChocolate.Utilities.Introspection.csproj +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/HotChocolate.Utilities.Introspection.csproj @@ -24,8 +24,8 @@ - + diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionClient.cs b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionClient.cs index afe9cdbf646..b223c7cf5be 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionClient.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionClient.cs @@ -2,6 +2,7 @@ using System.Text.Json; using HotChocolate.Language; using HotChocolate.Transport.Http; +using HotChocolate.Types; using static HotChocolate.Utilities.Introspection.CapabilityInspector; using static HotChocolate.Utilities.Introspection.IntrospectionQueryHelper; diff --git a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs index 16443d7a052..0748992eabd 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs +++ b/src/HotChocolate/Utilities/src/Utilities.Introspection/IntrospectionFormatter.cs @@ -1,5 +1,7 @@ using HotChocolate.Language; +using HotChocolate.Types; using HotChocolate.Utilities.Introspection.Properties; +using DirectiveLocation = HotChocolate.Language.DirectiveLocation; namespace HotChocolate.Utilities.Introspection; @@ -333,10 +335,10 @@ private static IReadOnlyList CreateDeprecatedDirective( { new DirectiveNode ( - WellKnownDirectives.Deprecated, + DirectiveNames.Deprecated.Name, new ArgumentNode ( - WellKnownDirectives.DeprecationReasonArgument, + DirectiveNames.Deprecated.Arguments.Reason, new StringValueNode(deprecationReason) ) ) From 3fd40c3ba40fe33fba16a012b74da788cf58187b Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 27 Nov 2025 15:30:50 +0100 Subject: [PATCH 07/42] wip --- .../Types/Execution/Processing/Fragment.cs | 10 +- .../Types/Execution/Processing/ISelection.cs | 5 + .../Types/Execution/Processing/Selection.cs | 17 +- .../Properties/TextJsonResources.Designer.cs | 16 +- .../Types/Properties/TextJsonResources.resx | 12 +- .../Types/Text/Json/ResultDocument.DbRow.cs | 63 +-- .../Types/Text/Json/ResultDocument.MetaDb.cs | 53 +- .../Json/ResultDocument.TryGetProperty.cs | 14 +- .../Types/Text/Json/ResultDocument.WriteTo.cs | 2 +- .../src/Types/Text/Json/ResultDocument.cs | 360 +++++++++--- .../Json/ResultElement.ObjectEnumerator.cs | 14 +- .../Core/src/Types/Text/Json/ResultElement.cs | 526 +++++++++++++++++- ...iteResultProperty.cs => ResultProperty.cs} | 18 +- .../Text/Json/CompositeResultElement.cs | 302 +++++++++- .../Text/Json/CompositeResultProperty.cs | 4 +- 15 files changed, 1193 insertions(+), 223 deletions(-) rename src/HotChocolate/Core/src/Types/Text/Json/{CompositeResultProperty.cs => ResultProperty.cs} (89%) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs index 713b9cb28df..3e3d2a1c42c 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs @@ -5,8 +5,8 @@ namespace HotChocolate.Execution.Processing; internal sealed class Fragment : IFragment { - private readonly long _includeCondition; - private readonly long _deferIfCondition; + private readonly ulong _includeCondition; + private readonly ulong _deferIfCondition; public Fragment( int id, @@ -14,8 +14,8 @@ public Fragment( ISyntaxNode syntaxNode, IReadOnlyList directives, ISelectionSet selectionSet, - long includeCondition, - long deferIfCondition, + ulong includeCondition, + ulong deferIfCondition, bool isInternal = false) { Id = id; @@ -45,7 +45,7 @@ public Fragment( public string? GetLabel(IVariableValueCollection variables) => Directives.GetDeferDirective(variables)?.Label; - public bool IsIncluded(long includeFlags, bool allowInternals = false) + public bool IsIncluded(ulong includeFlags, bool allowInternals = false) => (includeFlags & _includeCondition) == _includeCondition && (_deferIfCondition is 0 || (includeFlags & _deferIfCondition) != _deferIfCondition) && (!IsInternal || allowInternals); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs index d4880429f14..f6979a4a84f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs @@ -19,6 +19,11 @@ public interface ISelection : IOptionalSelection /// string ResponseName { get; } + /// + /// Gets the UTF-8 encoded name this field will have in the response map. + /// + byte[] Utf8ResponseName { get; } + /// /// Gets the field that was selected. /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index 309faace72b..1ed864d2455 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Text; using HotChocolate.Execution.Properties; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -12,7 +13,7 @@ namespace HotChocolate.Execution.Processing; public class Selection : ISelection { private static readonly ArgumentMap s_emptyArguments = ArgumentMap.Empty; - private long[] _includeConditions; + private ulong[] _includeConditions; private long _streamIfCondition; private Flags _flags; private FieldNode _syntaxNode; @@ -26,7 +27,7 @@ public Selection( FieldNode syntaxNode, string responseName, ArgumentMap? arguments = null, - long[]? includeConditions = null, + ulong[]? includeConditions = null, bool isInternal = false, bool isParallelExecutable = true, FieldDelegate? resolverPipeline = null, @@ -121,6 +122,10 @@ protected Selection(Selection selection) /// public string ResponseName { get; } + /// + public byte[] Utf8ResponseName => _utf8ResponseName ??= Encoding.UTF8.GetBytes(ResponseName); + private byte[]? _utf8ResponseName; + /// public FieldDelegate? ResolverPipeline { get; private set; } @@ -147,9 +152,9 @@ public bool HasStreamDirective(long includeFlags) public bool IsConditional => _includeConditions.Length > 0 || (_flags & Flags.Internal) == Flags.Internal; - internal ReadOnlySpan IncludeConditions => _includeConditions; + internal ReadOnlySpan IncludeConditions => _includeConditions; - public bool IsIncluded(long includeFlags, bool allowInternals = false) + public bool IsIncluded(ulong includeFlags, bool allowInternals = false) { // in most case we do not have any include condition, // so we can take the easy way out here if we do not have any flags. @@ -190,7 +195,7 @@ public bool IsIncluded(long includeFlags, bool allowInternals = false) public override string ToString() => _syntaxNode.ToString(); - internal void AddSelection(FieldNode selectionSyntax, long includeCondition = 0) + internal void AddSelection(FieldNode selectionSyntax, ulong includeCondition = 0) { if ((_flags & Flags.Sealed) == Flags.Sealed) { @@ -412,7 +417,7 @@ public Sealed( FieldNode syntaxNode, string responseName, ArgumentMap? arguments = null, - long[]? includeConditions = null, + ulong[]? includeConditions = null, bool isInternal = false, bool isParallelExecutable = true, FieldDelegate? resolverPipeline = null, diff --git a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs index 47f922f9119..872b64ad013 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.Designer.cs @@ -45,21 +45,21 @@ internal static System.Globalization.CultureInfo Culture { } } - internal static string CompositeResultElement_GetBoolean_JsonElementHasWrongType { + internal static string ResultElement_GetBoolean_JsonElementHasWrongType { get { - return ResourceManager.GetString("CompositeResultElement_GetBoolean_JsonElementHasWrongType", resourceCulture); + return ResourceManager.GetString("ResultElement_GetBoolean_JsonElementHasWrongType", resourceCulture); } } - internal static string SourceResultElement_GetBoolean_JsonElementHasWrongType { + internal static string Rethrowable { get { - return ResourceManager.GetString("SourceResultElement_GetBoolean_JsonElementHasWrongType", resourceCulture); + return ResourceManager.GetString("Rethrowable", resourceCulture); } } - internal static string Rethrowable { + internal static string ResultElement_SetObjectValue_NotObjectType { get { - return ResourceManager.GetString("Rethrowable", resourceCulture); + return ResourceManager.GetString("ResultElement_SetObjectValue_NotObjectType", resourceCulture); } } @@ -81,9 +81,9 @@ internal static string ThrowHelper_ReadIncompleteUTF16 { } } - internal static string FixedSizeArrayPool_Return_InvalidArraySize { + internal static string ResultElement_SetArrayValue_NotListType { get { - return ResourceManager.GetString("FixedSizeArrayPool_Return_InvalidArraySize", resourceCulture); + return ResourceManager.GetString("ResultElement_SetArrayValue_NotListType", resourceCulture); } } } diff --git a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx index 9375281edf6..e98294406cd 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx +++ b/src/HotChocolate/Core/src/Types/Properties/TextJsonResources.resx @@ -18,15 +18,15 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - The requested operation requires an element of type '{0}', but the target element has type '{1}'. - - + The requested operation requires an element of type '{0}', but the target element has type '{1}'. HotChocolate.Text.Json.Rethrowable + + The element is not a composite type. + Cannot transcode invalid UTF-8 JSON text to UTF-16 string. @@ -36,7 +36,7 @@ Cannot read incomplete UTF-16 JSON text as string with missing low surrogate. - - Buffer size {0} does not match expected chunk size {1} + + The location type `{0}` is not a list. diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs index 701c7734e40..5e613d3f224 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs @@ -15,23 +15,22 @@ internal readonly struct DbRow // 27 bits for location + 2 bits OpRefType + 3 reserved bits private readonly int _locationAndOpRefType; - // Sign bit for HasComplexChildren + 31 bits for size/length + // 27 bits for size/length + sign bit for HasComplexChildren + 4 reserved bits private readonly int _sizeOrLengthUnion; - // 4 bits TokenType + 27 bits NumberOfRows + 1 reserved bit - private readonly int _numberOfRowsTypeAndReserved; + // 27 bits NumberOfRows + 1 reserved bit + 4 bits TokenType + private readonly int _tokenTypeAndNumberOfRows; - // 15 bits SourceDocumentId + 17 bits (high 17 bits of ParentRow) - private readonly int _sourceAndParentHigh; + // 27 bits ParentRow + 5 reserved bits + private readonly int _parentRow; - // 15 bits OperationReferenceId + 6 bits Flags + 11 bits (low bits of ParentRow) - private readonly int _selectionSetFlagsAndParentLow; + // 15 bits OperationReferenceId + 8 bits Flags + 9 reserved bits + private readonly int _opRefIdAndFlags; public DbRow( ElementTokenType tokenType, int location, int sizeOrLength = 0, - int sourceDocumentId = 0, int parentRow = 0, int operationReferenceId = 0, OperationReferenceType operationReferenceType = OperationReferenceType.None, @@ -40,20 +39,19 @@ public DbRow( { Debug.Assert((byte)tokenType < 16); Debug.Assert(location is >= 0 and <= 0x07FFFFFF); // 27 bits - Debug.Assert(sizeOrLength >= UnknownSize); - Debug.Assert(sourceDocumentId is >= 0 and <= 0x7FFF); // 15 bits - Debug.Assert(parentRow is >= 0 and <= 0x0FFFFFFF); // 28 bits + Debug.Assert(sizeOrLength == UnknownSize || sizeOrLength is >= 0 and <= 0x07FFFFFF); // 27 bits + Debug.Assert(parentRow is >= 0 and <= 0x07FFFFFF); // 27 bits Debug.Assert(operationReferenceId is >= 0 and <= 0x7FFF); // 15 bits Debug.Assert(numberOfRows is >= 0 and <= 0x07FFFFFF); // 27 bits - Debug.Assert((byte)flags <= 63); // 6 bits (0x3F) + Debug.Assert((byte)flags <= 255); // 8 bits (0xFF) Debug.Assert((byte)operationReferenceType <= 3); // 2 bits Debug.Assert(Unsafe.SizeOf() == Size); _locationAndOpRefType = location | ((int)operationReferenceType << 27); _sizeOrLengthUnion = sizeOrLength; - _numberOfRowsTypeAndReserved = ((int)tokenType << 28) | (numberOfRows & 0x07FFFFFF); - _sourceAndParentHigh = sourceDocumentId | ((parentRow >> 11) << 15); - _selectionSetFlagsAndParentLow = operationReferenceId | ((int)flags << 15) | ((parentRow & 0x7FF) << 21); + _tokenTypeAndNumberOfRows = ((int)tokenType << 28) | (numberOfRows & 0x07FFFFFF); + _parentRow = parentRow; + _opRefIdAndFlags = operationReferenceId | ((int)flags << 15); } /// @@ -62,7 +60,7 @@ public DbRow( /// /// 4 bits = possible values /// - public ElementTokenType TokenType => (ElementTokenType)(unchecked((uint)_numberOfRowsTypeAndReserved) >> 28); + public ElementTokenType TokenType => (ElementTokenType)(unchecked((uint)_tokenTypeAndNumberOfRows) >> 28); /// /// Operation reference type indicating the type of GraphQL operation element. @@ -77,7 +75,7 @@ public OperationReferenceType OperationReferenceType /// Byte offset in source data OR metaDb row index for references. /// /// - /// 2 bits = 4 possible values + /// 27 bits = 134M limit /// public int Location => _locationAndOpRefType & 0x07FFFFFF; @@ -87,7 +85,7 @@ public OperationReferenceType OperationReferenceType /// /// 27 bits = 134M limit /// - public int SizeOrLength => _sizeOrLengthUnion & int.MaxValue; + public int SizeOrLength => _sizeOrLengthUnion & 0x07FFFFFF; /// /// String/PropertyName: Unescaping required. @@ -105,30 +103,32 @@ public OperationReferenceType OperationReferenceType /// /// 27 bits = 134M rows /// - public int NumberOfRows => _numberOfRowsTypeAndReserved & 0x07FFFFFF; + public int NumberOfRows => _tokenTypeAndNumberOfRows & 0x07FFFFFF; /// /// Index of parent element in metadb for navigation and null propagation. /// /// - /// 28 bits = 268M rows + /// 27 bits = 134M rows /// - public int ParentRow - => ((int)((uint)_sourceAndParentHigh >> 15) << 11) | ((_selectionSetFlagsAndParentLow >> 21) & 0x7FF); + public int ParentRow => _parentRow & 0x07FFFFFF; /// /// Reference to GraphQL selection set or selection metadata. /// 15 bits = 32K selections /// - public int OperationReferenceId => _selectionSetFlagsAndParentLow & 0x7FFF; + /// + /// 15 bits = 32K selections + /// + public int OperationReferenceId => _opRefIdAndFlags & 0x7FFF; /// /// Element metadata flags. /// /// - /// 6 bits = 64 combinations + /// 8 bits = 256 combinations /// - public ElementFlags Flags => (ElementFlags)((_selectionSetFlagsAndParentLow >> 15) & 0x3F); + public ElementFlags Flags => (ElementFlags)((_opRefIdAndFlags >> 15) & 0xFF); /// /// True for primitive JSON values (strings, numbers, booleans, null). @@ -147,11 +147,12 @@ internal enum OperationReferenceType : byte internal enum ElementFlags : byte { None = 0, - Invalidated = 1, - SourceResult = 2, - IsNullable = 4, - IsRoot = 8, - IsInternal = 16, - IsExcluded = 32 + IsRoot = 1, + IsObject = 2, + IsList = 4, + IsInternal = 8, + IsExcluded = 16, + IsNullable = 32, + IsInvalidated = 64 } } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs index 46af3d2c6b3..af81d3cc647 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.MetaDb.cs @@ -49,7 +49,6 @@ internal Cursor Append( ElementTokenType tokenType, int location = 0, int sizeOrLength = 0, - int sourceDocumentId = 0, int parentRow = 0, int operationReferenceId = 0, OperationReferenceType operationReferenceType = OperationReferenceType.None, @@ -110,7 +109,6 @@ internal Cursor Append( tokenType, location, sizeOrLength, - sourceDocumentId, parentRow, operationReferenceId, operationReferenceType, @@ -131,7 +129,6 @@ internal void Replace( ElementTokenType tokenType, int location = 0, int sizeOrLength = 0, - int sourceDocumentId = 0, int parentRow = 0, int operationReferenceId = 0, OperationReferenceType operationReferenceType = OperationReferenceType.None, @@ -144,7 +141,6 @@ internal void Replace( tokenType, location, sizeOrLength, - sourceDocumentId, parentRow, operationReferenceId, operationReferenceType, @@ -215,13 +211,8 @@ internal int GetParent(Cursor cursor) { AssertValidCursor(cursor); - var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); - - var sourceAndParentHigh = MemoryMarshal.Read(span[12..]); - var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span[16..]); - - return (sourceAndParentHigh >>> 15 << 11) - | ((selectionSetFlagsAndParentLow >> 21) & 0x7FF); + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 12); + return MemoryMarshal.Read(span) & 0x07FFFFFF; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -229,14 +220,8 @@ internal Cursor GetParentCursor(Cursor cursor) { AssertValidCursor(cursor); - var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset); - - var sourceAndParentHigh = MemoryMarshal.Read(span[12..]); - var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span[16..]); - - var index = (sourceAndParentHigh >>> 15 << 11) - | ((selectionSetFlagsAndParentLow >> 21) & 0x7FF); - + var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 12); + var index = MemoryMarshal.Read(span) & 0x07FFFFFF; return Cursor.FromIndex(index); } @@ -248,7 +233,7 @@ internal int GetNumberOfRows(Cursor cursor) var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset); var value = MemoryMarshal.Read(span); - return value & 0x0FFFFFFF; + return value & 0x07FFFFFF; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -258,21 +243,21 @@ internal ElementFlags GetFlags(Cursor cursor) var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 16); - var selectionSetFlagsAndParentLow = MemoryMarshal.Read(span); - return (ElementFlags)((selectionSetFlagsAndParentLow >> 15) & 0x3F); + var value = MemoryMarshal.Read(span); + return (ElementFlags)((value >> 15) & 0xFF); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void SetFlags(Cursor cursor, ElementFlags flags) { AssertValidCursor(cursor); - Debug.Assert((byte)flags <= 63, "Flags value exceeds 6-bit limit"); + Debug.Assert((byte)flags <= 255, "Flags value exceeds 8-bit limit"); var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 16); var currentValue = MemoryMarshal.Read(fieldSpan); - var clearedValue = currentValue & 0xFFE07FFF; // ~(0x3F << 15) - var newValue = (int)(clearedValue | (uint)((int)flags << 15)); + var clearedValue = currentValue & unchecked((int)0xFF807FFF); // ~(0xFF << 15) + var newValue = clearedValue | ((int)flags << 15); MemoryMarshal.Write(fieldSpan, newValue); } @@ -285,21 +270,21 @@ internal int GetSizeOrLength(Cursor cursor) var span = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); var value = MemoryMarshal.Read(span); - return value & int.MaxValue; + return value & 0x07FFFFFF; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void SetSizeOrLength(Cursor cursor, int sizeOrLength) { AssertValidCursor(cursor); - Debug.Assert(sizeOrLength >= 0, "SizeOrLength value exceeds 31-bit limit"); + Debug.Assert(sizeOrLength >= 0 && sizeOrLength <= 0x07FFFFFF, "SizeOrLength value exceeds 27-bit limit"); var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + 4); var currentValue = MemoryMarshal.Read(fieldSpan); - // Keep only the sign bit (HasComplexChildren) - var clearedValue = currentValue & unchecked((int)0x80000000); - var newValue = clearedValue | (sizeOrLength & int.MaxValue); + // Keep only the sign bit (HasComplexChildren) + 4 reserved bits + var clearedValue = currentValue & unchecked((int)0xF8000000); + var newValue = clearedValue | (sizeOrLength & 0x07FFFFFF); MemoryMarshal.Write(fieldSpan, newValue); } @@ -308,14 +293,14 @@ internal void SetSizeOrLength(Cursor cursor, int sizeOrLength) internal void SetNumberOfRows(Cursor cursor, int numberOfRows) { AssertValidCursor(cursor); - Debug.Assert(numberOfRows >= 0 && numberOfRows <= 0x0FFFFFFF, "NumberOfRows value exceeds 28-bit limit"); + Debug.Assert(numberOfRows >= 0 && numberOfRows <= 0x07FFFFFF, "NumberOfRows value exceeds 27-bit limit"); var fieldSpan = _chunks[cursor.Chunk].AsSpan(cursor.ByteOffset + TokenTypeOffset); var currentValue = MemoryMarshal.Read(fieldSpan); - // Keep only the top 4 bits (token type) - var clearedValue = currentValue & unchecked((int)0xF0000000); - var newValue = clearedValue | (numberOfRows & 0x0FFFFFFF); + // Keep only the top 5 bits (4 bits token type + 1 reserved) + var clearedValue = currentValue & unchecked((int)0xF8000000); + var newValue = clearedValue | (numberOfRows & 0x07FFFFFF); MemoryMarshal.Write(fieldSpan, newValue); } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs index 9fc7679a472..01b41ac815e 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.TryGetProperty.cs @@ -8,7 +8,7 @@ public sealed partial class ResultDocument internal bool TryGetNamedPropertyValue( Cursor startCursor, string propertyName, - out CompositeResultElement value) + out ResultElement value) { ObjectDisposedException.ThrowIf(_disposed, this); @@ -35,7 +35,7 @@ internal bool TryGetNamedPropertyValue( var propertyCursor = startCursor + propertyRowIndex; Debug.Assert(_metaDb.GetElementTokenType(propertyCursor) is ElementTokenType.PropertyName); Debug.Assert(_metaDb.Get(propertyCursor).OperationReferenceId == selection.Id); - value = new CompositeResultElement(this, propertyCursor + 1); + value = new ResultElement(this, propertyCursor + 1); return true; } } @@ -116,7 +116,7 @@ internal bool TryGetNamedPropertyValue( internal bool TryGetNamedPropertyValue( Cursor startCursor, ReadOnlySpan propertyName, - out CompositeResultElement value) + out ResultElement value) { ObjectDisposedException.ThrowIf(_disposed, this); @@ -143,7 +143,7 @@ internal bool TryGetNamedPropertyValue( var propertyCursor = startCursor + propertyRowIndex; Debug.Assert(_metaDb.GetElementTokenType(propertyCursor) is ElementTokenType.PropertyName); Debug.Assert(_metaDb.Get(propertyCursor).OperationReferenceId == selection.Id); - value = new CompositeResultElement(this, propertyCursor + 1); + value = new ResultElement(this, propertyCursor + 1); return true; } } @@ -161,7 +161,7 @@ private bool TryGetNamedPropertyValue( Cursor startCursor, Cursor endCursor, ReadOnlySpan propertyName, - out CompositeResultElement value) + out ResultElement value) { Span utf8UnescapedStack = stackalloc byte[JsonConstants.StackallocByteThreshold]; var cursor = endCursor; @@ -206,7 +206,7 @@ private bool TryGetNamedPropertyValue( if (utf8Unescaped[..written].SequenceEqual(propertyName[idx..])) { // If the property name is a match, the answer is the next element. - value = new CompositeResultElement(this, cursor + 1); + value = new ResultElement(this, cursor + 1); return true; } } @@ -224,7 +224,7 @@ private bool TryGetNamedPropertyValue( else if (currentPropertyName.SequenceEqual(propertyName)) { // If the property name is a match, the answer is the next element. - value = new CompositeResultElement(this, cursor + 1); + value = new ResultElement(this, cursor + 1); return true; } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs index c5c86bd324a..869b8c26d26 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -77,7 +77,7 @@ public void Write() } if (row.TokenType is ElementTokenType.Null - || (ElementFlags.Invalidated & row.Flags) == ElementFlags.Invalidated) + || (ElementFlags.IsInvalidated & row.Flags) == ElementFlags.IsInvalidated) { writer.Write(JsonConstants.NullValue); } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index c34fedfd4ca..780e99ee305 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Text; +using HotChocolate.Buffers; using HotChocolate.Execution.Processing; using HotChocolate.Types; @@ -12,13 +13,17 @@ public sealed partial class ResultDocument : IDisposable private static readonly Encoding s_utf8Encoding = Encoding.UTF8; private readonly Operation _operation; private readonly ulong _includeFlags; - private List? _errors; internal MetaDb _metaDb; + private int _nextDataIndex; + private int _rentedDataSize; + private readonly List _data = []; + private readonly object _dataChunkLock = new(); + private List? _errors; private bool _disposed; internal ResultDocument(Operation operation, ulong includeFlags) { - _metaDb = MetaDb.CreateForEstimatedRows(Cursor.RowsPerChunk * 8); + _metaDb = MetaDb.CreateForEstimatedRows(Cursor.RowsPerChunk); _operation = operation; _includeFlags = includeFlags; @@ -228,7 +233,7 @@ internal bool IsInvalidated(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + return (flags & ElementFlags.IsInvalidated) == ElementFlags.IsInvalidated; } if (tokenType is ElementTokenType.Reference) @@ -239,7 +244,7 @@ internal bool IsInvalidated(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + return (flags & ElementFlags.IsInvalidated) == ElementFlags.IsInvalidated; } } @@ -260,7 +265,7 @@ internal bool IsNullOrInvalidated(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + return (flags & ElementFlags.IsInvalidated) == ElementFlags.IsInvalidated; } if (tokenType is ElementTokenType.Reference) @@ -271,7 +276,7 @@ internal bool IsNullOrInvalidated(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - return (flags & ElementFlags.Invalidated) == ElementFlags.Invalidated; + return (flags & ElementFlags.IsInvalidated) == ElementFlags.IsInvalidated; } } @@ -307,7 +312,7 @@ internal void Invalidate(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - _metaDb.SetFlags(current, flags | ElementFlags.Invalidated); + _metaDb.SetFlags(current, flags | ElementFlags.IsInvalidated); return; } @@ -319,7 +324,7 @@ internal void Invalidate(Cursor current) if (tokenType is ElementTokenType.StartObject) { var flags = _metaDb.GetFlags(current); - _metaDb.SetFlags(current, flags | ElementFlags.Invalidated); + _metaDb.SetFlags(current, flags | ElementFlags.IsInvalidated); } return; @@ -329,58 +334,117 @@ internal void Invalidate(Cursor current) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteRawValueTo(IBufferWriter writer, DbRow row, int indentLevel, bool indented) + private void WriteRawValueTo(IBufferWriter writer, DbRow row) { - if ((row.Flags & ElementFlags.SourceResult) == ElementFlags.SourceResult) + switch (row.TokenType) { - var document = _sources[row.SourceDocumentId]; + case ElementTokenType.Null: + WriteToBuffer(writer, JsonConstants.NullValue); + return; - if (row.TokenType is ElementTokenType.StartObject or ElementTokenType.StartArray) - { - // Reconstruct the source cursor from stored Location (Chunk) and SizeOrLength (Row) - var sourceCursor = SourceResultDocument.Cursor.From(row.Location, row.SizeOrLength); - var formatter = new SourceResultDocument.RawJsonFormatter(document, writer, indentLevel, indented); - formatter.WriteValue(sourceCursor); + case ElementTokenType.True: + WriteToBuffer(writer, JsonConstants.TrueValue); return; - } - // For simple values, write directly using location and size - document.WriteRawValueTo(writer, row.Location, row.SizeOrLength); - return; + case ElementTokenType.False: + WriteToBuffer(writer, JsonConstants.FalseValue); + return; + + case ElementTokenType.PropertyName: + WriteToBuffer(writer, _operation.GetSelectionById(row.OperationReferenceId).Utf8ResponseName); + return; + + case ElementTokenType.String: + case ElementTokenType.Number: + WriteLocalDataTo(writer, row.Location, row.SizeOrLength); + return; + + default: + throw new NotSupportedException(); } + } - throw new NotSupportedException(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WriteToBuffer(IBufferWriter writer, ReadOnlySpan data) + { + var span = writer.GetSpan(data.Length); + data.CopyTo(span); + writer.Advance(data.Length); } - private ReadOnlySpan ReadRawValue(DbRow row) + /// + /// Writes local data to the buffer, handling chunk boundaries. + /// + private void WriteLocalDataTo(IBufferWriter writer, int location, int size) { - if (row.TokenType == ElementTokenType.Null) - { - return JsonConstants.NullValue; - } + var remaining = size; + var currentPos = location; - if (row.TokenType == ElementTokenType.True) + while (remaining > 0) { - return JsonConstants.TrueValue; - } + var chunkIndex = currentPos / JsonMemory.BufferSize; + var offset = currentPos % JsonMemory.BufferSize; + var availableInChunk = JsonMemory.BufferSize - offset; + var toWrite = Math.Min(remaining, availableInChunk); - if (row.TokenType == ElementTokenType.False) - { - return JsonConstants.FalseValue; + var source = _data[chunkIndex].AsSpan(offset, toWrite); + var dest = writer.GetSpan(toWrite); + source.CopyTo(dest); + writer.Advance(toWrite); + + currentPos += toWrite; + remaining -= toWrite; } + } - if (row.TokenType == ElementTokenType.PropertyName) + private ReadOnlySpan ReadRawValue(DbRow row) + { + switch (row.TokenType) { - return _operation.GetSelectionById(row.OperationReferenceId).Utf8ResponseName; + case ElementTokenType.Null: + return JsonConstants.NullValue; + + case ElementTokenType.True: + return JsonConstants.TrueValue; + + case ElementTokenType.False: + return JsonConstants.FalseValue; + + case ElementTokenType.PropertyName: + return _operation.GetSelectionById(row.OperationReferenceId).Utf8ResponseName; + + case ElementTokenType.String: + case ElementTokenType.Number: + return ReadLocalData(row.Location, row.SizeOrLength); + + default: + throw new NotSupportedException(); } + } + + /// + /// Reads local data from the data chunks. + /// + /// + /// This method only supports data that fits within a single chunk. + /// Data that spans chunk boundaries should use instead. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ReadOnlySpan ReadLocalData(int location, int size) + { + var chunkIndex = location / JsonMemory.BufferSize; + var offset = location % JsonMemory.BufferSize; - if ((row.Flags & ElementFlags.SourceResult) == ElementFlags.SourceResult) + // Fast path: data fits in a single chunk + if (offset + size <= JsonMemory.BufferSize) { - var document = _sources[row.SourceDocumentId]; - return document.ReadRawValue(row.Location, row.SizeOrLength); + return _data[chunkIndex].AsSpan(offset, size); } - throw new NotSupportedException(); + // Data spans chunk boundaries - this should be rare for typical JSON values + throw new NotSupportedException( + "Reading data that spans chunk boundaries as a span is not supported. " + + "Use WriteLocalDataTo for writing to an IBufferWriter instead."); } internal ResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) @@ -399,6 +463,20 @@ internal ResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) return new ResultElement(this, startObjectCursor); } + internal ResultElement CreateObject(Cursor parent, int propertyCount) + { + var startObjectCursor = WriteStartObject(parent, isSelectionSet: false); + + for (var i = 0; i < propertyCount; i++) + { + WriteEmptyProperty(startObjectCursor); + } + + WriteEndObject(startObjectCursor, propertyCount); + + return new ResultElement(this, startObjectCursor); + } + internal ResultElement CreateArray(Cursor parent, int length) { var cursor = WriteStartArray(parent, length); @@ -414,7 +492,7 @@ internal ResultElement CreateArray(Cursor parent, int length) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AssignCompositeValue(ResultElement target, ResultElement value) + internal void AssignObjectOrArray(ResultElement target, ResultElement value) { _metaDb.Replace( cursor: target.Cursor, @@ -424,45 +502,48 @@ internal void AssignCompositeValue(ResultElement target, ResultElement value) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void AssignSourceValue(ResultElement target, ResultElement source) + internal void AssignStringValue(ResultElement target, ReadOnlySpan value) { - var value = source.GetValuePointer(); - var parent = source._parent; - - if (parent.Id == -1) - { - Debug.Assert(!_sources.Contains(parent), "The source document is marked as unbound but is already registered."); - parent.Id = _sources.Count; - _sources.Add(parent); - } + var totalSize = value.Length + 2; + var position = ClaimDataSpace(totalSize); + WriteData(position, value, withQuotes: true); - Debug.Assert(_sources.Contains(parent), "Expected the source document of the source element to be registered."); + _metaDb.Replace( + cursor: target.Cursor, + tokenType: ElementTokenType.String, + location: position, + sizeOrLength: totalSize, + parentRow: _metaDb.GetParent(target.Cursor)); + } - var tokenType = source.TokenType.ToElementTokenType(); + internal void AssignPropertyName(ResultElement target, ReadOnlySpan propertyName) + { + var totalSize = propertyName.Length + 2; + var position = ClaimDataSpace(totalSize); + WriteData(position, propertyName, withQuotes: true); + } - if (tokenType is ElementTokenType.StartObject or ElementTokenType.StartArray) - { - var sourceCursor = source._cursor; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AssignNumberValue(ResultElement target, ReadOnlySpan value) + { + var position = ClaimDataSpace(value.Length); + WriteData(position, value); - _metaDb.Replace( - cursor: target.Cursor, - tokenType: source.TokenType.ToElementTokenType(), - location: sourceCursor.Chunk, - sizeOrLength: sourceCursor.Row, - sourceDocumentId: parent.Id, - parentRow: _metaDb.GetParent(target.Cursor), - flags: ElementFlags.SourceResult); - return; - } + _metaDb.Replace( + cursor: target.Cursor, + tokenType: ElementTokenType.Number, + location: position, + sizeOrLength: value.Length, + parentRow: _metaDb.GetParent(target.Cursor)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void AssignBooleanValue(ResultElement target, bool value) + { _metaDb.Replace( cursor: target.Cursor, - tokenType: source.TokenType.ToElementTokenType(), - location: value.Location, - sizeOrLength: value.Size, - sourceDocumentId: parent.Id, - parentRow: _metaDb.GetParent(target.Cursor), - flags: ElementFlags.SourceResult); + tokenType: value ? ElementTokenType.True : ElementTokenType.False, + parentRow: _metaDb.GetParent(target.Cursor)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -475,7 +556,110 @@ internal void AssignNullValue(ResultElement target) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Cursor WriteStartObject(Cursor parent, int selectionSetId = 0) + private int ClaimDataSpace(int size) + { + // Atomically claim space + var endPosition = Interlocked.Add(ref _nextDataIndex, size); + var startPosition = endPosition - size; + + // Fast path: we check if we already have enough rented memory + // if so we can directly return and write the data without locking. + if (endPosition <= Volatile.Read(ref _rentedDataSize)) + { + return startPosition; + } + + // Slow path: we need to rent more chunks so in this case + // we will need to do a proper synchronization. + EnsureDataCapacity(endPosition); + return startPosition; + } + + private void EnsureDataCapacity(int requiredSize) + { + lock (_dataChunkLock) + { + // Double-check after acquiring lock + var currentSize = _rentedDataSize; + if (requiredSize <= currentSize) + { + return; + } + + // Rent chunks until we have enough + while (currentSize < requiredSize) + { + _data.Add(JsonMemory.Rent(JsonMemoryKind.Json)); + currentSize += JsonMemory.BufferSize; + } + + // Publish new size (volatile write) + Volatile.Write(ref _rentedDataSize, currentSize); + } + } + + /// + /// Writes data to the data chunks, handling chunk boundaries. + /// + /// The position to start writing at. + /// The data to write. + /// If true, wraps the data with JSON quotes. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteData(int position, ReadOnlySpan data, bool withQuotes = false) + { + if (withQuotes) + { + WriteByte(position, JsonConstants.Quote); + WriteDataCore(position + 1, data); + WriteByte(position + 1 + data.Length, JsonConstants.Quote); + } + else + { + WriteDataCore(position, data); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteByte(int position, byte value) + { + var chunkIndex = position / JsonMemory.BufferSize; + var offset = position % JsonMemory.BufferSize; + _data[chunkIndex][offset] = value; + } + + private void WriteDataCore(int position, ReadOnlySpan data) + { + var chunkIndex = position / JsonMemory.BufferSize; + var offset = position % JsonMemory.BufferSize; + var availableInChunk = JsonMemory.BufferSize - offset; + + // Fast path: we can write all the data into single chunk + if (data.Length <= availableInChunk) + { + data.CopyTo(_data[chunkIndex].AsSpan(offset, data.Length)); + return; + } + + // Slow path: data spans multiple chunks so we need to loop + var remaining = data; + var currentPos = position; + + while (remaining.Length > 0) + { + chunkIndex = currentPos / JsonMemory.BufferSize; + offset = currentPos % JsonMemory.BufferSize; + availableInChunk = JsonMemory.BufferSize - offset; + var toWrite = Math.Min(remaining.Length, availableInChunk); + + remaining[..toWrite].CopyTo(_data[chunkIndex].AsSpan(offset, toWrite)); + + currentPos += toWrite; + remaining = remaining[toWrite..]; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Cursor WriteStartObject(Cursor parent, int selectionSetId = 0, bool isSelectionSet = true) { var flags = ElementFlags.None; var parentRow = ToIndex(parent); @@ -490,7 +674,9 @@ private Cursor WriteStartObject(Cursor parent, int selectionSetId = 0) ElementTokenType.StartObject, parentRow: parentRow, operationReferenceId: selectionSetId, - operationReferenceType: OperationReferenceType.SelectionSet, + operationReferenceType: isSelectionSet + ? OperationReferenceType.SelectionSet + : OperationReferenceType.None, flags: flags); } @@ -546,6 +732,16 @@ private void WriteEmptyProperty(Cursor parent, ISelection selection) flags |= ElementFlags.IsNullable; } + if (selection.Type.IsListType()) + { + flags |= ElementFlags.IsList; + } + + if (selection.Type.IsCompositeType()) + { + flags |= ElementFlags.IsObject; + } + var prop = _metaDb.Append( ElementTokenType.PropertyName, parentRow: ToIndex(parent), @@ -558,6 +754,18 @@ private void WriteEmptyProperty(Cursor parent, ISelection selection) parentRow: ToIndex(prop)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void WriteEmptyProperty(Cursor parent) + { + var prop = _metaDb.Append( + ElementTokenType.PropertyName, + parentRow: ToIndex(parent)); + + _metaDb.Append( + ElementTokenType.None, + parentRow: ToIndex(prop)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteEmptyValue(Cursor parent) { @@ -582,6 +790,12 @@ public void Dispose() if (!_disposed) { _metaDb.Dispose(); + + if (_data.Count > 0) + { + JsonMemory.Return(JsonMemoryKind.Json, _data); + } + _disposed = true; } } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs index 58d8d5d163b..90725204ee3 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.ObjectEnumerator.cs @@ -1,6 +1,6 @@ using System.Collections; using System.Diagnostics; -using static HotChocolate.Fusion.Text.Json.CompositeResultDocument; +using static HotChocolate.Text.Json.ResultDocument; namespace HotChocolate.Text.Json; @@ -10,14 +10,14 @@ public readonly partial struct ResultElement /// An enumerable and enumerator for the properties of a JSON object. /// [DebuggerDisplay("{Current,nq}")] - public struct ObjectEnumerator : IEnumerable, IEnumerator + public struct ObjectEnumerator : IEnumerable, IEnumerator { - private readonly CompositeResultDocument _document; + private readonly ResultDocument _document; private readonly Cursor _start; private readonly Cursor _end; private Cursor _cursor; - internal ObjectEnumerator(CompositeResultElement target) + internal ObjectEnumerator(ResultElement target) { _document = target._parent; (_start, var tokenType) = _document._metaDb.GetStartCursor(target._cursor); @@ -27,7 +27,7 @@ internal ObjectEnumerator(CompositeResultElement target) } /// - public CompositeResultProperty Current + public ResultProperty Current { get { @@ -36,7 +36,7 @@ public CompositeResultProperty Current return default; } - return new CompositeResultProperty(new CompositeResultElement(_document, _cursor + 1)); + return new ResultProperty(new ResultElement(_document, _cursor + 1)); } } @@ -65,7 +65,7 @@ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// - IEnumerator IEnumerable.GetEnumerator() + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs index 94b91ddb9bf..5b363b8bb8a 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -1,5 +1,7 @@ using System.Buffers; +using System.Buffers.Text; using System.Diagnostics; +using System.Text; using System.Text.Json; using HotChocolate.Execution; using HotChocolate.Execution.Processing; @@ -24,10 +26,16 @@ internal ResultElement(ResultDocument parent, ResultDocument.Cursor cursor) _cursor = cursor; } + /// + /// Writes this element as JSON to the specified buffer writer. + /// + /// The buffer writer to write to. + /// + /// true to write indented JSON; otherwise, false. + /// public void WriteTo(IBufferWriter writer, bool indented = false) { var formatter = new ResultDocument.RawJsonFormatter(_parent, writer, indented); - var row = _parent._metaDb.Get(_cursor); formatter.WriteValue(_cursor, row); } @@ -41,25 +49,19 @@ public void WriteTo(IBufferWriter writer, bool indented = false) private ElementTokenType TokenType => _parent?.GetElementTokenType(_cursor) ?? ElementTokenType.None; /// - /// The that the value is. + /// Gets the of this element. /// - /// - /// The parent has been disposed. - /// public JsonValueKind ValueKind => TokenType.ToValueKind(); /// - /// Get the value at a specified index when the current value is a - /// . + /// Gets the element at the specified index when the current element is an array. /// + /// The zero-based index of the element to get. /// - /// This value's is not . + /// This element's is not . /// /// - /// is not in the range [0, ()). - /// - /// - /// The parent has been disposed. + /// is not in the range [0, ()). /// public ResultElement this[int index] { @@ -71,6 +73,9 @@ public ResultElement this[int index] } } + /// + /// Gets the operation this element belongs to. + /// public IOperation Operation { get @@ -81,6 +86,10 @@ public IOperation Operation } } + /// + /// Gets the if this element represents the data of a selection set; + /// otherwise, null. + /// public ISelectionSet? SelectionSet { get @@ -91,6 +100,10 @@ public ISelectionSet? SelectionSet } } + /// + /// Gets the if this element represents the data of a field selection; + /// otherwise, null. + /// public ISelection? Selection { get @@ -107,6 +120,10 @@ public ISelection? Selection } } + /// + /// Gets the if this element represents the data of a field selection; + /// otherwise, null. + /// public IType? Type { get @@ -134,6 +151,9 @@ public IType? Type } } + /// + /// Gets a value indicating whether this element has been invalidated during null propagation. + /// public bool IsInvalidated { get @@ -144,6 +164,9 @@ public bool IsInvalidated } } + /// + /// Gets a value indicating whether this element is either null or was invalidated during null propagation. + /// public bool IsNullOrInvalidated { get @@ -157,6 +180,9 @@ public bool IsNullOrInvalidated } } + /// + /// Gets the path to this element within the result document. + /// public Path Path { get @@ -167,6 +193,9 @@ public Path Path } } + /// + /// Gets the parent element that contains this element. + /// public ResultElement Parent { get @@ -177,6 +206,9 @@ public ResultElement Parent } } + /// + /// Gets a value indicating whether this element is nullable according to the GraphQL type system. + /// public bool IsNullable { get @@ -192,6 +224,10 @@ public bool IsNullable } } + /// + /// Gets a value indicating whether this element represents internal data + /// that is required for processing and must not be written to the GraphQL response. + /// public bool IsInternal { get @@ -202,6 +238,15 @@ public bool IsInternal } } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a selection set. + /// public ISelectionSet AssertSelectionSet() { var selectionSet = SelectionSet; @@ -214,6 +259,15 @@ public ISelectionSet AssertSelectionSet() return selectionSet; } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a field selection. + /// public ISelection AssertSelection() { var selection = Selection; @@ -226,6 +280,15 @@ public ISelection AssertSelection() return selection; } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a field selection. + /// public IType AssertType() { var type = Type; @@ -238,6 +301,10 @@ public IType AssertType() return type; } + /// + /// Marks this element as invalidated, which occurs during null propagation + /// when a non-nullable field returns null. + /// public void Invalidate() { CheckValidInstance(); @@ -246,8 +313,11 @@ public void Invalidate() } /// - /// Get the number of values contained within the current array value. + /// Gets the number of elements contained within the current array element. /// + /// + /// The number of elements in the array. + /// public int GetArrayLength() { CheckValidInstance(); @@ -256,8 +326,11 @@ public int GetArrayLength() } /// - /// Get the number of properties contained within the current object value. + /// Gets the number of properties contained within the current object element. /// + /// + /// The number of properties in the object. + /// public int GetPropertyCount() { CheckValidInstance(); @@ -265,6 +338,14 @@ public int GetPropertyCount() return _parent.GetPropertyCount(_cursor); } + /// + /// Gets a property by name when the current element is an object. + /// + /// The name of the property to find. + /// The property value. + /// + /// No property with the specified name was found. + /// public ResultElement GetProperty(string propertyName) { ArgumentNullException.ThrowIfNull(propertyName); @@ -277,6 +358,14 @@ public ResultElement GetProperty(string propertyName) throw new KeyNotFoundException(); } + /// + /// Gets a property by UTF-8 encoded name when the current element is an object. + /// + /// The UTF-8 encoded name of the property to find. + /// The property value. + /// + /// No property with the specified name was found. + /// public ResultElement GetProperty(ReadOnlySpan utf8PropertyName) { if (TryGetProperty(utf8PropertyName, out var property)) @@ -287,6 +376,16 @@ public ResultElement GetProperty(ReadOnlySpan utf8PropertyName) throw new KeyNotFoundException(); } + /// + /// Attempts to get a property by name when the current element is an object. + /// + /// The name of the property to find. + /// + /// When this method returns, contains the property value if found; otherwise, the default value. + /// + /// + /// true if the property was found; otherwise, false. + /// public bool TryGetProperty(string propertyName, out ResultElement value) { ArgumentNullException.ThrowIfNull(propertyName); @@ -294,6 +393,16 @@ public bool TryGetProperty(string propertyName, out ResultElement value) return _parent.TryGetNamedPropertyValue(_cursor, propertyName, out value); } + /// + /// Attempts to get a property by UTF-8 encoded name when the current element is an object. + /// + /// The UTF-8 encoded name of the property to find. + /// + /// When this method returns, contains the property value if found; otherwise, the default value. + /// + /// + /// true if the property was found; otherwise, false. + /// public bool TryGetProperty(ReadOnlySpan utf8PropertyName, out ResultElement value) { CheckValidInstance(); @@ -301,6 +410,13 @@ public bool TryGetProperty(ReadOnlySpan utf8PropertyName, out ResultElemen return _parent.TryGetNamedPropertyValue(_cursor, utf8PropertyName, out value); } + /// + /// Gets the value as a . + /// + /// The boolean value. + /// + /// This element's is not or . + /// public bool GetBoolean() { var type = TokenType; @@ -324,6 +440,10 @@ static bool ThrowJsonElementWrongTypeException(ElementTokenType actualType) } } + /// + /// Gets the value as a . + /// + /// The string value, or null if this element is a JSON null. public string? GetString() { CheckValidInstance(); @@ -331,6 +451,13 @@ static bool ThrowJsonElementWrongTypeException(ElementTokenType actualType) return _parent.GetString(_cursor, ElementTokenType.String); } + /// + /// Gets the value as a non-null . + /// + /// The string value. + /// + /// This element is a JSON null. + /// public string AssertString() { CheckValidInstance(); @@ -338,6 +465,11 @@ public string AssertString() return _parent.GetRequiredString(_cursor, ElementTokenType.String); } + /// + /// Attempts to get the value as an . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetSByte(out sbyte value) { CheckValidInstance(); @@ -345,8 +477,18 @@ public bool TryGetSByte(out sbyte value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as an . + /// + /// The value. + /// The value cannot be parsed as an . public sbyte GetSByte() => TryGetSByte(out var value) ? value : throw new FormatException(); + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetByte(out byte value) { CheckValidInstance(); @@ -354,6 +496,11 @@ public bool TryGetByte(out byte value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public byte GetByte() { if (TryGetByte(out var value)) @@ -364,6 +511,11 @@ public byte GetByte() throw new FormatException(); } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt16(out short value) { CheckValidInstance(); @@ -371,6 +523,11 @@ public bool TryGetInt16(out short value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public short GetInt16() { if (TryGetInt16(out var value)) @@ -381,6 +538,11 @@ public short GetInt16() throw new FormatException(); } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt16(out ushort value) { CheckValidInstance(); @@ -388,6 +550,11 @@ public bool TryGetUInt16(out ushort value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public ushort GetUInt16() { if (TryGetUInt16(out var value)) @@ -398,6 +565,11 @@ public ushort GetUInt16() throw new FormatException(); } + /// + /// Attempts to get the value as an . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt32(out int value) { CheckValidInstance(); @@ -405,6 +577,11 @@ public bool TryGetInt32(out int value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as an . + /// + /// The value. + /// The value cannot be parsed as an . public int GetInt32() { if (!TryGetInt32(out var value)) @@ -415,6 +592,11 @@ public int GetInt32() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt32(out uint value) { CheckValidInstance(); @@ -422,6 +604,11 @@ public bool TryGetUInt32(out uint value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public uint GetUInt32() { if (!TryGetUInt32(out var value)) @@ -432,6 +619,11 @@ public uint GetUInt32() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt64(out long value) { CheckValidInstance(); @@ -439,6 +631,11 @@ public bool TryGetInt64(out long value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public long GetInt64() { if (!TryGetInt64(out var value)) @@ -449,6 +646,11 @@ public long GetInt64() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt64(out ulong value) { CheckValidInstance(); @@ -456,6 +658,11 @@ public bool TryGetUInt64(out ulong value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public ulong GetUInt64() { if (!TryGetUInt64(out var value)) @@ -466,6 +673,11 @@ public ulong GetUInt64() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetDouble(out double value) { CheckValidInstance(); @@ -473,6 +685,11 @@ public bool TryGetDouble(out double value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public double GetDouble() { if (!TryGetDouble(out var value)) @@ -483,6 +700,11 @@ public double GetDouble() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetSingle(out float value) { CheckValidInstance(); @@ -490,6 +712,11 @@ public bool TryGetSingle(out float value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public float GetSingle() { if (!TryGetSingle(out var value)) @@ -500,6 +727,11 @@ public float GetSingle() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetDecimal(out decimal value) { CheckValidInstance(); @@ -507,6 +739,11 @@ public bool TryGetDecimal(out decimal value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public decimal GetDecimal() { if (!TryGetDecimal(out var value)) @@ -531,6 +768,10 @@ internal ReadOnlySpan GetPropertyNameRaw() return _parent.GetPropertyNameRaw(_cursor); } + /// + /// Gets the raw JSON text representing this element. + /// + /// The raw JSON text. public string GetRawText() { CheckValidInstance(); @@ -545,6 +786,13 @@ internal ReadOnlySpan GetRawValue(bool includeQuotes = true) return _parent.GetRawValue(_cursor, includeQuotes: true); } + /// + /// Compares the text of this element to the specified string. + /// + /// The text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(string? text) { if (TokenType == ElementTokenType.Null) @@ -555,6 +803,13 @@ public bool ValueEquals(string? text) return TextEqualsHelper(text.AsSpan(), isPropertyName: false); } + /// + /// Compares the text of this element to the specified UTF-8 encoded text. + /// + /// The UTF-8 encoded text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(ReadOnlySpan utf8Text) { if (TokenType == ElementTokenType.Null) @@ -567,6 +822,13 @@ public bool ValueEquals(ReadOnlySpan utf8Text) return TextEqualsHelper(utf8Text, isPropertyName: false, shouldUnescape: true); } + /// + /// Compares the text of this element to the specified character span. + /// + /// The text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(ReadOnlySpan text) { if (TokenType == ElementTokenType.Null) @@ -600,6 +862,13 @@ internal string GetPropertyRawText() return _parent.GetPropertyRawValueAsString(_cursor); } + /// + /// Gets an enumerator to enumerate the elements of this array. + /// + /// An enumerator for the array elements. + /// + /// This element's is not . + /// public ArrayEnumerator EnumerateArray() { CheckValidInstance(); @@ -620,6 +889,13 @@ public ArrayEnumerator EnumerateArray() return new ArrayEnumerator(this); } + /// + /// Gets an enumerator to enumerate the properties of this object. + /// + /// An enumerator for the object properties. + /// + /// This element's is not . + /// public ObjectEnumerator EnumerateObject() { CheckValidInstance(); @@ -643,34 +919,242 @@ internal void SetObjectValue(SelectionSet selectionSet) ArgumentNullException.ThrowIfNull(selectionSet); + if (Type is { } type && !type.IsObjectType()) + { + throw new InvalidOperationException( + string.Format(ResultElement_SetObjectValue_NotObjectType, type)); + } + var obj = _parent.CreateObject(_cursor, selectionSet: selectionSet); - _parent.AssignCompositeValue(this, obj); + _parent.AssignObjectOrArray(this, obj); + } + + public void SetObjectValue(int propertyCount) + { + CheckValidInstance(); + + ArgumentOutOfRangeException.ThrowIfLessThan(propertyCount, 0); + + var obj = _parent.CreateObject(_cursor, propertyCount); + _parent.AssignObjectOrArray(this, obj); + } + + public void SetPropertyName(ReadOnlySpan propertyName) + { + CheckValidInstance(); + + if (propertyName.Length == 0) + { + throw new ArgumentNullException(nameof(propertyName)); + } + + var requiredBytes = Encoding.UTF8.GetByteCount(propertyName); + byte[]? rented = null; + var buffer = JsonConstants.StackallocByteThreshold <= requiredBytes + ? stackalloc byte[propertyName.Length] + : (rented = ArrayPool.Shared.Rent(requiredBytes)); + + try + { + var usedBytes = Encoding.UTF8.GetBytes(propertyName, buffer); + _parent.AssignPropertyName(this, buffer[..usedBytes]); + } + finally + { + if (rented is not null) + { + ArrayPool.Shared.Return(rented); + } + } } - internal void SetArrayValue(int length) + public void SetPropertyName(ReadOnlySpan propertyName) + { + CheckValidInstance(); + + if (propertyName.Length == 0) + { + throw new ArgumentNullException(nameof(propertyName)); + } + + _parent.AssignPropertyName(this, propertyName); + } + + public void SetArrayValue(int length) { CheckValidInstance(); ArgumentOutOfRangeException.ThrowIfNegative(length); + if (Type is { } type && !type.IsListType()) + { + throw new InvalidOperationException( + string.Format(ResultElement_SetArrayValue_NotListType, type)); + } + var arr = _parent.CreateArray(_cursor, length); - _parent.AssignCompositeValue(this, arr); + _parent.AssignObjectOrArray(this, arr); } - internal void SetLeafValue(SourceResultElement source) + public void SetNullValue() { CheckValidInstance(); - _parent.AssignSourceValue(this, source); + _parent.AssignNullValue(this); } - internal void SetNullValue() + public void SetBooleanValue(bool value) { CheckValidInstance(); - _parent.AssignNullValue(this); + _parent.AssignBooleanValue(this, value); + } + + public void SetStringValue(ReadOnlySpan value) + { + CheckValidInstance(); + + _parent.AssignStringValue(this, value); + } + + public void SetStringValue(ReadOnlySpan value) + { + CheckValidInstance(); + + // If we have an empty string, we can directly assign it. + if (value.Length == 0) + { + _parent.AssignStringValue(this, []); + return; + } + + var requiredBytes = Encoding.UTF8.GetByteCount(value); + byte[]? rented = null; + var buffer = JsonConstants.StackallocByteThreshold <= requiredBytes + ? stackalloc byte[value.Length] + : (rented = ArrayPool.Shared.Rent(requiredBytes)); + + try + { + var usedBytes = Encoding.UTF8.GetBytes(value, buffer); + _parent.AssignStringValue(this, buffer[..usedBytes]); + } + finally + { + if (rented is not null) + { + ArrayPool.Shared.Return(rented); + } + } + } + + public void SetNumberValue(ReadOnlySpan value) + { + CheckValidInstance(); + + _parent.AssignNumberValue(this, value); + } + + public void SetNumberValue(sbyte value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[4]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(byte value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[3]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(short value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[6]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(ushort value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[5]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(int value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[11]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(uint value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[10]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(long value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[20]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(ulong value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[20]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(float value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[16]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(double value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[24]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); + } + + public void SetNumberValue(decimal value) + { + CheckValidInstance(); + + Span buffer = stackalloc byte[31]; + Utf8Formatter.TryFormat(value, buffer, out var bytesWritten); + _parent.AssignNumberValue(this, buffer[..bytesWritten]); } + /// public override string ToString() { switch (TokenType) diff --git a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs similarity index 89% rename from src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs rename to src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs index d34e5576f8c..695bc20aa08 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/CompositeResultProperty.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs @@ -1,16 +1,16 @@ using System.Diagnostics; using System.Text.Json; -using HotChocolate.Fusion.Execution.Nodes; +using HotChocolate.Execution.Processing; -namespace HotChocolate.Fusion.Text.Json; +namespace HotChocolate.Text.Json; /// /// Represents a single property for a JSON object. /// [DebuggerDisplay("{DebuggerDisplay,nq}")] -public readonly struct CompositeResultProperty +public readonly struct ResultProperty { - internal CompositeResultProperty(CompositeResultElement value) + internal ResultProperty(ResultElement value) { Value = value; } @@ -18,7 +18,7 @@ internal CompositeResultProperty(CompositeResultElement value) /// /// The value of this property. /// - public CompositeResultElement Value { get; } + public ResultElement Value { get; } /// /// The name of this property. @@ -26,9 +26,9 @@ internal CompositeResultProperty(CompositeResultElement value) /// public string Name => Value.GetPropertyName(); - public Selection? Selection => Value.Selection; + public ISelection? Selection => Value.Selection; - public Selection GetRequiredSelection() => Value.AssertSelection(); + public ISelection AssertSelection() => Value.AssertSelection(); /// /// Compares to the name of this property. @@ -115,9 +115,9 @@ public override string ToString() private string DebuggerDisplay => Value.ValueKind == JsonValueKind.Undefined ? "" : $"\"{ToString()}\""; - public void Deconstruct(out Selection selection, out CompositeResultElement value) + public void Deconstruct(out ISelection selection, out ResultElement value) { - selection = GetRequiredSelection(); + selection = AssertSelection(); value = Value; } } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs index 551df5e0349..a72d6ac3b94 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs @@ -24,6 +24,13 @@ internal CompositeResultElement(CompositeResultDocument parent, CompositeResultD _cursor = cursor; } + /// + /// Writes this element as JSON to the specified buffer writer. + /// + /// The buffer writer to write to. + /// + /// true to write indented JSON; otherwise, false. + /// public void WriteTo(IBufferWriter writer, bool indented = false) { var formatter = new CompositeResultDocument.RawJsonFormatter(_parent, writer, indented); @@ -41,25 +48,19 @@ public void WriteTo(IBufferWriter writer, bool indented = false) private ElementTokenType TokenType => _parent?.GetElementTokenType(_cursor) ?? ElementTokenType.None; /// - /// The that the value is. + /// Gets the of this element. /// - /// - /// The parent has been disposed. - /// public JsonValueKind ValueKind => TokenType.ToValueKind(); /// - /// Get the value at a specified index when the current value is a - /// . + /// Gets the element at the specified index when the current element is an array. /// + /// The zero-based index of the element to get. /// - /// This value's is not . + /// This element's is not . /// /// - /// is not in the range [0, ()). - /// - /// - /// The parent has been disposed. + /// is not in the range [0, ()). /// public CompositeResultElement this[int index] { @@ -71,6 +72,9 @@ public CompositeResultElement this[int index] } } + /// + /// Gets the operation this element belongs to. + /// public Operation Operation { get @@ -81,6 +85,10 @@ public Operation Operation } } + /// + /// Gets the if this element represents the data of a selection set; + /// otherwise, null. + /// public SelectionSet? SelectionSet { get @@ -91,6 +99,10 @@ public SelectionSet? SelectionSet } } + /// + /// Gets the if this element represents the data of a field selection; + /// otherwise, null. + /// public Selection? Selection { get @@ -107,6 +119,10 @@ public Selection? Selection } } + /// + /// Gets the if this element represents the data of a field selection; + /// otherwise, null. + /// public IType? Type { get @@ -134,6 +150,9 @@ public IType? Type } } + /// + /// Gets a value indicating whether this element has been invalidated during null propagation. + /// public bool IsInvalidated { get @@ -144,6 +163,9 @@ public bool IsInvalidated } } + /// + /// Gets a value indicating whether this element is either null or was invalidated during null propagation. + /// public bool IsNullOrInvalidated { get @@ -157,6 +179,9 @@ public bool IsNullOrInvalidated } } + /// + /// Gets the path to this element within the result document. + /// public Path Path { get @@ -167,6 +192,9 @@ public Path Path } } + /// + /// Gets the parent element that contains this element. + /// public CompositeResultElement Parent { get @@ -177,6 +205,9 @@ public CompositeResultElement Parent } } + /// + /// Gets a value indicating whether this element is nullable according to the GraphQL type system. + /// public bool IsNullable { get @@ -192,6 +223,10 @@ public bool IsNullable } } + /// + /// Gets a value indicating whether this element represents internal data + /// that is required for processing and must not be written to the GraphQL response. + /// public bool IsInternal { get @@ -202,6 +237,15 @@ public bool IsInternal } } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a selection set. + /// public SelectionSet AssertSelectionSet() { var selectionSet = SelectionSet; @@ -214,6 +258,15 @@ public SelectionSet AssertSelectionSet() return selectionSet; } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a field selection. + /// public Selection AssertSelection() { var selection = Selection; @@ -226,6 +279,15 @@ public Selection AssertSelection() return selection; } + /// + /// Gets the for this element. + /// + /// + /// The instance. + /// + /// + /// This element does not represent the data of a field selection. + /// public IType AssertType() { var type = Type; @@ -238,6 +300,10 @@ public IType AssertType() return type; } + /// + /// Marks this element as invalidated, which occurs during null propagation + /// when a non-nullable field returns null. + /// public void Invalidate() { CheckValidInstance(); @@ -246,8 +312,11 @@ public void Invalidate() } /// - /// Get the number of values contained within the current array value. + /// Gets the number of elements contained within the current array element. /// + /// + /// The number of elements in the array. + /// public int GetArrayLength() { CheckValidInstance(); @@ -256,8 +325,11 @@ public int GetArrayLength() } /// - /// Get the number of properties contained within the current object value. + /// Gets the number of properties contained within the current object element. /// + /// + /// The number of properties in the object. + /// public int GetPropertyCount() { CheckValidInstance(); @@ -265,6 +337,14 @@ public int GetPropertyCount() return _parent.GetPropertyCount(_cursor); } + /// + /// Gets a property by name when the current element is an object. + /// + /// The name of the property to find. + /// The property value. + /// + /// No property with the specified name was found. + /// public CompositeResultElement GetProperty(string propertyName) { ArgumentNullException.ThrowIfNull(propertyName); @@ -277,6 +357,14 @@ public CompositeResultElement GetProperty(string propertyName) throw new KeyNotFoundException(); } + /// + /// Gets a property by UTF-8 encoded name when the current element is an object. + /// + /// The UTF-8 encoded name of the property to find. + /// The property value. + /// + /// No property with the specified name was found. + /// public CompositeResultElement GetProperty(ReadOnlySpan utf8PropertyName) { if (TryGetProperty(utf8PropertyName, out var property)) @@ -287,6 +375,16 @@ public CompositeResultElement GetProperty(ReadOnlySpan utf8PropertyName) throw new KeyNotFoundException(); } + /// + /// Attempts to get a property by name when the current element is an object. + /// + /// The name of the property to find. + /// + /// When this method returns, contains the property value if found; otherwise, the default value. + /// + /// + /// true if the property was found; otherwise, false. + /// public bool TryGetProperty(string propertyName, out CompositeResultElement value) { ArgumentNullException.ThrowIfNull(propertyName); @@ -294,6 +392,16 @@ public bool TryGetProperty(string propertyName, out CompositeResultElement value return _parent.TryGetNamedPropertyValue(_cursor, propertyName, out value); } + /// + /// Attempts to get a property by UTF-8 encoded name when the current element is an object. + /// + /// The UTF-8 encoded name of the property to find. + /// + /// When this method returns, contains the property value if found; otherwise, the default value. + /// + /// + /// true if the property was found; otherwise, false. + /// public bool TryGetProperty(ReadOnlySpan utf8PropertyName, out CompositeResultElement value) { CheckValidInstance(); @@ -301,6 +409,13 @@ public bool TryGetProperty(ReadOnlySpan utf8PropertyName, out CompositeRes return _parent.TryGetNamedPropertyValue(_cursor, utf8PropertyName, out value); } + /// + /// Gets the value as a . + /// + /// The boolean value. + /// + /// This element's is not or . + /// public bool GetBoolean() { var type = TokenType; @@ -324,6 +439,10 @@ static bool ThrowJsonElementWrongTypeException(ElementTokenType actualType) } } + /// + /// Gets the value as a . + /// + /// The string value, or null if this element is a JSON null. public string? GetString() { CheckValidInstance(); @@ -331,6 +450,13 @@ static bool ThrowJsonElementWrongTypeException(ElementTokenType actualType) return _parent.GetString(_cursor, ElementTokenType.String); } + /// + /// Gets the value as a non-null . + /// + /// The string value. + /// + /// This element is a JSON null. + /// public string AssertString() { CheckValidInstance(); @@ -338,6 +464,11 @@ public string AssertString() return _parent.GetRequiredString(_cursor, ElementTokenType.String); } + /// + /// Attempts to get the value as an . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetSByte(out sbyte value) { CheckValidInstance(); @@ -345,8 +476,18 @@ public bool TryGetSByte(out sbyte value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as an . + /// + /// The value. + /// The value cannot be parsed as an . public sbyte GetSByte() => TryGetSByte(out var value) ? value : throw new FormatException(); + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetByte(out byte value) { CheckValidInstance(); @@ -354,6 +495,11 @@ public bool TryGetByte(out byte value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public byte GetByte() { if (TryGetByte(out var value)) @@ -364,6 +510,11 @@ public byte GetByte() throw new FormatException(); } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt16(out short value) { CheckValidInstance(); @@ -371,6 +522,11 @@ public bool TryGetInt16(out short value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public short GetInt16() { if (TryGetInt16(out var value)) @@ -381,6 +537,11 @@ public short GetInt16() throw new FormatException(); } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt16(out ushort value) { CheckValidInstance(); @@ -388,6 +549,11 @@ public bool TryGetUInt16(out ushort value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public ushort GetUInt16() { if (TryGetUInt16(out var value)) @@ -398,6 +564,11 @@ public ushort GetUInt16() throw new FormatException(); } + /// + /// Attempts to get the value as an . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt32(out int value) { CheckValidInstance(); @@ -405,6 +576,11 @@ public bool TryGetInt32(out int value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as an . + /// + /// The value. + /// The value cannot be parsed as an . public int GetInt32() { if (!TryGetInt32(out var value)) @@ -415,6 +591,11 @@ public int GetInt32() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt32(out uint value) { CheckValidInstance(); @@ -422,6 +603,11 @@ public bool TryGetUInt32(out uint value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public uint GetUInt32() { if (!TryGetUInt32(out var value)) @@ -432,6 +618,11 @@ public uint GetUInt32() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetInt64(out long value) { CheckValidInstance(); @@ -439,6 +630,11 @@ public bool TryGetInt64(out long value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public long GetInt64() { if (!TryGetInt64(out var value)) @@ -449,6 +645,11 @@ public long GetInt64() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetUInt64(out ulong value) { CheckValidInstance(); @@ -456,6 +657,11 @@ public bool TryGetUInt64(out ulong value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public ulong GetUInt64() { if (!TryGetUInt64(out var value)) @@ -466,6 +672,11 @@ public ulong GetUInt64() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetDouble(out double value) { CheckValidInstance(); @@ -473,6 +684,11 @@ public bool TryGetDouble(out double value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public double GetDouble() { if (!TryGetDouble(out var value)) @@ -483,6 +699,11 @@ public double GetDouble() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetSingle(out float value) { CheckValidInstance(); @@ -490,6 +711,11 @@ public bool TryGetSingle(out float value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public float GetSingle() { if (!TryGetSingle(out var value)) @@ -500,6 +726,11 @@ public float GetSingle() return value; } + /// + /// Attempts to get the value as a . + /// + /// When this method returns, contains the parsed value. + /// true if the value could be parsed; otherwise, false. public bool TryGetDecimal(out decimal value) { CheckValidInstance(); @@ -507,6 +738,11 @@ public bool TryGetDecimal(out decimal value) return _parent.TryGetValue(_cursor, out value); } + /// + /// Gets the value as a . + /// + /// The value. + /// The value cannot be parsed as a . public decimal GetDecimal() { if (!TryGetDecimal(out var value)) @@ -531,6 +767,10 @@ internal ReadOnlySpan GetPropertyNameRaw() return _parent.GetPropertyNameRaw(_cursor); } + /// + /// Gets the raw JSON text representing this element. + /// + /// The raw JSON text. public string GetRawText() { CheckValidInstance(); @@ -545,6 +785,13 @@ internal ReadOnlySpan GetRawValue(bool includeQuotes = true) return _parent.GetRawValue(_cursor, includeQuotes: true); } + /// + /// Compares the text of this element to the specified string. + /// + /// The text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(string? text) { if (TokenType == ElementTokenType.Null) @@ -555,6 +802,13 @@ public bool ValueEquals(string? text) return TextEqualsHelper(text.AsSpan(), isPropertyName: false); } + /// + /// Compares the text of this element to the specified UTF-8 encoded text. + /// + /// The UTF-8 encoded text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(ReadOnlySpan utf8Text) { if (TokenType == ElementTokenType.Null) @@ -567,6 +821,13 @@ public bool ValueEquals(ReadOnlySpan utf8Text) return TextEqualsHelper(utf8Text, isPropertyName: false, shouldUnescape: true); } + /// + /// Compares the text of this element to the specified character span. + /// + /// The text to compare against. + /// + /// true if this element's value equals the specified text; otherwise, false. + /// public bool ValueEquals(ReadOnlySpan text) { if (TokenType == ElementTokenType.Null) @@ -600,6 +861,13 @@ internal string GetPropertyRawText() return _parent.GetPropertyRawValueAsString(_cursor); } + /// + /// Gets an enumerator to enumerate the elements of this array. + /// + /// An enumerator for the array elements. + /// + /// This element's is not . + /// public ArrayEnumerator EnumerateArray() { CheckValidInstance(); @@ -620,6 +888,13 @@ public ArrayEnumerator EnumerateArray() return new ArrayEnumerator(this); } + /// + /// Gets an enumerator to enumerate the properties of this object. + /// + /// An enumerator for the object properties. + /// + /// This element's is not . + /// public ObjectEnumerator EnumerateObject() { CheckValidInstance(); @@ -671,6 +946,7 @@ internal void SetNullValue() _parent.AssignNullValue(this); } + /// public override string ToString() { switch (TokenType) diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultProperty.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultProperty.cs index d34e5576f8c..e61eab856d8 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultProperty.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultProperty.cs @@ -28,7 +28,7 @@ internal CompositeResultProperty(CompositeResultElement value) public Selection? Selection => Value.Selection; - public Selection GetRequiredSelection() => Value.AssertSelection(); + public Selection AssertSelection() => Value.AssertSelection(); /// /// Compares to the name of this property. @@ -117,7 +117,7 @@ private string DebuggerDisplay public void Deconstruct(out Selection selection, out CompositeResultElement value) { - selection = GetRequiredSelection(); + selection = AssertSelection(); value = Value; } } From 971333fb830b529475f640d5c9892189aae936a0 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 27 Nov 2025 22:52:04 +0100 Subject: [PATCH 08/42] wip --- .../Types/Execution/Processing/IOperation.cs | 2 +- .../Types/Execution/Processing/ISelection.cs | 2 +- .../Execution/Processing/ISelectionSet.cs | 30 ++++ .../Types/Execution/Processing/Operation.cs | 4 + .../OperationCompiler.SelectionSetInfo.cs | 6 +- .../Execution/Processing/OperationCompiler.cs | 14 +- .../Processing/OperationContext.Operation.cs | 2 +- .../Types/Execution/Processing/Selection.cs | 6 +- .../Processing/SelectionCollection.cs | 12 +- .../Execution/Processing/SelectionLookup.cs | 156 ++++++++++++++++++ .../Execution/Processing/SelectionSet.cs | 16 +- .../Text/Json/JsonReaderHelper.cs | 2 +- 12 files changed, 229 insertions(+), 23 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs index 9ad9097c0c2..29635565407 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs @@ -104,7 +104,7 @@ public interface IOperation : IHasReadOnlyContextData, IEnumerable /// Returns the include flags for the specified variable values. /// - long CreateIncludeFlags(IVariableValueCollection variables); + ulong CreateIncludeFlags(IVariableValueCollection variables); bool TryGetState(out TState? state); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs index f6979a4a84f..5eba9ad5385 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs @@ -109,5 +109,5 @@ public interface ISelection : IOptionalSelection /// /// Returns if this selection is annotated with the stream directive. /// - bool HasStreamDirective(long includeFlags); + bool HasStreamDirective(ulong includeFlags); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs index df45aea7ef5..6ef00358cc4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace HotChocolate.Execution.Processing; /// @@ -31,4 +33,32 @@ public interface ISelectionSet /// Gets the declaring operation. /// IOperation DeclaringOperation { get; } + + /// + /// Tries to resolve a selection by name. + /// + /// + /// The selection response name. + /// + /// + /// The resolved selection. + /// + /// + /// Returns true if the selection was successfully resolved. + /// + bool TryGetSelection(string responseName, [NotNullWhen(true)] out ISelection? selection); + + /// + /// Tries to resolve a selection by name. + /// + /// + /// The selection response name. + /// + /// + /// The resolved selection. + /// + /// + /// Returns true if the selection was successfully resolved. + /// + bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out ISelection? selection); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 0c2e3384b3f..ed5b4c63bf0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -9,7 +9,11 @@ namespace HotChocolate.Execution.Processing; internal sealed class Operation : IOperation { +#if NET9_0_OR_GREATER + private readonly Lock _writeLock = new(); +#else private readonly object _writeLock = new(); +#endif private SelectionVariants[] _selectionVariants = []; private IncludeCondition[] _includeConditions = []; private ImmutableDictionary _contextData = diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs index a6363e4c195..7c46db01ff7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs @@ -4,10 +4,12 @@ namespace HotChocolate.Execution.Processing; public sealed partial class OperationCompiler { - internal readonly struct SelectionSetInfo(SelectionSetNode selectionSet, long includeCondition) + internal readonly struct SelectionSetInfo( + SelectionSetNode selectionSet, + ulong includeCondition) { public SelectionSetNode SelectionSet { get; } = selectionSet; - public long IncludeCondition { get; } = includeCondition; + public ulong IncludeCondition { get; } = includeCondition; } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 02446a02fbd..174bc3ca348 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -370,7 +370,7 @@ private void CollectFields(CompilerContext context) private void CollectFields( CompilerContext context, SelectionSetNode selectionSet, - long includeCondition) + ulong includeCondition) { for (var j = 0; j < selectionSet.Selections.Count; j++) { @@ -411,7 +411,7 @@ private void ResolveFields( private void ResolveField( CompilerContext context, FieldNode selection, - long includeCondition) + ulong includeCondition) { includeCondition = GetSelectionIncludeCondition(selection, includeCondition); @@ -514,7 +514,7 @@ private void ResolveFragment( NamedTypeNode? typeCondition, SelectionSetNode selectionSet, IReadOnlyList directives, - long includeCondition) + ulong includeCondition) { if (typeCondition is null || (context.Schema.Types.TryGetType(typeCondition, out IType? typeCon) @@ -528,7 +528,7 @@ private void ResolveFragment( var nullValue = NullValueNode.Default; var ifValue = deferDirective?.GetArgumentValue(DirectiveNames.Defer.Arguments.If) ?? nullValue; - long ifConditionFlags = 0; + ulong ifConditionFlags = 0; if (ifValue.Kind is not SyntaxKind.NullValue) { @@ -649,9 +649,9 @@ private SelectionVariants GetOrCreateSelectionVariants(int selectionSetId) return variants; } - private long GetSelectionIncludeCondition( + private ulong GetSelectionIncludeCondition( ISelectionNode selectionSyntax, - long parentIncludeCondition) + ulong parentIncludeCondition) { var condition = IncludeCondition.FromSelection(selectionSyntax); @@ -697,7 +697,7 @@ private long GetSelectionIncludeCondition( private long GetSelectionIncludeCondition( IncludeCondition condition, - long parentIncludeCondition) + ulong parentIncludeCondition) { var pos = Array.IndexOf(_includeConditions, condition); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs index 8239f55055b..0005bf324d2 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs @@ -44,7 +44,7 @@ public IVariableValueCollection Variables /// /// Gets the include flags for the current request. /// - public long IncludeFlags { get; private set; } + public ulong IncludeFlags { get; private set; } /// /// Gets the value representing the instance of the diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index 1ed864d2455..9470b054e68 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -14,7 +14,7 @@ public class Selection : ISelection { private static readonly ArgumentMap s_emptyArguments = ArgumentMap.Empty; private ulong[] _includeConditions; - private long _streamIfCondition; + private ulong _streamIfCondition; private Flags _flags; private FieldNode _syntaxNode; private FieldNode[] _syntaxNodes; @@ -136,7 +136,7 @@ protected Selection(Selection selection) public ArgumentMap Arguments { get; } /// - public bool HasStreamDirective(long includeFlags) + public bool HasStreamDirective(ulong includeFlags) => (_flags & Flags.Stream) == Flags.Stream && (_streamIfCondition is 0 || (includeFlags & _streamIfCondition) != _streamIfCondition); @@ -313,7 +313,7 @@ internal void SetSelectionSetId(int selectionSetId) SelectionSetId = selectionSetId; } - internal void MarkAsStream(long ifCondition) + internal void MarkAsStream(ulong ifCondition) { if ((_flags & Flags.Sealed) == Flags.Sealed) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs index 58fb04ac373..6a7370dfe04 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs @@ -14,7 +14,7 @@ internal sealed class SelectionCollection( Schema schema, IOperation operation, ISelection[] selections, - long includeFlags) + ulong includeFlags) : ISelectionCollection { private readonly Schema _schema = schema ?? throw new ArgumentNullException(nameof(schema)); @@ -119,7 +119,7 @@ public bool IsSelected(string fieldName) static bool IsChildSelected( IOperation operation, - long includeFlags, + ulong includeFlags, ObjectType objectType, ISelection parent, string fieldName) @@ -199,7 +199,7 @@ public bool IsSelected(string fieldName1, string fieldName2) static bool IsChildSelected( IOperation operation, - long includeFlags, + ulong includeFlags, ObjectType objectType, ISelection parent, string fieldName1, @@ -284,7 +284,7 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) static bool IsChildSelected( IOperation operation, - long includeFlags, + ulong includeFlags, ObjectType objectType, ISelection parent, string fieldName1, @@ -360,7 +360,7 @@ public bool IsSelected(ISet fieldNames) static bool IsChildSelected( IOperation operation, - long includeFlags, + ulong includeFlags, ObjectType objectType, ISelection parent, ISet fieldNames) @@ -481,7 +481,7 @@ private bool CollectSelections( private static void CollectFields( ReadOnlySpan fieldNames, - long includeFlags, + ulong includeFlags, ref ISelection[] buffer, ISelectionSet selectionSet, int index, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs new file mode 100644 index 00000000000..3986a6aab5a --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs @@ -0,0 +1,156 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace HotChocolate.Execution.Processing; + +internal sealed class SelectionLookup +{ + private readonly Entry[] _table; + private readonly int _seed; + private readonly int _mask; + + private SelectionLookup(Entry[] table, int seed, int mask) + { + _table = table; + _seed = seed; + _mask = mask; + } + + public static SelectionLookup Create(SelectionSet selectionSet) + { + var selections = selectionSet.Selections; + var tableSize = NextPowerOfTwo(Math.Max(selections.Count * 2, 4)); + var mask = tableSize - 1; + var table = new Entry[tableSize]; + + // We try multiple seeds to find one with minimal clustering + var bestSeed = 0; + var bestMaxProbeLength = int.MaxValue; + + for (var seed = 0; seed < 100; seed++) + { + Array.Clear(table); + var maxProbeLength = 0; + + foreach (var selection in selections) + { + var hashCode = ComputeHash(selection.Utf8ResponseName, seed); + var index = hashCode & mask; + var probeLength = 0; + + // Linear probe to find empty slot + while (table[index].Selection != null) + { + index = (index + 1) & mask; + probeLength++; + } + + table[index] = new Entry(hashCode, selection); + maxProbeLength = Math.Max(maxProbeLength, probeLength); + } + + // Track best seed + if (maxProbeLength < bestMaxProbeLength) + { + bestMaxProbeLength = maxProbeLength; + bestSeed = seed; + + // If we found excellent distribution, stop early + if (maxProbeLength <= 2) + { + break; + } + } + } + + // Rebuild table with best seed + Array.Clear(table); + foreach (var selection in selections) + { + var hashCode = ComputeHash(selection.Utf8ResponseName, bestSeed); + var index = hashCode & mask; + + while (table[index].Selection != null) + { + index = (index + 1) & mask; + } + + table[index] = new Entry(hashCode, selection); + } + + return new SelectionLookup(table, bestSeed, mask); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetSelection(ReadOnlySpan name, [NotNullWhen(true)] out ISelection? selection) + { + var table = _table.AsSpan(); + + if (table.Length == 0) + { + selection = null!; + return false; + } + + var hashCode = ComputeHash(name, _seed); + var index = hashCode & _mask; + + while (true) + { + ref var entry = ref table[index]; + + // if we hit an empty slot, then there is no selection with the specified name. + if (entry.Selection is null) + { + selection = null; + return false; + } + + if (entry.HashCode == hashCode && name.SequenceEqual(entry.Selection.Utf8ResponseName)) + { + selection = entry.Selection; + return true; + } + + // we had a hash collision need to find the next slot. + index = (index + 1) & _mask; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int ComputeHash(ReadOnlySpan bytes, int seed) + { + var hash = (uint)seed; + + foreach (var b in bytes) + { + hash = hash * 31 + b; + } + + return (int)(hash & 0x7FFFFFFF); + } + + private static int NextPowerOfTwo(int n) + { + if (n <= 0) + { + return 1; + } + + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; + } + + private readonly struct Entry(int hashCode, ISelection selection) + { + public readonly int HashCode = hashCode; + public readonly ISelection? Selection = selection; + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index cd38b9f6388..88223788ca3 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -1,3 +1,5 @@ +using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using HotChocolate.Types; @@ -13,6 +15,8 @@ internal sealed class SelectionSet : ISelectionSet { private static readonly Fragment[] s_empty = []; private readonly Selection[] _selections; + private readonly FrozenDictionary _responseNameLookup; + private readonly SelectionLookup _utf8ResponseNameLookup; private readonly Fragment[] _fragments; private Flags _flags; @@ -30,7 +34,7 @@ internal sealed class SelectionSet : ISelectionSet /// some of the execution. /// /// - /// Defines if this list needs post processing for skip and include. + /// Defines if this list needs post-processing for skip and include. /// public SelectionSet( int id, @@ -40,6 +44,8 @@ public SelectionSet( { Id = id; _selections = selections; + _responseNameLookup = _selections.ToFrozenDictionary(t => t.ResponseName, ISelection (t) => t); + _utf8ResponseNameLookup = SelectionLookup.Create(this); _fragments = fragments ?? s_empty; _flags = isConditional ? Flags.Conditional : Flags.None; } @@ -59,6 +65,14 @@ public SelectionSet( /// public IOperation DeclaringOperation { get; private set; } = null!; + /// + public bool TryGetSelection(string responseName, [NotNullWhen(true)] out ISelection? selection) + => _responseNameLookup.TryGetValue(responseName, out selection); + + /// + public bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out ISelection? selection) + => _utf8ResponseNameLookup.TryGetSelection(utf8ResponseName, out selection); + /// /// Completes the selection set without sealing it. /// diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs index 100366d0af1..edbbcac3f24 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/JsonReaderHelper.cs @@ -10,7 +10,7 @@ namespace HotChocolate.Fusion.Text.Json; #else -using static HotChocolate.Properties.TypeResources; +using static HotChocolate.Properties.TextJsonResources; namespace HotChocolate.Text.Json; #endif From 0388821aaee84e6c6dc34ddc5fc5ffa8979f6bba Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 28 Nov 2025 11:34:39 +0100 Subject: [PATCH 09/42] wip --- .../ISelectionSet.cs | 5 + .../Types/Execution/Processing/ArgumentMap.cs | 91 +- .../Processing/CreateFieldPipeline.cs | 10 + .../Processing/DeferredExecutionTask.cs | 85 -- .../Processing/DeferredExecutionTaskResult.cs | 20 - .../Execution/Processing/DeferredFragment.cs | 98 -- .../Execution/Processing/DeferredStream.cs | 158 --- .../Processing/DeferredWorkScheduler.cs | 178 --- .../Execution/Processing/DeferredWorkState.cs | 215 ---- .../Types/Execution/Processing/Fragment.cs | 52 - .../Types/Execution/Processing/IFragment.cs | 46 - .../Types/Execution/Processing/IOperation.cs | 194 --- .../Processing/IOptionalSelection.cs | 31 - .../Types/Execution/Processing/ISelection.cs | 113 -- .../Execution/Processing/ISelectionSet.cs | 64 - .../Execution/Processing/IncludeCondition.cs | 173 --- .../Types/Execution/Processing/Operation.cs | 353 +++--- .../OperationCompiler.CoerceArgumentValues.cs | 122 ++ .../Execution/Processing/OperationCompiler.cs | 1074 +++++++---------- .../Processing/OperationFeatureCollection.cs | 113 ++ .../Types/Execution/Processing/Selection.cs | 365 ++---- .../Execution/Processing/SelectionSet.cs | 108 +- .../Execution/Processing/SelectionVariants.cs | 194 --- ...s => _OperationCompiler.ArgumentValues.cs} | 5 - .../Processing/_OperationCompiler.cs | 787 ++++++++++++ .../Core/src/Types/HotChocolate.Types.csproj | 2 + .../Nodes/IncludeConditionCollection.cs | 9 +- .../Execution/Nodes/SelectionSet.cs | 19 +- 28 files changed, 1903 insertions(+), 2781 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/CreateFieldPipeline.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IFragment.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs rename src/HotChocolate/Core/src/Types/Execution/Processing/{OperationCompiler.ArgumentValues.cs => _OperationCompiler.ArgumentValues.cs} (98%) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs diff --git a/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelectionSet.cs b/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelectionSet.cs index 7bd3aeef3d3..a64c48f961a 100644 --- a/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelectionSet.cs +++ b/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelectionSet.cs @@ -2,6 +2,11 @@ namespace HotChocolate.Execution; +/// +/// A selection set is primarily composed of field selections. +/// When needed a selection set can preserve fragments so that the execution engine +/// can branch the processing of these fragments. +/// public interface ISelectionSet { /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs index e48ca10171d..354e3bdfd73 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs @@ -1,24 +1,25 @@ using System.Collections; +using System.Collections.Frozen; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using HotChocolate.Resolvers; namespace HotChocolate.Execution.Processing; /// -/// Represents the map of argument values that can be accessed on the . +/// Represents a read-only map of argument values for a field selection in a GraphQL query. +/// This map provides efficient access to coerced argument values and tracks coercion errors. /// -public sealed class ArgumentMap - : IReadOnlyDictionary - , IEnumerable +public sealed class ArgumentMap : IReadOnlyDictionary { - private readonly Dictionary _arguments; - private readonly bool _isFinal; + private readonly FrozenDictionary _arguments; private readonly bool _hasErrors; internal ArgumentMap(Dictionary arguments) { - _arguments = arguments; - _isFinal = true; + _arguments = arguments.ToFrozenDictionary(StringComparer.Ordinal); + IsFullyCoercedNoErrors = true; if (_arguments.Count > 0) { @@ -26,7 +27,7 @@ internal ArgumentMap(Dictionary arguments) { if (!argument.IsFullyCoerced) { - _isFinal = false; + IsFullyCoercedNoErrors = false; } if (argument.HasError) @@ -38,49 +39,79 @@ internal ArgumentMap(Dictionary arguments) } /// - /// Gets an empty argument map. + /// Gets an empty argument map with no arguments. /// public static ArgumentMap Empty { get; } = new([]); /// - /// This indexer allows to access the - /// by the argument . + /// Gets the for the specified argument name. /// /// /// The argument name. /// + /// + /// The associated with the specified name. + /// + /// + /// Thrown when the specified is not found. + /// public ArgumentValue this[string name] => _arguments[name]; /// - /// Specifies if the argument map is fully coerced and has no errors. + /// Gets a value indicating whether all arguments in this map are + /// fully coerced and no errors occurred during coercion. /// - public bool IsFullyCoercedNoErrors => _isFinal && !_hasErrors; + /// + /// true if all arguments are fully coerced without errors; otherwise, false. + /// + public bool IsFullyCoercedNoErrors => field && !_hasErrors; /// - /// Specifies if this argument map has errors. + /// Gets a value indicating whether any argument in this map has coercion errors. /// + /// + /// true if at least one argument has errors; otherwise, false. + /// public bool HasErrors => _hasErrors; /// - /// The argument count. + /// Gets the number of arguments in this map. /// + /// + /// The total count of arguments. + /// public int Count => _arguments.Count; + /// + /// Gets an immutable array containing all argument names in this map. + /// + /// + /// An of argument names. + /// + public ImmutableArray ArgumentNames => _arguments.Keys; + IEnumerable IReadOnlyDictionary.Keys => _arguments.Keys; + /// + /// Gets an immutable array containing all argument values in this map. + /// + /// + /// An of instances. + /// + public ImmutableArray Values => _arguments.Values; + IEnumerable IReadOnlyDictionary.Values => _arguments.Values; /// - /// This method allows to check if an argument value with the specified - /// argument exists. + /// Determines whether this map contains an argument with the specified name. /// /// - /// The argument name. + /// The argument name to check. /// /// - /// true if the argument exists; otherwise, false. + /// true if an argument with the specified exists; otherwise, false. /// public bool ContainsName(string name) => _arguments.ContainsKey(name); @@ -88,17 +119,17 @@ bool IReadOnlyDictionary.ContainsKey(string key) => ContainsName(key); /// - /// Tries to get an by its . + /// Attempts to retrieve the associated with the specified argument name. /// /// - /// The argument name. + /// The argument name to locate. /// /// - /// The argument value. + /// When this method returns, contains the associated with the specified + /// , if found; otherwise, null. /// /// - /// true if an argument value with the specified - /// was retrieved; otherwise, false. + /// true if an argument with the specified was found; otherwise, false. /// public bool TryGetValue(string name, [NotNullWhen(true)] out ArgumentValue? value) => _arguments.TryGetValue(name, out value); @@ -108,14 +139,8 @@ bool IReadOnlyDictionary.TryGetValue( out ArgumentValue value) => TryGetValue(key, out value!); - /// - /// Gets an enumerator for the argument values. - /// - public IEnumerator GetEnumerator() - => _arguments.Values.GetEnumerator(); - - IEnumerator> - IEnumerable>.GetEnumerator() + /// + public IEnumerator> GetEnumerator() => _arguments.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/CreateFieldPipeline.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/CreateFieldPipeline.cs new file mode 100644 index 00000000000..6d2647936b3 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/CreateFieldPipeline.cs @@ -0,0 +1,10 @@ +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types; + +namespace HotChocolate.Execution.Processing; + +internal delegate FieldDelegate CreateFieldPipeline( + Schema schema, + ObjectField field, + FieldNode selection); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs deleted file mode 100644 index f4de9856a12..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTask.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Utilities; -using static HotChocolate.WellKnownContextData; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a deprioritized part of the query that will be executed after -/// the main execution has finished. -/// -internal abstract class DeferredExecutionTask -{ - /// - /// Initializes a new instance of . - /// - protected DeferredExecutionTask(IImmutableDictionary scopedContextData) - { - ScopedContextData = scopedContextData; - } - - /// - /// Gets the preserved scoped context from the parent resolver. - /// - public IImmutableDictionary ScopedContextData { get; } - - /// - /// Starts executing the deferred execution task. - /// - /// - /// The operation context owner. - /// - /// - /// The internal result identifier. - /// - /// - /// The internal identifier of the object that the result will be patched into. - /// - public void Begin(OperationContextOwner operationContextOwner, uint resultId, uint patchId) - { - // retrieve the task on which this task depends upon. We do this to ensure that the result - // of this task is not delivered before the parent result is delivered. - uint parentResultId = 0; - if (ScopedContextData.TryGetValue(DeferredResultId, out var value) - && value is uint id) - { - parentResultId = id; - } - - var capturedContext = ExecutionContext.Capture(); - if (capturedContext is null) - { - ExecuteAsync(operationContextOwner, resultId, parentResultId, patchId).FireAndForget(); - } - else - { - var execute = () => - ExecutionContext.Run( - capturedContext, - _ => ExecuteAsync(operationContextOwner, resultId, parentResultId, patchId), - null); - execute.FireAndForget(); - } - } - - /// - /// The task execution logic. - /// - /// - /// The operation context owner. - /// - /// - /// The internal result identifier. - /// - /// - /// The parent result identifier. - /// - /// - /// The internal identifier of the object that the result will be patched into. - /// - protected abstract Task ExecuteAsync( - OperationContextOwner operationContextOwner, - uint resultId, - uint parentResultId, - uint patchId); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs deleted file mode 100644 index 23fad4d1ea5..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredExecutionTaskResult.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -internal readonly struct DeferredExecutionTaskResult -{ - public DeferredExecutionTaskResult( - uint taskId, - uint parentTaskId, - IOperationResult? result = null) - { - TaskId = taskId; - ParentTaskId = parentTaskId; - Result = result; - } - - public uint TaskId { get; } - - public uint ParentTaskId { get; } - - public IOperationResult? Result { get; } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs deleted file mode 100644 index 90faf750543..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredFragment.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Collections.Immutable; -using static HotChocolate.Execution.Processing.Tasks.ResolverTaskFactory; -using static HotChocolate.WellKnownContextData; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a deprioritized fragment of the query that will be executed after -/// the main execution has finished. -/// -internal sealed class DeferredFragment : DeferredExecutionTask -{ - /// - /// Initializes a new instance of . - /// - public DeferredFragment( - IFragment fragment, - string? label, - Path path, - object? parent, - IImmutableDictionary scopedContextData) - : base(scopedContextData) - { - Fragment = fragment; - Label = label; - Path = path; - Parent = parent; - } - - /// - /// Gets the deferred fragment. - /// - public IFragment Fragment { get; } - - /// - /// If this argument label has a value other than null, it will be passed - /// on to the result of this defer directive. This label is intended to - /// give client applications a way to identify to which fragment a deferred - /// result belongs to. - /// - public string? Label { get; } - - /// - /// Gets the result path into which this deferred fragment shall be patched. - /// - public Path Path { get; } - - /// - /// Gets the parent / source value. - /// - public object? Parent { get; } - - protected override async Task ExecuteAsync( - OperationContextOwner operationContextOwner, - uint resultId, - uint parentResultId, - uint patchId) - { - try - { - var operationContext = operationContextOwner.OperationContext; - var parentResult = operationContext.Result.RentObject(Fragment.SelectionSet.Selections.Count); - - parentResult.PatchPath = Path; - - EnqueueResolverTasks( - operationContext, - Fragment.SelectionSet, - Parent, - Path, - // for the execution of this task we set the deferred task ID so that - // child deferrals can lookup their dependency to this task. - ScopedContextData.SetItem(DeferredResultId, resultId), - parentResult); - - // start executing the deferred fragment. - await operationContext.Scheduler.ExecuteAsync().ConfigureAwait(false); - - // we create the result but will not create the final result object yet. - // We will leave the final creation to the deferred work scheduler so that the - // has next property can be correctly set. - var result = - operationContext - .SetLabel(Label) - .SetPath(Path) - .SetData(parentResult) - .SetPatchId(patchId) - .BuildResult(); - - // complete the task and provide the result - operationContext.DeferredScheduler.Complete(new(resultId, parentResultId, result)); - } - finally - { - operationContextOwner.Dispose(); - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs deleted file mode 100644 index f5d6b220101..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredStream.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Execution.Processing.Tasks; -using static HotChocolate.WellKnownContextData; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents the work to executed the deferred elements of a stream. -/// -internal sealed class DeferredStream : DeferredExecutionTask -{ - private StreamExecutionTask? _task; - - /// - /// Initializes a new instance of . - /// - public DeferredStream( - ISelection selection, - string? label, - Path path, - object? parent, - int index, - IAsyncEnumerator enumerator, - IImmutableDictionary scopedContextData) - : base(scopedContextData) - { - Selection = selection; - Label = label; - Path = path; - Parent = parent; - Index = index; - Enumerator = enumerator; - } - - /// - /// Gets the selection of the streamed field. - /// - public ISelection Selection { get; } - - /// - /// If this argument label has a value other than null, it will be passed - /// on to the result of this defer directive. This label is intended to - /// give client applications a way to identify to which fragment a deferred - /// result belongs to. - /// - public string? Label { get; } - - /// - /// Gets the result path into which this deferred fragment shall be patched. - /// - public Path Path { get; } - - /// - /// Gets the index of the last element. - /// - public int Index { get; private set; } - - /// - /// Gets the parent / source value. - /// - public object? Parent { get; } - - /// - /// Gets the enumerator to retrieve the payloads of the stream. - /// - public IAsyncEnumerator Enumerator { get; } - - protected override async Task ExecuteAsync( - OperationContextOwner operationContextOwner, - uint resultId, - uint parentResultId, - uint patchId) - { - var operationContext = operationContextOwner.OperationContext; - - try - { - _task ??= new StreamExecutionTask(this); - _task.Reset(operationContext, resultId); - operationContext.Scheduler.Register(_task); - await operationContext.Scheduler.ExecuteAsync().ConfigureAwait(false); - - // if there is no child task, then there is no more data, so we can complete. - if (_task.ChildTask is null) - { - operationContext.DeferredScheduler.Complete(new(resultId, parentResultId)); - return; - } - - var item = _task.ChildTask.ParentResult[0].Value!; - - var result = operationContext - .SetLabel(Label) - .SetPath(Path.Append(Index)) - .SetItems([item]) - .SetPatchId(patchId) - .BuildResult(); - - await _task.ChildTask.CompleteUnsafeAsync().ConfigureAwait(false); - - // we will register this same task again to get the next item. - operationContext.DeferredScheduler.Register(this, patchId); - operationContext.DeferredScheduler.Complete(new(resultId, parentResultId, result)); - } - catch (Exception ex) - { - var result = OperationResultBuilder.CreateError(ErrorBuilder.FromException(ex).Build()); - operationContext.DeferredScheduler.Complete(new(resultId, parentResultId, result)); - } - finally - { - operationContextOwner.Dispose(); - } - } - - private sealed class StreamExecutionTask : ExecutionTask - { - private readonly DeferredStream _deferredStream; - private OperationContext _operationContext = null!; - private IImmutableDictionary _scopedContextData; - - public StreamExecutionTask(DeferredStream deferredStream) - { - _deferredStream = deferredStream; - _scopedContextData = _deferredStream.ScopedContextData; - } - - protected override IExecutionTaskContext Context => _operationContext; - - public ResolverTask? ChildTask { get; private set; } - - protected override async ValueTask ExecuteAsync(CancellationToken cancellationToken) - { - ChildTask = null; - _deferredStream.Index++; - var hasNext = await _deferredStream.Enumerator.MoveNextAsync(); - - if (hasNext) - { - ChildTask = ResolverTaskFactory.EnqueueElementTasks( - _operationContext, - _deferredStream.Selection, - _deferredStream.Parent, - _deferredStream.Path, - _deferredStream.Index, - _deferredStream.Enumerator, - _scopedContextData); - } - } - - public void Reset(OperationContext operationContext, uint taskId) - { - _operationContext = operationContext; - _scopedContextData = _scopedContextData.SetItem(DeferredResultId, taskId); - Reset(); - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs deleted file mode 100644 index 4bbccb2a888..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkScheduler.cs +++ /dev/null @@ -1,178 +0,0 @@ -using HotChocolate.Execution.DependencyInjection; -using HotChocolate.Execution.Instrumentation; -using Microsoft.Extensions.DependencyInjection; -using static HotChocolate.Execution.OperationResultBuilder; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a backlog for deferred work. -/// -internal sealed class DeferredWorkScheduler -{ - private readonly object _stateSync = new(); - private IFactory _operationContextFactory = null!; - private IFactory _deferredWorkStateFactory = null!; - private OperationContext _parentContext = null!; - private DeferredWorkStateOwner? _stateOwner; - - private DeferredWorkStateOwner StateOwner - { - get - { - if (_stateOwner is null) - { - lock (_stateSync) - { - _stateOwner ??= _deferredWorkStateFactory.Create(); - } - } - - return _stateOwner; - } - } - - /// - /// Specifies if there was deferred work enqueued. - /// - public bool HasResults => _stateOwner?.State.HasResults is true; - - public void Initialize(OperationContext operationContext) - { - var services = operationContext.Services; - - _stateOwner = null; - _parentContext = operationContext; - _operationContextFactory = services.GetRequiredService>(); - _deferredWorkStateFactory = services.GetRequiredService>(); - } - - public void InitializeFrom(OperationContext operationContext, DeferredWorkScheduler scheduler) - { - _stateOwner = scheduler.StateOwner; - _parentContext = operationContext; - _operationContextFactory = scheduler._operationContextFactory; - _deferredWorkStateFactory = scheduler._deferredWorkStateFactory; - } - - /// - /// Registers deferred work - /// - public void Register(DeferredExecutionTask task, ResultData parentResult) - { - // first we get the result identifier which is used to refer to the result that we defer. - var resultId = StateOwner.State.CreateId(); - - // next we assign a patch identifier to the result set into which the deferred result - // shall be patched into. - var patchId = StateOwner.State.AssignPatchId(parentResult); - - // for the spawned execution we need an operation context which we will initialize - // from the current operation context. - var taskContextOwner = _operationContextFactory.Create(); - taskContextOwner.OperationContext.InitializeFrom(_parentContext); - - // Last we register our patch identifier with the parent result so that - // we can more efficiently mark discarded result sets to not send down - // patches that cannot be applied. - _parentContext.Result.AddPatchId(patchId); - - // with all in place we will start the execution of the deferred task. - task.Begin(taskContextOwner, resultId, patchId); - } - - public void Register(DeferredExecutionTask task, uint patchId) - { - var resultId = StateOwner.State.CreateId(); - var taskContextOwner = _operationContextFactory.Create(); - taskContextOwner.OperationContext.InitializeFrom(_parentContext); - task.Begin(taskContextOwner, resultId, patchId); - } - - public void Complete(DeferredExecutionTaskResult result) - => StateOwner.State.Complete(result); - - public IAsyncEnumerable CreateResultStream(IOperationResult initialResult) - => new DeferredResultStream( - initialResult, - StateOwner, - _parentContext.Operation, - _parentContext.DiagnosticEvents); - - public void Clear() - { - _stateOwner = null; - _operationContextFactory = null!; - _deferredWorkStateFactory = null!; - _parentContext = null!; - } - - private class DeferredResultStream : IAsyncEnumerable - { - private readonly IOperationResult _initialResult; - private readonly DeferredWorkStateOwner _stateOwner; - private readonly IOperation _operation; - private readonly IExecutionDiagnosticEvents _diagnosticEvents; - - public DeferredResultStream( - IOperationResult initialResult, - DeferredWorkStateOwner stateOwner, - IOperation operation, - IExecutionDiagnosticEvents diagnosticEvents) - { - _initialResult = FromResult(initialResult).SetHasNext(true).Build(); - _stateOwner = stateOwner; - _operation = operation; - _diagnosticEvents = diagnosticEvents; - } - - public async IAsyncEnumerator GetAsyncEnumerator( - CancellationToken cancellationToken = default) - { - var span = _diagnosticEvents.ExecuteStream(_operation); - var state = _stateOwner.State; - var hasNext = true; - var completed = false; - - try - { - yield return _initialResult; - - while (!cancellationToken.IsCancellationRequested) - { - var result = await state - .TryDequeueResultsAsync(cancellationToken) - .ConfigureAwait(false); - - if (result is not null) - { - hasNext = result.HasNext ?? false; - yield return result; - } - else if (state.IsCompleted) - { - if (hasNext) - { - yield return new OperationResult(null, hasNext: false); - } - - yield break; - } - } - - completed = !cancellationToken.IsCancellationRequested; - } - finally - { - span.Dispose(); - } - - // we only return the state back to its pool if the operation was not cancelled - // or otherwise faulted. - if (completed) - { - _stateOwner.Dispose(); - } - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs deleted file mode 100644 index ad678864378..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkState.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System.Runtime.CompilerServices; -using static HotChocolate.WellKnownContextData; - -namespace HotChocolate.Execution.Processing; - -internal sealed class DeferredWorkState -{ - private readonly object _completeSync = new(); - private readonly object _deliverSync = new(); - private readonly object _patchSync = new(); - - private readonly List _ready = []; - private readonly Queue _deliverable = new(); - private readonly HashSet _completed = []; - private readonly HashSet _notPatchable = []; - private SemaphoreSlim _semaphore = new(0); - private uint _taskId; - private uint _work; - private uint _patchId; - - public bool HasResults => _taskId > 0; - - public bool IsCompleted => _work is 0; - - public uint CreateId() - { - lock (_deliverSync) - { - _work++; - return ++_taskId; - } - } - - public uint AssignPatchId(ResultData resultData) - { - if (resultData.PatchId == 0) - { - lock (_patchSync) - { - if (resultData.PatchId == 0) - { - var patchId = ++_patchId; - resultData.PatchId = patchId; - return patchId; - } - } - } - - return resultData.PatchId; - } - - public void Complete(DeferredExecutionTaskResult result) - { - var update = true; - - try - { - lock (_completeSync) - { - if (result.ParentTaskId is 0 || _completed.Contains(result.ParentTaskId)) - { - _completed.Add(result.TaskId); - EnqueueResult(result.Result); - - var evaluateDeferredResults = _ready.Count > 0; - - while (evaluateDeferredResults) - { - var i = 0; - evaluateDeferredResults = false; - - while (_ready.Count > 0 && i < _ready.Count) - { - var current = _ready[i]; - - if (_completed.Contains(current.ParentTaskId)) - { - _completed.Add(current.TaskId); - _ready.RemoveAt(i); - EnqueueResult(current.Result); - evaluateDeferredResults = true; - } - else - { - i++; - } - } - } - } - else - { - _ready.Add(result); - update = false; - } - } - } - finally - { - if (update) - { - _semaphore.Release(); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnqueueResult(IOperationResult? queryResult) - { - lock (_deliverSync) - { - if (queryResult is not null) - { - _deliverable.Enqueue(queryResult); - } - else - { - _work--; - } - } - } - - public async ValueTask TryDequeueResultsAsync( - CancellationToken cancellationToken) - { - await _semaphore.WaitAsync(cancellationToken); - - lock (_deliverSync) - { - if (_deliverable.Count > 0) - { - var hasNext = true; - var result = new IOperationResult[_deliverable.Count]; - var consumed = 0; - - for (var i = 0; i < result.Length; i++) - { - var deliverable = _deliverable.Dequeue(); - - if (--_work is 0) - { - _semaphore.Release(); - hasNext = false; - } - - // if the deferred result can still be patched into the result set from which - // it was being spawned of we will add it to the result batch. - if ((deliverable.ContextData?.TryGetValue(PatchId, out var value) ?? false) - && value is uint patchId - && !_notPatchable.Contains(patchId)) - { - AddRemovedResultSetsToNotPatchable(deliverable, _notPatchable); - result[consumed++] = deliverable; - } - - // if the item is not patchable we will discard it and mark all dependant - // results as not patchable. - else - { - AddAllResultSetsToNotPatchable(deliverable, _notPatchable); - } - } - - if (consumed < result.Length) - { - Array.Resize(ref result, consumed); - } - - return new OperationResult(null, incremental: result, hasNext: hasNext); - } - } - - return null; - - static void AddRemovedResultSetsToNotPatchable( - IOperationResult result, - HashSet notPatchable) - { - if ((result.ContextData?.TryGetValue(RemovedResults, out var value) ?? false) - && value is IEnumerable patchIds) - { - foreach (var patchId in patchIds) - { - notPatchable.Add(patchId); - } - } - } - - static void AddAllResultSetsToNotPatchable( - IOperationResult result, - HashSet notPatchable) - { - if ((result.ContextData?.TryGetValue(ExpectedPatches, out var value) ?? false) - && value is IEnumerable patchIds) - { - foreach (var patchId in patchIds) - { - notPatchable.Add(patchId); - } - } - } - } - - public void Reset() - { - _semaphore.Dispose(); - _semaphore = new SemaphoreSlim(0); - _ready.Clear(); - _completed.Clear(); - _deliverable.Clear(); - _notPatchable.Clear(); - _taskId = 0; - _work = 0; - _patchId = 0; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs deleted file mode 100644 index 3e3d2a1c42c..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Fragment.cs +++ /dev/null @@ -1,52 +0,0 @@ -using HotChocolate.Language; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -internal sealed class Fragment : IFragment -{ - private readonly ulong _includeCondition; - private readonly ulong _deferIfCondition; - - public Fragment( - int id, - IObjectTypeDefinition typeCondition, - ISyntaxNode syntaxNode, - IReadOnlyList directives, - ISelectionSet selectionSet, - ulong includeCondition, - ulong deferIfCondition, - bool isInternal = false) - { - Id = id; - TypeCondition = typeCondition; - SyntaxNode = syntaxNode; - Directives = directives; - SelectionSet = selectionSet; - _includeCondition = includeCondition; - _deferIfCondition = deferIfCondition; - IsInternal = isInternal; - } - - public int Id { get; } - - public IObjectTypeDefinition TypeCondition { get; } - - public ISyntaxNode SyntaxNode { get; } - - public IReadOnlyList Directives { get; } - - public ISelectionSet SelectionSet { get; } - - public bool IsInternal { get; } - - public bool IsConditional => _includeCondition is not 0 || _deferIfCondition is not 0; - - public string? GetLabel(IVariableValueCollection variables) - => Directives.GetDeferDirective(variables)?.Label; - - public bool IsIncluded(ulong includeFlags, bool allowInternals = false) - => (includeFlags & _includeCondition) == _includeCondition - && (_deferIfCondition is 0 || (includeFlags & _deferIfCondition) != _deferIfCondition) - && (!IsInternal || allowInternals); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IFragment.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IFragment.cs deleted file mode 100644 index a2947ee1382..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IFragment.cs +++ /dev/null @@ -1,46 +0,0 @@ -using HotChocolate.Language; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a deferred fragment. -/// -public interface IFragment : IOptionalSelection -{ - /// - /// Gets the internal fragment identifier. - /// - int Id { get; } - - /// - /// Gets the type condition. - /// - IObjectTypeDefinition TypeCondition { get; } - - /// - /// Gets the syntax node from the original GraphQL request document. - /// - ISyntaxNode SyntaxNode { get; } - - /// - /// Gets the collection of directives that are annotated to this fragment. - /// - IReadOnlyList Directives { get; } - - /// - /// Gets the selection set of this fragment. - /// - ISelectionSet SelectionSet { get; } - - /// - /// Gets the fragment label. - /// - /// - /// The variable values. - /// - /// - /// Returns the fragment label. - /// - string? GetLabel(IVariableValueCollection variables); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs deleted file mode 100644 index 29635565407..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IOperation.cs +++ /dev/null @@ -1,194 +0,0 @@ -using HotChocolate.Language; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a compiled GraphQL operation. -/// -public interface IOperation : IHasReadOnlyContextData, IEnumerable -{ - /// - /// Gets the internal unique identifier for this operation. - /// - string Id { get; } - - /// - /// Gets the parsed query document that contains the - /// operation-. - /// - DocumentNode Document { get; } - - /// - /// Gets the syntax node representing the operation definition. - /// - OperationDefinitionNode Definition { get; } - - /// - /// Gets the root type on which the operation is executed. - /// - ObjectType RootType { get; } - - /// - /// Gets the name of the operation. - /// - string? Name { get; } - - /// - /// Gets the operation type (Query, Mutation, Subscription). - /// - OperationType Type { get; } - - /// - /// Gets the prepared root selections for this operation. - /// - /// - /// Returns the prepared root selections for this operation. - /// - ISelectionSet RootSelectionSet { get; } - - /// - /// Gets all selection variants of this operation. - /// - IReadOnlyList SelectionVariants { get; } - - /// - /// Defines if this operation has deferred fragments or streams. - /// - bool HasIncrementalParts { get; } - - /// - /// Gets the schema for which this operation is compiled. - /// - ISchemaDefinition Schema { get; } - - /// - /// Gets the selection set for the specified and - /// . - /// - /// - /// The selection set for which the selection set shall be resolved. - /// - /// - /// The result type context. - /// - /// - /// Returns the selection set for the specified and - /// . - /// - /// - /// The specified has no selection set. - /// - ISelectionSet GetSelectionSet(ISelection selection, ObjectType typeContext); - - /// - /// Gets the possible return types for the . - /// - /// - /// The selection for which the possible result types shall be returned. - /// - /// - /// Returns the possible return types for the specified . - /// - /// - /// The specified has no selection set. - /// - IEnumerable GetPossibleTypes(ISelection selection); - - /// - /// Creates the include flags for the specified variable values. - /// - /// - /// The variable values. - /// - /// - /// Returns the include flags for the specified variable values. - /// - ulong CreateIncludeFlags(IVariableValueCollection variables); - - bool TryGetState(out TState? state); - - bool TryGetState(string key, out TState? state); - - /// - /// Gets or adds state to this operation. - /// - /// - /// The type of the state. - /// - /// - /// The factory that creates the state if it does not exist. - /// - /// - /// Returns the state. - /// - TState GetOrAddState( - Func createState); - - /// - /// Gets or adds state to this operation. - /// - /// - /// The type of the state. - /// - /// - /// The type of the context. - /// - /// - /// The factory that creates the state if it does not exist. - /// - /// - /// The context that is passed to the factory. - /// - /// - /// Returns the state. - /// - TState GetOrAddState( - Func createState, - TContext context); - - /// - /// Gets or adds state to this operation. - /// - /// - /// The type of the state. - /// - /// - /// The key of the state. - /// - /// - /// The factory that creates the state if it does not exist. - /// - /// - /// Returns the state. - /// - TState GetOrAddState( - string key, - Func createState); - - /// - /// Gets or adds state to this operation. - /// - /// - /// The type of the state. - /// - /// - /// The type of the context. - /// - /// - /// The key of the state. - /// - /// - /// The factory that creates the state if it does not exist. - /// - /// - /// The context that is passed to the factory. - /// - /// - /// Returns the state. - /// - TState GetOrAddState( - string key, - Func createState, - TContext context); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs deleted file mode 100644 index fb6839101d4..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IOptionalSelection.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -/// -/// Represents selections with inclusion conditions. -/// -public interface IOptionalSelection -{ - /// - /// Defines that this selection is only needed for internal processing. - /// - bool IsInternal { get; } - - /// - /// Defines that this selection is conditional and will not always be included. - /// - bool IsConditional { get; } - - /// - /// Defines if this selection will be included into the request execution. - /// - /// - /// The execution include flags. - /// - /// - /// Allow internal selections to be included. - /// - /// - /// True, if this selection shall be included into the request execution. - /// - bool IsIncluded(ulong includeFlags, bool allowInternals = false); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs deleted file mode 100644 index 5eba9ad5385..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelection.cs +++ /dev/null @@ -1,113 +0,0 @@ -using HotChocolate.Language; -using HotChocolate.Resolvers; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a field selection during execution. -/// -public interface ISelection : IOptionalSelection -{ - /// - /// Gets an operation unique identifier of this selection. - /// - int Id { get; } - - /// - /// Gets the name this field will have in the response map. - /// - string ResponseName { get; } - - /// - /// Gets the UTF-8 encoded name this field will have in the response map. - /// - byte[] Utf8ResponseName { get; } - - /// - /// Gets the field that was selected. - /// - ObjectField Field { get; } - - /// - /// Gets the type of the selection. - /// - IType Type { get; } - - /// - /// Gets the type kind of the selection. - /// - TypeKind TypeKind { get; } - - /// - /// Specifies if the return type of this selection is a list type. - /// - bool IsList { get; } - - /// - /// Gets the type that declares the field that is selected by this selection. - /// - ObjectType DeclaringType { get; } - - /// - /// Gets the selectionSet that declares this selection. - /// - ISelectionSet DeclaringSelectionSet { get; } - - /// - /// Gets the operation that declares this selection. - /// - IOperation DeclaringOperation { get; } - - /// - /// Gets the merged field selection syntax node. - /// - FieldNode SyntaxNode { get; } - - /// - /// Gets the field selection syntax node. - /// - IReadOnlyList SyntaxNodes { get; } - - /// - /// If this selection selects a field that returns a composite type - /// then this selection set represents the fields that are selected - /// on that returning composite type. - /// - /// If this selection however selects a leaf field than this - /// selection set will be null. - /// - SelectionSetNode? SelectionSet { get; } - - /// - /// Gets the execution kind. - /// - SelectionExecutionStrategy Strategy { get; } - - /// - /// The compiled resolver pipeline for this selection. - /// - FieldDelegate? ResolverPipeline { get; } - - /// - /// The compiled pure resolver. - /// - PureFieldDelegate? PureResolver { get; } - - /// - /// The arguments that have been pre-coerced for this field selection. - /// - ArgumentMap Arguments { get; } - - /// - /// Defines if this selection is annotated with the stream directive. - /// - /// - /// The execution include flags that determine if the stream directive is applied for the - /// current execution run. - /// - /// - /// Returns if this selection is annotated with the stream directive. - /// - bool HasStreamDirective(ulong includeFlags); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs deleted file mode 100644 index 6ef00358cc4..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionSet.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace HotChocolate.Execution.Processing; - -/// -/// A selection set is primarily composed of field selections. -/// When needed a selection set can preserve fragments so that the execution engine -/// can branch the processing of these fragments. -/// -public interface ISelectionSet -{ - /// - /// Gets an operation unique selection-set identifier of this selection. - /// - int Id { get; } - - /// - /// Defines if this list needs post-processing for skip and include. - /// - bool IsConditional { get; } - - /// - /// Gets the selections that shall be executed. - /// - IReadOnlyList Selections { get; } - - /// - /// Gets the deferred fragments if any were preserved for execution. - /// - IReadOnlyList Fragments { get; } - - /// - /// Gets the declaring operation. - /// - IOperation DeclaringOperation { get; } - - /// - /// Tries to resolve a selection by name. - /// - /// - /// The selection response name. - /// - /// - /// The resolved selection. - /// - /// - /// Returns true if the selection was successfully resolved. - /// - bool TryGetSelection(string responseName, [NotNullWhen(true)] out ISelection? selection); - - /// - /// Tries to resolve a selection by name. - /// - /// - /// The selection response name. - /// - /// - /// The resolved selection. - /// - /// - /// Returns true if the selection was successfully resolved. - /// - bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out ISelection? selection); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs deleted file mode 100644 index 87061dba0df..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System.Runtime.CompilerServices; -using HotChocolate.Language; -using HotChocolate.Types; -using HotChocolate.Utilities; - -namespace HotChocolate.Execution.Processing; - -/// -/// This struct represents the include condition of a Field, InlineFragment or FragmentSpread. -/// -public readonly struct IncludeCondition : IEquatable -{ - internal IncludeCondition(IValueNode skip, IValueNode include) - { - Skip = skip; - Include = include; - } - - /// - /// Gets the skip value. - /// - public IValueNode Skip { get; } - - /// - /// Gets the include value. - /// - public IValueNode Include { get; } - - /// - /// If and are null then - /// there is no valid include condition. - /// - public bool IsDefault => Skip is null && Include is null; - - /// - /// Specifies if selections with this include condition are included with the - /// current variable values. - /// - /// - /// The variable values. - /// - /// - /// Returns true if selections with this include condition are included. - /// - public bool IsIncluded(IVariableValueCollection variables) - { - ArgumentNullException.ThrowIfNull(variables); - - if (Skip is null || Include is null) - { - return true; - } - - var skip = false; - - if (Skip.Kind is SyntaxKind.BooleanValue) - { - skip = ((BooleanValueNode)Skip).Value; - } - else if (Skip.Kind is SyntaxKind.Variable) - { - var variable = Unsafe.As(Skip); - skip = variables.GetValue(variable.Name.Value).Value; - } - - var include = true; - - if (Include.Kind is SyntaxKind.BooleanValue) - { - include = ((BooleanValueNode)Include).Value; - } - else if (Include.Kind is SyntaxKind.Variable) - { - var variable = Unsafe.As(Include); - include = variables.GetValue(variable.Name.Value).Value; - } - - return !skip && include; - } - - /// - /// Indicates whether the current object is equal to another object of the same type. - /// - /// An object to compare with this object. - /// - /// if the current object is equal to the - /// parameter; otherwise, . - /// - public bool Equals(IncludeCondition other) - => Skip.Equals(other.Skip, SyntaxComparison.Syntax) - && Include.Equals(other.Include, SyntaxComparison.Syntax); - - /// - /// Indicates whether this instance and a specified object are equal. - /// - /// - /// The object to compare with the current instance. - /// - /// - /// if and this instance is the same - /// type and represents the same value; otherwise, . - /// - public override bool Equals(object? obj) - => obj is IncludeCondition other && Equals(other); - - /// - /// Returns the hash code for this instance. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - public override int GetHashCode() - => HashCode.Combine( - SyntaxComparer.BySyntax.GetHashCode(Skip), - SyntaxComparer.BySyntax.GetHashCode(Include)); - - /// - /// Tries to extract the include condition from a field. - /// - /// - /// The selection to extract the include condition from. - /// - /// - /// Returns true if the selection has a custom visibility configuration. - /// - public static IncludeCondition FromSelection(ISelectionNode selection) - { - ArgumentNullException.ThrowIfNull(selection); - - IValueNode? skip = null; - IValueNode? include = null; - - if (selection.Directives.Count == 0) - { - return default; - } - - for (var i = 0; i < selection.Directives.Count; i++) - { - var directive = selection.Directives[i]; - - if (directive.Arguments.Count != 1) - { - // the skip and include arguments have a single argument. - continue; - } - - if (directive.Name.Value.EqualsOrdinal(DirectiveNames.Skip.Name)) - { - skip = directive.Arguments[0].Value; - } - - if (directive.Name.Value.EqualsOrdinal(DirectiveNames.Include.Name)) - { - include = directive.Arguments[0].Value; - } - - if (skip is not null && include is not null) - { - break; - } - } - - if (skip is null && include is null) - { - return default; - } - - return new IncludeCondition( - skip ?? NullValueNode.Default, - include ?? NullValueNode.Default); - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index ed5b4c63bf0..72c8ed60f88 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -1,5 +1,8 @@ -using System.Collections; -using System.Collections.Immutable; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Types; using static HotChocolate.Execution.Properties.Resources; @@ -7,226 +10,252 @@ namespace HotChocolate.Execution.Processing; -internal sealed class Operation : IOperation +public sealed class Operation : IOperation { #if NET9_0_OR_GREATER - private readonly Lock _writeLock = new(); + private readonly Lock _sync = new(); #else - private readonly object _writeLock = new(); + private readonly object _sync = new(); #endif - private SelectionVariants[] _selectionVariants = []; - private IncludeCondition[] _includeConditions = []; - private ImmutableDictionary _contextData = -#if NET10_0_OR_GREATER - []; -#else - ImmutableDictionary.Empty; -#endif - private bool _sealed; - public Operation( + private readonly ConcurrentDictionary<(int, string), SelectionSet> _selectionSets = []; + private readonly OperationCompiler2 _compiler; + private readonly IncludeConditionCollection _includeConditions; + private readonly OperationFeatureCollection _features; + private readonly bool _isFinal; + private object[] _elementsById; + private int _lastId; + + internal Operation( string id, - DocumentNode document, + string hash, OperationDefinitionNode definition, ObjectType rootType, - ISchemaDefinition schema) + Schema schema, + SelectionSet rootSelectionSet, + OperationCompiler2 compiler, + IncludeConditionCollection includeConditions, + int lastId, + object[] elementsById, + bool isFinal) { + ArgumentException.ThrowIfNullOrWhiteSpace(id); + ArgumentException.ThrowIfNullOrWhiteSpace(hash); + ArgumentNullException.ThrowIfNull(definition); + ArgumentNullException.ThrowIfNull(rootType); + ArgumentNullException.ThrowIfNull(schema); + ArgumentNullException.ThrowIfNull(rootSelectionSet); + ArgumentNullException.ThrowIfNull(compiler); + ArgumentNullException.ThrowIfNull(includeConditions); + ArgumentNullException.ThrowIfNull(elementsById); + Id = id; - Document = document; + Hash = hash; Definition = definition; RootType = rootType; - Type = definition.Operation; Schema = schema; - - if (definition.Name?.Value is { } name) - { - Name = name; - } + RootSelectionSet = rootSelectionSet; + _compiler = compiler; + _includeConditions = includeConditions; + _lastId = lastId; + _elementsById = elementsById; + _isFinal = isFinal; + + _features = new OperationFeatureCollection(); + rootSelectionSet.Complete(this, seal: isFinal); } + /// + /// Gets the internal unique identifier for this operation. + /// public string Id { get; } - public DocumentNode Document { get; } + /// + /// Gets the hash of the original operation document. + /// + public string Hash { get; } + /// + /// Gets the name of the operation. + /// + public string? Name => Definition.Name?.Value; + + /// + /// Gets the syntax node representing the operation definition. + /// public OperationDefinitionNode Definition { get; } + /// + /// Gets the root type on which the operation is executed. + /// public ObjectType RootType { get; } - public string? Name { get; } - - public OperationType Type { get; } - - public ISelectionSet RootSelectionSet { get; private set; } = null!; - - public IReadOnlyList SelectionVariants - => _selectionVariants; - - public bool HasIncrementalParts { get; private set; } - - public IReadOnlyList IncludeConditions - => _includeConditions; - - public IReadOnlyDictionary ContextData => _contextData; - - public ISchemaDefinition Schema { get; } - - public ISelectionSet GetSelectionSet(ISelection selection, ObjectType typeContext) + IObjectTypeDefinition IOperation.RootType => RootType; + + public OperationType Kind => Definition.Operation; + + /// + /// Gets the schema for which this operation is compiled. + /// + public Schema Schema { get; } + + ISchemaDefinition IOperation.Schema => Schema; + + /// + /// Gets the prepared root selections for this operation. + /// + /// + /// Returns the prepared root selections for this operation. + /// + public SelectionSet RootSelectionSet { get; } + + ISelectionSet IOperation.RootSelectionSet + => RootSelectionSet; + + /// + public IFeatureCollection Features => _features; + + /// + /// Gets the selection set for the specified + /// if the selections named return type is an object type. + /// + /// + /// The selection set for which the selection set shall be resolved. + /// + /// + /// Returns the selection set for the specified and + /// the named return type of the selection. + /// + /// + /// - The specified has no selection set. + /// - The specified returns an abstract named type. + /// + public SelectionSet GetSelectionSet(Selection selection) { ArgumentNullException.ThrowIfNull(selection); - ArgumentNullException.ThrowIfNull(typeContext); - - var selectionSetId = ((Selection)selection).SelectionSetId; - - if (selectionSetId is -1) - { - throw Operation_NoSelectionSet(); - } - - return _selectionVariants[selectionSetId].GetSelectionSet(typeContext); + var typeContext = selection.Field.Type.NamedType(); + return GetSelectionSet(selection, typeContext); } - public IEnumerable GetPossibleTypes(ISelection selection) + /// + /// Gets the selection set for the specified and + /// . + /// + /// + /// The selection set for which the selection set shall be resolved. + /// + /// + /// The result type context. + /// + /// + /// Returns the selection set for the specified and + /// . + /// + /// + /// The specified has no selection set. + /// + public SelectionSet GetSelectionSet(Selection selection, IObjectTypeDefinition typeContext) { ArgumentNullException.ThrowIfNull(selection); + ArgumentNullException.ThrowIfNull(typeContext); - var selectionSetId = ((Selection)selection).SelectionSetId; - - if (selectionSetId == -1) - { - throw new ArgumentException(Operation_GetPossibleTypes_NoSelectionSet); - } - - return _selectionVariants[selectionSetId].GetPossibleTypes(); - } - - public long CreateIncludeFlags(IVariableValueCollection variables) - { - long context = 0; - - for (var i = 0; i < _includeConditions.Length; i++) - { - if (_includeConditions[i].IsIncluded(variables)) - { - long flag = 1; - flag <<= i; - context |= flag; - } - } - - return context; - } - - public bool TryGetState(out TState? state) - { - var key = typeof(TState).FullName ?? throw new InvalidOperationException(); - return TryGetState(key, out state); - } - - public bool TryGetState(string key, out TState? state) - { - if (_contextData.TryGetValue(key, out var value) - && value is TState casted) + if (typeContext is not ObjectType objectType) { - state = casted; - return true; + throw new ArgumentException( + "typeContext is not an ObjectType object.", + nameof(typeContext)); } - state = default; - return false; - } - - public TState GetOrAddState(Func createState) - => GetOrAddState(_ => createState(), null); - - public TState GetOrAddState(Func createState, TContext context) - { - var key = typeof(TState).FullName ?? throw new InvalidOperationException(); + var key = (selection.Id, typeContext.Name); - // ReSharper disable once InconsistentlySynchronizedField - if (!_contextData.TryGetValue(key, out var state)) + if (!_selectionSets.TryGetValue(key, out var selectionSet)) { - lock (_writeLock) + lock (_sync) { - if (!_contextData.TryGetValue(key, out state)) + if (!_selectionSets.TryGetValue(key, out selectionSet)) { - var newState = createState(context); - _contextData = _contextData.SetItem(key, newState); - return newState; + selectionSet = + _compiler.CompileSelectionSet( + selection, + objectType, + _includeConditions, + ref _elementsById, + ref _lastId); + selectionSet.Complete(this, seal: _isFinal); + _selectionSets.TryAdd(key, selectionSet); } } } - return (TState)state!; + return selectionSet; } - public TState GetOrAddState( - string key, - Func createState) - => GetOrAddState(key, (k, _) => createState(k), null); - - public TState GetOrAddState( - string key, - Func createState, - TContext context) + ISelectionSet IOperation.GetSelectionSet(ISelection selection, IObjectTypeDefinition typeContext) { - // ReSharper disable once InconsistentlySynchronizedField - if (!_contextData.TryGetValue(key, out var state)) - { - lock (_writeLock) - { - if (!_contextData.TryGetValue(key, out state)) - { - var newState = createState(key, context); - _contextData = _contextData.SetItem(key, newState); - return newState; - } - } - } - - return (TState)state!; - } + ArgumentNullException.ThrowIfNull(selection); + ArgumentNullException.ThrowIfNull(typeContext); - internal void Seal( - IReadOnlyDictionary contextData, - SelectionVariants[] selectionVariants, - bool hasIncrementalParts, - IncludeCondition[] includeConditions) - { - if (!_sealed) + if (selection is not Selection internalSelection) { - _contextData = contextData.ToImmutableDictionary(); - var root = selectionVariants[0]; - RootSelectionSet = root.GetSelectionSet(RootType); - _selectionVariants = selectionVariants; - HasIncrementalParts = hasIncrementalParts; - _includeConditions = includeConditions; - _sealed = true; + throw new InvalidOperationException( + $"Only selections of the type {typeof(Selection).FullName} are supported."); } - } - - public SelectionSet GetSelectionSetById(int selectionSetId) - { + return GetSelectionSet(internalSelection, typeContext); } - public Selection GetSelectionById(int selectionSetId) + /// + /// Gets the possible return types for the . + /// + /// + /// The selection for which the possible result types shall be returned. + /// + /// + /// Returns the possible return types for the specified . + /// + /// + /// The specified has no selection set. + /// + public IEnumerable GetPossibleTypes(Selection selection) { + ArgumentNullException.ThrowIfNull(selection); + return Schema.GetPossibleTypes(selection.Field.Type.NamedType()); } - public IEnumerator GetEnumerator() + IEnumerable IOperation.GetPossibleTypes(ISelection selection) + => Schema.GetPossibleTypes(selection.Field.Type.NamedType()); + + /// + /// Creates the include flags for the specified variable values. + /// + /// + /// The variable values. + /// + /// + /// Returns the include flags for the specified variable values. + /// + public ulong CreateIncludeFlags(IVariableValueCollection variables) { - foreach (var selectionVariant in _selectionVariants) + var index = 0; + var includeFlags = 0ul; + + foreach (var includeCondition in _includeConditions) { - foreach (var objectType in selectionVariant.GetPossibleTypes()) + if (includeCondition.IsIncluded(variables)) { - yield return selectionVariant.GetSelectionSet(objectType); + includeFlags |= 1ul << index++; } } + + return includeFlags; } - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); + internal Selection GetSelectionById(int id) + => Unsafe.As(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_elementsById), id)); + + internal SelectionSet GetSelectionSetById(int id) + => Unsafe.As(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_elementsById), id)); public override string ToString() => OperationPrinter.Print(this); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs new file mode 100644 index 00000000000..8f6068bbf80 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs @@ -0,0 +1,122 @@ +using System.Buffers; +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Fusion.Rewriters; +using HotChocolate.Language; +using HotChocolate.Language.Visitors; +using HotChocolate.Resolvers; +using HotChocolate.Types; +using Microsoft.Extensions.ObjectPool; + +namespace HotChocolate.Execution.Processing; + +internal sealed partial class OperationCompiler2 +{ + private ArgumentMap? CoerceArgumentValues( + ObjectField field, + FieldNode selection) + { + if (field.Arguments.Count == 0) + { + return null; + } + + var arguments = new Dictionary(StringComparer.Ordinal); + + for (var i = 0; i < selection.Arguments.Count; i++) + { + var argumentValue = selection.Arguments[i]; + if (field.Arguments.TryGetField( + argumentValue.Name.Value, + out var argument)) + { + arguments[argument.Name] = CreateArgumentValue(argument, argumentValue, argumentValue.Value, false); + } + } + + for (var i = 0; i < field.Arguments.Count; i++) + { + var argument = field.Arguments[i]; + if (!arguments.ContainsKey(argument.Name)) + { + var value = argument.DefaultValue ?? NullValueNode.Default; + arguments[argument.Name] = CreateArgumentValue(argument, null, value, true); + } + } + + return new ArgumentMap(arguments); + } + + private ArgumentValue CreateArgumentValue( + Argument argument, + ArgumentNode? argumentValue, + IValueNode value, + bool isDefaultValue) + { + var validationResult = + ArgumentNonNullValidator.Validate( + argument, + value, + Path.Root.Append(argument.Name)); + + if (argumentValue is not null && validationResult.HasErrors) + { + return new ArgumentValue( + argument, + ErrorHelper.ArgumentNonNullError( + argumentValue, + validationResult)); + } + + if (argument.Type.IsLeafType() && CanBeCompiled(value)) + { + try + { + return new ArgumentValue( + argument, + value.GetValueKind(), + true, + isDefaultValue, + _inputValueParser.ParseLiteral(value, argument), + value); + } + catch (SerializationException ex) + { + return new ArgumentValue( + argument, + ErrorHelper.ArgumentValueIsInvalid(argumentValue, ex)); + } + } + + return new ArgumentValue( + argument, + value.GetValueKind(), + false, + isDefaultValue, + null, + value); + } + + private static bool CanBeCompiled(IValueNode valueLiteral) + { + switch (valueLiteral.Kind) + { + case SyntaxKind.Variable: + case SyntaxKind.ObjectValue: + return false; + + case SyntaxKind.ListValue: + var list = (ListValueNode)valueLiteral; + for (var i = 0; i < list.Items.Count; i++) + { + if (!CanBeCompiled(list.Items[i])) + { + return false; + } + } + break; + } + + return true; + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 174bc3ca348..0984e29625a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -1,787 +1,633 @@ -using System.Collections.Immutable; -using System.Runtime.CompilerServices; +using System.Buffers; +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Fusion.Rewriters; using HotChocolate.Language; -using HotChocolate.Resolvers; +using HotChocolate.Language.Visitors; using HotChocolate.Types; -using HotChocolate.Utilities; -using static System.Runtime.InteropServices.CollectionsMarshal; -using static System.Runtime.InteropServices.MemoryMarshal; -using static System.StringComparer; -using static HotChocolate.Execution.Properties.Resources; -using static HotChocolate.Execution.ThrowHelper; +using Microsoft.Extensions.ObjectPool; namespace HotChocolate.Execution.Processing; -/// -/// The operation compiler will analyze a specific operation of a GraphQL request document -/// and create from it an optimized executable operation tree. -/// -public sealed partial class OperationCompiler +internal sealed partial class OperationCompiler2 { - private readonly InputParser _parser; - private readonly CreateFieldPipeline _createFieldPipeline; - private readonly Queue _backlog = []; - private readonly Dictionary _selectionLookup = []; - private readonly Dictionary _selectionSetIdLookup = []; - private readonly Dictionary _selectionVariants = []; - private readonly Dictionary _fragmentDefinitions = []; - private readonly Dictionary _contextData = []; - private readonly List _selections = []; - private readonly HashSet _directiveNames = new(Ordinal); - private readonly List _pipelineComponents = []; - private readonly HashSet _enqueuedSelectionSets = []; - private IncludeCondition[] _includeConditions = []; - private CompilerContext? _deferContext; - private ImmutableArray _operationOptimizers = []; - private int _nextSelectionId; - private int _nextSelectionSetRefId; - private int _nextSelectionSetId; - private int _nextFragmentId; - private bool _hasIncrementalParts; - private OperationCompilerMetrics _metrics; - - public OperationCompiler(InputParser parser) + private readonly Schema _schema; + private readonly ObjectPool>> _fieldsPool; + private readonly DocumentRewriter _documentRewriter; + private readonly InputParser _inputValueParser; + private static readonly ArrayPool s_objectArrayPool = ArrayPool.Shared; + + public OperationCompiler2( + Schema schema, + InputParser inputValueParser, + ObjectPool>> fieldsPool) { - _parser = parser ?? throw new ArgumentNullException(nameof(parser)); - - _createFieldPipeline = - (schema, field, selection) - => CreateFieldPipeline( - schema, - field, - selection, - null, - _directiveNames, - _pipelineComponents); - } + ArgumentNullException.ThrowIfNull(schema); + ArgumentNullException.ThrowIfNull(fieldsPool); - internal OperationCompilerMetrics Metrics => _metrics; + _schema = schema; + _inputValueParser = inputValueParser; + _fieldsPool = fieldsPool; + _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); + } - public IOperation Compile(OperationCompilerRequest request) + public Operation Compile(string id, string hash, OperationDefinitionNode operationDefinition) { - ArgumentException.ThrowIfNullOrEmpty(request.Id, nameof(request)); + ArgumentException.ThrowIfNullOrWhiteSpace(id); + ArgumentNullException.ThrowIfNull(operationDefinition); - try - { - var backlogMaxSize = 0; - var selectionSetOptimizers = request.SelectionSetOptimizers; - _operationOptimizers = request.OperationOptimizers; - - // collect root fields - var rootPath = SelectionPath.Root; - var id = GetOrCreateSelectionSetRefId(request.Definition.SelectionSet, request.RootType.Name, rootPath); - var variants = GetOrCreateSelectionVariants(id); - SelectionSetInfo[] infos = [new(request.Definition.SelectionSet, 0)]; - - var context = new CompilerContext((Schema)request.Schema, request.Document); - context.Initialize(request.RootType, variants, infos, rootPath, selectionSetOptimizers); - CompileSelectionSet(context); - - // process consecutive selections - while (_backlog.Count > 0) - { - backlogMaxSize = Math.Max(backlogMaxSize, _backlog.Count); + var document = new DocumentNode(new IDefinitionNode[] { operationDefinition }); + document = _documentRewriter.RewriteDocument(document); + operationDefinition = (OperationDefinitionNode)document.Definitions[0]; - var current = _backlog.Dequeue(); - var type = current.Type; - variants = GetOrCreateSelectionVariants(current.SelectionSetId); + var includeConditions = new IncludeConditionCollection(); + IncludeConditionVisitor.Instance.Visit(operationDefinition, includeConditions); + var fields = _fieldsPool.Get(); - if (!variants.ContainsSelectionSet(type)) - { - infos = _selectionLookup[current.Selection]; - context.Initialize(type, variants, infos, current.Path, current.Optimizers); - CompileSelectionSet(context); - } - } + var compilationContext = new CompilationContext(s_objectArrayPool.Rent(128)); - // create operation - var operation = CreateOperation(request); - - _metrics = new OperationCompilerMetrics( - _nextSelectionId, - _selectionVariants.Count, - backlogMaxSize); + try + { + var lastId = 0; + const ulong parentIncludeFlags = 0ul; + var rootType = _schema.GetOperationType(operationDefinition.Operation); - return operation; + CollectFields( + parentIncludeFlags, + operationDefinition.SelectionSet.Selections, + rootType, + fields, + includeConditions); + + var selectionSet = BuildSelectionSet( + fields, + rootType, + compilationContext, + ref lastId); + + compilationContext.Register(selectionSet, selectionSet.Id); + + return new Operation( + id, + hash, + operationDefinition, + rootType, + _schema, + selectionSet, + this, + includeConditions, + lastId, + compilationContext.ElementsById, + isFinal: true); // todo : add the interceptors back } finally { - _nextSelectionId = 0; - _nextSelectionSetRefId = 0; - _nextSelectionId = 0; - _nextFragmentId = 0; - _hasIncrementalParts = false; - - _backlog.Clear(); - _selectionLookup.Clear(); - _selectionSetIdLookup.Clear(); - _selectionVariants.Clear(); - _fragmentDefinitions.Clear(); - _contextData.Clear(); - _selections.Clear(); - _directiveNames.Clear(); - _pipelineComponents.Clear(); - _enqueuedSelectionSets.Clear(); - - _operationOptimizers = []; - - _includeConditions = []; - _deferContext = null; + _fieldsPool.Return(fields); } } - private Operation CreateOperation(OperationCompilerRequest request) + internal SelectionSet CompileSelectionSet( + Selection selection, + ObjectType objectType, + IncludeConditionCollection includeConditions, + ref object[] elementsById, + ref int lastId) { - var operation = new Operation( - request.Id, - request.Document, - request.Definition, - request.RootType, - request.Schema); - - var schema = Unsafe.As(request.Schema); + var compilationContext = new CompilationContext(elementsById); + var fields = _fieldsPool.Get(); + fields.Clear(); - var variants = new SelectionVariants[_selectionVariants.Count]; - - if (_operationOptimizers.Length == 0) + try { - CompleteResolvers(schema); + var nodes = selection.SyntaxNodes; + var first = nodes[0]; - // if we do not have any optimizers, we will copy - // the variants and seal them in one go. - foreach (var item in _selectionVariants) + CollectFields( + first.PathIncludeFlags, + first.Node.SelectionSet!.Selections, + objectType, + fields, + includeConditions); + + if (nodes.Length > 1) { - variants[item.Key] = item.Value; - item.Value.Seal(operation); + for (var i = 1; i < nodes.Length; i++) + { + var node = nodes[i]; + + CollectFields( + node.PathIncludeFlags, + node.Node.SelectionSet!.Selections, + objectType, + fields, + includeConditions); + } } + + var selectionSet = BuildSelectionSet(fields, objectType, compilationContext, ref lastId); + compilationContext.Register(selectionSet, selectionSet.Id); + elementsById = compilationContext.ElementsById; + return selectionSet; } - else + finally { - // if we have optimizers, we will first copy the variants to its array, - // after that we will run the optimizers and give them a chance to do some - // more mutations on the compiled selection variants. - // after we have executed all optimizers, we will seal the selection variants. - var context = new OperationOptimizerContext( - request.Id, - request.Document, - request.Definition, - schema, - request.RootType, - variants, - _includeConditions, - _contextData, - _hasIncrementalParts, - _createFieldPipeline); - - foreach (var item in _selectionVariants) - { - variants[item.Key] = item.Value; - } - - // we will complete the selection variants, sets and selections - // without sealing them so that analyzers in this step can fully - // inspect them. - var variantsSpan = variants.AsSpan(); - ref var variantsStart = ref GetReference(variantsSpan); - ref var variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length); - - while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) - { - variantsStart.Complete(operation); - variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; - } + _fieldsPool.Return(fields); + } + } - var optSpan = _operationOptimizers.AsSpan(); - ref var optStart = ref GetReference(optSpan); - ref var optEnd = ref Unsafe.Add(ref optStart, optSpan.Length); + private void CollectFields( + ulong parentIncludeFlags, + IReadOnlyList selections, + IObjectTypeDefinition typeContext, + OrderedDictionary> fields, + IncludeConditionCollection includeConditions) + { + for (var i = 0; i < selections.Count; i++) + { + var selection = selections[i]; - while (Unsafe.IsAddressLessThan(ref optStart, ref optEnd)) + if (selection is FieldNode fieldNode) { - optStart.OptimizeOperation(context); - optStart = ref Unsafe.Add(ref optStart, 1)!; - } + var responseName = fieldNode.Alias?.Value ?? fieldNode.Name.Value; + var pathIncludeFlags = parentIncludeFlags; - CompleteResolvers(schema); + if (!fields.TryGetValue(responseName, out var nodes)) + { + nodes = []; + fields.Add(responseName, nodes); + } - variantsSpan = variants.AsSpan(); - variantsStart = ref GetReference(variantsSpan)!; - variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length)!; + if (IncludeCondition.TryCreate(fieldNode, out var includeCondition)) + { + var index = includeConditions.IndexOf(includeCondition); + pathIncludeFlags |= 1ul << index; + } - while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) - { - variantsStart.Seal(operation); - variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; + nodes.Add(new FieldSelectionNode(fieldNode, pathIncludeFlags)); } - } - - operation.Seal(_contextData, variants, _hasIncrementalParts, _includeConditions); - return operation; - } - private void CompleteResolvers(Schema schema) - { - ref var searchSpace = ref GetReference(AsSpan(_selections)); - - Path? path = null; - for (var i = 0; i < _selections.Count; i++) - { - var selection = Unsafe.Add(ref searchSpace, i); - path = path?.Append(selection.ResponseName); - if (selection.ResolverPipeline is null && selection.PureResolver is null) + if (selection is InlineFragmentNode inlineFragmentNode + && DoesTypeApply(inlineFragmentNode.TypeCondition, typeContext)) { - var field = selection.Field; - var syntaxNode = selection.SyntaxNode; - if (syntaxNode.Directives.Count > 0 && path == null) + var pathIncludeFlags = parentIncludeFlags; + + if (IncludeCondition.TryCreate(inlineFragmentNode, out var includeCondition)) { - // create the path only on demand - path = PathHelper.CreatePathFromSelection(_selections, i + 1); + var index = includeConditions.IndexOf(includeCondition); + pathIncludeFlags |= 1ul << index; } - var resolver = CreateFieldPipeline( - schema, - field, - syntaxNode, - path, - _directiveNames, - _pipelineComponents); - var pureResolver = TryCreatePureField(schema, field, syntaxNode); - selection.SetResolvers(resolver, pureResolver); + CollectFields( + pathIncludeFlags, + inlineFragmentNode.SelectionSet.Selections, + typeContext, + fields, + includeConditions); } } } - private void CompileSelectionSet(CompilerContext context) - { - // We first collect the fields that we find in the selection set ... - CollectFields(context); - - // next we will call the selection set optimizers to rewrite the - // selection set if necessary. - OptimizeSelectionSet(context); - - // after that we start completing the selections and build the SelectionSet from - // the completed selections. - CompleteSelectionSet(context); - } - - private void CompleteSelectionSet(CompilerContext context) + private SelectionSet BuildSelectionSet( + OrderedDictionary> fieldMap, + ObjectType typeContext, + CompilationContext compilationContext, + ref int lastId) { - var selections = new Selection[context.Fields.Values.Count]; - var fragments = context.Fragments.Count is not 0 - ? new Fragment[context.Fragments.Count] - : []; - var selectionIndex = 0; + var i = 0; + var selections = new Selection[fieldMap.Count]; var isConditional = false; + var includeFlags = new List(); + var selectionSetId = ++lastId; - foreach (var selection in context.Fields.Values) + foreach (var (responseName, nodes) in fieldMap) { - // if the field of the selection returns a composite type, we will traverse - // the child selection-sets as well. - var fieldType = selection.Type.NamedType(); - var selectionSetId = -1; + includeFlags.Clear(); - if (selection.IsConditional) + var first = nodes[0]; + var isInternal = IsInternal(first.Node); + + if (first.PathIncludeFlags > 0) { - isConditional = true; + includeFlags.Add(first.PathIncludeFlags); } - // Determines if the type is a composite type. - if (fieldType.IsCompositeType()) + if (nodes.Count > 1) { - if (selection.SelectionSet is null) + for (var j = 1; j < nodes.Count; j++) { - // composite fields always have to have a selection-set - // otherwise we need to throw. - throw QueryCompiler_CompositeTypeSelectionSet(selection.SyntaxNode); - } - - var selectionPath = context.Path.Append(selection.ResponseName); - selectionSetId = GetOrCreateSelectionSetRefId(selection.SelectionSet, fieldType.Name, selectionPath); - var possibleTypes = context.Schema.GetPossibleTypes(fieldType); + var next = nodes[j]; - if (_enqueuedSelectionSets.Add(selectionSetId)) - { - for (var i = possibleTypes.Count - 1; i >= 0; i--) + if (!first.Node.Name.Value.Equals(next.Node.Name.Value, StringComparison.Ordinal)) { - _backlog.Enqueue( - new BacklogItem( - possibleTypes[i], - selectionSetId, - selection, - selectionPath, - ResolveOptimizers(context.Optimizers, selection.Field))); + throw new InvalidOperationException( + $"The syntax nodes for the response name {responseName} are not all the same."); } - } - // We are waiting for the latest stream and defer spec discussions to be codified - // before we change the overall stream handling. - // - // For now, we only allow streams on lists of composite types. - if (selection.SyntaxNode.IsStreamable()) - { - var streamDirective = selection.SyntaxNode.GetStreamDirective(); - var nullValue = NullValueNode.Default; - var ifValue = streamDirective?.GetArgumentValue(DirectiveNames.Stream.Arguments.If) ?? nullValue; - long ifConditionFlags = 0; - - if (ifValue.Kind is not SyntaxKind.NullValue) + if (next.PathIncludeFlags > 0) { - var ifCondition = new IncludeCondition(ifValue, nullValue); - ifConditionFlags = GetSelectionIncludeCondition(ifCondition, 0); + includeFlags.Add(next.PathIncludeFlags); } - selection.MarkAsStream(ifConditionFlags); - _hasIncrementalParts = true; + if (isInternal) + { + isInternal = IsInternal(next.Node); + } } } - selection.SetSelectionSetId(selectionSetId); - selections[selectionIndex++] = selection; - _selections.Add(selection); - } - - if (context.Fragments.Count > 0) - { - for (var i = 0; i < context.Fragments.Count; i++) + if (includeFlags.Count > 1) { - fragments[i] = context.Fragments[i]; + CollapseIncludeFlags(includeFlags); } - } - context.SelectionVariants.AddSelectionSet( - _nextSelectionSetId++, - context.Type, - selections, - fragments, - isConditional); - } + var field = typeContext.Fields[first.Node.Name.Value]; - private void CollectFields(CompilerContext context) - { - foreach (var selectionSetInfo in context.SelectionInfos) - { - CollectFields( - context, - selectionSetInfo.SelectionSet, - selectionSetInfo.IncludeCondition); - } - } + var selection = new Selection( + ++lastId, + responseName, + field, + nodes.ToArray(), + includeFlags.ToArray(), + isInternal); - private void CollectFields( - CompilerContext context, - SelectionSetNode selectionSet, - ulong includeCondition) - { - for (var j = 0; j < selectionSet.Selections.Count; j++) - { - ResolveFields(context, selectionSet.Selections[j], includeCondition); - } - } + // Register the selection in the elements array + compilationContext.Register(selection, selection.Id); + selections[i++] = selection; - private void ResolveFields( - CompilerContext context, - ISelectionNode selection, - long includeCondition) - { - switch (selection.Kind) - { - case SyntaxKind.Field: - ResolveField( - context, - (FieldNode)selection, - includeCondition); - break; - - case SyntaxKind.InlineFragment: - ResolveInlineFragment( - context, - (InlineFragmentNode)selection, - includeCondition); - break; - - case SyntaxKind.FragmentSpread: - ResolveFragmentSpread( - context, - (FragmentSpreadNode)selection, - includeCondition); - break; + if (includeFlags.Count > 1) + { + isConditional = true; + } } + + return new SelectionSet(selectionSetId, typeContext, selections, isConditional); } - private void ResolveField( - CompilerContext context, - FieldNode selection, - ulong includeCondition) + private static void CollapseIncludeFlags(List includeFlags) { - includeCondition = GetSelectionIncludeCondition(selection, includeCondition); + // we sort the include flags to improve early elimination and stability + includeFlags.Sort(); - var fieldName = selection.Name.Value; - var responseName = selection.Alias?.Value ?? fieldName; + var write = 0; - if (context.Type.Fields.TryGetField(fieldName, out var field)) + for (var read = 0; read < includeFlags.Count; read++) { - var fieldType = field.Type; + var candidate = includeFlags[read]; + var covered = false; - if (context.Fields.TryGetValue(responseName, out var preparedSelection)) + // we check if the candidate is already covered + for (var i = 0; i < write; i++) { - preparedSelection.AddSelection(selection, includeCondition); - - if (selection.SelectionSet is not null) + if ((candidate & includeFlags[i]) == includeFlags[i]) { - var selectionSetInfo = new SelectionSetInfo( - selection.SelectionSet!, - includeCondition); - var selectionInfos = _selectionLookup[preparedSelection]; - var next = selectionInfos.Length; - Array.Resize(ref selectionInfos, next + 1); - selectionInfos[next] = selectionSetInfo; - _selectionLookup[preparedSelection] = selectionInfos; + covered = true; + break; } } - else + + if (!covered) { - var id = GetNextSelectionId(); - - // if this is the first time we've found a selection to this field, we have to - // create a new prepared selection. - preparedSelection = new Selection.Sealed( - id, - context.Type, - field, - fieldType, - selection.SelectionSet is not null - ? selection.WithSelectionSet( - selection.SelectionSet.WithSelections( - selection.SelectionSet.Selections)) - : selection, - responseName: responseName, - arguments: CoerceArgumentValues(field, selection), - includeConditions: includeCondition == 0 - ? null - : [includeCondition], - isParallelExecutable: field.IsParallelExecutable); - - context.Fields.Add(responseName, preparedSelection); - - if (selection.SelectionSet is not null) + // lastly we remove more restrictive flags from the already written range + for (var i = 0; i < write;) + { + if ((includeFlags[i] & candidate) == candidate) + { + includeFlags[i] = includeFlags[--write]; + } + else + { + i++; + } + } + + if (write < read) { - var selectionSetInfo = new SelectionSetInfo( - selection.SelectionSet!, - includeCondition); - _selectionLookup.Add(preparedSelection, [selectionSetInfo]); + includeFlags[write] = candidate; } + write++; } } - else + + // we trim the list to the collapsed set + if (write < includeFlags.Count) { - throw FieldDoesNotExistOnType(selection, context.Type.Name); + includeFlags.RemoveRange(write, includeFlags.Count - write); } } - private void ResolveInlineFragment( - CompilerContext context, - InlineFragmentNode inlineFragment, - long includeCondition) + private bool DoesTypeApply(NamedTypeNode? typeCondition, IObjectTypeDefinition typeContext) { - ResolveFragment( - context, - inlineFragment, - inlineFragment.TypeCondition, - inlineFragment.SelectionSet, - inlineFragment.Directives, - includeCondition); - } + if (typeCondition is null) + { + return true; + } - private void ResolveFragmentSpread( - CompilerContext context, - FragmentSpreadNode fragmentSpread, - long includeCondition) - { - var fragmentDef = GetFragmentDefinition(context, fragmentSpread); - - ResolveFragment( - context, - fragmentSpread, - fragmentDef.TypeCondition, - fragmentDef.SelectionSet, - fragmentSpread.Directives, - includeCondition); + if (typeCondition.Name.Value.Equals(typeContext.Name, StringComparison.Ordinal)) + { + return true; + } + + if (_schema.Types.TryGetType(typeCondition.Name.Value, out var type)) + { + return type.IsAssignableFrom(typeContext); + } + + return false; } - private void ResolveFragment( - CompilerContext context, - ISelectionNode selection, - NamedTypeNode? typeCondition, - SelectionSetNode selectionSet, - IReadOnlyList directives, - ulong includeCondition) + private static bool IsInternal(FieldNode fieldNode) { - if (typeCondition is null - || (context.Schema.Types.TryGetType(typeCondition, out IType? typeCon) - && DoesTypeApply(typeCon, context.Type))) - { - includeCondition = GetSelectionIncludeCondition(selection, includeCondition); + const string isInternal = "fusion__requirement"; + var directives = fieldNode.Directives; - if (directives.IsDeferrable()) - { - var deferDirective = directives.GetDeferDirectiveNode(); - var nullValue = NullValueNode.Default; - var ifValue = deferDirective?.GetArgumentValue(DirectiveNames.Defer.Arguments.If) ?? nullValue; + if (directives.Count == 0) + { + return false; + } - ulong ifConditionFlags = 0; + if (directives.Count == 1) + { + return directives[0].Name.Value.Equals(isInternal, StringComparison.Ordinal); + } - if (ifValue.Kind is not SyntaxKind.NullValue) - { - var ifCondition = new IncludeCondition(ifValue, nullValue); - ifConditionFlags = GetSelectionIncludeCondition(ifCondition, includeCondition); - } + if (directives.Count == 2) + { + return directives[0].Name.Value.Equals(isInternal, StringComparison.Ordinal) + || directives[1].Name.Value.Equals(isInternal, StringComparison.Ordinal); + } - var typeName = typeCondition?.Name.Value ?? context.Type.Name; - var id = GetOrCreateSelectionSetRefId(selectionSet, typeName, context.Path); - var variants = GetOrCreateSelectionVariants(id); - var infos = new SelectionSetInfo[] { new(selectionSet, includeCondition) }; + if (directives.Count == 3) + { + return directives[0].Name.Value.Equals(isInternal, StringComparison.Ordinal) + || directives[1].Name.Value.Equals(isInternal, StringComparison.Ordinal) + || directives[2].Name.Value.Equals(isInternal, StringComparison.Ordinal); + } - if (!variants.ContainsSelectionSet(context.Type)) - { - var deferContext = RentContext(context); - deferContext.Initialize(context.Type, variants, infos, context.Path); - CompileSelectionSet(deferContext); - ReturnContext(deferContext); - } + for (var i = 0; i < directives.Count; i++) + { + var directive = directives[i]; - var fragment = new Fragment( - GetNextFragmentId(), - context.Type, - selection, - directives, - variants.GetSelectionSet(context.Type), - includeCondition, - ifConditionFlags); - - context.Fragments.Add(fragment); - _hasIncrementalParts = true; - - // if we have if-condition flags, there will be a runtime validation if something - // shall be deferred, so we need to prepare for both cases. - // - // this means that we will collect the fields with our if condition flags as - // if the fragment was not deferred. - if (ifConditionFlags is not 0) - { - CollectFields(context, selectionSet, ifConditionFlags); - } - } - else + if (directive.Name.Value.Equals(isInternal, StringComparison.Ordinal)) { - CollectFields(context, selectionSet, includeCondition); + return true; } } + + return false; } - private static bool DoesTypeApply(IType typeCondition, IObjectTypeDefinition current) - => typeCondition.Kind switch - { - TypeKind.Object => ReferenceEquals(typeCondition, current), - TypeKind.Interface => current.IsImplementing((InterfaceType)typeCondition), - TypeKind.Union => ((UnionType)typeCondition).Types.ContainsName(current.Name), - _ => false - }; - - private FragmentDefinitionNode GetFragmentDefinition( - CompilerContext context, - FragmentSpreadNode fragmentSpread) + private class IncludeConditionVisitor : SyntaxWalker { - var fragmentName = fragmentSpread.Name.Value; + public static readonly IncludeConditionVisitor Instance = new(); - if (!_fragmentDefinitions.TryGetValue(fragmentName, out var value)) + protected override ISyntaxVisitorAction Enter( + FieldNode node, + IncludeConditionCollection context) { - var document = context.Document; - - for (var i = 0; i < document.Definitions.Count; i++) + if (IncludeCondition.TryCreate(node, out var condition)) { - if (document.Definitions[i] is FragmentDefinitionNode fragmentDefinition - && fragmentDefinition.Name.Value.EqualsOrdinal(fragmentName)) - { - value = fragmentDefinition; - _fragmentDefinitions.Add(fragmentName, value); - goto EXIT; - } + context.Add(condition); } - throw new InvalidOperationException( - string.Format( - OperationCompiler_FragmentNotFound, - fragmentName)); + return base.Enter(node, context); } -EXIT: - return value; - } - - internal int GetNextSelectionId() => _nextSelectionId++; + protected override ISyntaxVisitorAction Enter( + InlineFragmentNode node, + IncludeConditionCollection context) + { + if (IncludeCondition.TryCreate(node, out var condition)) + { + context.Add(condition); + } - private int GetNextFragmentId() => _nextFragmentId++; + return base.Enter(node, context); + } + } - private int GetOrCreateSelectionSetRefId( - SelectionSetNode selectionSet, - string selectionSetTypeName, - SelectionPath path) + private class CompilationContext(object[] elementsById) { - var selectionSetRef = new SelectionSetRef(selectionSet, selectionSetTypeName, path); + private object[] _elementsById = elementsById; - if (!_selectionSetIdLookup.TryGetValue(selectionSetRef, out var selectionSetId)) + public object[] ElementsById => _elementsById; + + public void Register(object element, int id) { - selectionSetId = _nextSelectionSetRefId++; - _selectionSetIdLookup.Add(selectionSetRef, selectionSetId); - } + if (id >= _elementsById.Length) + { + var newArray = s_objectArrayPool.Rent(_elementsById.Length * 2); + _elementsById.AsSpan().CopyTo(newArray); + s_objectArrayPool.Return(_elementsById); + _elementsById = newArray; + } - return selectionSetId; + _elementsById[id] = element; + } } +} + +/// +/// Represents a field selection node with its path include flags. +/// +/// +/// The syntax node that represents the field selection. +/// +/// +/// The flags that must be all set for this selection to be included. +/// +internal sealed record FieldSelectionNode(FieldNode Node, ulong PathIncludeFlags); + +internal class IncludeConditionCollection : ICollection +{ + private readonly OrderedDictionary _dictionary = []; + + public IncludeCondition this[int index] + => _dictionary.GetAt(index).Key; + + public int Count => _dictionary.Count; + + public bool IsReadOnly => false; - private SelectionVariants GetOrCreateSelectionVariants(int selectionSetId) + public bool Add(IncludeCondition item) { - if (!_selectionVariants.TryGetValue(selectionSetId, out var variants)) + if (_dictionary.Count == 64) { - variants = new SelectionVariants(selectionSetId); - _selectionVariants.Add(selectionSetId, variants); + throw new InvalidOperationException( + "The maximum number of include conditions has been reached."); } - return variants; + return _dictionary.TryAdd(item, _dictionary.Count); } - private ulong GetSelectionIncludeCondition( - ISelectionNode selectionSyntax, - ulong parentIncludeCondition) + void ICollection.Add(IncludeCondition item) + => Add(item); + + public bool Remove(IncludeCondition item) + => throw new InvalidOperationException("This is an add only collection."); + + void ICollection.Clear() + => throw new InvalidOperationException("This is an add only collection."); + + public bool Contains(IncludeCondition item) + => _dictionary.ContainsKey(item); + + public int IndexOf(IncludeCondition item) + => _dictionary.GetValueOrDefault(item, -1); + + public void CopyTo(IncludeCondition[] array, int arrayIndex) + => _dictionary.Keys.CopyTo(array, arrayIndex); + + public IEnumerator GetEnumerator() + => _dictionary.Keys.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); +} + +internal readonly struct IncludeCondition : IEquatable +{ + private readonly string? _skip; + private readonly string? _include; + + public IncludeCondition(string? skip, string? include) { - var condition = IncludeCondition.FromSelection(selectionSyntax); + _skip = skip; + _include = include; + } - if (condition.IsDefault) - { - return parentIncludeCondition; - } + public string? Skip => _skip; - var pos = Array.IndexOf(_includeConditions, condition); + public string? Include => _include; - if (pos == -1) + public bool IsIncluded(IVariableValueCollection variableValues) + { + if (_skip is not null) { - pos = _includeConditions.Length; - - if (pos == 64) + if (!variableValues.TryGetValue(_skip, out var value)) { - throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); + throw new InvalidOperationException($"The variable {_skip} has an invalid value."); } - if (_includeConditions.Length == 0) + if (value.Value) { - _includeConditions = new IncludeCondition[1]; + return false; } - else + } + + if (_include is not null) + { + if (!variableValues.TryGetValue(_include, out var value)) { - Array.Resize(ref _includeConditions, pos + 1); + throw new InvalidOperationException($"The variable {_include} has an invalid value."); } - _includeConditions[pos] = condition; + if (!value.Value) + { + return false; + } } - long selectionIncludeCondition = 1; - selectionIncludeCondition <<= pos; + return true; + } - if (parentIncludeCondition == 0) - { - return selectionIncludeCondition; - } + public bool Equals(IncludeCondition other) + => string.Equals(Skip, other.Skip, StringComparison.Ordinal) + && string.Equals(Include, other.Include, StringComparison.Ordinal); - parentIncludeCondition |= selectionIncludeCondition; - return parentIncludeCondition; - } + public override bool Equals([NotNullWhen(true)] object? obj) + => obj is IncludeCondition other && Equals(other); + + public override int GetHashCode() + => HashCode.Combine(Skip, Include); + + public static bool TryCreate(FieldNode field, out IncludeCondition includeCondition) + => TryCreate(field.Directives, out includeCondition); + + public static bool TryCreate(InlineFragmentNode inlineFragment, out IncludeCondition includeCondition) + => TryCreate(inlineFragment.Directives, out includeCondition); - private long GetSelectionIncludeCondition( - IncludeCondition condition, - ulong parentIncludeCondition) + private static bool TryCreate(IReadOnlyList directives, out IncludeCondition includeCondition) { - var pos = Array.IndexOf(_includeConditions, condition); + string? skip = null; + string? include = null; - if (pos == -1) + if (directives.Count == 0) { - pos = _includeConditions.Length; + includeCondition = default; + return false; + } - if (pos == 64) + if (directives.Count == 1) + { + TryParseDirective(directives[0], ref skip, ref include); + if (TryCreateIncludeCondition(out includeCondition)) { - throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); + return true; } + } - if (_includeConditions.Length == 0) - { - _includeConditions = new IncludeCondition[1]; - } - else + if (directives.Count == 2) + { + TryParseDirective(directives[0], ref skip, ref include); + TryParseDirective(directives[1], ref skip, ref include); + return TryCreateIncludeCondition(out includeCondition); + } + + if (directives.Count == 3) + { + TryParseDirective(directives[0], ref skip, ref include); + TryParseDirective(directives[1], ref skip, ref include); + + if (skip is not null && include is not null) { - Array.Resize(ref _includeConditions, pos + 1); + includeCondition = new IncludeCondition(skip, include); + return true; } - _includeConditions[pos] = condition; + TryParseDirective(directives[2], ref skip, ref include); + return TryCreateIncludeCondition(out includeCondition); } - long selectionIncludeCondition = 1; - selectionIncludeCondition <<= pos; - - if (parentIncludeCondition == 0) + for (var i = 0; i < directives.Count; i++) { - return selectionIncludeCondition; + TryParseDirective(directives[i], ref skip, ref include); + + if (skip is not null && include is not null) + { + includeCondition = new IncludeCondition(skip, include); + return true; + } } - parentIncludeCondition |= selectionIncludeCondition; - return parentIncludeCondition; - } + includeCondition = default; + return false; - private CompilerContext RentContext(CompilerContext context) - { - if (_deferContext is null) + bool TryCreateIncludeCondition(out IncludeCondition includeCondition) { - return new CompilerContext(context.Schema, context.Document); - } + if (skip is not null || include is not null) + { + includeCondition = new IncludeCondition(skip, include); + return true; + } - var temp = _deferContext; - _deferContext = null; - return temp; + includeCondition = default; + return false; + } } - private void ReturnContext(CompilerContext context) - => _deferContext ??= context; - - internal void RegisterNewSelection(Selection newSelection) + private static void TryParseDirective(DirectiveNode directive, ref string? skip, ref string? include) { - if (newSelection.SyntaxNode.SelectionSet is not null) + if (directive.Name.Value.Equals(DirectiveNames.Skip.Name, StringComparison.Ordinal) + && directive.Arguments.Count == 1 + && directive.Arguments[0].Value is VariableNode skipVariable) { - var selectionSetInfo = new SelectionSetInfo(newSelection.SelectionSet!, 0); - _selectionLookup.Add(newSelection, [selectionSetInfo]); + skip = skipVariable.Name.Value; + } + else if (directive.Name.Value.Equals(DirectiveNames.Include.Name, StringComparison.Ordinal) + && directive.Arguments.Count == 1 + && directive.Arguments[0].Value is VariableNode includeVariable) + { + include = includeVariable.Name.Value; } - } - - private readonly struct SelectionSetRef( - SelectionSetNode selectionSet, - string selectionSetTypeName, - SelectionPath path) - : IEquatable - { - public readonly SelectionSetNode SelectionSet = selectionSet; - - public readonly SelectionPath Path = path; - - public readonly string SelectionSetTypeName = selectionSetTypeName; - - public bool Equals(SelectionSetRef other) - => SyntaxComparer.BySyntax.Equals(SelectionSet, other.SelectionSet) - && Path.Equals(other.Path) - && Ordinal.Equals(SelectionSetTypeName, other.SelectionSetTypeName); - - public override bool Equals(object? obj) - => obj is SelectionSetRef other && Equals(other); - - public override int GetHashCode() - => HashCode.Combine( - SyntaxComparer.BySyntax.GetHashCode(SelectionSet), - Path.GetHashCode(), - Ordinal.GetHashCode(SelectionSetTypeName)); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs new file mode 100644 index 00000000000..025d3eb9600 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs @@ -0,0 +1,113 @@ +using System.Collections; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Features; + +namespace HotChocolate.Execution.Processing; + +[SuppressMessage("ReSharper", "NonAtomicCompoundOperator")] +internal sealed class OperationFeatureCollection : IFeatureCollection +{ +#if NET9_0_OR_GREATER + private readonly Lock _writeLock = new(); +#else + private readonly object _writeLock = new(); +#endif +#if NET10_0_OR_GREATER + private ImmutableDictionary _features = []; +#else + private ImmutableDictionary _features = ImmutableDictionary.Empty; +#endif + private volatile int _containerRevision; + + /// + /// Initializes a new instance of . + /// + public OperationFeatureCollection() + { + } + + /// + public bool IsReadOnly => false; + + /// + public bool IsEmpty => _features.Count == 0; + + /// + public int Revision => _containerRevision; + + /// + public object? this[Type key] + { + get + { + ArgumentNullException.ThrowIfNull(key); + + return _features.GetValueOrDefault(key); + } + set + { + ArgumentNullException.ThrowIfNull(key); + + lock (_writeLock) + { + if (value == null) + { + _features = _features.Remove(key); + _containerRevision++; + return; + } + + _features = _features.SetItem(key, value); + _containerRevision++; + } + } + } + + /// + public TFeature? Get() + { + if (typeof(TFeature).IsValueType) + { + var feature = this[typeof(TFeature)]; + if (feature is null && Nullable.GetUnderlyingType(typeof(TFeature)) is null) + { + throw new InvalidOperationException( + $"{typeof(TFeature).FullName} does not exist in the feature collection " + + "and because it is a struct the method can't return null. " + + $"Use 'featureCollection[typeof({typeof(TFeature).FullName})] is not null' " + + "to check if the feature exists."); + } + + return (TFeature?)feature; + } + + return (TFeature?)this[typeof(TFeature)]; + } + + /// + public bool TryGet([NotNullWhen(true)] out TFeature? feature) + { + if (_features.TryGetValue(typeof(TFeature), out var result) + && result is TFeature f) + { + feature = f; + return true; + } + + feature = default; + return false; + } + + /// + public void Set(TFeature? instance) + { + this[typeof(TFeature)] = instance; + } + + /// + public IEnumerator> GetEnumerator() + => _features.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index 9470b054e68..26be9ca9c7f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -1,5 +1,7 @@ using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Text; +using HotChocolate.Caching.Memory; using HotChocolate.Execution.Properties; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -13,280 +15,158 @@ namespace HotChocolate.Execution.Processing; public class Selection : ISelection { private static readonly ArgumentMap s_emptyArguments = ArgumentMap.Empty; - private ulong[] _includeConditions; - private ulong _streamIfCondition; + private readonly FieldSelectionNode[] _syntaxNodes; + private readonly ulong[] _includeFlags; + private readonly byte[] _utf8ResponseName; private Flags _flags; - private FieldNode _syntaxNode; - private FieldNode[] _syntaxNodes; - public Selection( + internal Selection( int id, - ObjectType declaringType, - ObjectField field, - IType type, - FieldNode syntaxNode, string responseName, + ObjectField field, + FieldSelectionNode[] syntaxNodes, + ulong[] includeFlags, + bool isInternal, ArgumentMap? arguments = null, - ulong[]? includeConditions = null, - bool isInternal = false, bool isParallelExecutable = true, FieldDelegate? resolverPipeline = null, PureFieldDelegate? pureResolver = null) { + ArgumentNullException.ThrowIfNull(field); + + if (syntaxNodes.Length == 0) + { + throw new ArgumentException( + "The syntaxNodes collection cannot be empty.", + nameof(syntaxNodes)); + } + Id = id; - DeclaringType = declaringType; - Field = field; - Type = type; - _syntaxNode = syntaxNode; - _syntaxNodes = [syntaxNode]; ResponseName = responseName; + Field = field; Arguments = arguments ?? s_emptyArguments; ResolverPipeline = resolverPipeline; PureResolver = pureResolver; - Strategy = InferStrategy(!isParallelExecutable, pureResolver is not null); - - _includeConditions = includeConditions ?? []; - - _flags = isInternal - ? Flags.Internal - : Flags.None; + Strategy = InferStrategy( + isSerial: !isParallelExecutable, + hasPureResolver: pureResolver is not null); + _syntaxNodes = syntaxNodes; + _includeFlags = includeFlags; + _flags = isInternal ? Flags.Internal : Flags.None; + + if (field.Type.NamedType().IsLeafType()) + { + _flags |= Flags.Leaf; + } - if (Type.IsListType()) + if (field.Type.IsListType()) { _flags |= Flags.List; } - } - protected Selection(Selection selection) - { - ArgumentNullException.ThrowIfNull(selection); - - Id = selection.Id; - Strategy = selection.Strategy; - DeclaringType = selection.DeclaringType; - Field = selection.Field; - Type = selection.Type; - _syntaxNode = selection._syntaxNode; - _syntaxNodes = selection._syntaxNodes; - ResponseName = selection.ResponseName; - ResolverPipeline = selection.ResolverPipeline; - PureResolver = selection.PureResolver; - Arguments = selection.Arguments; - _flags = selection._flags; - - _includeConditions = - selection._includeConditions.Length == 0 - ? [] - : selection._includeConditions.ToArray(); + _utf8ResponseName = Utf8StringCache.GetUtf8String(responseName); } /// public int Id { get; } - public CustomOptionsFlags CustomOptions { get; private set; } - /// - public SelectionExecutionStrategy Strategy { get; private set; } - - /// - public ObjectType DeclaringType { get; } - - /// - public ISelectionSet DeclaringSelectionSet { get; private set; } = null!; - - public IOperation DeclaringOperation { get; private set; } = null!; + public string ResponseName { get; } - /// - public ObjectField Field { get; } + internal ReadOnlySpan Utf8ResponseName => _utf8ResponseName; - /// - public IType Type { get; } + public bool IsInternal => (_flags & Flags.Internal) == Flags.Internal; - /// - public TypeKind TypeKind => Type.Kind; + public bool IsConditional => _includeFlags.Length > 0; - /// public bool IsList => (_flags & Flags.List) == Flags.List; - /// - public FieldNode SyntaxNode => _syntaxNode; - - /// - public IReadOnlyList SyntaxNodes => _syntaxNodes; + public bool IsLeaf => (_flags & Flags.Leaf) == Flags.Leaf; - public int SelectionSetId { get; private set; } + public ObjectField Field { get; } /// - public SelectionSetNode? SelectionSet => _syntaxNode.SelectionSet; + IOutputFieldDefinition ISelection.Field => Field; - /// - public string ResponseName { get; } + public IType Type => Field.Type; - /// - public byte[] Utf8ResponseName => _utf8ResponseName ??= Encoding.UTF8.GetBytes(ResponseName); - private byte[]? _utf8ResponseName; + public ObjectType DeclaringType => Field.DeclaringType; - /// - public FieldDelegate? ResolverPipeline { get; private set; } + public SelectionSet DeclaringSelectionSet { get; private set; } = null!; - /// - public PureFieldDelegate? PureResolver { get; private set; } + ISelectionSet ISelection.DeclaringSelectionSet => DeclaringSelectionSet; - /// - public ArgumentMap Arguments { get; } + public Operation DeclaringOperation => DeclaringSelectionSet.DeclaringOperation; - /// - public bool HasStreamDirective(ulong includeFlags) - => (_flags & Flags.Stream) == Flags.Stream - && (_streamIfCondition is 0 || (includeFlags & _streamIfCondition) != _streamIfCondition); + public ArgumentMap Arguments { get; } - /// - /// Specifies if the current selection is immutable. - /// - public bool IsReadOnly => (_flags & Flags.Sealed) == Flags.Sealed; + public SelectionExecutionStrategy Strategy { get; private set; } - /// - public bool IsInternal => (_flags & Flags.Internal) == Flags.Internal; + public FieldDelegate? ResolverPipeline { get; private set; } - /// - public bool IsConditional - => _includeConditions.Length > 0 || (_flags & Flags.Internal) == Flags.Internal; + public PureFieldDelegate? PureResolver { get; private set; } - internal ReadOnlySpan IncludeConditions => _includeConditions; + internal ReadOnlySpan SyntaxNodes => _syntaxNodes; - public bool IsIncluded(ulong includeFlags, bool allowInternals = false) + IEnumerable ISelection.GetSyntaxNodes() { - // in most case we do not have any include condition, - // so we can take the easy way out here if we do not have any flags. - if (_includeConditions.Length is 0) - { - return !IsInternal || allowInternals; - } - - // if there are flags in most cases we just have one, so we can - // check the first and optimize for this. - var includeCondition = _includeConditions[0]; - - if ((includeFlags & includeCondition) == includeCondition) - { - return !IsInternal || allowInternals; - } - - // if we just have one flag and the flags are not fulfilled we can just exit. - if (_includeConditions.Length is 1) - { - return false; - } - - // else, we will iterate over the rest of the conditions and validate them one by one. - for (var i = 1; i < _includeConditions.Length; i++) + for (var i = 0; i < SyntaxNodes.Length; i++) { - includeCondition = _includeConditions[i]; - - if ((includeFlags & includeCondition) == includeCondition) - { - return !IsInternal || allowInternals; - } + yield return SyntaxNodes[i].Node; } - - return false; } - public override string ToString() - => _syntaxNode.ToString(); - - internal void AddSelection(FieldNode selectionSyntax, ulong includeCondition = 0) + public bool IsIncluded(ulong includeFlags) { - if ((_flags & Flags.Sealed) == Flags.Sealed) + if (_includeFlags.Length == 0) { - throw new NotSupportedException(Resources.PreparedSelection_ReadOnly); + return true; } - if (includeCondition == 0) + if (_includeFlags.Length == 1) { - if (_includeConditions.Length > 0) - { - _includeConditions = []; - } + var flags1 = _includeFlags[0]; + return (flags1 & includeFlags) == flags1; } - else if (_includeConditions.Length > 0 && Array.IndexOf(_includeConditions, includeCondition) == -1) + + if (_includeFlags.Length == 2) { - var next = _includeConditions.Length; - Array.Resize(ref _includeConditions, next + 1); - _includeConditions[next] = includeCondition; + var flags1 = _includeFlags[0]; + var flags2 = _includeFlags[1]; + return (flags1 & includeFlags) == flags1 || (flags2 & includeFlags) == flags2; } - if (!_syntaxNode.Equals(selectionSyntax, SyntaxComparison.Syntax)) + if (_includeFlags.Length == 3) { - // enlarge the syntax nodes array and add the new syntax node. - var temp = new FieldNode[_syntaxNodes.Length + 1]; - Array.Copy(_syntaxNodes, temp, _syntaxNodes.Length); - temp[_syntaxNodes.Length] = selectionSyntax; - _syntaxNodes = temp; - - _syntaxNode = MergeField(_syntaxNode, selectionSyntax); + var flags1 = _includeFlags[0]; + var flags2 = _includeFlags[1]; + var flags3 = _includeFlags[2]; + return (flags1 & includeFlags) == flags1 + || (flags2 & includeFlags) == flags2 + || (flags3 & includeFlags) == flags3; } - } - private static FieldNode MergeField( - FieldNode first, - FieldNode other) - { - var directives = first.Directives; + var span = _includeFlags.AsSpan(); - if (other.Directives.Count > 0) + for (var i = 0; i < span.Length; i++) { - if (directives.Count == 0) - { - directives = other.Directives; - } - else + if ((span[i] & includeFlags) == span[i]) { - var temp = new DirectiveNode[directives.Count + other.Directives.Count]; - var next = 0; - - for (var i = 0; i < directives.Count; i++) - { - temp[next++] = directives[i]; - } - - for (var i = 0; i < other.Directives.Count; i++) - { - temp[next++] = other.Directives[i]; - } - - directives = temp; + return true; } } - var selectionSet = first.SelectionSet; + return false; + } - if (selectionSet is not null && other.SelectionSet is not null) + public override string ToString() + { + if (SyntaxNodes[0].Node.Alias is not null) { - var selections = new ISelectionNode[ - selectionSet.Selections.Count + other.SelectionSet.Selections.Count]; - var next = 0; - - for (var i = 0; i < selectionSet.Selections.Count; i++) - { - selections[next++] = selectionSet.Selections[i]; - } - - for (var i = 0; i < other.SelectionSet.Selections.Count; i++) - { - selections[next++] = other.SelectionSet.Selections[i]; - } - - selectionSet = selectionSet.WithSelections(selections); + return $"{ResponseName} : {Field.Name}"; } - return new FieldNode( - first.Location, - first.Name, - first.Alias, - directives, - first.Arguments, - selectionSet); + return Field.Name; } internal void SetResolvers( @@ -303,67 +183,24 @@ internal void SetResolvers( Strategy = InferStrategy(hasPureResolver: pureResolver is not null); } - internal void SetSelectionSetId(int selectionSetId) - { - if ((_flags & Flags.Sealed) == Flags.Sealed) - { - throw new NotSupportedException(Resources.PreparedSelection_ReadOnly); - } - - SelectionSetId = selectionSetId; - } - - internal void MarkAsStream(ulong ifCondition) - { - if ((_flags & Flags.Sealed) == Flags.Sealed) - { - throw new NotSupportedException(Resources.PreparedSelection_ReadOnly); - } - - _streamIfCondition = ifCondition; - _flags |= Flags.Stream; - } - - public void SetOption(CustomOptionsFlags customOptions) - { - if ((_flags & Flags.Sealed) == Flags.Sealed) - { - throw new NotSupportedException(Resources.PreparedSelection_ReadOnly); - } - - CustomOptions |= customOptions; - } - /// /// Completes the selection without sealing it. /// - internal void Complete(IOperation declaringOperation, ISelectionSet declaringSelectionSet) + internal void Complete(SelectionSet selectionSet, bool seal) { - Debug.Assert(declaringSelectionSet is not null); + ArgumentNullException.ThrowIfNull(selectionSet); - if ((_flags & Flags.Sealed) != Flags.Sealed) + if ((_flags & Flags.Sealed) == Flags.Sealed) { - DeclaringSelectionSet = declaringSelectionSet; - DeclaringOperation = declaringOperation; + throw new InvalidOperationException("Selection is already sealed."); } - Debug.Assert( - ReferenceEquals(declaringSelectionSet, DeclaringSelectionSet), - "Selections can only belong to a single selectionSet."); - } + DeclaringSelectionSet = selectionSet; - internal void Seal(IOperation declaringOperation, ISelectionSet declaringSelectionSet) - { - if ((_flags & Flags.Sealed) != Flags.Sealed) + if (seal) { - DeclaringSelectionSet = declaringSelectionSet; - DeclaringOperation = declaringOperation; _flags |= Flags.Sealed; } - - Debug.Assert( - ReferenceEquals(declaringSelectionSet, DeclaringSelectionSet), - "Selections can only belong to a single selectionSet."); } private SelectionExecutionStrategy InferStrategy( @@ -391,20 +228,8 @@ private enum Flags Internal = 1, Sealed = 2, List = 4, - Stream = 8 - } - - [Flags] - public enum CustomOptionsFlags : byte - { - None = 0, - Option1 = 1, - Option2 = 2, - Option3 = 4, - Option4 = 8, - Option5 = 16, - Option6 = 32, - Option7 = 64 + Stream = 8, + Leaf = 16 } internal sealed class Sealed : Selection @@ -438,3 +263,13 @@ public Sealed( } } } + +internal static class Utf8StringCache +{ + private static readonly Encoding s_utf8 = Encoding.UTF8; + private static readonly Cache s_cache = new(capacity: 4 * 1024); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUtf8String(string s) + => s_cache.GetOrCreate(s, static k => s_utf8.GetBytes(k)); +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 88223788ca3..6968ad6a7a3 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -1,5 +1,4 @@ using System.Collections.Frozen; -using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using HotChocolate.Types; @@ -11,97 +10,74 @@ namespace HotChocolate.Execution.Processing; /// When needed a selection set can preserve fragments so that the execution engine /// can branch the processing of these fragments. /// -internal sealed class SelectionSet : ISelectionSet +public sealed class SelectionSet : ISelectionSet { - private static readonly Fragment[] s_empty = []; private readonly Selection[] _selections; - private readonly FrozenDictionary _responseNameLookup; + private readonly FrozenDictionary _responseNameLookup; private readonly SelectionLookup _utf8ResponseNameLookup; - private readonly Fragment[] _fragments; private Flags _flags; - /// - /// Initializes a new instance of . - /// - /// - /// The selection set unique id. - /// - /// - /// A list of executable field selections. - /// - /// - /// A list of preserved fragments that can be used to branch of - /// some of the execution. - /// - /// - /// Defines if this list needs post-processing for skip and include. - /// - public SelectionSet( - int id, - Selection[] selections, - Fragment[]? fragments, - bool isConditional) + public SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, bool isConditional) { + ArgumentNullException.ThrowIfNull(selections); + + if (selections.Length == 0) + { + throw new ArgumentException("Selections cannot be empty.", nameof(selections)); + } + Id = id; + Type = type; + _flags = isConditional ? Flags.Conditional : Flags.None; _selections = selections; - _responseNameLookup = _selections.ToFrozenDictionary(t => t.ResponseName, ISelection (t) => t); + _responseNameLookup = _selections.ToFrozenDictionary(t => t.ResponseName); _utf8ResponseNameLookup = SelectionLookup.Create(this); - _fragments = fragments ?? s_empty; - _flags = isConditional ? Flags.Conditional : Flags.None; } - /// + /// + /// Gets an operation unique selection-set identifier of this selection. + /// public int Id { get; } - /// + /// + /// Defines if this list needs post-processing for skip and include. + /// public bool IsConditional => (_flags & Flags.Conditional) == Flags.Conditional; - /// - public IReadOnlyList Selections => _selections; - - /// - public IReadOnlyList Fragments => _fragments; - - /// - public IOperation DeclaringOperation { get; private set; } = null!; + /// + /// Gets the type that declares this selection set. + /// + public IObjectTypeDefinition Type { get; } - /// - public bool TryGetSelection(string responseName, [NotNullWhen(true)] out ISelection? selection) - => _responseNameLookup.TryGetValue(responseName, out selection); + /// + /// Gets the declaring operation. + /// + public Operation DeclaringOperation { get; private set; } = null!; - /// - public bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out ISelection? selection) - => _utf8ResponseNameLookup.TryGetSelection(utf8ResponseName, out selection); + IOperation ISelectionSet.DeclaringOperation => DeclaringOperation; /// - /// Completes the selection set without sealing it. + /// Gets the selections that shall be executed. /// - internal void Complete(IOperation declaringOperation) - { - if ((_flags & Flags.Sealed) != Flags.Sealed) - { - DeclaringOperation = declaringOperation; - - for (var i = 0; i < _selections.Length; i++) - { - _selections[i].Complete(declaringOperation, this); - } - } - } + public ReadOnlySpan Selections => _selections; - internal void Seal(IOperation declaringOperation) + IEnumerable ISelectionSet.GetSelections() => _selections; + + internal void Complete(Operation declaringOperation, bool seal) { - if ((_flags & Flags.Sealed) != Flags.Sealed) + if ((_flags & Flags.Sealed) == Flags.Sealed) { - DeclaringOperation = declaringOperation; + throw new InvalidOperationException("Selection set is already sealed."); + } - for (var i = 0; i < _selections.Length; i++) - { - _selections[i].Seal(declaringOperation, this); - } + DeclaringOperation = declaringOperation; - _flags |= Flags.Sealed; + foreach (var selection in _selections) + { + selection.Complete(declaringOperation, this); } + + _flags |= Flags.Sealed; } /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs deleted file mode 100644 index 7cc029c1c6c..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionVariants.cs +++ /dev/null @@ -1,194 +0,0 @@ -using HotChocolate.Types; -using static HotChocolate.Execution.Properties.Resources; -using static HotChocolate.Execution.ThrowHelper; - -namespace HotChocolate.Execution.Processing; - -internal sealed class SelectionVariants(int id) : ISelectionVariants -{ - private ObjectType? _firstType; - private SelectionSet? _firstSelectionSet; - private ObjectType? _secondType; - private SelectionSet? _secondSelectionSet; - private Dictionary? _map; - private bool _readOnly; - - /// - public int Id { get; } = id; - - /// - public IOperation DeclaringOperation { get; private set; } = null!; - - public IEnumerable GetPossibleTypes() - => _map?.Keys ?? GetPossibleTypesLazy(); - - public bool IsPossibleType(ObjectType typeContext) - { - if (_map is not null) - { - return _map.ContainsKey(typeContext); - } - - if (ReferenceEquals(_firstType, typeContext)) - { - return true; - } - - if (ReferenceEquals(_secondType, typeContext)) - { - return true; - } - - return false; - } - - private IEnumerable GetPossibleTypesLazy() - { - yield return _firstType!; - - if (_secondType is not null) - { - yield return _secondType; - } - } - - public ISelectionSet GetSelectionSet(ObjectType typeContext) - { - if (_map is not null) - { - if (_map.TryGetValue(typeContext, out var selections)) - { - return selections; - } - else - { - throw SelectionSet_TypeContextInvalid(typeContext); - } - } - - if (ReferenceEquals(_firstType, typeContext)) - { - return _firstSelectionSet!; - } - - if (ReferenceEquals(_secondType, typeContext)) - { - return _secondSelectionSet!; - } - - throw SelectionSet_TypeContextInvalid(typeContext); - } - - internal bool ContainsSelectionSet(ObjectType typeContext) - { - if (_map is not null) - { - return _map.ContainsKey(typeContext); - } - - if (ReferenceEquals(_firstType, typeContext)) - { - return true; - } - - if (ReferenceEquals(_secondType, typeContext)) - { - return true; - } - - return false; - } - - internal void AddSelectionSet( - int id, - ObjectType typeContext, - Selection[] selections, - Fragment[]? fragments, - bool isConditional) - { - if (_readOnly) - { - throw new NotSupportedException(SelectionVariants_ReadOnly); - } - - var selectionSet = new SelectionSet(id, selections, fragments, isConditional); - - if (_map is not null) - { - _map[typeContext] = selectionSet; - } - else - { - if (_firstType is null) - { - _firstType = typeContext; - _firstSelectionSet = selectionSet; - } - else if (_secondType is null) - { - if (typeContext == _firstType) - { - throw SelectionSet_TypeAlreadyAdded(typeContext); - } - - _secondType = typeContext; - _secondSelectionSet = selectionSet; - } - else - { - _map = new Dictionary - { - { _firstType, _firstSelectionSet! }, - { _secondType, _secondSelectionSet! }, - { typeContext, selectionSet } - }; - - _firstType = null; - _firstSelectionSet = null; - _secondType = null; - _secondSelectionSet = null; - } - } - } - - /// - /// Completes the selection variant without sealing it. - /// - internal void Complete(IOperation declaringOperation) - { - if (!_readOnly) - { - DeclaringOperation = declaringOperation; - _firstSelectionSet?.Complete(declaringOperation); - _secondSelectionSet?.Complete(declaringOperation); - - if (_map is not null) - { - foreach (var selectionSet in _map.Values) - { - selectionSet.Complete(declaringOperation); - } - } - } - } - - internal void Seal(IOperation declaringOperation) - { - if (!_readOnly) - { - DeclaringOperation = declaringOperation; - _firstSelectionSet?.Seal(declaringOperation); - _secondSelectionSet?.Seal(declaringOperation); - - if (_map is not null) - { - foreach (var selectionSet in _map.Values) - { - selectionSet.Seal(declaringOperation); - } - } - - _readOnly = true; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.ArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs similarity index 98% rename from src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.ArgumentValues.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs index a5c2aaf134a..c867fbb89d8 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.ArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs @@ -215,8 +215,3 @@ private static void BuildDirectivePipeline( } } } - -internal delegate FieldDelegate CreateFieldPipeline( - Schema schema, - ObjectField field, - FieldNode selection); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs new file mode 100644 index 00000000000..174bc3ca348 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs @@ -0,0 +1,787 @@ +using System.Collections.Immutable; +using System.Runtime.CompilerServices; +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types; +using HotChocolate.Utilities; +using static System.Runtime.InteropServices.CollectionsMarshal; +using static System.Runtime.InteropServices.MemoryMarshal; +using static System.StringComparer; +using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Execution.ThrowHelper; + +namespace HotChocolate.Execution.Processing; + +/// +/// The operation compiler will analyze a specific operation of a GraphQL request document +/// and create from it an optimized executable operation tree. +/// +public sealed partial class OperationCompiler +{ + private readonly InputParser _parser; + private readonly CreateFieldPipeline _createFieldPipeline; + private readonly Queue _backlog = []; + private readonly Dictionary _selectionLookup = []; + private readonly Dictionary _selectionSetIdLookup = []; + private readonly Dictionary _selectionVariants = []; + private readonly Dictionary _fragmentDefinitions = []; + private readonly Dictionary _contextData = []; + private readonly List _selections = []; + private readonly HashSet _directiveNames = new(Ordinal); + private readonly List _pipelineComponents = []; + private readonly HashSet _enqueuedSelectionSets = []; + private IncludeCondition[] _includeConditions = []; + private CompilerContext? _deferContext; + private ImmutableArray _operationOptimizers = []; + private int _nextSelectionId; + private int _nextSelectionSetRefId; + private int _nextSelectionSetId; + private int _nextFragmentId; + private bool _hasIncrementalParts; + private OperationCompilerMetrics _metrics; + + public OperationCompiler(InputParser parser) + { + _parser = parser ?? throw new ArgumentNullException(nameof(parser)); + + _createFieldPipeline = + (schema, field, selection) + => CreateFieldPipeline( + schema, + field, + selection, + null, + _directiveNames, + _pipelineComponents); + } + + internal OperationCompilerMetrics Metrics => _metrics; + + public IOperation Compile(OperationCompilerRequest request) + { + ArgumentException.ThrowIfNullOrEmpty(request.Id, nameof(request)); + + try + { + var backlogMaxSize = 0; + var selectionSetOptimizers = request.SelectionSetOptimizers; + _operationOptimizers = request.OperationOptimizers; + + // collect root fields + var rootPath = SelectionPath.Root; + var id = GetOrCreateSelectionSetRefId(request.Definition.SelectionSet, request.RootType.Name, rootPath); + var variants = GetOrCreateSelectionVariants(id); + SelectionSetInfo[] infos = [new(request.Definition.SelectionSet, 0)]; + + var context = new CompilerContext((Schema)request.Schema, request.Document); + context.Initialize(request.RootType, variants, infos, rootPath, selectionSetOptimizers); + CompileSelectionSet(context); + + // process consecutive selections + while (_backlog.Count > 0) + { + backlogMaxSize = Math.Max(backlogMaxSize, _backlog.Count); + + var current = _backlog.Dequeue(); + var type = current.Type; + variants = GetOrCreateSelectionVariants(current.SelectionSetId); + + if (!variants.ContainsSelectionSet(type)) + { + infos = _selectionLookup[current.Selection]; + context.Initialize(type, variants, infos, current.Path, current.Optimizers); + CompileSelectionSet(context); + } + } + + // create operation + var operation = CreateOperation(request); + + _metrics = new OperationCompilerMetrics( + _nextSelectionId, + _selectionVariants.Count, + backlogMaxSize); + + return operation; + } + finally + { + _nextSelectionId = 0; + _nextSelectionSetRefId = 0; + _nextSelectionId = 0; + _nextFragmentId = 0; + _hasIncrementalParts = false; + + _backlog.Clear(); + _selectionLookup.Clear(); + _selectionSetIdLookup.Clear(); + _selectionVariants.Clear(); + _fragmentDefinitions.Clear(); + _contextData.Clear(); + _selections.Clear(); + _directiveNames.Clear(); + _pipelineComponents.Clear(); + _enqueuedSelectionSets.Clear(); + + _operationOptimizers = []; + + _includeConditions = []; + _deferContext = null; + } + } + + private Operation CreateOperation(OperationCompilerRequest request) + { + var operation = new Operation( + request.Id, + request.Document, + request.Definition, + request.RootType, + request.Schema); + + var schema = Unsafe.As(request.Schema); + + var variants = new SelectionVariants[_selectionVariants.Count]; + + if (_operationOptimizers.Length == 0) + { + CompleteResolvers(schema); + + // if we do not have any optimizers, we will copy + // the variants and seal them in one go. + foreach (var item in _selectionVariants) + { + variants[item.Key] = item.Value; + item.Value.Seal(operation); + } + } + else + { + // if we have optimizers, we will first copy the variants to its array, + // after that we will run the optimizers and give them a chance to do some + // more mutations on the compiled selection variants. + // after we have executed all optimizers, we will seal the selection variants. + var context = new OperationOptimizerContext( + request.Id, + request.Document, + request.Definition, + schema, + request.RootType, + variants, + _includeConditions, + _contextData, + _hasIncrementalParts, + _createFieldPipeline); + + foreach (var item in _selectionVariants) + { + variants[item.Key] = item.Value; + } + + // we will complete the selection variants, sets and selections + // without sealing them so that analyzers in this step can fully + // inspect them. + var variantsSpan = variants.AsSpan(); + ref var variantsStart = ref GetReference(variantsSpan); + ref var variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length); + + while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) + { + variantsStart.Complete(operation); + variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; + } + + var optSpan = _operationOptimizers.AsSpan(); + ref var optStart = ref GetReference(optSpan); + ref var optEnd = ref Unsafe.Add(ref optStart, optSpan.Length); + + while (Unsafe.IsAddressLessThan(ref optStart, ref optEnd)) + { + optStart.OptimizeOperation(context); + optStart = ref Unsafe.Add(ref optStart, 1)!; + } + + CompleteResolvers(schema); + + variantsSpan = variants.AsSpan(); + variantsStart = ref GetReference(variantsSpan)!; + variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length)!; + + while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) + { + variantsStart.Seal(operation); + variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; + } + } + + operation.Seal(_contextData, variants, _hasIncrementalParts, _includeConditions); + return operation; + } + + private void CompleteResolvers(Schema schema) + { + ref var searchSpace = ref GetReference(AsSpan(_selections)); + + Path? path = null; + for (var i = 0; i < _selections.Count; i++) + { + var selection = Unsafe.Add(ref searchSpace, i); + path = path?.Append(selection.ResponseName); + if (selection.ResolverPipeline is null && selection.PureResolver is null) + { + var field = selection.Field; + var syntaxNode = selection.SyntaxNode; + if (syntaxNode.Directives.Count > 0 && path == null) + { + // create the path only on demand + path = PathHelper.CreatePathFromSelection(_selections, i + 1); + } + + var resolver = CreateFieldPipeline( + schema, + field, + syntaxNode, + path, + _directiveNames, + _pipelineComponents); + var pureResolver = TryCreatePureField(schema, field, syntaxNode); + selection.SetResolvers(resolver, pureResolver); + } + } + } + + private void CompileSelectionSet(CompilerContext context) + { + // We first collect the fields that we find in the selection set ... + CollectFields(context); + + // next we will call the selection set optimizers to rewrite the + // selection set if necessary. + OptimizeSelectionSet(context); + + // after that we start completing the selections and build the SelectionSet from + // the completed selections. + CompleteSelectionSet(context); + } + + private void CompleteSelectionSet(CompilerContext context) + { + var selections = new Selection[context.Fields.Values.Count]; + var fragments = context.Fragments.Count is not 0 + ? new Fragment[context.Fragments.Count] + : []; + var selectionIndex = 0; + var isConditional = false; + + foreach (var selection in context.Fields.Values) + { + // if the field of the selection returns a composite type, we will traverse + // the child selection-sets as well. + var fieldType = selection.Type.NamedType(); + var selectionSetId = -1; + + if (selection.IsConditional) + { + isConditional = true; + } + + // Determines if the type is a composite type. + if (fieldType.IsCompositeType()) + { + if (selection.SelectionSet is null) + { + // composite fields always have to have a selection-set + // otherwise we need to throw. + throw QueryCompiler_CompositeTypeSelectionSet(selection.SyntaxNode); + } + + var selectionPath = context.Path.Append(selection.ResponseName); + selectionSetId = GetOrCreateSelectionSetRefId(selection.SelectionSet, fieldType.Name, selectionPath); + var possibleTypes = context.Schema.GetPossibleTypes(fieldType); + + if (_enqueuedSelectionSets.Add(selectionSetId)) + { + for (var i = possibleTypes.Count - 1; i >= 0; i--) + { + _backlog.Enqueue( + new BacklogItem( + possibleTypes[i], + selectionSetId, + selection, + selectionPath, + ResolveOptimizers(context.Optimizers, selection.Field))); + } + } + + // We are waiting for the latest stream and defer spec discussions to be codified + // before we change the overall stream handling. + // + // For now, we only allow streams on lists of composite types. + if (selection.SyntaxNode.IsStreamable()) + { + var streamDirective = selection.SyntaxNode.GetStreamDirective(); + var nullValue = NullValueNode.Default; + var ifValue = streamDirective?.GetArgumentValue(DirectiveNames.Stream.Arguments.If) ?? nullValue; + long ifConditionFlags = 0; + + if (ifValue.Kind is not SyntaxKind.NullValue) + { + var ifCondition = new IncludeCondition(ifValue, nullValue); + ifConditionFlags = GetSelectionIncludeCondition(ifCondition, 0); + } + + selection.MarkAsStream(ifConditionFlags); + _hasIncrementalParts = true; + } + } + + selection.SetSelectionSetId(selectionSetId); + selections[selectionIndex++] = selection; + _selections.Add(selection); + } + + if (context.Fragments.Count > 0) + { + for (var i = 0; i < context.Fragments.Count; i++) + { + fragments[i] = context.Fragments[i]; + } + } + + context.SelectionVariants.AddSelectionSet( + _nextSelectionSetId++, + context.Type, + selections, + fragments, + isConditional); + } + + private void CollectFields(CompilerContext context) + { + foreach (var selectionSetInfo in context.SelectionInfos) + { + CollectFields( + context, + selectionSetInfo.SelectionSet, + selectionSetInfo.IncludeCondition); + } + } + + private void CollectFields( + CompilerContext context, + SelectionSetNode selectionSet, + ulong includeCondition) + { + for (var j = 0; j < selectionSet.Selections.Count; j++) + { + ResolveFields(context, selectionSet.Selections[j], includeCondition); + } + } + + private void ResolveFields( + CompilerContext context, + ISelectionNode selection, + long includeCondition) + { + switch (selection.Kind) + { + case SyntaxKind.Field: + ResolveField( + context, + (FieldNode)selection, + includeCondition); + break; + + case SyntaxKind.InlineFragment: + ResolveInlineFragment( + context, + (InlineFragmentNode)selection, + includeCondition); + break; + + case SyntaxKind.FragmentSpread: + ResolveFragmentSpread( + context, + (FragmentSpreadNode)selection, + includeCondition); + break; + } + } + + private void ResolveField( + CompilerContext context, + FieldNode selection, + ulong includeCondition) + { + includeCondition = GetSelectionIncludeCondition(selection, includeCondition); + + var fieldName = selection.Name.Value; + var responseName = selection.Alias?.Value ?? fieldName; + + if (context.Type.Fields.TryGetField(fieldName, out var field)) + { + var fieldType = field.Type; + + if (context.Fields.TryGetValue(responseName, out var preparedSelection)) + { + preparedSelection.AddSelection(selection, includeCondition); + + if (selection.SelectionSet is not null) + { + var selectionSetInfo = new SelectionSetInfo( + selection.SelectionSet!, + includeCondition); + var selectionInfos = _selectionLookup[preparedSelection]; + var next = selectionInfos.Length; + Array.Resize(ref selectionInfos, next + 1); + selectionInfos[next] = selectionSetInfo; + _selectionLookup[preparedSelection] = selectionInfos; + } + } + else + { + var id = GetNextSelectionId(); + + // if this is the first time we've found a selection to this field, we have to + // create a new prepared selection. + preparedSelection = new Selection.Sealed( + id, + context.Type, + field, + fieldType, + selection.SelectionSet is not null + ? selection.WithSelectionSet( + selection.SelectionSet.WithSelections( + selection.SelectionSet.Selections)) + : selection, + responseName: responseName, + arguments: CoerceArgumentValues(field, selection), + includeConditions: includeCondition == 0 + ? null + : [includeCondition], + isParallelExecutable: field.IsParallelExecutable); + + context.Fields.Add(responseName, preparedSelection); + + if (selection.SelectionSet is not null) + { + var selectionSetInfo = new SelectionSetInfo( + selection.SelectionSet!, + includeCondition); + _selectionLookup.Add(preparedSelection, [selectionSetInfo]); + } + } + } + else + { + throw FieldDoesNotExistOnType(selection, context.Type.Name); + } + } + + private void ResolveInlineFragment( + CompilerContext context, + InlineFragmentNode inlineFragment, + long includeCondition) + { + ResolveFragment( + context, + inlineFragment, + inlineFragment.TypeCondition, + inlineFragment.SelectionSet, + inlineFragment.Directives, + includeCondition); + } + + private void ResolveFragmentSpread( + CompilerContext context, + FragmentSpreadNode fragmentSpread, + long includeCondition) + { + var fragmentDef = GetFragmentDefinition(context, fragmentSpread); + + ResolveFragment( + context, + fragmentSpread, + fragmentDef.TypeCondition, + fragmentDef.SelectionSet, + fragmentSpread.Directives, + includeCondition); + } + + private void ResolveFragment( + CompilerContext context, + ISelectionNode selection, + NamedTypeNode? typeCondition, + SelectionSetNode selectionSet, + IReadOnlyList directives, + ulong includeCondition) + { + if (typeCondition is null + || (context.Schema.Types.TryGetType(typeCondition, out IType? typeCon) + && DoesTypeApply(typeCon, context.Type))) + { + includeCondition = GetSelectionIncludeCondition(selection, includeCondition); + + if (directives.IsDeferrable()) + { + var deferDirective = directives.GetDeferDirectiveNode(); + var nullValue = NullValueNode.Default; + var ifValue = deferDirective?.GetArgumentValue(DirectiveNames.Defer.Arguments.If) ?? nullValue; + + ulong ifConditionFlags = 0; + + if (ifValue.Kind is not SyntaxKind.NullValue) + { + var ifCondition = new IncludeCondition(ifValue, nullValue); + ifConditionFlags = GetSelectionIncludeCondition(ifCondition, includeCondition); + } + + var typeName = typeCondition?.Name.Value ?? context.Type.Name; + var id = GetOrCreateSelectionSetRefId(selectionSet, typeName, context.Path); + var variants = GetOrCreateSelectionVariants(id); + var infos = new SelectionSetInfo[] { new(selectionSet, includeCondition) }; + + if (!variants.ContainsSelectionSet(context.Type)) + { + var deferContext = RentContext(context); + deferContext.Initialize(context.Type, variants, infos, context.Path); + CompileSelectionSet(deferContext); + ReturnContext(deferContext); + } + + var fragment = new Fragment( + GetNextFragmentId(), + context.Type, + selection, + directives, + variants.GetSelectionSet(context.Type), + includeCondition, + ifConditionFlags); + + context.Fragments.Add(fragment); + _hasIncrementalParts = true; + + // if we have if-condition flags, there will be a runtime validation if something + // shall be deferred, so we need to prepare for both cases. + // + // this means that we will collect the fields with our if condition flags as + // if the fragment was not deferred. + if (ifConditionFlags is not 0) + { + CollectFields(context, selectionSet, ifConditionFlags); + } + } + else + { + CollectFields(context, selectionSet, includeCondition); + } + } + } + + private static bool DoesTypeApply(IType typeCondition, IObjectTypeDefinition current) + => typeCondition.Kind switch + { + TypeKind.Object => ReferenceEquals(typeCondition, current), + TypeKind.Interface => current.IsImplementing((InterfaceType)typeCondition), + TypeKind.Union => ((UnionType)typeCondition).Types.ContainsName(current.Name), + _ => false + }; + + private FragmentDefinitionNode GetFragmentDefinition( + CompilerContext context, + FragmentSpreadNode fragmentSpread) + { + var fragmentName = fragmentSpread.Name.Value; + + if (!_fragmentDefinitions.TryGetValue(fragmentName, out var value)) + { + var document = context.Document; + + for (var i = 0; i < document.Definitions.Count; i++) + { + if (document.Definitions[i] is FragmentDefinitionNode fragmentDefinition + && fragmentDefinition.Name.Value.EqualsOrdinal(fragmentName)) + { + value = fragmentDefinition; + _fragmentDefinitions.Add(fragmentName, value); + goto EXIT; + } + } + + throw new InvalidOperationException( + string.Format( + OperationCompiler_FragmentNotFound, + fragmentName)); + } + +EXIT: + return value; + } + + internal int GetNextSelectionId() => _nextSelectionId++; + + private int GetNextFragmentId() => _nextFragmentId++; + + private int GetOrCreateSelectionSetRefId( + SelectionSetNode selectionSet, + string selectionSetTypeName, + SelectionPath path) + { + var selectionSetRef = new SelectionSetRef(selectionSet, selectionSetTypeName, path); + + if (!_selectionSetIdLookup.TryGetValue(selectionSetRef, out var selectionSetId)) + { + selectionSetId = _nextSelectionSetRefId++; + _selectionSetIdLookup.Add(selectionSetRef, selectionSetId); + } + + return selectionSetId; + } + + private SelectionVariants GetOrCreateSelectionVariants(int selectionSetId) + { + if (!_selectionVariants.TryGetValue(selectionSetId, out var variants)) + { + variants = new SelectionVariants(selectionSetId); + _selectionVariants.Add(selectionSetId, variants); + } + + return variants; + } + + private ulong GetSelectionIncludeCondition( + ISelectionNode selectionSyntax, + ulong parentIncludeCondition) + { + var condition = IncludeCondition.FromSelection(selectionSyntax); + + if (condition.IsDefault) + { + return parentIncludeCondition; + } + + var pos = Array.IndexOf(_includeConditions, condition); + + if (pos == -1) + { + pos = _includeConditions.Length; + + if (pos == 64) + { + throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); + } + + if (_includeConditions.Length == 0) + { + _includeConditions = new IncludeCondition[1]; + } + else + { + Array.Resize(ref _includeConditions, pos + 1); + } + + _includeConditions[pos] = condition; + } + + long selectionIncludeCondition = 1; + selectionIncludeCondition <<= pos; + + if (parentIncludeCondition == 0) + { + return selectionIncludeCondition; + } + + parentIncludeCondition |= selectionIncludeCondition; + return parentIncludeCondition; + } + + private long GetSelectionIncludeCondition( + IncludeCondition condition, + ulong parentIncludeCondition) + { + var pos = Array.IndexOf(_includeConditions, condition); + + if (pos == -1) + { + pos = _includeConditions.Length; + + if (pos == 64) + { + throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); + } + + if (_includeConditions.Length == 0) + { + _includeConditions = new IncludeCondition[1]; + } + else + { + Array.Resize(ref _includeConditions, pos + 1); + } + + _includeConditions[pos] = condition; + } + + long selectionIncludeCondition = 1; + selectionIncludeCondition <<= pos; + + if (parentIncludeCondition == 0) + { + return selectionIncludeCondition; + } + + parentIncludeCondition |= selectionIncludeCondition; + return parentIncludeCondition; + } + + private CompilerContext RentContext(CompilerContext context) + { + if (_deferContext is null) + { + return new CompilerContext(context.Schema, context.Document); + } + + var temp = _deferContext; + _deferContext = null; + return temp; + } + + private void ReturnContext(CompilerContext context) + => _deferContext ??= context; + + internal void RegisterNewSelection(Selection newSelection) + { + if (newSelection.SyntaxNode.SelectionSet is not null) + { + var selectionSetInfo = new SelectionSetInfo(newSelection.SelectionSet!, 0); + _selectionLookup.Add(newSelection, [selectionSetInfo]); + } + } + + private readonly struct SelectionSetRef( + SelectionSetNode selectionSet, + string selectionSetTypeName, + SelectionPath path) + : IEquatable + { + public readonly SelectionSetNode SelectionSet = selectionSet; + + public readonly SelectionPath Path = path; + + public readonly string SelectionSetTypeName = selectionSetTypeName; + + public bool Equals(SelectionSetRef other) + => SyntaxComparer.BySyntax.Equals(SelectionSet, other.SelectionSet) + && Path.Equals(other.Path) + && Ordinal.Equals(SelectionSetTypeName, other.SelectionSetTypeName); + + public override bool Equals(object? obj) + => obj is SelectionSetRef other && Equals(other); + + public override int GetHashCode() + => HashCode.Combine( + SyntaxComparer.BySyntax.GetHashCode(SelectionSet), + Path.GetHashCode(), + Ordinal.GetHashCode(SelectionSetTypeName)); + } +} diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index ae9e6fe3046..2729033aa3b 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -62,10 +62,12 @@ + + diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/IncludeConditionCollection.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/IncludeConditionCollection.cs index a4818fa44ee..c6eed75faa7 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/IncludeConditionCollection.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/IncludeConditionCollection.cs @@ -37,14 +37,7 @@ public bool Contains(IncludeCondition item) => _dictionary.ContainsKey(item); public int IndexOf(IncludeCondition item) - { - if (_dictionary.TryGetValue(item, out var index)) - { - return index; - } - - return -1; - } + => _dictionary.GetValueOrDefault(item, -1); public void CopyTo(IncludeCondition[] array, int arrayIndex) => _dictionary.Keys.CopyTo(array, arrayIndex); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/SelectionSet.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/SelectionSet.cs index 01a4d0a8b48..2ab53071b58 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/SelectionSet.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/SelectionSet.cs @@ -5,6 +5,11 @@ namespace HotChocolate.Fusion.Execution.Nodes; +/// +/// A selection set is primarily composed of field selections. +/// When needed a selection set can preserve fragments so that the execution engine +/// can branch the processing of these fragments. +/// public sealed class SelectionSet : ISelectionSet { private readonly Selection[] _selections; @@ -44,6 +49,13 @@ public SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, /// public IObjectTypeDefinition Type { get; } + /// + /// Gets the declaring operation. + /// + public Operation DeclaringOperation { get; private set; } = null!; + + IOperation ISelectionSet.DeclaringOperation => DeclaringOperation; + /// /// Gets the selections that shall be executed. /// @@ -81,13 +93,6 @@ public bool TryGetSelection(string responseName, [NotNullWhen(true)] out Selecti public bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out Selection? selection) => _utf8ResponseNameLookup.TryGetSelection(utf8ResponseName, out selection); - /// - /// Gets the declaring operation. - /// - public Operation DeclaringOperation { get; private set; } = null!; - - IOperation ISelectionSet.DeclaringOperation => DeclaringOperation; - internal void Seal(Operation operation) { if (_isSealed) From 95ae2c6224fe7496fbf58c9e02366dd5107776a7 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 28 Nov 2025 11:46:47 +0100 Subject: [PATCH 10/42] wip --- .../ISelection.cs | 2 +- .../DeferredWorkStateOwnerFactory.cs | 39 ------------------- .../InternalServiceCollectionExtensions.cs | 27 ------------- .../Processing/DeferredWorkStateOwner.cs | 25 ------------ .../Processing/MiddlewareContext.Selection.cs | 12 ++---- .../Processing/OperationContext.Operation.cs | 4 +- .../src/Types/Resolvers/IResolverContext.cs | 16 ++++---- .../Types/Resolvers/ISelectionCollection.cs | 6 +-- .../src/Types/Text/Json/ResultDocument.cs | 3 +- .../Core/src/Types/Text/Json/ResultElement.cs | 6 +-- .../src/Types/Text/Json/ResultProperty.cs | 4 +- 11 files changed, 25 insertions(+), 119 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs diff --git a/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelection.cs b/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelection.cs index 40d92b1dd1e..5de00d5bd0b 100644 --- a/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelection.cs +++ b/src/HotChocolate/Core/src/Execution.Operation.Abstractions/ISelection.cs @@ -96,7 +96,7 @@ public interface ISelection /// Gets the original syntax nodes that contributed to this selection. /// /// - /// An enumerable of field nodes from the original GraphQL document that + /// An enumerable collection of field nodes from the original GraphQL document that /// were merged to create this selection. Multiple nodes may be returned /// if field merging occurred (same response name, compatible arguments). /// diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs deleted file mode 100644 index 0e75c785bae..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/DeferredWorkStateOwnerFactory.cs +++ /dev/null @@ -1,39 +0,0 @@ -using HotChocolate.Execution.DependencyInjection; -using HotChocolate.Execution.Processing; -using Microsoft.Extensions.ObjectPool; - -namespace Microsoft.Extensions.DependencyInjection; - -/// -/// The deferred is injected as a scoped services and -/// preserves the instance it creates. -/// -/// This is done so that the executions running on one service scope share the deferred execution -/// state between each other. -/// -/// is disposable and will be disposed with the request scope. -/// -internal sealed class DeferredWorkStateOwnerFactory : IFactory -{ - private readonly object _sync = new(); - private readonly ObjectPool _pool; - private DeferredWorkStateOwner? _owner; - - public DeferredWorkStateOwnerFactory(ObjectPool pool) - { - _pool = pool; - } - - public DeferredWorkStateOwner Create() - { - if (_owner is null) - { - lock (_sync) - { - _owner ??= new DeferredWorkStateOwner(_pool); - } - } - - return _owner; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs index 62551e42713..6a1afa07ec7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs @@ -97,22 +97,6 @@ internal static IServiceCollection TryAddOperationContextPool( return services; } - internal static IServiceCollection TryAddDeferredWorkStatePool( - this IServiceCollection services) - { - services.TryAddSingleton( - sp => - { - var provider = sp.GetRequiredService(); - var policy = new DeferredWorkStatePooledObjectPolicy(); - return provider.Create(policy); - }); - - services.TryAddScoped, DeferredWorkStateOwnerFactory>(); - - return services; - } - internal static IServiceCollection TryAddTypeConverter( this IServiceCollection services) { @@ -233,15 +217,4 @@ public override bool Return(OperationContext obj) return false; } } - - private sealed class DeferredWorkStatePooledObjectPolicy : PooledObjectPolicy - { - public override DeferredWorkState Create() => new(); - - public override bool Return(DeferredWorkState obj) - { - obj.Reset(); - return true; - } - } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs deleted file mode 100644 index 4e9b95ed54d..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/DeferredWorkStateOwner.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.Extensions.ObjectPool; - -namespace HotChocolate.Execution.Processing; - -internal sealed class DeferredWorkStateOwner : IDisposable -{ - private readonly ObjectPool _pool; - private int _disposed; - - public DeferredWorkStateOwner(ObjectPool pool) - { - _pool = pool ?? throw new ArgumentNullException(nameof(pool)); - State = pool.Get(); - } - - public DeferredWorkState State { get; } - - public void Dispose() - { - if (_disposed == 0 && Interlocked.CompareExchange(ref _disposed, 1, 0) == 0) - { - _pool.Return(State); - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 96099d85405..8bf018d95db 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -8,7 +8,7 @@ namespace HotChocolate.Execution.Processing; internal partial class MiddlewareContext { private readonly PureResolverContext _childContext; - private ISelection _selection = null!; + private Selection _selection = null!; public ObjectType ObjectType => _selection.DeclaringType; @@ -43,14 +43,14 @@ public bool TryCreatePureContext( public IReadOnlyList GetSelections( ObjectType typeContext, - ISelection? selection = null, + Selection? selection = null, bool allowInternals = false) { ArgumentNullException.ThrowIfNull(typeContext); selection ??= _selection; - if (selection.SelectionSet is null) + if (selection.IsLeaf) { return []; } @@ -60,14 +60,10 @@ public IReadOnlyList GetSelections( if (selectionSet.IsConditional) { var operationIncludeFlags = _operationContext.IncludeFlags; - var selectionCount = selectionSet.Selections.Count; - ref var selectionRef = ref ((SelectionSet)selectionSet).GetSelectionsReference(); var finalFields = new List(); - for (var i = 0; i < selectionCount; i++) + foreach (var childSelection in selectionSet.Selections) { - var childSelection = Unsafe.Add(ref selectionRef, i); - if (childSelection.IsIncluded(operationIncludeFlags, allowInternals)) { finalFields.Add(childSelection); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs index 0005bf324d2..8921485ebd5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs @@ -20,7 +20,7 @@ public Schema Schema /// /// Gets the operation that is being executed. /// - public IOperation Operation + public Operation Operation { get { @@ -70,7 +70,7 @@ public object? RootValue /// The type context. /// /// - public ISelectionSet CollectFields(ISelection selection, ObjectType typeContext) + public SelectionSet CollectFields(Selection selection, ObjectType typeContext) { AssertInitialized(); return Operation.GetSelectionSet(selection, typeContext); diff --git a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs index f3cdd188068..207af448055 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs @@ -26,13 +26,13 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// /// Gets the operation from the query that is being executed. /// - IOperation Operation { get; } + Operation Operation { get; } /// /// Gets the field selection for which a field resolver is /// being executed. /// - ISelection Selection { get; } + Selection Selection { get; } /// /// Gets access to the coerced variable values of the request. @@ -48,7 +48,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// Gets the previous (parent) resolver result. /// /// - /// The type to which the result shall be casted. + /// The type to which the result shall be cast. /// /// /// Returns the previous (parent) resolver result. @@ -62,7 +62,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// The argument name. /// /// - /// The type to which the argument shall be casted to. + /// The type to which the argument shall be cast to. /// /// /// Returns the value of the specified field argument as literal. @@ -76,7 +76,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// The argument name. /// /// - /// The type to which the argument shall be casted to. + /// The type to which the argument shall be cast to. /// /// /// Returns the value of the specified field argument as literal. @@ -90,7 +90,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// The argument name. /// /// - /// The type to which the argument shall be casted to. + /// The type to which the argument shall be cast to. /// /// /// Returns the value of the specified field argument as optional. @@ -182,7 +182,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// /// Notifies when the connection underlying this request is aborted - /// and thus request operations should be cancelled. + /// and thus request operations should be canceled. /// CancellationToken RequestAborted { get; } @@ -249,7 +249,7 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// Returns the pre-compiled selections for the /// with the specified . /// - IReadOnlyList GetSelections( + IReadOnlyList GetSelections( ObjectType typeContext, ISelection? selection = null, bool allowInternals = false); diff --git a/src/HotChocolate/Core/src/Types/Resolvers/ISelectionCollection.cs b/src/HotChocolate/Core/src/Types/Resolvers/ISelectionCollection.cs index 569871e746b..27de07f4665 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/ISelectionCollection.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/ISelectionCollection.cs @@ -1,4 +1,4 @@ -using HotChocolate.Execution.Processing; +using HotChocolate.Execution; using HotChocolate.Types; namespace HotChocolate.Resolvers; @@ -37,14 +37,14 @@ public interface ISelectionCollection : IReadOnlyList ISelectionCollection Select(ReadOnlySpan fieldNames); /// - /// Selects all selections where the typeContext is assignable from the field`s declaring type. + /// Selects all selections where the typeContext is assignable from the field's declaring type. /// /// /// The type context to select. /// /// /// Returns a containing - /// the selections where the typeContext is assignable from the field`s declaring type. + /// the selections where the typeContext is assignable from the field's declaring type. /// ISelectionCollection Select(ITypeDefinition typeContext); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index 780e99ee305..da69ffbf89d 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using System.Text; using HotChocolate.Buffers; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Types; @@ -447,7 +448,7 @@ private ReadOnlySpan ReadLocalData(int location, int size) + "Use WriteLocalDataTo for writing to an IBufferWriter instead."); } - internal ResultElement CreateObject(Cursor parent, ISelectionSet selectionSet) + internal ResultElement CreateObject(Cursor parent, SelectionSet selectionSet) { var startObjectCursor = WriteStartObject(parent, selectionSet.Id); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs index 5b363b8bb8a..1cf8c384bb6 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -76,7 +76,7 @@ public ResultElement this[int index] /// /// Gets the operation this element belongs to. /// - public IOperation Operation + public Operation Operation { get { @@ -90,7 +90,7 @@ public IOperation Operation /// Gets the if this element represents the data of a selection set; /// otherwise, null. /// - public ISelectionSet? SelectionSet + public SelectionSet? SelectionSet { get { @@ -104,7 +104,7 @@ public ISelectionSet? SelectionSet /// Gets the if this element represents the data of a field selection; /// otherwise, null. /// - public ISelection? Selection + public Selection? Selection { get { diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs index 695bc20aa08..b76011d25ca 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs @@ -26,9 +26,9 @@ internal ResultProperty(ResultElement value) /// public string Name => Value.GetPropertyName(); - public ISelection? Selection => Value.Selection; + public Selection? Selection => Value.Selection; - public ISelection AssertSelection() => Value.AssertSelection(); + public Selection AssertSelection() => Value.AssertSelection(); /// /// Compares to the name of this property. From 4630aba9d17fb97b47ff55615f08fa33566c8c8b Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 28 Nov 2025 14:07:12 +0100 Subject: [PATCH 11/42] wip --- ...fsetPaginationResolverContextExtensions.cs | 15 ++- .../Processing/MiddlewareContext.Arguments.cs | 26 ++--- .../Processing/MiddlewareContext.Global.cs | 24 +++-- .../Processing/MiddlewareContext.Pooling.cs | 2 +- .../Processing/MiddlewareContext.Pure.cs | 36 ++++--- .../Processing/MiddlewareContext.Selection.cs | 27 +----- .../OperationCompiler.CompileResolver.cs | 97 +++++++++++++++++++ .../Execution/Processing/OperationCompiler.cs | 15 ++- .../Processing/OperationContext.Execution.cs | 13 --- .../Types/Execution/Processing/Selection.cs | 5 +- .../_OperationCompiler.ArgumentValues.cs | 2 +- ... => _OperationCompiler.CompilerContext.cs} | 0 .../Core/src/Types/HotChocolate.Types.csproj | 28 ++++++ .../src/Types/Resolvers/IMiddlewareContext.cs | 2 +- .../src/Types/Resolvers/IResolverContext.cs | 4 +- .../Types/Resolvers/SelectionEnumerator.cs | 77 +++++++++++++++ .../Core/src/Types/Text/Json/ResultElement.cs | 4 +- .../src/Types/Text/Json/ResultProperty.cs | 2 +- .../src/Types/Types/Relay/NodeTypeFeature.cs | 6 +- 19 files changed, 295 insertions(+), 90 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs rename src/HotChocolate/Core/src/Types/Execution/Processing/{OperationCompiler.CompilerContext.cs => _OperationCompiler.CompilerContext.cs} (100%) create mode 100644 src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs diff --git a/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs index e29fbba5915..63f5829a6a9 100644 --- a/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs @@ -6,10 +6,11 @@ namespace HotChocolate.Types.Pagination; internal static class OffsetPaginationResolverContextExtensions { /// + /// /// TotalCount is one of the heaviest operations. It is only necessary to load totalCount /// when it is enabled (IncludeTotalCount) and when it is contained in the selection set. - /// - /// This method checks if the total count is selected + /// + /// This method checks if the total count is selected /// /// /// @@ -17,10 +18,14 @@ public static bool IsTotalCountSelected(this IResolverContext context) { // TotalCount is one of the heaviest operations. It is only necessary to load totalCount // when it is enabled (IncludeTotalCount) and when it is contained in the selection set. - if (context.Selection.Type is ObjectType objectType - && context.Selection.SyntaxNode.SelectionSet is not null) + if (context.Selection is { Type: ObjectType objectType, IsLeaf: false }) { - var selections = context.GetSelections(objectType, null, true); + var selectionSet = context.Selection.DeclaringOperation.GetSelectionSet(context.Selection, objectType); + + foreach (var selection in selectionSet.Selections) + { )) + + } for (var i = 0; i < selections.Count; i++) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs index 92e99932d2b..e69ab937ba7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs @@ -17,7 +17,7 @@ public T ArgumentValue(string name) if (!Arguments.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } try @@ -40,7 +40,7 @@ public Optional ArgumentOptional(string name) if (!Arguments.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } return argument.IsDefaultValue @@ -54,7 +54,7 @@ public TValueNode ArgumentLiteral(string name) where TValueNode : IV if (!Arguments.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } var literal = argument.ValueLiteral!; @@ -65,7 +65,11 @@ public TValueNode ArgumentLiteral(string name) where TValueNode : IV } throw ResolverContext_LiteralNotCompatible( - _selection.SyntaxNode, Path, name, typeof(TValueNode), literal.GetType()); + _selection.SyntaxNodes[0].Node, + Path, + name, + typeof(TValueNode), + literal.GetType()); } public ValueKind ArgumentKind(string name) @@ -74,10 +78,10 @@ public ValueKind ArgumentKind(string name) if (!Arguments.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } - // There can only be no kind if there was an error which would have + // There can only be no kind of there was an error which would have // already been raised at this point. return argument.Kind ?? ValueKind.Unknown; } @@ -114,7 +118,7 @@ private T CoerceArgumentValue(ArgumentValue argument) if (typeof(IValueNode).IsAssignableFrom(typeof(T))) { throw ResolverContext_LiteralsNotSupported( - _selection.SyntaxNode, + _selection.SyntaxNodes[0].Node, Path, argument.Name, typeof(T)); @@ -122,7 +126,7 @@ private T CoerceArgumentValue(ArgumentValue argument) // we are unable to convert the argument to the request type. throw ResolverContext_CannotConvertArgument( - _selection.SyntaxNode, + _selection.SyntaxNodes[0].Node, Path, argument.Name, typeof(T), @@ -173,16 +177,14 @@ public ArgumentValue ReplaceArgument(string argumentName, ArgumentValue newArgum Arguments = mutableArguments; } - if (!mutableArguments.TryGetValue(argumentName, out var argumentValue)) + // we remove the original argument name ... + if (!mutableArguments.Remove(argumentName, out var argumentValue)) { throw new ArgumentException( string.Format(MiddlewareContext_ReplaceArgument_InvalidKey, argumentName), nameof(argumentName)); } - // we remove the original argument name ... - mutableArguments.Remove(argumentName); - // and allow the argument to be replaces with a new argument that could also have // a new name. mutableArguments.Add(newArgumentValue.Name, newArgumentValue); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs index 4b665e1c6fe..9211f4d4c0e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs @@ -2,7 +2,6 @@ using HotChocolate.Language; using HotChocolate.Resolvers; using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; namespace HotChocolate.Execution.Processing; @@ -26,7 +25,7 @@ public IServiceProvider Services public Schema Schema => _operationContext.Schema; - public IOperation Operation => _operationContext.Operation; + public Operation Operation => _operationContext.Operation; public IOperationResultBuilder OperationResult => _operationResultBuilder; @@ -48,7 +47,7 @@ public void ReportError(string errorMessage) ErrorBuilder.New() .SetMessage(errorMessage) .SetPath(Path) - .AddLocation(_selection.SyntaxNode) + .AddLocations(_selection) .Build()); } @@ -75,7 +74,7 @@ public void ReportError(Exception exception, Action? configure = n var errorBuilder = ErrorBuilder .FromException(exception) .SetPath(Path) - .AddLocation(_selection.SyntaxNode); + .AddLocations(_selection); configure?.Invoke(errorBuilder); @@ -108,14 +107,14 @@ void ReportSingle(IError singleError) { foreach (var ie in ar.Errors) { - var errorWithPath = EnsurePathAndLocation(ie, _selection.SyntaxNode, Path); + var errorWithPath = EnsurePathAndLocation(ie, _selection.SyntaxNodes[0].Node, Path); _operationContext.Result.AddError(errorWithPath, _selection); diagnosticEvents.ResolverError(this, errorWithPath); } } else { - var errorWithPath = EnsurePathAndLocation(handled, _selection.SyntaxNode, Path); + var errorWithPath = EnsurePathAndLocation(handled, _selection.SyntaxNodes[0].Node, Path); _operationContext.Result.AddError(errorWithPath, _selection); diagnosticEvents.ResolverError(this, errorWithPath); } @@ -290,3 +289,16 @@ c is null s))); } } + +file static class Extensions +{ + public static ErrorBuilder AddLocations(this ErrorBuilder errorBuilder, Selection selection) + { + foreach (var (node, _) in selection.SyntaxNodes) + { + errorBuilder.AddLocation(node); + } + + return errorBuilder; + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs index 6f29541152f..73d88af6347 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs @@ -18,7 +18,7 @@ public MiddlewareContext() public void Initialize( OperationContext operationContext, - ISelection selection, + Selection selection, ObjectResult parentResult, int responseIndex, object? parent, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs index c8e21be1f27..20c1d467e6f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs @@ -5,7 +5,6 @@ using HotChocolate.Resolvers; using HotChocolate.Types; using HotChocolate.Utilities; -using Microsoft.Extensions.DependencyInjection; using static HotChocolate.Execution.ThrowHelper; namespace HotChocolate.Execution.Processing; @@ -16,13 +15,13 @@ private sealed class PureResolverContext(MiddlewareContext parentContext) : IRes { private ITypeConverter? _typeConverter; private IReadOnlyDictionary _argumentValues = null!; - private ISelection _selection = null!; + private Selection _selection = null!; private ObjectType _parentType = null!; private ObjectResult _parentResult = null!; private object? _parent; public bool Initialize( - ISelection selection, + Selection selection, ObjectType parentType, ObjectResult parentResult, object? parent) @@ -60,9 +59,9 @@ public void Clear() public ObjectType ObjectType => _parentType; - public IOperation Operation => parentContext.Operation; + public Operation Operation => parentContext.Operation; - public ISelection Selection => _selection; + public Selection Selection => _selection; public Path Path => PathHelper.CreatePathFromContext(_selection, _parentResult, -1); @@ -77,9 +76,9 @@ public void ReportError(IError error) public void ReportError(Exception exception, Action? configure = null) => throw new NotSupportedException(); - public IReadOnlyList GetSelections( + public SelectionEnumerator GetSelections( ObjectType typeContext, - ISelection? selection = null, + Selection? selection = null, bool allowInternals = false) => throw new NotSupportedException(); @@ -135,7 +134,7 @@ public T ArgumentValue(string name) if (!_argumentValues.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } return CoerceArgumentValue(argument); @@ -148,7 +147,7 @@ public TValueNode ArgumentLiteral(string name) if (!_argumentValues.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } var literal = argument.ValueLiteral!; @@ -159,7 +158,11 @@ public TValueNode ArgumentLiteral(string name) } throw ResolverContext_LiteralNotCompatible( - _selection.SyntaxNode, Path, name, typeof(TValueNode), literal.GetType()); + _selection.SyntaxNodes[0].Node, + Path, + name, + typeof(TValueNode), + literal.GetType()); } public Optional ArgumentOptional(string name) @@ -168,7 +171,7 @@ public Optional ArgumentOptional(string name) if (!_argumentValues.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } return argument.IsDefaultValue @@ -180,10 +183,10 @@ public ValueKind ArgumentKind(string name) { if (!_argumentValues.TryGetValue(name, out var argument)) { - throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNode, Path, name); + throw ResolverContext_ArgumentDoesNotExist(_selection.SyntaxNodes[0].Node, Path, name); } - // There can only be no kind if there was an error which would have + // There can only be no kind of there was an error which would have // already been raised at this point. return argument.Kind ?? ValueKind.Unknown; } @@ -243,7 +246,10 @@ private T CoerceArgumentValue(ArgumentValue argument) if (typeof(IValueNode).IsAssignableFrom(typeof(T))) { throw ResolverContext_LiteralsNotSupported( - _selection.SyntaxNode, Path, argument.Name, typeof(T)); + _selection.SyntaxNodes[0].Node, + Path, + argument.Name, + typeof(T)); } // If the object is internally held as a dictionary structure we will try to @@ -270,7 +276,7 @@ private T CoerceArgumentValue(ArgumentValue argument) // we are unable to convert the argument to the request type. throw ResolverContext_CannotConvertArgument( - _selection.SyntaxNode, + _selection.SyntaxNodes[0].Node, Path, argument.Name, typeof(T), diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 8bf018d95db..660e99ded09 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -14,7 +14,7 @@ internal partial class MiddlewareContext public ObjectField Field => _selection.Field; - public ISelection Selection => _selection; + public Selection Selection => _selection; public string ResponseName => _selection.ResponseName; @@ -25,7 +25,7 @@ internal partial class MiddlewareContext public PureFieldDelegate? PureResolver => _selection.PureResolver; public bool TryCreatePureContext( - ISelection selection, + Selection selection, ObjectType parentType, ObjectResult parentResult, object? parent, @@ -41,7 +41,7 @@ public bool TryCreatePureContext( return false; } - public IReadOnlyList GetSelections( + public SelectionEnumerator GetSelections( ObjectType typeContext, Selection? selection = null, bool allowInternals = false) @@ -52,28 +52,11 @@ public IReadOnlyList GetSelections( if (selection.IsLeaf) { - return []; + return default; } var selectionSet = _operationContext.CollectFields(selection, typeContext); - - if (selectionSet.IsConditional) - { - var operationIncludeFlags = _operationContext.IncludeFlags; - var finalFields = new List(); - - foreach (var childSelection in selectionSet.Selections) - { - if (childSelection.IsIncluded(operationIncludeFlags, allowInternals)) - { - finalFields.Add(childSelection); - } - } - - return finalFields; - } - - return selectionSet.Selections; + return new SelectionEnumerator(selectionSet, _operationContext.IncludeFlags); } public ISelectionCollection Select() diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs new file mode 100644 index 00000000000..d5b73c6b40a --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs @@ -0,0 +1,97 @@ +using HotChocolate.Language; +using HotChocolate.Resolvers; +using HotChocolate.Types; + +namespace HotChocolate.Execution.Processing; + +internal sealed partial class OperationCompiler2 +{ + internal static FieldDelegate CreateFieldPipeline(Schema schema, ObjectField field, FieldNode selection) + { + var pipeline = field.Middleware; + + if (selection.Directives.Count == 0) + { + return pipeline; + } + + var pipelineComponents = new List(); + + // if we have selection directives we will inspect them and try to build a + // pipeline from them if they have middleware components. + BuildDirectivePipeline(schema, selection, pipelineComponents); + + // if we found middleware components on the selection directives we will build a new + // pipeline. + if (pipelineComponents.Count > 0) + { + var next = pipeline; + + for (var i = pipelineComponents.Count - 1; i >= 0; i--) + { + next = pipelineComponents[i](next); + } + + pipeline = next; + } + + return pipeline; + } + + private static PureFieldDelegate? TryCreatePureField( + Schema schema, + ObjectField field, + FieldNode selection) + { + if (field.PureResolver is not null && selection.Directives.Count == 0) + { + return field.PureResolver; + } + + for (var i = 0; i < selection.Directives.Count; i++) + { + if (schema.DirectiveTypes.TryGetDirective(selection.Directives[i].Name.Value, out var type) + && type.Middleware is not null) + { + return null; + } + } + + return field.PureResolver; + } + + // TODO : this needs a rewrite, we need to discuss how we handle field merging with directives + private static void BuildDirectivePipeline( + Schema schema, + FieldNode selection, + List pipelineComponents) + { + for (var i = 0; i < selection.Directives.Count; i++) + { + var directiveNode = selection.Directives[i]; + if (schema.DirectiveTypes.TryGetDirective(directiveNode.Name.Value, out var directiveType) + && directiveType.Middleware is not null) + { + Directive directive; + try + { + directive = new Directive( + directiveType, + directiveNode, + directiveType.Parse(directiveNode)); + } + catch (SerializationException ex) + { + throw new SerializationException( + ErrorBuilder.FromError(ex.Errors[0]) + .TryAddLocation(directiveNode) + .Build(), + ex.Type); + } + + var directiveMiddleware = directiveType.Middleware; + pipelineComponents.Add(next => directiveMiddleware(next, directive)); + } + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 0984e29625a..211d81d9e7d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -241,6 +241,14 @@ private SelectionSet BuildSelectionSet( } var field = typeContext.Fields[first.Node.Name.Value]; + var fieldDelegate = CreateFieldPipeline(_schema, field, first.Node); + var pureFieldDelegate = TryCreatePureField(_schema, field, first.Node); + var arguments = ArgumentMap.Empty; + + if (first.Node.Arguments.Count > 0) + { + arguments = CoerceArgumentValues(field, first.Node); + } var selection = new Selection( ++lastId, @@ -248,7 +256,10 @@ private SelectionSet BuildSelectionSet( field, nodes.ToArray(), includeFlags.ToArray(), - isInternal); + isInternal, + arguments, + fieldDelegate, + pureFieldDelegate); // Register the selection in the elements array compilationContext.Register(selection, selection.Id); @@ -435,7 +446,7 @@ public void Register(object element, int id) /// /// The flags that must be all set for this selection to be included. /// -internal sealed record FieldSelectionNode(FieldNode Node, ulong PathIncludeFlags); +public sealed record FieldSelectionNode(FieldNode Node, ulong PathIncludeFlags); internal class IncludeConditionCollection : ICollection { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs index 862fb41a59a..6e74fb6e5ea 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs @@ -21,19 +21,6 @@ internal set } } - /// - /// Gets the backlog of the task that shall be processed after - /// all the main tasks have been executed. - /// - public DeferredWorkScheduler DeferredScheduler - { - get - { - AssertInitialized(); - return _deferredWorkScheduler; - } - } - /// /// The result helper which provides utilities to build up the result. /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index 26be9ca9c7f..1d44a51e445 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -28,7 +28,6 @@ internal Selection( ulong[] includeFlags, bool isInternal, ArgumentMap? arguments = null, - bool isParallelExecutable = true, FieldDelegate? resolverPipeline = null, PureFieldDelegate? pureResolver = null) { @@ -48,7 +47,7 @@ internal Selection( ResolverPipeline = resolverPipeline; PureResolver = pureResolver; Strategy = InferStrategy( - isSerial: !isParallelExecutable, + isSerial: !field.IsParallelExecutable, hasPureResolver: pureResolver is not null); _syntaxNodes = syntaxNodes; _includeFlags = includeFlags; @@ -106,7 +105,7 @@ internal Selection( public PureFieldDelegate? PureResolver { get; private set; } - internal ReadOnlySpan SyntaxNodes => _syntaxNodes; + public ReadOnlySpan SyntaxNodes => _syntaxNodes; IEnumerable ISelection.GetSyntaxNodes() { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs index c867fbb89d8..b614190999a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs @@ -149,7 +149,7 @@ internal static FieldDelegate CreateFieldPipeline( pipeline = next; } - // at last we clear the rented lists + // at last, we clear the rented lists processed.Clear(); pipelineComponents.Clear(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompilerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs similarity index 100% rename from src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompilerContext.cs rename to src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 2729033aa3b..08a474f7f21 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -143,6 +143,34 @@ True TextJsonResources.resx + + + MiddlewareContext.Global.cs + + + + MiddlewareContext.Global.cs + + + + MiddlewareContext.Global.cs + + + + MiddlewareContext.Global.cs + + + + MiddlewareContext.Global.cs + + + + OperationCompiler.cs + + + + OperationCompiler.cs + diff --git a/src/HotChocolate/Core/src/Types/Resolvers/IMiddlewareContext.cs b/src/HotChocolate/Core/src/Types/Resolvers/IMiddlewareContext.cs index 0c79f8c852f..3ad1043b3b4 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/IMiddlewareContext.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/IMiddlewareContext.cs @@ -33,7 +33,7 @@ public interface IMiddlewareContext : IResolverContext /// Executes the field resolver and returns its result. /// /// - /// The type to which the result shall be casted. + /// The type to which the result shall be cast. /// /// /// Returns the resolved field value. diff --git a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs index 207af448055..5eef2e5429d 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs @@ -249,9 +249,9 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// Returns the pre-compiled selections for the /// with the specified . /// - IReadOnlyList GetSelections( + SelectionEnumerator GetSelections( ObjectType typeContext, - ISelection? selection = null, + Selection? selection = null, bool allowInternals = false); /// diff --git a/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs b/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs new file mode 100644 index 00000000000..aed4577252b --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs @@ -0,0 +1,77 @@ +using System.Collections; +using HotChocolate.Execution.Processing; + +namespace HotChocolate.Resolvers; + +/// +/// An SelectionSet enumerator. +/// +public struct SelectionEnumerator : IEnumerable, IEnumerator +{ + private readonly SelectionSet _selectionSet; + private readonly ulong _includeFlags; + private int _position = -1; + + internal SelectionEnumerator(SelectionSet selectionSet, ulong includeFlags) + { + _selectionSet = selectionSet; + _includeFlags = includeFlags; + Current = null!; + } + + /// + /// The currently selected selection. + /// + public Selection Current { get; private set; } + + object? IEnumerator.Current => Current; + + /// + /// Moves to the next visible selection. + /// + /// + /// true if there is another visible selection. + /// + public bool MoveNext() + { + if (_selectionSet is null) + { + return false; + } + + var length = _selectionSet.Selections.Length; + + while (_position < length) + { + _position++; + + if (_position >= length) + { + break; + } + + var selection = _selectionSet.Selections[_position]; + if (selection.IsIncluded(_includeFlags)) + { + Current = selection; + return true; + } + } + + Current = null!; + return false; + } + + public void Reset() + { + _position = -1; + } + + public SelectionEnumerator GetEnumerator() => this; + + IEnumerator IEnumerable.GetEnumerator() => this; + + IEnumerator IEnumerable.GetEnumerator() => this; + + public void Dispose() { } +} diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs index 1cf8c384bb6..de454de6cd1 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -247,7 +247,7 @@ public bool IsInternal /// /// This element does not represent the data of a selection set. /// - public ISelectionSet AssertSelectionSet() + public SelectionSet AssertSelectionSet() { var selectionSet = SelectionSet; @@ -268,7 +268,7 @@ public ISelectionSet AssertSelectionSet() /// /// This element does not represent the data of a field selection. /// - public ISelection AssertSelection() + public Selection AssertSelection() { var selection = Selection; diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs index b76011d25ca..06e15a446d4 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultProperty.cs @@ -115,7 +115,7 @@ public override string ToString() private string DebuggerDisplay => Value.ValueKind == JsonValueKind.Undefined ? "" : $"\"{ToString()}\""; - public void Deconstruct(out ISelection selection, out ResultElement value) + public void Deconstruct(out Selection selection, out ResultElement value) { selection = AssertSelection(); value = Value; diff --git a/src/HotChocolate/Core/src/Types/Types/Relay/NodeTypeFeature.cs b/src/HotChocolate/Core/src/Types/Types/Relay/NodeTypeFeature.cs index 9106c0b2bfe..d1616dd5694 100644 --- a/src/HotChocolate/Core/src/Types/Types/Relay/NodeTypeFeature.cs +++ b/src/HotChocolate/Core/src/Types/Types/Relay/NodeTypeFeature.cs @@ -4,11 +4,9 @@ namespace HotChocolate.Types.Relay; internal sealed class NodeTypeFeature : ISealable { - private NodeResolverInfo? _nodeResolver; - public NodeResolverInfo? NodeResolver { - get => _nodeResolver; + get; set { if (IsReadOnly) @@ -17,7 +15,7 @@ public NodeResolverInfo? NodeResolver "The node resolver cannot be set after the feature is sealed."); } - _nodeResolver = value; + field = value; } } From fe8a8e63a4c0ed6c2b6c4347cc294a659b69b297 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 1 Dec 2025 09:16:15 +0100 Subject: [PATCH 12/42] wip --- .../Internal/ArgumentCoercionHelper.cs | 4 +- .../Internal/FieldMapPooledObjectPolicy.cs | 21 + .../Pipeline/OperationResolverMiddleware.cs | 89 +- .../Types/Execution/Processing/ArgumentMap.cs | 2 +- .../Types/Execution/Processing/Operation.cs | 4 +- .../OperationCompiler.BacklogItem.cs | 25 - .../OperationCompiler.CoerceArgumentValues.cs | 2 +- .../OperationCompiler.CompileResolver.cs | 2 +- .../OperationCompiler.Optimizers.cs | 62 -- .../OperationCompiler.SelectionSetInfo.cs | 15 - .../Execution/Processing/OperationCompiler.cs | 4 +- .../Processing/OperationCompilerOptimizers.cs | 54 +- .../Processing/OperationCompilerPool.cs | 31 - .../Processing/OperationContext.Pooling.cs | 12 +- .../_OperationCompiler.ArgumentValues.cs | 217 ----- .../_OperationCompiler.CompilerContext.cs | 46 - .../Processing/_OperationCompiler.cs | 787 ------------------ .../Types/Execution/RequestExecutorManager.cs | 16 + .../ObjectPoolProviderExtensions.cs | 15 + .../Extensions/ResolverContextExtensions.cs | 12 +- .../Core/src/Types/HotChocolate.Types.csproj | 24 + .../Pipeline/OperationPlanMiddleware.cs | 2 +- 22 files changed, 120 insertions(+), 1326 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Internal/FieldMapPooledObjectPolicy.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs create mode 100644 src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs diff --git a/src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs index d1ee668a617..17ff11f9ac3 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Internal/ArgumentCoercionHelper.cs @@ -41,7 +41,7 @@ public static bool TryCoerceArguments( // signal that this resolver task has errors and shall end. if (arguments.HasErrors) { - foreach (var argument in arguments) + foreach (var argument in arguments.ArgumentValues) { if (argument.HasError) { @@ -73,7 +73,7 @@ internal static void CoerceArguments( { // if there are arguments that have variables and need variable replacement we will // rewrite the arguments that need variable replacement. - foreach (var argument in arguments) + foreach (var argument in arguments.ArgumentValues) { if (argument.IsFullyCoerced) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Internal/FieldMapPooledObjectPolicy.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/FieldMapPooledObjectPolicy.cs new file mode 100644 index 00000000000..aca098df582 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Internal/FieldMapPooledObjectPolicy.cs @@ -0,0 +1,21 @@ +using HotChocolate.Execution.Processing; +using Microsoft.Extensions.ObjectPool; + +namespace HotChocolate.Execution; + +internal sealed class FieldMapPooledObjectPolicy + : DefaultPooledObjectPolicy>> +{ + public override OrderedDictionary> Create() => new(StringComparer.Ordinal); + + public override bool Return(OrderedDictionary> obj) + { + if (obj.Count > 256) + { + return false; + } + + obj.Clear(); + return base.Return(obj); + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs index 730872b3e4f..9c85a312c1d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs @@ -1,10 +1,6 @@ -using System.Runtime.CompilerServices; using HotChocolate.Execution.Instrumentation; using HotChocolate.Execution.Processing; -using HotChocolate.Language; -using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.ObjectPool; +using HotChocolate.Fusion.Rewriters; using static HotChocolate.Execution.ErrorHelper; namespace HotChocolate.Execution.Pipeline; @@ -12,24 +8,24 @@ namespace HotChocolate.Execution.Pipeline; internal sealed class OperationResolverMiddleware { private readonly RequestDelegate _next; - private readonly ObjectPool _operationCompilerPool; - private readonly OperationCompilerOptimizers _operationCompilerOptimizers; + private readonly OperationCompiler _operationPlanner; + private readonly DocumentRewriter _documentRewriter; private readonly IExecutionDiagnosticEvents _diagnosticEvents; private OperationResolverMiddleware( RequestDelegate next, - ObjectPool operationCompilerPool, - OperationCompilerOptimizers operationCompilerOptimizer, + ISchemaDefinition schema, + OperationCompiler operationPlanner, IExecutionDiagnosticEvents diagnosticEvents) { ArgumentNullException.ThrowIfNull(next); - ArgumentNullException.ThrowIfNull(operationCompilerPool); - ArgumentNullException.ThrowIfNull(operationCompilerOptimizer); + ArgumentNullException.ThrowIfNull(schema); + ArgumentNullException.ThrowIfNull(operationPlanner); ArgumentNullException.ThrowIfNull(diagnosticEvents); _next = next; - _operationCompilerPool = operationCompilerPool; - _operationCompilerOptimizers = operationCompilerOptimizer; + _operationPlanner = operationPlanner; + _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); _diagnosticEvents = diagnosticEvents; } @@ -46,21 +42,17 @@ public async ValueTask InvokeAsync(RequestContext context) { using (_diagnosticEvents.CompileOperation(context)) { - var operationDef = documentInfo.Document.GetOperation(context.Request.OperationName); - var operationType = ResolveOperationType(operationDef.Operation, Unsafe.As(context.Schema)); - - if (operationType is null) - { - context.Result = RootTypeNotFound(operationDef.Operation); - return; - } - - operation = CompileOperation( - documentInfo.Document, - operationDef, - operationType, + // Before we can plan an operation, we must de-fragmentize it and remove static include conditions. + var operationDocument = documentInfo.Document; + var operationName = context.Request.OperationName; + operationDocument = _documentRewriter.RewriteDocument(operationDocument, operationName); + var operationNode = operationDocument.GetOperation(operationName); + + // After optimizing the query structure we can begin the planning process. + operation = _operationPlanner.Compile( operationId ?? Guid.NewGuid().ToString("N"), - context.Schema); + documentInfo.Hash.Value, + operationNode); context.SetOperation(operation); } @@ -72,51 +64,18 @@ public async ValueTask InvokeAsync(RequestContext context) context.Result = StateInvalidForOperationResolver(); } - private IOperation CompileOperation( - DocumentNode document, - OperationDefinitionNode operationDefinition, - ObjectType operationType, - string operationId, - ISchemaDefinition schema) - { - var request = new OperationCompilerRequest( - operationId, - document, - operationDefinition, - operationType, - schema, - _operationCompilerOptimizers.OperationOptimizers, - _operationCompilerOptimizers.SelectionSetOptimizers); - - var compiler = _operationCompilerPool.Get(); - var operation = compiler.Compile(request); - _operationCompilerPool.Return(compiler); - - return operation; - } - - private static ObjectType? ResolveOperationType( - OperationType operationType, - Schema schema) - => operationType switch - { - OperationType.Query => schema.QueryType, - OperationType.Mutation => schema.MutationType, - OperationType.Subscription => schema.SubscriptionType, - _ => throw ThrowHelper.RootTypeNotSupported(operationType) - }; - public static RequestMiddlewareConfiguration Create() => new RequestMiddlewareConfiguration( (core, next) => { - var operationCompilerPool = core.Services.GetRequiredService>(); - var optimizers = core.SchemaServices.GetRequiredService(); + var schema = core.Schema; + var operationCompiler = core.Services.GetRequiredService(); var diagnosticEvents = core.SchemaServices.GetRequiredService(); + var middleware = new OperationResolverMiddleware( next, - operationCompilerPool, - optimizers, + schema, + operationCompiler, diagnosticEvents); return context => middleware.InvokeAsync(context); }, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs index 354e3bdfd73..118c9dbd800 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ArgumentMap.cs @@ -99,7 +99,7 @@ IEnumerable IReadOnlyDictionary.Keys /// /// An of instances. /// - public ImmutableArray Values => _arguments.Values; + public ImmutableArray ArgumentValues => _arguments.Values; IEnumerable IReadOnlyDictionary.Values => _arguments.Values; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 72c8ed60f88..216d6fd00cd 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -19,7 +19,7 @@ public sealed class Operation : IOperation #endif private readonly ConcurrentDictionary<(int, string), SelectionSet> _selectionSets = []; - private readonly OperationCompiler2 _compiler; + private readonly OperationCompiler _compiler; private readonly IncludeConditionCollection _includeConditions; private readonly OperationFeatureCollection _features; private readonly bool _isFinal; @@ -33,7 +33,7 @@ internal Operation( ObjectType rootType, Schema schema, SelectionSet rootSelectionSet, - OperationCompiler2 compiler, + OperationCompiler compiler, IncludeConditionCollection includeConditions, int lastId, object[] elementsById, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs deleted file mode 100644 index 3345a16fd42..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.BacklogItem.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -public sealed partial class OperationCompiler -{ - private readonly struct BacklogItem( - ObjectType type, - int selectionSetId, - Selection selection, - SelectionPath path, - ImmutableArray optimizers) - { - public ObjectType Type { get; } = type; - - public int SelectionSetId { get; } = selectionSetId; - - public Selection Selection { get; } = selection; - - public SelectionPath Path { get; } = path; - - public ImmutableArray Optimizers { get; } = optimizers; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs index 8f6068bbf80..f601fa279a6 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs @@ -10,7 +10,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler2 +internal sealed partial class OperationCompiler { private ArgumentMap? CoerceArgumentValues( ObjectField field, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs index d5b73c6b40a..372d52fd5b7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler2 +internal sealed partial class OperationCompiler { internal static FieldDelegate CreateFieldPipeline(Schema schema, ObjectField field, FieldNode selection) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs deleted file mode 100644 index 50b9d9e2ecf..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.Optimizers.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Types; -using static HotChocolate.Execution.Processing.OperationCompilerOptimizerHelper; - -namespace HotChocolate.Execution.Processing; - -public partial class OperationCompiler -{ - private void OptimizeSelectionSet(CompilerContext context) - { - if (context.Optimizers.Length == 0) - { - return; - } - - var optimizerContext = - new SelectionSetOptimizerContext( - this, - context, - _selectionLookup, - _contextData, - _createFieldPipeline, - context.Path); - - if (context.Optimizers.Length == 1) - { - context.Optimizers[0].OptimizeSelectionSet(optimizerContext); - } - else - { - for (var i = 0; i < context.Optimizers.Length; i++) - { - context.Optimizers[i].OptimizeSelectionSet(optimizerContext); - } - } - } - - private static ImmutableArray ResolveOptimizers( - ImmutableArray optimizers, - ObjectField field) - { - if (!TryGetOptimizers(field, out var fieldOptimizers)) - { - return optimizers; - } - - if (optimizers.IsEmpty) - { - return fieldOptimizers; - } - - foreach (var optimizer in fieldOptimizers) - { - if (!optimizers.Contains(optimizer)) - { - optimizers = optimizers.Add(optimizer); - } - } - - return optimizers; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs deleted file mode 100644 index 7c46db01ff7..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.SelectionSetInfo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using HotChocolate.Language; - -namespace HotChocolate.Execution.Processing; - -public sealed partial class OperationCompiler -{ - internal readonly struct SelectionSetInfo( - SelectionSetNode selectionSet, - ulong includeCondition) - { - public SelectionSetNode SelectionSet { get; } = selectionSet; - - public ulong IncludeCondition { get; } = includeCondition; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 211d81d9e7d..33caee22385 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler2 +internal sealed partial class OperationCompiler { private readonly Schema _schema; private readonly ObjectPool>> _fieldsPool; @@ -17,7 +17,7 @@ internal sealed partial class OperationCompiler2 private readonly InputParser _inputValueParser; private static readonly ArrayPool s_objectArrayPool = ArrayPool.Shared; - public OperationCompiler2( + public OperationCompiler( Schema schema, InputParser inputValueParser, ObjectPool>> fieldsPool) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs index 726018644dd..e60919fe435 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs @@ -4,6 +4,7 @@ namespace HotChocolate.Execution.Processing; +// TODO : We might remove this internal sealed class OperationCompilerOptimizers { private ImmutableArray _operationOptimizers; @@ -49,56 +50,3 @@ private enum PropertyInitFlags SelectionSetOptimizers = 2 } } - -public readonly struct OperationCompilerRequest -{ - public OperationCompilerRequest( - string id, - DocumentNode document, - OperationDefinitionNode definition, - ObjectType rootType, - ISchemaDefinition schema, - ImmutableArray? operationOptimizers = null, - ImmutableArray? selectionSetOptimizers = null) - { - ArgumentException.ThrowIfNullOrEmpty(id); - - Id = id; - Document = document ?? throw new ArgumentNullException(nameof(document)); - Definition = definition ?? throw new ArgumentNullException(nameof(definition)); - RootType = rootType ?? throw new ArgumentNullException(nameof(rootType)); - Schema = schema ?? throw new ArgumentNullException(nameof(schema)); - OperationOptimizers = operationOptimizers ?? []; - SelectionSetOptimizers = selectionSetOptimizers ?? []; - } - - /// - /// Gets the internal unique identifier for this operation. - /// - public string Id { get; } - - /// - /// Gets the parsed query document that contains the - /// operation-. - /// - public DocumentNode Document { get; } - - /// - /// Gets the syntax node representing the operation definition. - /// - public OperationDefinitionNode Definition { get; } - - /// - /// Gets the root type on which the operation is executed. - /// - public ObjectType RootType { get; } - - /// - /// Gets the schema against which the operation shall be executed. - /// - public ISchemaDefinition Schema { get; } - - public ImmutableArray OperationOptimizers { get; } - - public ImmutableArray SelectionSetOptimizers { get; } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs deleted file mode 100644 index d62a317d0cb..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerPool.cs +++ /dev/null @@ -1,31 +0,0 @@ -using HotChocolate.Types; -using Microsoft.Extensions.ObjectPool; - -namespace HotChocolate.Execution.Processing; - -internal sealed class OperationCompilerPool : DefaultObjectPool -{ - public OperationCompilerPool(InputParser inputParser) - : base(new Policy(inputParser)) - { - } - - public OperationCompilerPool(InputParser inputParser, int maximumRetained) - : base(new Policy(inputParser), maximumRetained) - { - } - - private sealed class Policy : IPooledObjectPolicy - { - private readonly InputParser _inputParser; - - public Policy(InputParser inputParser) - { - _inputParser = inputParser; - } - - public OperationCompiler Create() => new(_inputParser); - - public bool Return(OperationCompiler obj) => true; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs index d5e09ed7818..c396301d366 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs @@ -6,7 +6,6 @@ using HotChocolate.Resolvers; using HotChocolate.Types; using HotChocolate.Utilities; -using Microsoft.Extensions.DependencyInjection; using static HotChocolate.Execution.ThrowHelper; namespace HotChocolate.Execution.Processing; @@ -16,7 +15,6 @@ internal sealed partial class OperationContext private readonly IFactory _resolverTaskFactory; private readonly WorkScheduler _workScheduler; private WorkScheduler _currentWorkScheduler; - private readonly DeferredWorkScheduler _deferredWorkScheduler; private readonly ResultBuilder _resultBuilder; private readonly AggregateServiceScopeInitializer _serviceScopeInitializer; private RequestContext _requestContext = null!; @@ -26,7 +24,7 @@ internal sealed partial class OperationContext private IExecutionDiagnosticEvents _diagnosticEvents = null!; private IDictionary _contextData = null!; private CancellationToken _requestAborted; - private IOperation _operation = null!; + private Operation _operation = null!; private IVariableValueCollection _variables = null!; private IServiceProvider _services = null!; private Func _resolveQueryRootValue = null!; @@ -45,7 +43,6 @@ public OperationContext( _resolverTaskFactory = resolverTaskFactory; _workScheduler = new WorkScheduler(this); _currentWorkScheduler = _workScheduler; - _deferredWorkScheduler = new DeferredWorkScheduler(); _resultBuilder = resultBuilder; _serviceScopeInitializer = serviceScopeInitializer; Converter = typeConverter; @@ -59,7 +56,7 @@ public void Initialize( RequestContext requestContext, IServiceProvider scopedServices, IBatchDispatcher batchDispatcher, - IOperation operation, + Operation operation, IVariableValueCollection variables, object? rootValue, Func resolveQueryRootValue, @@ -82,9 +79,8 @@ public void Initialize( _variableIndex = variableIndex; _isInitialized = true; - IncludeFlags = _operation.CreateIncludeFlags(variables); + IncludeFlags = operation.CreateIncludeFlags(variables); _workScheduler.Initialize(batchDispatcher); - _deferredWorkScheduler.Initialize(this); _resultBuilder.Initialize(_requestContext, _diagnosticEvents); if (requestContext.RequestIndex != -1) @@ -120,7 +116,6 @@ public void InitializeFrom(OperationContext context) IncludeFlags = _operation.CreateIncludeFlags(_variables); _workScheduler.Initialize(_batchDispatcher); - _deferredWorkScheduler.InitializeFrom(this, context._deferredWorkScheduler); _resultBuilder.Initialize(_requestContext, _diagnosticEvents); if (context._requestContext.RequestIndex != -1) @@ -143,7 +138,6 @@ public void Clean() _currentWorkScheduler = _workScheduler; _workScheduler.Clear(); _resultBuilder.Clear(); - _deferredWorkScheduler.Clear(); _requestContext = null!; _schema = null!; _errorHandler = null!; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs deleted file mode 100644 index b614190999a..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.ArgumentValues.cs +++ /dev/null @@ -1,217 +0,0 @@ -using System.Diagnostics; -using HotChocolate.Language; -using HotChocolate.Resolvers; -using HotChocolate.Types; -using static System.StringComparer; - -namespace HotChocolate.Execution.Processing; - -public sealed partial class OperationCompiler -{ - private ArgumentMap? CoerceArgumentValues( - ObjectField field, - FieldNode selection) - { - if (field.Arguments.Count == 0) - { - return null; - } - - var arguments = new Dictionary(Ordinal); - - for (var i = 0; i < selection.Arguments.Count; i++) - { - var argumentValue = selection.Arguments[i]; - if (field.Arguments.TryGetField( - argumentValue.Name.Value, - out var argument)) - { - arguments[argument.Name] = CreateArgumentValue(argument, argumentValue, argumentValue.Value, false); - } - } - - for (var i = 0; i < field.Arguments.Count; i++) - { - var argument = field.Arguments[i]; - if (!arguments.ContainsKey(argument.Name)) - { - var value = argument.DefaultValue ?? NullValueNode.Default; - arguments[argument.Name] = CreateArgumentValue(argument, null, value, true); - } - } - - return new ArgumentMap(arguments); - } - - private ArgumentValue CreateArgumentValue( - Argument argument, - ArgumentNode? argumentValue, - IValueNode value, - bool isDefaultValue) - { - var validationResult = - ArgumentNonNullValidator.Validate( - argument, - value, - Path.Root.Append(argument.Name)); - - if (argumentValue is not null && validationResult.HasErrors) - { - return new ArgumentValue( - argument, - ErrorHelper.ArgumentNonNullError( - argumentValue, - validationResult)); - } - - if (argument.Type.IsLeafType() && CanBeCompiled(value)) - { - try - { - return new ArgumentValue( - argument, - value.GetValueKind(), - true, - isDefaultValue, - _parser.ParseLiteral(value, argument), - value); - } - catch (SerializationException ex) - { - return new ArgumentValue( - argument, - ErrorHelper.ArgumentValueIsInvalid(argumentValue, ex)); - } - } - - return new ArgumentValue( - argument, - value.GetValueKind(), - false, - isDefaultValue, - null, - value); - } - - private static bool CanBeCompiled(IValueNode valueLiteral) - { - switch (valueLiteral.Kind) - { - case SyntaxKind.Variable: - case SyntaxKind.ObjectValue: - return false; - - case SyntaxKind.ListValue: - var list = (ListValueNode)valueLiteral; - for (var i = 0; i < list.Items.Count; i++) - { - if (!CanBeCompiled(list.Items[i])) - { - return false; - } - } - break; - } - - return true; - } - - internal static FieldDelegate CreateFieldPipeline( - Schema schema, - ObjectField field, - FieldNode selection, - Path? path, - HashSet processed, - List pipelineComponents) - { - var pipeline = field.Middleware; - - if (selection.Directives.Count == 0) - { - return pipeline; - } - - // if we have selection directives we will inspect them and try to build a - // pipeline from them if they have middleware components. - BuildDirectivePipeline(schema, selection, path, processed, pipelineComponents); - - // if we found middleware components on the selection directives we will build a new - // pipeline. - if (pipelineComponents.Count > 0) - { - var next = pipeline; - - for (var i = pipelineComponents.Count - 1; i >= 0; i--) - { - next = pipelineComponents[i](next); - } - - pipeline = next; - } - - // at last, we clear the rented lists - processed.Clear(); - pipelineComponents.Clear(); - - return pipeline; - } - - private static PureFieldDelegate? TryCreatePureField( - Schema schema, - ObjectField field, - FieldNode selection) - { - if (field.PureResolver is not null && selection.Directives.Count == 0) - { - return field.PureResolver; - } - - for (var i = 0; i < selection.Directives.Count; i++) - { - if (schema.DirectiveTypes.TryGetDirective(selection.Directives[i].Name.Value, out var type) - && type.Middleware is not null) - { - return null; - } - } - - return field.PureResolver; - } - - private static void BuildDirectivePipeline( - Schema schema, - FieldNode selection, - Path? path, - HashSet processed, - List pipelineComponents) - { - for (var i = 0; i < selection.Directives.Count; i++) - { - var directiveNode = selection.Directives[i]; - if (schema.DirectiveTypes.TryGetDirective(directiveNode.Name.Value, out var directiveType) - && directiveType.Middleware is not null - && (directiveType.IsRepeatable || processed.Add(directiveType.Name))) - { - Debug.Assert(path != null, "path should not be null if a directive is present."); - Directive directive; - try - { - directive = new Directive( - directiveType, - directiveNode, - directiveType.Parse(directiveNode)); - } - catch (SerializationException ex) - { - throw new SerializationException( - ErrorBuilder.FromError(ex.Errors[0]).SetPath(path).TryAddLocation(directiveNode).Build(), - ex.Type, - path); - } - - var directiveMiddleware = directiveType.Middleware; - pipelineComponents.Add(next => directiveMiddleware(next, directive)); - } - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs deleted file mode 100644 index 977984e19d6..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.CompilerContext.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Immutable; -using HotChocolate.Language; -using HotChocolate.Types; -using static System.StringComparer; - -namespace HotChocolate.Execution.Processing; - -public sealed partial class OperationCompiler -{ - internal sealed class CompilerContext(Schema schema, DocumentNode document) - { - public Schema Schema { get; } = schema; - - public DocumentNode Document { get; } = document; - - public ObjectType Type { get; private set; } = null!; - - public SelectionSetInfo[] SelectionInfos { get; private set; } = null!; - - public SelectionPath Path { get; private set; } = SelectionPath.Root; - - public Dictionary Fields { get; } = new(Ordinal); - - public List Fragments { get; } = []; - - public SelectionVariants SelectionVariants { get; private set; } = null!; - - public ImmutableArray Optimizers { get; private set; } - - public void Initialize( - ObjectType type, - SelectionVariants selectionVariants, - SelectionSetInfo[] selectionInfos, - SelectionPath path, - ImmutableArray? optimizers = null) - { - Type = type; - SelectionVariants = selectionVariants; - SelectionInfos = selectionInfos; - Path = path; - Optimizers = optimizers ?? []; - Fields.Clear(); - Fragments.Clear(); - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs deleted file mode 100644 index 174bc3ca348..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/_OperationCompiler.cs +++ /dev/null @@ -1,787 +0,0 @@ -using System.Collections.Immutable; -using System.Runtime.CompilerServices; -using HotChocolate.Language; -using HotChocolate.Resolvers; -using HotChocolate.Types; -using HotChocolate.Utilities; -using static System.Runtime.InteropServices.CollectionsMarshal; -using static System.Runtime.InteropServices.MemoryMarshal; -using static System.StringComparer; -using static HotChocolate.Execution.Properties.Resources; -using static HotChocolate.Execution.ThrowHelper; - -namespace HotChocolate.Execution.Processing; - -/// -/// The operation compiler will analyze a specific operation of a GraphQL request document -/// and create from it an optimized executable operation tree. -/// -public sealed partial class OperationCompiler -{ - private readonly InputParser _parser; - private readonly CreateFieldPipeline _createFieldPipeline; - private readonly Queue _backlog = []; - private readonly Dictionary _selectionLookup = []; - private readonly Dictionary _selectionSetIdLookup = []; - private readonly Dictionary _selectionVariants = []; - private readonly Dictionary _fragmentDefinitions = []; - private readonly Dictionary _contextData = []; - private readonly List _selections = []; - private readonly HashSet _directiveNames = new(Ordinal); - private readonly List _pipelineComponents = []; - private readonly HashSet _enqueuedSelectionSets = []; - private IncludeCondition[] _includeConditions = []; - private CompilerContext? _deferContext; - private ImmutableArray _operationOptimizers = []; - private int _nextSelectionId; - private int _nextSelectionSetRefId; - private int _nextSelectionSetId; - private int _nextFragmentId; - private bool _hasIncrementalParts; - private OperationCompilerMetrics _metrics; - - public OperationCompiler(InputParser parser) - { - _parser = parser ?? throw new ArgumentNullException(nameof(parser)); - - _createFieldPipeline = - (schema, field, selection) - => CreateFieldPipeline( - schema, - field, - selection, - null, - _directiveNames, - _pipelineComponents); - } - - internal OperationCompilerMetrics Metrics => _metrics; - - public IOperation Compile(OperationCompilerRequest request) - { - ArgumentException.ThrowIfNullOrEmpty(request.Id, nameof(request)); - - try - { - var backlogMaxSize = 0; - var selectionSetOptimizers = request.SelectionSetOptimizers; - _operationOptimizers = request.OperationOptimizers; - - // collect root fields - var rootPath = SelectionPath.Root; - var id = GetOrCreateSelectionSetRefId(request.Definition.SelectionSet, request.RootType.Name, rootPath); - var variants = GetOrCreateSelectionVariants(id); - SelectionSetInfo[] infos = [new(request.Definition.SelectionSet, 0)]; - - var context = new CompilerContext((Schema)request.Schema, request.Document); - context.Initialize(request.RootType, variants, infos, rootPath, selectionSetOptimizers); - CompileSelectionSet(context); - - // process consecutive selections - while (_backlog.Count > 0) - { - backlogMaxSize = Math.Max(backlogMaxSize, _backlog.Count); - - var current = _backlog.Dequeue(); - var type = current.Type; - variants = GetOrCreateSelectionVariants(current.SelectionSetId); - - if (!variants.ContainsSelectionSet(type)) - { - infos = _selectionLookup[current.Selection]; - context.Initialize(type, variants, infos, current.Path, current.Optimizers); - CompileSelectionSet(context); - } - } - - // create operation - var operation = CreateOperation(request); - - _metrics = new OperationCompilerMetrics( - _nextSelectionId, - _selectionVariants.Count, - backlogMaxSize); - - return operation; - } - finally - { - _nextSelectionId = 0; - _nextSelectionSetRefId = 0; - _nextSelectionId = 0; - _nextFragmentId = 0; - _hasIncrementalParts = false; - - _backlog.Clear(); - _selectionLookup.Clear(); - _selectionSetIdLookup.Clear(); - _selectionVariants.Clear(); - _fragmentDefinitions.Clear(); - _contextData.Clear(); - _selections.Clear(); - _directiveNames.Clear(); - _pipelineComponents.Clear(); - _enqueuedSelectionSets.Clear(); - - _operationOptimizers = []; - - _includeConditions = []; - _deferContext = null; - } - } - - private Operation CreateOperation(OperationCompilerRequest request) - { - var operation = new Operation( - request.Id, - request.Document, - request.Definition, - request.RootType, - request.Schema); - - var schema = Unsafe.As(request.Schema); - - var variants = new SelectionVariants[_selectionVariants.Count]; - - if (_operationOptimizers.Length == 0) - { - CompleteResolvers(schema); - - // if we do not have any optimizers, we will copy - // the variants and seal them in one go. - foreach (var item in _selectionVariants) - { - variants[item.Key] = item.Value; - item.Value.Seal(operation); - } - } - else - { - // if we have optimizers, we will first copy the variants to its array, - // after that we will run the optimizers and give them a chance to do some - // more mutations on the compiled selection variants. - // after we have executed all optimizers, we will seal the selection variants. - var context = new OperationOptimizerContext( - request.Id, - request.Document, - request.Definition, - schema, - request.RootType, - variants, - _includeConditions, - _contextData, - _hasIncrementalParts, - _createFieldPipeline); - - foreach (var item in _selectionVariants) - { - variants[item.Key] = item.Value; - } - - // we will complete the selection variants, sets and selections - // without sealing them so that analyzers in this step can fully - // inspect them. - var variantsSpan = variants.AsSpan(); - ref var variantsStart = ref GetReference(variantsSpan); - ref var variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length); - - while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) - { - variantsStart.Complete(operation); - variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; - } - - var optSpan = _operationOptimizers.AsSpan(); - ref var optStart = ref GetReference(optSpan); - ref var optEnd = ref Unsafe.Add(ref optStart, optSpan.Length); - - while (Unsafe.IsAddressLessThan(ref optStart, ref optEnd)) - { - optStart.OptimizeOperation(context); - optStart = ref Unsafe.Add(ref optStart, 1)!; - } - - CompleteResolvers(schema); - - variantsSpan = variants.AsSpan(); - variantsStart = ref GetReference(variantsSpan)!; - variantsEnd = ref Unsafe.Add(ref variantsStart, variantsSpan.Length)!; - - while (Unsafe.IsAddressLessThan(ref variantsStart, ref variantsEnd)) - { - variantsStart.Seal(operation); - variantsStart = ref Unsafe.Add(ref variantsStart, 1)!; - } - } - - operation.Seal(_contextData, variants, _hasIncrementalParts, _includeConditions); - return operation; - } - - private void CompleteResolvers(Schema schema) - { - ref var searchSpace = ref GetReference(AsSpan(_selections)); - - Path? path = null; - for (var i = 0; i < _selections.Count; i++) - { - var selection = Unsafe.Add(ref searchSpace, i); - path = path?.Append(selection.ResponseName); - if (selection.ResolverPipeline is null && selection.PureResolver is null) - { - var field = selection.Field; - var syntaxNode = selection.SyntaxNode; - if (syntaxNode.Directives.Count > 0 && path == null) - { - // create the path only on demand - path = PathHelper.CreatePathFromSelection(_selections, i + 1); - } - - var resolver = CreateFieldPipeline( - schema, - field, - syntaxNode, - path, - _directiveNames, - _pipelineComponents); - var pureResolver = TryCreatePureField(schema, field, syntaxNode); - selection.SetResolvers(resolver, pureResolver); - } - } - } - - private void CompileSelectionSet(CompilerContext context) - { - // We first collect the fields that we find in the selection set ... - CollectFields(context); - - // next we will call the selection set optimizers to rewrite the - // selection set if necessary. - OptimizeSelectionSet(context); - - // after that we start completing the selections and build the SelectionSet from - // the completed selections. - CompleteSelectionSet(context); - } - - private void CompleteSelectionSet(CompilerContext context) - { - var selections = new Selection[context.Fields.Values.Count]; - var fragments = context.Fragments.Count is not 0 - ? new Fragment[context.Fragments.Count] - : []; - var selectionIndex = 0; - var isConditional = false; - - foreach (var selection in context.Fields.Values) - { - // if the field of the selection returns a composite type, we will traverse - // the child selection-sets as well. - var fieldType = selection.Type.NamedType(); - var selectionSetId = -1; - - if (selection.IsConditional) - { - isConditional = true; - } - - // Determines if the type is a composite type. - if (fieldType.IsCompositeType()) - { - if (selection.SelectionSet is null) - { - // composite fields always have to have a selection-set - // otherwise we need to throw. - throw QueryCompiler_CompositeTypeSelectionSet(selection.SyntaxNode); - } - - var selectionPath = context.Path.Append(selection.ResponseName); - selectionSetId = GetOrCreateSelectionSetRefId(selection.SelectionSet, fieldType.Name, selectionPath); - var possibleTypes = context.Schema.GetPossibleTypes(fieldType); - - if (_enqueuedSelectionSets.Add(selectionSetId)) - { - for (var i = possibleTypes.Count - 1; i >= 0; i--) - { - _backlog.Enqueue( - new BacklogItem( - possibleTypes[i], - selectionSetId, - selection, - selectionPath, - ResolveOptimizers(context.Optimizers, selection.Field))); - } - } - - // We are waiting for the latest stream and defer spec discussions to be codified - // before we change the overall stream handling. - // - // For now, we only allow streams on lists of composite types. - if (selection.SyntaxNode.IsStreamable()) - { - var streamDirective = selection.SyntaxNode.GetStreamDirective(); - var nullValue = NullValueNode.Default; - var ifValue = streamDirective?.GetArgumentValue(DirectiveNames.Stream.Arguments.If) ?? nullValue; - long ifConditionFlags = 0; - - if (ifValue.Kind is not SyntaxKind.NullValue) - { - var ifCondition = new IncludeCondition(ifValue, nullValue); - ifConditionFlags = GetSelectionIncludeCondition(ifCondition, 0); - } - - selection.MarkAsStream(ifConditionFlags); - _hasIncrementalParts = true; - } - } - - selection.SetSelectionSetId(selectionSetId); - selections[selectionIndex++] = selection; - _selections.Add(selection); - } - - if (context.Fragments.Count > 0) - { - for (var i = 0; i < context.Fragments.Count; i++) - { - fragments[i] = context.Fragments[i]; - } - } - - context.SelectionVariants.AddSelectionSet( - _nextSelectionSetId++, - context.Type, - selections, - fragments, - isConditional); - } - - private void CollectFields(CompilerContext context) - { - foreach (var selectionSetInfo in context.SelectionInfos) - { - CollectFields( - context, - selectionSetInfo.SelectionSet, - selectionSetInfo.IncludeCondition); - } - } - - private void CollectFields( - CompilerContext context, - SelectionSetNode selectionSet, - ulong includeCondition) - { - for (var j = 0; j < selectionSet.Selections.Count; j++) - { - ResolveFields(context, selectionSet.Selections[j], includeCondition); - } - } - - private void ResolveFields( - CompilerContext context, - ISelectionNode selection, - long includeCondition) - { - switch (selection.Kind) - { - case SyntaxKind.Field: - ResolveField( - context, - (FieldNode)selection, - includeCondition); - break; - - case SyntaxKind.InlineFragment: - ResolveInlineFragment( - context, - (InlineFragmentNode)selection, - includeCondition); - break; - - case SyntaxKind.FragmentSpread: - ResolveFragmentSpread( - context, - (FragmentSpreadNode)selection, - includeCondition); - break; - } - } - - private void ResolveField( - CompilerContext context, - FieldNode selection, - ulong includeCondition) - { - includeCondition = GetSelectionIncludeCondition(selection, includeCondition); - - var fieldName = selection.Name.Value; - var responseName = selection.Alias?.Value ?? fieldName; - - if (context.Type.Fields.TryGetField(fieldName, out var field)) - { - var fieldType = field.Type; - - if (context.Fields.TryGetValue(responseName, out var preparedSelection)) - { - preparedSelection.AddSelection(selection, includeCondition); - - if (selection.SelectionSet is not null) - { - var selectionSetInfo = new SelectionSetInfo( - selection.SelectionSet!, - includeCondition); - var selectionInfos = _selectionLookup[preparedSelection]; - var next = selectionInfos.Length; - Array.Resize(ref selectionInfos, next + 1); - selectionInfos[next] = selectionSetInfo; - _selectionLookup[preparedSelection] = selectionInfos; - } - } - else - { - var id = GetNextSelectionId(); - - // if this is the first time we've found a selection to this field, we have to - // create a new prepared selection. - preparedSelection = new Selection.Sealed( - id, - context.Type, - field, - fieldType, - selection.SelectionSet is not null - ? selection.WithSelectionSet( - selection.SelectionSet.WithSelections( - selection.SelectionSet.Selections)) - : selection, - responseName: responseName, - arguments: CoerceArgumentValues(field, selection), - includeConditions: includeCondition == 0 - ? null - : [includeCondition], - isParallelExecutable: field.IsParallelExecutable); - - context.Fields.Add(responseName, preparedSelection); - - if (selection.SelectionSet is not null) - { - var selectionSetInfo = new SelectionSetInfo( - selection.SelectionSet!, - includeCondition); - _selectionLookup.Add(preparedSelection, [selectionSetInfo]); - } - } - } - else - { - throw FieldDoesNotExistOnType(selection, context.Type.Name); - } - } - - private void ResolveInlineFragment( - CompilerContext context, - InlineFragmentNode inlineFragment, - long includeCondition) - { - ResolveFragment( - context, - inlineFragment, - inlineFragment.TypeCondition, - inlineFragment.SelectionSet, - inlineFragment.Directives, - includeCondition); - } - - private void ResolveFragmentSpread( - CompilerContext context, - FragmentSpreadNode fragmentSpread, - long includeCondition) - { - var fragmentDef = GetFragmentDefinition(context, fragmentSpread); - - ResolveFragment( - context, - fragmentSpread, - fragmentDef.TypeCondition, - fragmentDef.SelectionSet, - fragmentSpread.Directives, - includeCondition); - } - - private void ResolveFragment( - CompilerContext context, - ISelectionNode selection, - NamedTypeNode? typeCondition, - SelectionSetNode selectionSet, - IReadOnlyList directives, - ulong includeCondition) - { - if (typeCondition is null - || (context.Schema.Types.TryGetType(typeCondition, out IType? typeCon) - && DoesTypeApply(typeCon, context.Type))) - { - includeCondition = GetSelectionIncludeCondition(selection, includeCondition); - - if (directives.IsDeferrable()) - { - var deferDirective = directives.GetDeferDirectiveNode(); - var nullValue = NullValueNode.Default; - var ifValue = deferDirective?.GetArgumentValue(DirectiveNames.Defer.Arguments.If) ?? nullValue; - - ulong ifConditionFlags = 0; - - if (ifValue.Kind is not SyntaxKind.NullValue) - { - var ifCondition = new IncludeCondition(ifValue, nullValue); - ifConditionFlags = GetSelectionIncludeCondition(ifCondition, includeCondition); - } - - var typeName = typeCondition?.Name.Value ?? context.Type.Name; - var id = GetOrCreateSelectionSetRefId(selectionSet, typeName, context.Path); - var variants = GetOrCreateSelectionVariants(id); - var infos = new SelectionSetInfo[] { new(selectionSet, includeCondition) }; - - if (!variants.ContainsSelectionSet(context.Type)) - { - var deferContext = RentContext(context); - deferContext.Initialize(context.Type, variants, infos, context.Path); - CompileSelectionSet(deferContext); - ReturnContext(deferContext); - } - - var fragment = new Fragment( - GetNextFragmentId(), - context.Type, - selection, - directives, - variants.GetSelectionSet(context.Type), - includeCondition, - ifConditionFlags); - - context.Fragments.Add(fragment); - _hasIncrementalParts = true; - - // if we have if-condition flags, there will be a runtime validation if something - // shall be deferred, so we need to prepare for both cases. - // - // this means that we will collect the fields with our if condition flags as - // if the fragment was not deferred. - if (ifConditionFlags is not 0) - { - CollectFields(context, selectionSet, ifConditionFlags); - } - } - else - { - CollectFields(context, selectionSet, includeCondition); - } - } - } - - private static bool DoesTypeApply(IType typeCondition, IObjectTypeDefinition current) - => typeCondition.Kind switch - { - TypeKind.Object => ReferenceEquals(typeCondition, current), - TypeKind.Interface => current.IsImplementing((InterfaceType)typeCondition), - TypeKind.Union => ((UnionType)typeCondition).Types.ContainsName(current.Name), - _ => false - }; - - private FragmentDefinitionNode GetFragmentDefinition( - CompilerContext context, - FragmentSpreadNode fragmentSpread) - { - var fragmentName = fragmentSpread.Name.Value; - - if (!_fragmentDefinitions.TryGetValue(fragmentName, out var value)) - { - var document = context.Document; - - for (var i = 0; i < document.Definitions.Count; i++) - { - if (document.Definitions[i] is FragmentDefinitionNode fragmentDefinition - && fragmentDefinition.Name.Value.EqualsOrdinal(fragmentName)) - { - value = fragmentDefinition; - _fragmentDefinitions.Add(fragmentName, value); - goto EXIT; - } - } - - throw new InvalidOperationException( - string.Format( - OperationCompiler_FragmentNotFound, - fragmentName)); - } - -EXIT: - return value; - } - - internal int GetNextSelectionId() => _nextSelectionId++; - - private int GetNextFragmentId() => _nextFragmentId++; - - private int GetOrCreateSelectionSetRefId( - SelectionSetNode selectionSet, - string selectionSetTypeName, - SelectionPath path) - { - var selectionSetRef = new SelectionSetRef(selectionSet, selectionSetTypeName, path); - - if (!_selectionSetIdLookup.TryGetValue(selectionSetRef, out var selectionSetId)) - { - selectionSetId = _nextSelectionSetRefId++; - _selectionSetIdLookup.Add(selectionSetRef, selectionSetId); - } - - return selectionSetId; - } - - private SelectionVariants GetOrCreateSelectionVariants(int selectionSetId) - { - if (!_selectionVariants.TryGetValue(selectionSetId, out var variants)) - { - variants = new SelectionVariants(selectionSetId); - _selectionVariants.Add(selectionSetId, variants); - } - - return variants; - } - - private ulong GetSelectionIncludeCondition( - ISelectionNode selectionSyntax, - ulong parentIncludeCondition) - { - var condition = IncludeCondition.FromSelection(selectionSyntax); - - if (condition.IsDefault) - { - return parentIncludeCondition; - } - - var pos = Array.IndexOf(_includeConditions, condition); - - if (pos == -1) - { - pos = _includeConditions.Length; - - if (pos == 64) - { - throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); - } - - if (_includeConditions.Length == 0) - { - _includeConditions = new IncludeCondition[1]; - } - else - { - Array.Resize(ref _includeConditions, pos + 1); - } - - _includeConditions[pos] = condition; - } - - long selectionIncludeCondition = 1; - selectionIncludeCondition <<= pos; - - if (parentIncludeCondition == 0) - { - return selectionIncludeCondition; - } - - parentIncludeCondition |= selectionIncludeCondition; - return parentIncludeCondition; - } - - private long GetSelectionIncludeCondition( - IncludeCondition condition, - ulong parentIncludeCondition) - { - var pos = Array.IndexOf(_includeConditions, condition); - - if (pos == -1) - { - pos = _includeConditions.Length; - - if (pos == 64) - { - throw new InvalidOperationException(OperationCompiler_ToManyIncludeConditions); - } - - if (_includeConditions.Length == 0) - { - _includeConditions = new IncludeCondition[1]; - } - else - { - Array.Resize(ref _includeConditions, pos + 1); - } - - _includeConditions[pos] = condition; - } - - long selectionIncludeCondition = 1; - selectionIncludeCondition <<= pos; - - if (parentIncludeCondition == 0) - { - return selectionIncludeCondition; - } - - parentIncludeCondition |= selectionIncludeCondition; - return parentIncludeCondition; - } - - private CompilerContext RentContext(CompilerContext context) - { - if (_deferContext is null) - { - return new CompilerContext(context.Schema, context.Document); - } - - var temp = _deferContext; - _deferContext = null; - return temp; - } - - private void ReturnContext(CompilerContext context) - => _deferContext ??= context; - - internal void RegisterNewSelection(Selection newSelection) - { - if (newSelection.SyntaxNode.SelectionSet is not null) - { - var selectionSetInfo = new SelectionSetInfo(newSelection.SelectionSet!, 0); - _selectionLookup.Add(newSelection, [selectionSetInfo]); - } - } - - private readonly struct SelectionSetRef( - SelectionSetNode selectionSet, - string selectionSetTypeName, - SelectionPath path) - : IEquatable - { - public readonly SelectionSetNode SelectionSet = selectionSet; - - public readonly SelectionPath Path = path; - - public readonly string SelectionSetTypeName = selectionSetTypeName; - - public bool Equals(SelectionSetRef other) - => SyntaxComparer.BySyntax.Equals(SelectionSet, other.SelectionSet) - && Path.Equals(other.Path) - && Ordinal.Equals(SelectionSetTypeName, other.SelectionSetTypeName); - - public override bool Equals(object? obj) - => obj is SelectionSetRef other && Equals(other); - - public override int GetHashCode() - => HashCode.Combine( - SyntaxComparer.BySyntax.GetHashCode(SelectionSet), - Path.GetHashCode(), - Ordinal.GetHashCode(SelectionSetTypeName)); - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs index 2dac198ab62..c26e30ec3db 100644 --- a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs +++ b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs @@ -266,6 +266,22 @@ await typeModuleChangeMonitor.ConfigureAsync(context, cancellationToken) serviceCollection.AddSingleton(new SchemaVersionInfo(version)); + serviceCollection.AddSingleton(context.DescriptorContext.TypeConverter); + + serviceCollection.AddSingleton( + static sp => new InputParser(sp.GetRequiredService())); + + serviceCollection.AddSingleton( + static sp => new OperationCompiler( + sp.GetRequiredService(), + sp.GetRequiredService(), + sp.GetRequiredService>>>())); + + serviceCollection.AddSingleton( + static _ => new DefaultObjectPoolProvider()); + serviceCollection.AddSingleton( + static sp => sp.GetRequiredService().CreateStringBuilderPool()); + serviceCollection.AddSingleton(executorOptions); serviceCollection.AddSingleton( static sp => sp.GetRequiredService()); diff --git a/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs new file mode 100644 index 00000000000..5a4feb791b5 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs @@ -0,0 +1,15 @@ +using HotChocolate.Execution; +using HotChocolate.Execution.Processing; +using Microsoft.Extensions.ObjectPool; + +namespace HotChocolate; + +internal static class ObjectPoolProviderExtensions +{ + public static ObjectPool>> CreateFieldMapPool( + this ObjectPoolProvider provider) + { + ArgumentNullException.ThrowIfNull(provider); + return provider.Create(new FieldMapPooledObjectPolicy()); + } +} diff --git a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs index 3d237262f67..8936dc920b4 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs @@ -18,7 +18,7 @@ public static class ResolverContextExtensions /// /// Returns the global state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T? GetGlobalStateOrDefault( this IResolverContext context, @@ -51,7 +51,7 @@ public static class ResolverContextExtensions /// /// Returns the global state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T GetGlobalStateOrDefault( this IResolverContext context, @@ -114,7 +114,7 @@ public static T GetGlobalState( /// /// Returns the scoped state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T? GetScopedStateOrDefault( this IResolverContext context, @@ -147,7 +147,7 @@ public static T GetGlobalState( /// /// Returns the scoped state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T GetScopedStateOrDefault( this IResolverContext context, @@ -211,7 +211,7 @@ public static T GetScopedState( /// /// Returns the local state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T? GetLocalStateOrDefault( this IResolverContext context, @@ -244,7 +244,7 @@ public static T GetScopedState( /// /// Returns the local state for the specified /// or the default value of , if the state - /// could not be found or casted to . + /// could not be found or cast to . /// public static T GetLocalStateOrDefault( this IResolverContext context, diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 08a474f7f21..2d0e7d9066a 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -171,6 +171,30 @@ OperationCompiler.cs + + + OperationContext.cs + + + + OperationContext.cs + + + + OperationContext.cs + + + + OperationContext.cs + + + + OperationContext.cs + + + + OperationContext.cs + diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationPlanMiddleware.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationPlanMiddleware.cs index 1c47df2b5db..d6df81b3a5d 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationPlanMiddleware.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationPlanMiddleware.cs @@ -21,7 +21,7 @@ private OperationPlanMiddleware( IEnumerable? interceptors, IFusionExecutionDiagnosticEvents diagnosticsEvents) { - _documentRewriter = new(schema, removeStaticallyExcludedSelections: true); + _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); _planner = planner; _interceptors = interceptors?.ToArray() ?? []; _diagnosticsEvents = diagnosticsEvents; From 152c43ccd7e70681789456ac91f904e195a58288 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 1 Dec 2025 22:55:14 +0100 Subject: [PATCH 13/42] wip --- .../CacheControlConstraintsOptimizer.cs | 33 ++- .../ErrorBuilderExtensions.cs | 161 +++++++------- .../Execution.Projections/ExpressionCache.cs | 86 ++++++++ ...tChocolateExecutionDataLoaderExtensions.cs | 13 ++ ...otChocolateExecutionSelectionExtensions.cs | 154 ++++++------- .../SelectionExpressionBuilder.cs | 15 +- .../Caching/DefaultPreparedOperationCache.cs | 6 +- .../Caching/IPreparedOperationCache.cs | 4 +- .../InternalServiceCollectionExtensions.cs | 8 - ...uestExecutorServiceCollectionExtensions.cs | 2 - ...colateExecutionRequestContextExtensions.cs | 151 ++++++------- .../Extensions/OperationContextExtensions.cs | 165 +++++++------- .../Pipeline/OperationCacheMiddleware.cs | 1 - .../Pipeline/OperationExecutionMiddleware.cs | 51 +++-- .../Types/Execution/Pipeline/OperationInfo.cs | 2 +- .../Processing/MiddlewareContext.Selection.cs | 7 +- .../Types/Execution/Processing/Operation.cs | 4 +- .../Processing/OperationFeatureCollection.cs | 26 ++- .../Processing/OperationOptimizerContext.cs | 89 ++------ .../Result/ResultBuilder.NonNullHandling.cs | 3 +- .../Types/Execution/Processing/Selection.cs | 5 + .../Processing/SelectionCollection.cs | 206 ++++++++---------- .../Execution/Processing/SelectionLookup.cs | 8 +- .../Execution/Processing/SelectionSet.cs | 9 +- .../Processing/SubscriptionExecutor.cs | 2 +- .../Processing/Tasks/ResolverTask.Execute.cs | 18 +- .../Processing/Tasks/ResolverTask.Pooling.cs | 2 +- .../Processing/Tasks/ResolverTask.cs | 8 +- .../Processing/Tasks/ResolverTaskFactory.cs | 77 +------ .../Core/src/Types/HotChocolate.Types.csproj | 12 + .../OperationParameterExpressionBuilder.cs | 11 +- 31 files changed, 643 insertions(+), 696 deletions(-) create mode 100644 src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs diff --git a/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs b/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs index c23eefea748..2fa588c8518 100644 --- a/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs +++ b/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using System.Runtime.CompilerServices; using HotChocolate.Execution.Processing; using HotChocolate.Language; using HotChocolate.Types; @@ -15,15 +14,16 @@ internal sealed class CacheControlConstraintsOptimizer : IOperationOptimizer { public void OptimizeOperation(OperationOptimizerContext context) { - if (context.Definition.Operation is not OperationType.Query - || context.HasIncrementalParts + // TODO : we need to include this again when defer is back. + if (context.Operation.Kind is not OperationType.Query + // || context.HasIncrementalParts || ContainsIntrospectionFields(context)) { // if this is an introspection query, we will not cache it. return; } - var constraints = ComputeCacheControlConstraints(context.CreateOperation()); + var constraints = ComputeCacheControlConstraints(context.Operation); if (constraints.MaxAge is not null || constraints.SharedMaxAge is not null) { @@ -56,7 +56,7 @@ public void OptimizeOperation(OperationOptimizerContext context) } private static ImmutableCacheConstraints ComputeCacheControlConstraints( - IOperation operation) + Operation operation) { var constraints = new CacheControlConstraints(); var rootSelections = operation.RootSelectionSet.Selections; @@ -91,9 +91,9 @@ private static ImmutableCacheConstraints ComputeCacheControlConstraints( } private static void ProcessSelection( - ISelection selection, + Selection selection, CacheControlConstraints constraints, - IOperation operation) + Operation operation) { var field = selection.Field; var maxAgeSet = false; @@ -117,19 +117,18 @@ private static void ProcessSelection( } } - if (selection.SelectionSet is not null) + if (selection.HasSelections) { var possibleTypes = operation.GetPossibleTypes(selection); foreach (var type in possibleTypes) { - var selectionSet = Unsafe.As(operation.GetSelectionSet(selection, type)); - var length = selectionSet.Selections.Count; - ref var start = ref selectionSet.GetSelectionsReference(); + var selectionSet = operation.GetSelectionSet(selection, type); + var selections = selectionSet.Selections; - for (var i = 0; i < length; i++) + foreach (var childSelection in selections) { - ProcessSelection(Unsafe.Add(ref start, i), constraints, operation); + ProcessSelection(childSelection, constraints, operation); } } } @@ -223,13 +222,11 @@ void ExtractCacheControlDetailsFromDirectives( private static bool ContainsIntrospectionFields(OperationOptimizerContext context) { - var length = context.RootSelectionSet.Selections.Count; - ref var start = ref ((SelectionSet)context.RootSelectionSet).GetSelectionsReference(); + var selections = context.Operation.RootSelectionSet.Selections; - for (var i = 0; i < length; i++) + foreach (var selection in selections) { - var field = Unsafe.Add(ref start, i).Field; - + var field = selection.Field; if (field.IsIntrospectionField && !field.Name.EqualsOrdinal(IntrospectionFieldNames.TypeName)) { diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs index 628a75e4eb4..9c4d6c88050 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs @@ -8,109 +8,102 @@ namespace HotChocolate; /// public static class ErrorBuilderExtensions { - /// - /// Sets the field coordinate of the error. - /// - /// The error builder. - /// The field coordinate. - /// The error builder. - public static ErrorBuilder SetCoordinate( - this ErrorBuilder builder, - SchemaCoordinate coordinate) + extension(ErrorBuilder builder) { - ArgumentNullException.ThrowIfNull(builder); - - return builder.SetExtension(nameof(coordinate), coordinate.ToString()); - } + /// + /// Sets the field coordinate of the error. + /// + /// The field coordinate. + /// The error builder. + public ErrorBuilder SetCoordinate(SchemaCoordinate coordinate) + { + ArgumentNullException.ThrowIfNull(builder); - /// - /// Sets the input path of the error. - /// - /// The error builder. - /// The input path. - /// The error builder. - public static ErrorBuilder SetInputPath( - this ErrorBuilder builder, - Path inputPath) - { - ArgumentNullException.ThrowIfNull(builder); + return builder.SetExtension(nameof(coordinate), coordinate.ToString()); + } - return builder.SetExtension(nameof(inputPath), inputPath); - } + /// + /// Sets the input path of the error. + /// + /// The input path. + /// The error builder. + public ErrorBuilder SetInputPath(Path inputPath) + { + ArgumentNullException.ThrowIfNull(builder); - /// - /// Sets the message of the error. - /// - /// The error builder. - /// The format of the message. - /// The arguments for the message. - /// The error builder. - public static ErrorBuilder SetMessage(this ErrorBuilder builder, string format, params object[] args) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentException.ThrowIfNullOrEmpty(format); - ArgumentNullException.ThrowIfNull(args); + return builder.SetExtension(nameof(inputPath), inputPath); + } - return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, args)); - } + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The arguments for the message. + /// The error builder. + public ErrorBuilder SetMessage(string format, params object[] args) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + ArgumentNullException.ThrowIfNull(args); - /// - /// Adds a location to the error. - /// - /// The error builder. - /// The syntax node. - /// The error builder. - public static ErrorBuilder AddLocation(this ErrorBuilder builder, ISyntaxNode node) - { - ArgumentNullException.ThrowIfNull(node); + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, args)); + } - if (node.Location is null) + /// + /// Adds a location to the error. + /// + /// The syntax node. + /// The error builder. + public ErrorBuilder AddLocation(ISyntaxNode node) { - return builder; - } + ArgumentNullException.ThrowIfNull(node); - builder.AddLocation(new Location(node.Location.Line, node.Location.Column)); - return builder; - } + if (node.Location is null) + { + return builder; + } - /// - /// Adds a location to the error if the error does not already have a location. - /// - /// The error builder. - /// The syntax node. - /// The error builder. - public static ErrorBuilder TryAddLocation(this ErrorBuilder builder, ISyntaxNode? node) - { - if (node?.Location is null) - { + builder.AddLocation(new Location(node.Location.Line, node.Location.Column)); return builder; } - builder.TryAddLocation(new Location(node.Location.Line, node.Location.Column)); - return builder; - } + /// + /// Adds a location to the error if the error does not already have a location. + /// + /// The syntax node. + /// The error builder. + public ErrorBuilder TryAddLocation(ISyntaxNode? node) + { + if (node?.Location is null) + { + return builder; + } - /// - /// Adds multiple locations to the error. - /// - /// The error builder. - /// The syntax nodes. - /// The error builder. - public static ErrorBuilder AddLocations(this ErrorBuilder builder, IEnumerable nodes) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(nodes); + builder.TryAddLocation(new Location(node.Location.Line, node.Location.Column)); + return builder; + } - foreach (var node in nodes) + /// + /// Adds multiple locations to the error. + /// + /// The syntax nodes. + /// The error builder. + public ErrorBuilder AddLocations(IEnumerable nodes) { - if (node.Location is null) + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(nodes); + + foreach (var node in nodes) { - continue; + if (node.Location is null) + { + continue; + } + + builder.AddLocation(new Location(node.Location.Line, node.Location.Column)); } - builder.AddLocation(new Location(node.Location.Line, node.Location.Column)); + return builder; } - - return builder; } } diff --git a/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs b/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs new file mode 100644 index 00000000000..17d66d918ec --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs @@ -0,0 +1,86 @@ +// ReSharper disable InconsistentlySynchronizedField +using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Linq.Expressions; +using GreenDonut.Data; +using HotChocolate.Execution.Processing; + +namespace HotChocolate.Execution.Projections; + +internal sealed class ExpressionCache +{ + private readonly object _writeLock = new(); + private readonly ConcurrentDictionary _cache = new(); + + public bool TryGetExpression( + Selection selection, + [NotNullWhen(true)] out Expression>? expression) + { + if (_cache.TryGetValue(selection.Id, out var cachedExpression) + && cachedExpression is Expression> casted) + { + expression = casted; + return true; + } + + expression = null; + return false; + } + + public Expression> GetOrCreateExpression( + Selection selection, + SelectionExpressionBuilder expressionBuilder) + { + if (!TryGetExpression(selection, out var expression)) + { + lock (_writeLock) + { + if (!TryGetExpression(selection, out expression)) + { + expression = expressionBuilder.BuildExpression(selection); + _cache.TryAdd(selection.Id, expression); + } + } + } + + return expression; + } + + public Expression> GetOrCreateExpression( + Selection selection, + ISelectorBuilder expressionBuilder) + { + if (!TryGetExpression(selection, out var expression)) + { + lock (_writeLock) + { + if (!TryGetExpression(selection, out expression)) + { + expression = expressionBuilder.TryCompile()!; + _cache.TryAdd(selection.Id, expression); + } + } + } + + return expression; + } + + public Expression> GetOrCreateNodeExpression( + Selection selection, + SelectionExpressionBuilder expressionBuilder) + { + if (!TryGetExpression(selection, out var expression)) + { + lock (_writeLock) + { + if (!TryGetExpression(selection, out expression)) + { + expression = expressionBuilder.BuildNodeExpression(selection); + _cache.TryAdd(selection.Id, expression); + } + } + } + + return expression; + } +} diff --git a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionDataLoaderExtensions.cs b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionDataLoaderExtensions.cs index e94f6f41dc8..3773922eee2 100644 --- a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionDataLoaderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionDataLoaderExtensions.cs @@ -1,3 +1,4 @@ +using HotChocolate.Execution; using HotChocolate.Execution.Processing; // ReSharper disable once CheckNamespace @@ -38,6 +39,18 @@ public static IDataLoader Select( return dataLoader.Select(expression); } + public static IDataLoader Select( + this IDataLoader dataLoader, + Selection selection) + where TKey : notnull + { + ArgumentNullException.ThrowIfNull(dataLoader); + ArgumentNullException.ThrowIfNull(selection); + + var expression = selection.AsSelector(); + return dataLoader.Select(expression); + } + /// /// Selects the fields that where selected in the GraphQL selection tree. /// diff --git a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs index 7dd18bcb0dd..6c7740745af 100644 --- a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs @@ -1,9 +1,6 @@ using System.Buffers; -using System.Buffers.Text; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; -using System.Text; -using System.Runtime.CompilerServices; using GreenDonut.Data; using HotChocolate.Execution.Projections; using HotChocolate.Types; @@ -18,8 +15,6 @@ namespace HotChocolate.Execution.Processing; /// public static class HotChocolateExecutionSelectionExtensions { - private static readonly SelectionExpressionBuilder s_builder = new(); - /// /// Creates a selector expression from a GraphQL selection. /// @@ -34,6 +29,31 @@ public static class HotChocolateExecutionSelectionExtensions /// public static Expression> AsSelector( this ISelection selection) + { + if (selection is not Selection casted) + { + throw new ArgumentException( + $"Expected {typeof(Selection).FullName!}.", + nameof(selection)); + } + + return AsSelector(casted); + } + + /// + /// Creates a selector expression from a GraphQL selection. + /// + /// + /// The selection that shall be converted into a selector expression. + /// + /// + /// The type of the value that is returned by the . + /// + /// + /// Returns a selector expression that can be used for data projections. + /// + public static Expression> AsSelector( + this Selection selection) { // we first check if we already have an expression for this selection, // this would be the cheapest way to get the expression. @@ -50,66 +70,48 @@ public static Expression> AsSelector( if ((flags & CoreFieldFlags.Connection) == CoreFieldFlags.Connection) { var builder = new DefaultSelectorBuilder(); - var buffer = ArrayPool.Shared.Rent(16); + var buffer = ArrayPool.Shared.Rent(16); var count = GetConnectionSelections(selection, buffer); for (var i = 0; i < count; i++) { - builder.Add(GetOrCreateExpression(buffer[i])); + builder.Add(buffer[i].GetOrCreateExpression()); } - ArrayPool.Shared.Return(buffer); - return GetOrCreateExpression(selection, builder); + ArrayPool.Shared.Return(buffer); + return selection.GetOrCreateExpression(builder); } if ((flags & CoreFieldFlags.CollectionSegment) == CoreFieldFlags.CollectionSegment) { var builder = new DefaultSelectorBuilder(); - var buffer = ArrayPool.Shared.Rent(16); + var buffer = ArrayPool.Shared.Rent(16); var count = GetCollectionSelections(selection, buffer); for (var i = 0; i < count; i++) { - builder.Add(GetOrCreateExpression(buffer[i])); + builder.Add(buffer[i].GetOrCreateExpression()); } - ArrayPool.Shared.Return(buffer); - return GetOrCreateExpression(selection, builder); + ArrayPool.Shared.Return(buffer); + return selection.GetOrCreateExpression(builder); } if ((flags & CoreFieldFlags.GlobalIdNodeField) == CoreFieldFlags.GlobalIdNodeField || (flags & CoreFieldFlags.GlobalIdNodesField) == CoreFieldFlags.GlobalIdNodesField) { - return GetOrCreateNodeExpression(selection); + return selection.GetOrCreateNodeExpression(); } - return GetOrCreateExpression(selection); + return selection.GetOrCreateExpression(); } - private static Expression> GetOrCreateExpression( - ISelection selection) - => selection.DeclaringOperation.GetOrAddState( - CreateExpressionKey(selection.Id), - static (_, ctx) => ctx._builder.BuildExpression(ctx.selection), - (_builder: s_builder, selection)); - - private static Expression> GetOrCreateExpression( - ISelection selection, - ISelectorBuilder builder) - => selection.DeclaringOperation.GetOrAddState( - CreateExpressionKey(selection.Id), - static (_, ctx) => ctx.builder.TryCompile()!, - (builder, selection)); - - private static Expression> GetOrCreateNodeExpression( - ISelection selection) - => selection.DeclaringOperation.GetOrAddState( - CreateNodeExpressionKey(selection.Id), - static (_, ctx) => ctx._builder.BuildNodeExpression(ctx.selection), - (_builder: s_builder, selection)); - private static bool TryGetExpression( - ISelection selection, + Selection selection, [NotNullWhen(true)] out Expression>? expression) - => selection.DeclaringOperation.TryGetState(CreateExpressionKey(selection.Id), out expression); + { + var features = selection.DeclaringOperation.Features; + var cache = features.GetOrSetSafe(); + return cache.TryGetExpression(selection, out expression); + } - private static int GetConnectionSelections(ISelection selection, Span buffer) + private static int GetConnectionSelections(Selection selection, Span buffer) { var pageType = (ObjectType)selection.Field.Type.NamedType(); var connectionSelections = selection.DeclaringOperation.GetSelectionSet(selection, pageType); @@ -149,7 +151,7 @@ private static int GetConnectionSelections(ISelection selection, Span buffer) + private static int GetCollectionSelections(Selection selection, Span buffer) { var pageType = (ObjectType)selection.Field.Type.NamedType(); var connectionSelections = selection.DeclaringOperation.GetSelectionSet(selection, pageType); @@ -170,59 +172,27 @@ private static int GetCollectionSelections(ISelection selection, Span span = stackalloc byte[requiredBufferSize]; - keyPrefix.CopyTo(span); - Utf8Formatter.TryFormat(key, span[keyPrefix.Length..], out var written, 'D'); - return Encoding.UTF8.GetString(span[..(written + keyPrefix.Length)]); - } - - private static string CreateNodeExpressionKey(int key) - { - var typeName = typeof(TValue).FullName!; - var typeNameLength = Encoding.UTF8.GetMaxByteCount(typeName.Length); - var keyPrefix = GetKeyPrefix(); - var requiredBufferSize = EstimateIntLength(key) + keyPrefix.Length + typeNameLength; - byte[]? rented = null; - var span = requiredBufferSize <= 256 - ? stackalloc byte[requiredBufferSize] - : (rented = ArrayPool.Shared.Rent(requiredBufferSize)); - - keyPrefix.CopyTo(span); - Utf8Formatter.TryFormat(key, span[keyPrefix.Length..], out var written, 'D'); - var typeNameWritten = Encoding.UTF8.GetBytes(typeName, span[(written + keyPrefix.Length)..]); - var keyString = Encoding.UTF8.GetString(span[..(written + keyPrefix.Length + typeNameWritten)]); - - if (rented is not null) - { - ArrayPool.Shared.Return(rented); - } - - return keyString; - } - - private static ReadOnlySpan GetKeyPrefix() - => "hc-dataloader-expr-"u8; +file static class Extensions +{ + private static readonly SelectionExpressionBuilder s_builder = new(); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int EstimateIntLength(int value) + extension(Selection selection) { - if (value == 0) - { - // to print 0 we need still 1 digit - return 1; - } - - // if the number is negative we need one more digit for the sign - var length = value < 0 ? 1 : 0; - - // we add the number of digits the number has to the length of the number. - length += (int)Math.Floor(Math.Log10(Math.Abs(value)) + 1); - - return length; + public Expression> GetOrCreateExpression() + => selection.DeclaringOperation.Features + .GetOrSetSafe() + .GetOrCreateExpression(selection, s_builder); + + public Expression> GetOrCreateExpression(ISelectorBuilder expressionBuilder) + => selection.DeclaringOperation.Features + .GetOrSetSafe() + .GetOrCreateExpression(selection, expressionBuilder); + + public Expression> GetOrCreateNodeExpression() + => selection.DeclaringOperation.Features + .GetOrSetSafe() + .GetOrCreateNodeExpression(selection, s_builder); } } diff --git a/src/HotChocolate/Core/src/Execution.Projections/SelectionExpressionBuilder.cs b/src/HotChocolate/Core/src/Execution.Projections/SelectionExpressionBuilder.cs index 4d812130668..2e511cff998 100644 --- a/src/HotChocolate/Core/src/Execution.Projections/SelectionExpressionBuilder.cs +++ b/src/HotChocolate/Core/src/Execution.Projections/SelectionExpressionBuilder.cs @@ -36,7 +36,7 @@ internal sealed class SelectionExpressionBuilder typeof(char?) ]; - public Expression> BuildExpression(ISelection selection) + public Expression> BuildExpression(Selection selection) { var rootType = typeof(TRoot); var parameter = Expression.Parameter(rootType, "root"); @@ -56,7 +56,7 @@ public Expression> BuildExpression(ISelection selectio return Expression.Lambda>(selectionSetExpression, parameter); } - public Expression> BuildNodeExpression(ISelection selection) + public Expression> BuildNodeExpression(Selection selection) { var rootType = typeof(TRoot); var parameter = Expression.Parameter(rootType, "root"); @@ -66,6 +66,7 @@ public Expression> BuildNodeExpression(ISelection sele var entityType = selection.DeclaringOperation .GetPossibleTypes(selection) + .Cast() .FirstOrDefault(t => t.RuntimeType == typeof(TRoot)); if (entityType is null) @@ -94,7 +95,7 @@ public Expression> BuildNodeExpression(ISelection sele return Expression.Lambda>(selectionSetExpression, parameter); } - private void CollectTypes(Context context, ISelection selection, TypeContainer parent) + private void CollectTypes(Context context, Selection selection, TypeContainer parent) { var namedType = selection.Type.NamedType(); @@ -105,7 +106,7 @@ private void CollectTypes(Context context, ISelection selection, TypeContainer p if (namedType.IsAbstractType()) { - foreach (var possibleType in selection.DeclaringOperation.GetPossibleTypes(selection)) + foreach (var possibleType in selection.DeclaringOperation.GetPossibleTypes(selection).Cast()) { var possibleTypeNode = new TypeNode(possibleType.RuntimeType); var possibleSelectionSet = selection.DeclaringOperation.GetSelectionSet(selection, possibleType); @@ -191,7 +192,7 @@ private void CollectTypes(Context context, ISelection selection, TypeContainer p private void CollectSelection( Context context, - ISelection selection, + Selection selection, TypeNode parent) { var namedType = selection.Field.Type.NamedType(); @@ -266,7 +267,7 @@ private static void TryAddAnyLeafField( private void CollectSelections( Context context, - ISelectionSet selectionSet, + SelectionSet selectionSet, TypeNode parent) { foreach (var selection in selectionSet.Selections) @@ -343,7 +344,7 @@ private readonly record struct Context( FieldRequirementsMetadata Requirements, NullabilityInfoContext NullabilityInfoContext) { - public TypeNode? GetRequirements(ISelection selection) + public TypeNode? GetRequirements(Selection selection) { var flags = selection.Field.Flags; return (flags & CoreFieldFlags.WithRequirements) == CoreFieldFlags.WithRequirements diff --git a/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs b/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs index a4f1107f8ce..c6f852a78ab 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Caching/DefaultPreparedOperationCache.cs @@ -6,15 +6,15 @@ namespace HotChocolate.Execution.Caching; internal sealed class DefaultPreparedOperationCache(int capacity = 256) : IPreparedOperationCache { - private readonly Cache _cache = new(capacity); + private readonly Cache _cache = new(capacity); public int Capacity => _cache.Capacity; public int Count => _cache.Count; - public void TryAddOperation(string operationId, IOperation operation) + public void TryAddOperation(string operationId, Operation operation) => _cache.GetOrCreate(operationId, static (_, op) => op, operation); - public bool TryGetOperation(string operationId, [NotNullWhen(true)] out IOperation? operation) + public bool TryGetOperation(string operationId, [NotNullWhen(true)] out Operation? operation) => _cache.TryGet(operationId, out operation); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs b/src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs index 8235bd73f45..65bca19c522 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Caching/IPreparedOperationCache.cs @@ -33,7 +33,7 @@ public interface IPreparedOperationCache /// true if an operation was found that matches the specified /// , otherwise false. /// - bool TryGetOperation(string operationId, [NotNullWhen(true)] out IOperation? operation); + bool TryGetOperation(string operationId, [NotNullWhen(true)] out Operation? operation); /// /// Tries to add a new compiled operation to the cache. @@ -44,5 +44,5 @@ public interface IPreparedOperationCache /// /// The operation that shall be cached. /// - void TryAddOperation(string operationId, IOperation operation); + void TryAddOperation(string operationId, Operation operation); } diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs index 6a1afa07ec7..be71c7446e7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs @@ -71,14 +71,6 @@ internal static IServiceCollection TryAddResolverTaskPool( return services; } - internal static IServiceCollection TryAddOperationCompilerPool( - this IServiceCollection services) - { - services.TryAddSingleton>( - sp => new OperationCompilerPool(sp.GetRequiredService())); - return services; - } - internal static IServiceCollection TryAddOperationContextPool( this IServiceCollection services) { diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs index 63b88e77e99..d78ec74851f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs @@ -57,8 +57,6 @@ public static IServiceCollection AddGraphQLCore(this IServiceCollection services .TryAddResultPool() .TryAddResolverTaskPool() .TryAddOperationContextPool() - .TryAddDeferredWorkStatePool() - .TryAddOperationCompilerPool() .TryAddSingleton>(new DocumentValidatorContextPool()); // global executor services diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs index 7032887c51f..2573e075aa9 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/HotChocolateExecutionRequestContextExtensions.cs @@ -8,106 +8,99 @@ namespace HotChocolate.Execution; public static class HotChocolateExecutionRequestContextExtensions { - public static bool TryGetOperationDefinition( - this RequestContext context, - [NotNullWhen(true)] out OperationDefinitionNode? operationDefinition) + extension(RequestContext context) { - ArgumentNullException.ThrowIfNull(context); + public bool TryGetOperationDefinition([NotNullWhen(true)] out OperationDefinitionNode? operationDefinition) + { + ArgumentNullException.ThrowIfNull(context); - var operationInfo = context.Features.GetOrSet(); + var operationInfo = context.Features.GetOrSet(); - if (operationInfo.Operation is not null) - { - operationDefinition = operationInfo.Operation.Definition; - return true; - } + if (operationInfo.Operation is not null) + { + operationDefinition = operationInfo.Operation.Definition; + return true; + } - if (operationInfo.Definition is not null) - { - operationDefinition = operationInfo.Definition; - return true; + if (operationInfo.Definition is not null) + { + operationDefinition = operationInfo.Definition; + return true; + } + + operationDefinition = null; + return false; } - operationDefinition = null; - return false; - } + public void SetOperationDefinition(OperationDefinitionNode operationDefinition) + { + ArgumentNullException.ThrowIfNull(context); - public static void SetOperationDefinition( - this RequestContext context, - OperationDefinitionNode operationDefinition) - { - ArgumentNullException.ThrowIfNull(context); + var operationInfo = context.Features.GetOrSet(); - var operationInfo = context.Features.GetOrSet(); + if (operationInfo.Operation is not null) + { + throw new InvalidOperationException( + "The operation definition cannot be set after " + + "the operation was already compiled."); + } - if (operationInfo.Operation is not null) - { - throw new InvalidOperationException( - "The operation definition cannot be set after " - + "the operation was already compiled."); + operationInfo.Definition = operationDefinition; } - operationInfo.Definition = operationDefinition; - } - - public static bool TryGetOperation( - this RequestContext context, - [NotNullWhen(true)] out IOperation? operation) - { - ArgumentNullException.ThrowIfNull(context); + public bool TryGetOperation([NotNullWhen(true)] out Operation? operation) + { + ArgumentNullException.ThrowIfNull(context); - var operationInfo = context.Features.GetOrSet(); - operation = operationInfo.Operation; - return operation is not null; - } + var operationInfo = context.Features.GetOrSet(); + operation = operationInfo.Operation; + return operation is not null; + } - public static bool TryGetOperation( - this RequestContext context, - [NotNullWhen(true)] out IOperation? operation, - [NotNullWhen(true)] out string? operationId) - { - ArgumentNullException.ThrowIfNull(context); + public bool TryGetOperation([NotNullWhen(true)] out Operation? operation, + [NotNullWhen(true)] out string? operationId) + { + ArgumentNullException.ThrowIfNull(context); - var operationInfo = context.Features.GetOrSet(); - operation = operationInfo.Operation; - operationId = operationInfo.Id; - return operation is not null; - } + var operationInfo = context.Features.GetOrSet(); + operation = operationInfo.Operation; + operationId = operationInfo.Id; + return operation is not null; + } - public static IOperation GetOperation(this RequestContext context) - { - ArgumentNullException.ThrowIfNull(context); + public Operation GetOperation() + { + ArgumentNullException.ThrowIfNull(context); - return context.Features.GetRequired().Operation - ?? throw new InvalidOperationException("The operation is not initialized."); - } + return context.Features.GetRequired().Operation + ?? throw new InvalidOperationException("The operation is not initialized."); + } - public static void SetOperation( - this RequestContext context, - IOperation operation) - { - ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(operation); + public void SetOperation(Operation operation) + { + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(operation); - var operationInfo = context.Features.GetOrSet(); - operationInfo.Operation = operation; - operationInfo.Id = operation.Id; - operationInfo.Definition = operation.Definition; - } + var operationInfo = context.Features.GetOrSet(); + operationInfo.Operation = operation; + operationInfo.Id = operation.Id; + operationInfo.Definition = operation.Definition; + } - public static bool TryGetOperationId(this RequestContext context, [NotNullWhen(true)] out string? operationId) - { - ArgumentNullException.ThrowIfNull(context); + public bool TryGetOperationId([NotNullWhen(true)] out string? operationId) + { + ArgumentNullException.ThrowIfNull(context); - operationId = context.Features.GetOrSet().Id; - return operationId is not null; - } + operationId = context.Features.GetOrSet().Id; + return operationId is not null; + } - public static void SetOperationId(this RequestContext context, string operationId) - { - ArgumentNullException.ThrowIfNull(context); + public void SetOperationId(string operationId) + { + ArgumentNullException.ThrowIfNull(context); - var operationInfo = context.Features.GetOrSet(); - operationInfo.Id = operationId; + var operationInfo = context.Features.GetOrSet(); + operationInfo.Id = operationId; + } } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs index 32a7fcb170f..d721a1e8f24 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs @@ -5,61 +5,99 @@ namespace HotChocolate.Execution; internal static class OperationContextExtensions { - public static OperationContext ReportError( - this OperationContext operationContext, - Exception exception, - MiddlewareContext resolverContext, - ISelection? selection = null, - Path? path = null) + extension(OperationContext context) { - selection ??= resolverContext.Selection; - path ??= resolverContext.Path; + public OperationContext ReportError(Exception exception, + MiddlewareContext resolverContext, + ISelection? selection = null, + Path? path = null) + { + selection ??= resolverContext.Selection; + path ??= resolverContext.Path; - ArgumentNullException.ThrowIfNull(exception); + ArgumentNullException.ThrowIfNull(exception); - if (exception is GraphQLException ex) - { - foreach (var error in ex.Errors) + if (exception is GraphQLException ex) + { + foreach (var error in ex.Errors) + { + ReportError(context, error, resolverContext, selection); + } + } + else { - ReportError(operationContext, error, resolverContext, selection); + var error = ErrorBuilder + .FromException(exception) + .SetPath(path) + .AddLocations(selection.GetSyntaxNodes()) + .Build(); + + ReportError(context, error, resolverContext, selection); } + + return context; } - else + + public OperationContext ReportError(IError error, + MiddlewareContext resolverContext, + ISelection? selection = null) { - var error = ErrorBuilder - .FromException(exception) - .SetPath(path) - .AddLocation(selection.SyntaxNode) - .Build(); + var errors = new List(); + + ReportSingleError( + context.ErrorHandler, + error, + errors); - ReportError(operationContext, error, resolverContext, selection); + selection ??= resolverContext.Selection; + + foreach (var handled in errors) + { + context.Result.AddError(handled, selection); + context.DiagnosticEvents.ResolverError(resolverContext, handled); + } + + return context; } - return operationContext; - } + public OperationContext SetLabel(string? label) + { + context.Result.SetLabel(label); + return context; + } - public static OperationContext ReportError( - this OperationContext operationContext, - IError error, - MiddlewareContext resolverContext, - ISelection? selection = null) - { - var errors = new List(); + public OperationContext SetPath(Path? path) + { + context.Result.SetPath(path); + return context; + } + + public OperationContext SetData(ObjectResult objectResult) + { + context.Result.SetData(objectResult); + return context; + } - ReportSingleError( - operationContext.ErrorHandler, - error, - errors); + public OperationContext SetItems(IReadOnlyList items) + { + context.Result.SetItems(items); + return context; + } - selection ??= resolverContext.Selection; + public OperationContext SetPatchId(uint patchId) + { + context.Result.SetContextData(WellKnownContextData.PatchId, patchId); + return context; + } - foreach (var handled in errors) + public OperationContext ClearResult() { - operationContext.Result.AddError(handled, selection); - operationContext.DiagnosticEvents.ResolverError(resolverContext, handled); + context.Result.Clear(); + return context; } - return operationContext; + public IOperationResult BuildResult() + => context.Result.BuildResult(); } private static void ReportSingleError( @@ -93,55 +131,4 @@ private static void ReportSingleError( errors.Add(error); } } - - public static OperationContext SetLabel( - this OperationContext context, - string? label) - { - context.Result.SetLabel(label); - return context; - } - - public static OperationContext SetPath( - this OperationContext context, - Path? path) - { - context.Result.SetPath(path); - return context; - } - - public static OperationContext SetData( - this OperationContext context, - ObjectResult objectResult) - { - context.Result.SetData(objectResult); - return context; - } - - public static OperationContext SetItems( - this OperationContext context, - IReadOnlyList items) - { - context.Result.SetItems(items); - return context; - } - - public static OperationContext SetPatchId( - this OperationContext context, - uint patchId) - { - context.Result.SetContextData(WellKnownContextData.PatchId, patchId); - return context; - } - - public static OperationContext ClearResult( - this OperationContext context) - { - context.Result.Clear(); - return context; - } - - public static IOperationResult BuildResult( - this OperationContext context) => - context.Result.BuildResult(); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs index b21a9ccaff5..5e0bad45ab0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationCacheMiddleware.cs @@ -1,6 +1,5 @@ using HotChocolate.Execution.Caching; using HotChocolate.Execution.Instrumentation; -using Microsoft.Extensions.DependencyInjection; namespace HotChocolate.Execution.Pipeline; diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs index a891e31e320..6355bf99f58 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs @@ -6,7 +6,6 @@ using HotChocolate.Fetching; using HotChocolate.Language; using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; using static HotChocolate.Execution.RequestFlags; using static HotChocolate.Execution.ThrowHelper; @@ -91,7 +90,7 @@ public async ValueTask InvokeAsync( private async Task ExecuteOperationRequestAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation) + Operation operation) { if (operation.Definition.Operation is OperationType.Subscription) { @@ -114,7 +113,7 @@ await ExecuteQueryOrMutationAsync( private async Task ExecuteVariableBatchRequestAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation) + Operation operation) { if (operation.Definition.Operation is OperationType.Query) { @@ -137,7 +136,7 @@ private async Task ExecuteVariableBatchRequestAsync( private async Task ExecuteVariableBatchRequestOptimizedAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation) + Operation operation) { var variableSets = context.VariableValues; var query = GetQueryRootValue(context); @@ -182,7 +181,7 @@ await _queryExecutor.ExecuteBatchAsync( static void Initialize( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation, + Operation operation, object? query, Span operationContexts, IVariableValueCollection variables, @@ -249,7 +248,7 @@ static void ReleaseResources( private async Task ExecuteQueryOrMutationAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation, + Operation operation, IVariableValueCollection variables) { var operationContextOwner = _contextFactory.Create(); @@ -266,15 +265,16 @@ await ExecuteQueryOrMutationAsync( variables) .ConfigureAwait(false); - if (operationContext.DeferredScheduler.HasResults) - { - var results = operationContext.DeferredScheduler.CreateResultStream(result); - var responseStream = new ResponseStream(() => results, ExecutionResultKind.DeferredResult); - responseStream.RegisterForCleanup(result); - responseStream.RegisterForCleanup(operationContextOwner); - operationContextOwner = null; - return responseStream; - } + // TODO : DEFER + // if (operationContext.DeferredScheduler.HasResults) + // { + // var results = operationContext.DeferredScheduler.CreateResultStream(result); + // var responseStream = new ResponseStream(() => results, ExecutionResultKind.DeferredResult); + // responseStream.RegisterForCleanup(result); + // responseStream.RegisterForCleanup(operationContextOwner); + // operationContextOwner = null; + // return responseStream; + // } return result; } @@ -296,7 +296,7 @@ await ExecuteQueryOrMutationAsync( private async Task ExecuteQueryOrMutationNoStreamAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation, + Operation operation, IVariableValueCollection variables, int variableIndex) { @@ -332,7 +332,7 @@ private async Task ExecuteQueryOrMutationNoStreamAsync( private async Task ExecuteQueryOrMutationAsync( RequestContext context, IBatchDispatcher batchDispatcher, - IOperation operation, + Operation operation, OperationContext operationContext, IVariableValueCollection variables, int variableIndex = -1) @@ -397,7 +397,7 @@ private async Task ExecuteQueryOrMutationAsync( Unsafe.As(context.Schema.MutationType)!, ref _cachedMutation); - private static bool IsOperationAllowed(IOperation operation, IOperationRequest request) + private static bool IsOperationAllowed(Operation operation, IOperationRequest request) { if (request.Flags is AllowAll) { @@ -412,21 +412,24 @@ private static bool IsOperationAllowed(IOperation operation, IOperationRequest r _ => true }; - if (allowed && operation.HasIncrementalParts) - { - return allowed && (request.Flags & AllowStreams) == AllowStreams; - } + // TODO : DEFER + // if (allowed && operation.HasIncrementalParts) + // { + // return allowed && (request.Flags & AllowStreams) == AllowStreams; + // } return allowed; } private static bool IsRequestTypeAllowed( - IOperation operation, + Operation operation, IReadOnlyList? variables) { if (variables is { Count: > 1 }) { - return operation.Definition.Operation is not OperationType.Subscription && !operation.HasIncrementalParts; + // TODO : DEFER + return operation.Definition.Operation is not OperationType.Subscription; + // && !operation.HasIncrementalParts; } return true; diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs index 831ae5e3aed..15a709dea36 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationInfo.cs @@ -7,7 +7,7 @@ internal sealed class OperationInfo : RequestFeature { public string? Id { get; set; } - public IOperation? Operation { get; set; } + public Operation? Operation { get; set; } public OperationDefinitionNode? Definition { get; set; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 660e99ded09..6efa2b63cac 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -61,8 +61,11 @@ public SelectionEnumerator GetSelections( public ISelectionCollection Select() { - var schema = Unsafe.As(_operationContext.Schema); - return new SelectionCollection(schema, Operation, [Selection], _operationContext.IncludeFlags); + return new SelectionCollection( + _operationContext.Schema, + Operation, + [Selection], + _operationContext.IncludeFlags); } public ISelectionCollection Select(string fieldName) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 216d6fd00cd..4c440b5b1c0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -113,7 +113,9 @@ ISelectionSet IOperation.RootSelectionSet => RootSelectionSet; /// - public IFeatureCollection Features => _features; + public OperationFeatureCollection Features => _features; + + IFeatureCollection IFeatureProvider.Features => Features; /// /// Gets the selection set for the specified diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs index 025d3eb9600..553e910d594 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Execution.Processing; [SuppressMessage("ReSharper", "NonAtomicCompoundOperator")] -internal sealed class OperationFeatureCollection : IFeatureCollection +public sealed class OperationFeatureCollection : IFeatureCollection { #if NET9_0_OR_GREATER private readonly Lock _writeLock = new(); @@ -23,7 +23,7 @@ internal sealed class OperationFeatureCollection : IFeatureCollection /// /// Initializes a new instance of . /// - public OperationFeatureCollection() + internal OperationFeatureCollection() { } @@ -85,6 +85,28 @@ public object? this[Type key] return (TFeature?)this[typeof(TFeature)]; } + public TFeature GetOrSetSafe() where TFeature : new() + => GetOrSetSafe(static () => new TFeature()); + + public TFeature GetOrSetSafe(Func factory) + { + ArgumentNullException.ThrowIfNull(factory); + + if (!TryGet(out var feature)) + { + lock (_writeLock) + { + if (!TryGet(out feature)) + { + feature = factory(); + this[typeof(TFeature)] = feature; + } + } + } + + return feature; + } + /// public bool TryGet([NotNullWhen(true)] out TFeature? feature) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs index 16f6fa38373..4aaabec22ae 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs @@ -10,86 +10,31 @@ namespace HotChocolate.Execution.Processing; /// public readonly ref struct OperationOptimizerContext { - private readonly SelectionVariants[] _variants; - private readonly IncludeCondition[] _includeConditions; - private readonly ObjectType _rootType; - private readonly Dictionary _contextData; - private readonly bool _hasIncrementalParts; private readonly CreateFieldPipeline _createFieldPipeline; /// /// Initializes a new instance of /// internal OperationOptimizerContext( - string id, - DocumentNode document, - OperationDefinitionNode definition, - Schema schema, - ObjectType rootType, - SelectionVariants[] variants, - IncludeCondition[] includeConditions, + Operation operation, Dictionary contextData, - bool hasIncrementalParts, CreateFieldPipeline createFieldPipeline) { - Id = id; - Document = document; - Definition = definition; - Schema = schema; - _rootType = rootType; - _variants = variants; - _includeConditions = includeConditions; - _contextData = contextData; - _hasIncrementalParts = hasIncrementalParts; + Operation = operation; + ContextData = contextData; _createFieldPipeline = createFieldPipeline; } /// - /// Gets the internal unique identifier for this operation. + /// Gets the operation. /// - public string Id { get; } - - /// - /// Gets the parsed query document that contains the - /// operation-. - /// - public DocumentNode Document { get; } - - /// - /// Gets the syntax node representing the operation definition. - /// - public OperationDefinitionNode Definition { get; } - - /// - /// Gets the schema for which the query is compiled. - /// - public Schema Schema { get; } - - /// - /// Gets the root type on which the operation is executed. - /// - public ObjectType RootType => _rootType; - - /// - /// Gets the prepared root selections for this operation. - /// - public ISelectionSet RootSelectionSet => _variants[0].GetSelectionSet(RootType); - - /// - /// Gets all selection variants of this operation. - /// - public IReadOnlyList SelectionVariants => _variants; + public Operation Operation { get; } /// /// The context data dictionary can be used by middleware components and /// resolvers to store and retrieve data during execution. /// - public IDictionary ContextData => _contextData; - - /// - /// Defines if the operation has incremental parts. - /// - public bool HasIncrementalParts => _hasIncrementalParts; + public IDictionary ContextData { get; } /// /// Sets the resolvers on the specified . @@ -104,29 +49,21 @@ internal OperationOptimizerContext( /// The pure resolver. /// public void SetResolver( - ISelection selection, + Selection selection, FieldDelegate? resolverPipeline = null, PureFieldDelegate? pureResolver = null) - => ((Selection)selection).SetResolvers(resolverPipeline, pureResolver); + => selection.SetResolvers(resolverPipeline, pureResolver); /// /// Allows to compile the field resolver pipeline for a field. /// /// The field. - /// The selection of the field. + /// The selection of the field. /// /// Returns a representing the field resolver pipeline. /// - public FieldDelegate CompileResolverPipeline(ObjectField field, FieldNode selection) - => _createFieldPipeline(Schema, field, selection); - - /// - /// Creates a temporary operation object for the optimizer. - /// - public IOperation CreateOperation() - { - var operation = new Operation(Id, Document, Definition, _rootType, Schema); - operation.Seal(_contextData, _variants, _hasIncrementalParts, _includeConditions); - return operation; - } + public FieldDelegate CompileResolverPipeline( + ObjectField field, + FieldNode fieldSelection) + => _createFieldPipeline(Operation.Schema, field, fieldSelection); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs index 8b127c59995..2eda9295e82 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs @@ -1,5 +1,4 @@ using HotChocolate.Language; -using Microsoft.Extensions.DependencyInjection; using static HotChocolate.Execution.ErrorHelper; namespace HotChocolate.Execution.Processing; @@ -30,7 +29,7 @@ private void ApplyNonNullViolations( continue; } - var error = NonNullOutputFieldViolation(violation.Path, violation.Selection.SyntaxNode); + var error = NonNullOutputFieldViolation(violation.Path, violation.Selection.GetSyntaxNodes().First()); error = errorHandler.Handle(error); _diagnosticEvents.ResolverError(_context, violation.Selection, error); errors.Add(error); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index 1d44a51e445..f4538b26dfe 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -82,6 +82,11 @@ internal Selection( public bool IsLeaf => (_flags & Flags.Leaf) == Flags.Leaf; + /// + /// Defines if this selection has child selections. + /// + public bool HasSelections => !IsLeaf; + public ObjectField Field { get; } /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs index 6a7370dfe04..4729fb96bde 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionCollection.cs @@ -10,20 +10,34 @@ namespace HotChocolate.Execution.Processing; -internal sealed class SelectionCollection( - Schema schema, - IOperation operation, - ISelection[] selections, - ulong includeFlags) - : ISelectionCollection +internal sealed class SelectionCollection : ISelectionCollection { - private readonly Schema _schema = schema ?? throw new ArgumentNullException(nameof(schema)); - private readonly IOperation _operation = operation ?? throw new ArgumentNullException(nameof(operation)); - private readonly ISelection[] _selections = selections ?? throw new ArgumentNullException(nameof(selections)); + private readonly Schema _schema; + private readonly Operation _operation; + private readonly Selection[] _selections; + private readonly ulong _includeFlags; + + public SelectionCollection( + Schema schema, + Operation operation, + Selection[] selections, + ulong includeFlags) + { + ArgumentNullException.ThrowIfNull(schema); + ArgumentNullException.ThrowIfNull(operation); + ArgumentNullException.ThrowIfNull(selections); + + _includeFlags = includeFlags; + _schema = schema; + _operation = operation; + _selections = selections; + } public int Count => _selections.Length; - public ISelection this[int index] => _selections[index]; + public Selection this[int index] => _selections[index]; + + ISelection IReadOnlyList.this[int index] => _selections[index]; public ISelectionCollection Select(string fieldName) { @@ -31,26 +45,26 @@ public ISelectionCollection Select(string fieldName) if (!CollectSelections(fieldName, out var buffer, out var size)) { - return new SelectionCollection(_schema, _operation, [], includeFlags); + return new SelectionCollection(_schema, _operation, [], _includeFlags); } - var selections = new ISelection[size]; + var selections = new Selection[size]; buffer.AsSpan()[..size].CopyTo(selections); - ArrayPool.Shared.Return(buffer); - return new SelectionCollection(_schema, _operation, selections, includeFlags); + ArrayPool.Shared.Return(buffer); + return new SelectionCollection(_schema, _operation, selections, _includeFlags); } public ISelectionCollection Select(ReadOnlySpan fieldNames) { if (!CollectSelections(fieldNames, out var buffer, out var size)) { - return new SelectionCollection(_schema, _operation, [], includeFlags); + return new SelectionCollection(_schema, _operation, [], _includeFlags); } - var selections = new ISelection[size]; + var selections = new Selection[size]; buffer.AsSpan()[..size].CopyTo(selections); - ArrayPool.Shared.Return(buffer); - return new SelectionCollection(_schema, _operation, selections, includeFlags); + ArrayPool.Shared.Return(buffer); + return new SelectionCollection(_schema, _operation, selections, _includeFlags); } public ISelectionCollection Select(ITypeDefinition typeContext) @@ -59,13 +73,13 @@ public ISelectionCollection Select(ITypeDefinition typeContext) if (!CollectSelections(typeContext, out var buffer, out var size)) { - return new SelectionCollection(_schema, _operation, [], includeFlags); + return new SelectionCollection(_schema, _operation, [], _includeFlags); } - var selections = new ISelection[size]; + var selections = new Selection[size]; buffer.AsSpan()[..size].CopyTo(selections); - ArrayPool.Shared.Return(buffer); - return new SelectionCollection(_schema, _operation, selections, includeFlags); + ArrayPool.Shared.Return(buffer); + return new SelectionCollection(_schema, _operation, selections, _includeFlags); } public bool IsSelected(string fieldName) @@ -90,7 +104,7 @@ public bool IsSelected(string fieldName) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, possibleType, start, fieldName)) @@ -103,7 +117,7 @@ public bool IsSelected(string fieldName) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, Unsafe.As(ref namedType), start, fieldName)) @@ -118,27 +132,22 @@ public bool IsSelected(string fieldName) return false; static bool IsChildSelected( - IOperation operation, + Operation operation, ulong includeFlags, ObjectType objectType, - ISelection parent, + Selection parent, string fieldName) { var selectionSet = operation.GetSelectionSet(parent, objectType); var operationIncludeFlags = includeFlags; - var selectionCount = selectionSet.Selections.Count; - ref var start = ref Unsafe.As(ref selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref start, selectionCount); - while (Unsafe.IsAddressLessThan(ref start, ref end)) + foreach (var child in selectionSet.Selections) { - if (start.IsIncluded(operationIncludeFlags) - && fieldName.EqualsOrdinal(start.Field.Name)) + if (child.IsIncluded(operationIncludeFlags) + && fieldName.EqualsOrdinal(child.Field.Name)) { return true; } - - start = ref Unsafe.Add(ref start, 1)!; } return false; @@ -168,7 +177,7 @@ public bool IsSelected(string fieldName1, string fieldName2) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, possibleType, start, fieldName1, @@ -182,7 +191,7 @@ public bool IsSelected(string fieldName1, string fieldName2) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, Unsafe.As(ref namedType), start, fieldName1, @@ -198,29 +207,25 @@ public bool IsSelected(string fieldName1, string fieldName2) return false; static bool IsChildSelected( - IOperation operation, + Operation operation, ulong includeFlags, ObjectType objectType, - ISelection parent, + Selection parent, string fieldName1, string fieldName2) { var selectionSet = operation.GetSelectionSet(parent, objectType); var operationIncludeFlags = includeFlags; - var selectionCount = selectionSet.Selections.Count; - ref var start = ref Unsafe.As(ref selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref start, selectionCount); + var selections = selectionSet.Selections; - while (Unsafe.IsAddressLessThan(ref start, ref end)) + foreach (var selection in selections) { - if (start.IsIncluded(operationIncludeFlags) - && (fieldName1.EqualsOrdinal(start.Field.Name) - || fieldName2.EqualsOrdinal(start.Field.Name))) + if (selection.IsIncluded(operationIncludeFlags) + && (fieldName1.EqualsOrdinal(selection.Field.Name) + || fieldName2.EqualsOrdinal(selection.Field.Name))) { return true; } - - start = ref Unsafe.Add(ref start, 1)!; } return false; @@ -251,7 +256,7 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, possibleType, start, fieldName1, @@ -266,7 +271,7 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, Unsafe.As(ref namedType), start, fieldName1, @@ -283,31 +288,27 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) return false; static bool IsChildSelected( - IOperation operation, + Operation operation, ulong includeFlags, ObjectType objectType, - ISelection parent, + Selection parent, string fieldName1, string fieldName2, string fieldName3) { var selectionSet = operation.GetSelectionSet(parent, objectType); var operationIncludeFlags = includeFlags; - var selectionCount = selectionSet.Selections.Count; - ref var start = ref Unsafe.As(ref selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref start, selectionCount); + var selections = selectionSet.Selections; - while (Unsafe.IsAddressLessThan(ref start, ref end)) + foreach (var selection in selections) { - if (start.IsIncluded(operationIncludeFlags) - && (fieldName1.EqualsOrdinal(start.Field.Name) - || fieldName2.EqualsOrdinal(start.Field.Name) - || fieldName3.EqualsOrdinal(start.Field.Name))) + if (selection.IsIncluded(operationIncludeFlags) + && (fieldName1.EqualsOrdinal(selection.Field.Name) + || fieldName2.EqualsOrdinal(selection.Field.Name) + || fieldName3.EqualsOrdinal(selection.Field.Name))) { return true; } - - start = ref Unsafe.Add(ref start, 1)!; } return false; @@ -334,7 +335,7 @@ public bool IsSelected(ISet fieldNames) { foreach (var possibleType in _schema.GetPossibleTypes(namedType)) { - if (IsChildSelected(_operation, includeFlags, possibleType, start, fieldNames)) + if (IsChildSelected(_operation, _includeFlags, possibleType, start, fieldNames)) { return true; } @@ -344,7 +345,7 @@ public bool IsSelected(ISet fieldNames) { if (IsChildSelected( _operation, - includeFlags, + _includeFlags, Unsafe.As(ref namedType), start, fieldNames)) @@ -359,27 +360,23 @@ public bool IsSelected(ISet fieldNames) return false; static bool IsChildSelected( - IOperation operation, + Operation operation, ulong includeFlags, ObjectType objectType, - ISelection parent, + Selection parent, ISet fieldNames) { var selectionSet = operation.GetSelectionSet(parent, objectType); var operationIncludeFlags = includeFlags; - var selectionCount = selectionSet.Selections.Count; - ref var start = ref Unsafe.As(ref selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref start, selectionCount); + var selections = selectionSet.Selections; - while (Unsafe.IsAddressLessThan(ref start, ref end)) + foreach (var selection in selections) { - if (start.IsIncluded(operationIncludeFlags) - && fieldNames.Contains(start.Field.Name)) + if (selection.IsIncluded(operationIncludeFlags) + && fieldNames.Contains(selection.Field.Name)) { return true; } - - start = ref Unsafe.Add(ref start, 1)!; } return false; @@ -388,7 +385,7 @@ static bool IsChildSelected( private bool CollectSelections( string fieldName, - out ISelection[] buffer, + out Selection[] buffer, out int size) { var fieldNames = ArrayPool.Shared.Rent(1); @@ -402,47 +399,42 @@ private bool CollectSelections( private bool CollectSelections( ReadOnlySpan fieldNames, - out ISelection[] buffer, + out Selection[] buffer, out int size) { - buffer = ArrayPool.Shared.Rent(4); + buffer = ArrayPool.Shared.Rent(4); size = 0; - ref var start = ref MemoryMarshal.GetReference(_selections.AsSpan()); - ref var end = ref Unsafe.Add(ref start, _selections.Length); - - while (Unsafe.IsAddressLessThan(ref start, ref end)) + foreach (var selection in _selections) { - var namedType = start.Type.NamedType(); + var namedType = selection.Type.NamedType(); if (!namedType.IsCompositeType()) { - goto NEXT; + continue; } if (namedType.IsAbstractType()) { foreach (var possibleType in _schema.GetPossibleTypes(namedType)) { - var selectionSet = _operation.GetSelectionSet(start, possibleType); - CollectFields(fieldNames, includeFlags, ref buffer, selectionSet, size, out var written); + var selectionSet = _operation.GetSelectionSet(selection, possibleType); + CollectFields(fieldNames, _includeFlags, ref buffer, selectionSet, size, out var written); size += written; } } else { - var selectionSet = _operation.GetSelectionSet(start, Unsafe.As(ref namedType)); - CollectFields(fieldNames, includeFlags, ref buffer, selectionSet, size, out var written); + var objectType = Unsafe.As(ref namedType); + var selectionSet = _operation.GetSelectionSet(selection, objectType); + CollectFields(fieldNames, _includeFlags, ref buffer, selectionSet, size, out var written); size += written; } - -NEXT: - start = ref Unsafe.Add(ref start, 1)!; } if (size == 0) { - ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(buffer); buffer = []; } @@ -451,10 +443,10 @@ private bool CollectSelections( private bool CollectSelections( ITypeDefinition typeContext, - out ISelection[] buffer, + out Selection[] buffer, out int size) { - buffer = ArrayPool.Shared.Rent(_selections.Length); + buffer = ArrayPool.Shared.Rent(_selections.Length); size = 0; ref var start = ref MemoryMarshal.GetReference(_selections.AsSpan()); @@ -472,7 +464,7 @@ private bool CollectSelections( if (size == 0) { - ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(buffer); buffer = []; } @@ -482,38 +474,32 @@ private bool CollectSelections( private static void CollectFields( ReadOnlySpan fieldNames, ulong includeFlags, - ref ISelection[] buffer, - ISelectionSet selectionSet, + ref Selection[] buffer, + SelectionSet selectionSet, int index, out int written) { written = 0; - var operationIncludeFlags = includeFlags; - var selectionCount = selectionSet.Selections.Count; + var selections = selectionSet.Selections; - ref var selectionRef = ref ((SelectionSet)selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref selectionRef, selectionCount); + EnsureCapacity(ref buffer, index, selections.Length); - EnsureCapacity(ref buffer, index, selectionCount); - - while (Unsafe.IsAddressLessThan(ref selectionRef, ref end)) + foreach (var selection in selections) { foreach (var fieldName in fieldNames) { - if (selectionRef.IsIncluded(operationIncludeFlags) - && selectionRef.Field.Name.EqualsOrdinal(fieldName)) + if (selection.IsIncluded(includeFlags) + && selection.Field.Name.EqualsOrdinal(fieldName)) { - buffer[index++] = selectionRef; + buffer[index++] = selection; written++; } } - - selectionRef = ref Unsafe.Add(ref selectionRef, 1)!; } } - private static void EnsureCapacity(ref ISelection[] buffer, int index, int requiredSpace) + private static void EnsureCapacity(ref Selection[] buffer, int index, int requiredSpace) { var capacity = buffer.Length - index; @@ -527,9 +513,9 @@ private static void EnsureCapacity(ref ISelection[] buffer, int index, int requi capacity *= 2; } - var newBuffer = ArrayPool.Shared.Rent(capacity); + var newBuffer = ArrayPool.Shared.Rent(capacity); buffer.AsSpan()[..index].CopyTo(newBuffer); - ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(buffer); buffer = newBuffer; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs index 3986a6aab5a..e6614d3827f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionLookup.cs @@ -19,7 +19,7 @@ private SelectionLookup(Entry[] table, int seed, int mask) public static SelectionLookup Create(SelectionSet selectionSet) { var selections = selectionSet.Selections; - var tableSize = NextPowerOfTwo(Math.Max(selections.Count * 2, 4)); + var tableSize = NextPowerOfTwo(Math.Max(selections.Length * 2, 4)); var mask = tableSize - 1; var table = new Entry[tableSize]; @@ -82,7 +82,7 @@ public static SelectionLookup Create(SelectionSet selectionSet) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryGetSelection(ReadOnlySpan name, [NotNullWhen(true)] out ISelection? selection) + public bool TryGetSelection(ReadOnlySpan name, [NotNullWhen(true)] out Selection? selection) { var table = _table.AsSpan(); @@ -148,9 +148,9 @@ private static int NextPowerOfTwo(int n) return n; } - private readonly struct Entry(int hashCode, ISelection selection) + private readonly struct Entry(int hashCode, Selection selection) { public readonly int HashCode = hashCode; - public readonly ISelection? Selection = selection; + public readonly Selection? Selection = selection; } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 6968ad6a7a3..39af1b52e5a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -62,7 +62,7 @@ public SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, public ReadOnlySpan Selections => _selections; IEnumerable ISelectionSet.GetSelections() => _selections; - + internal void Complete(Operation declaringOperation, bool seal) { if ((_flags & Flags.Sealed) == Flags.Sealed) @@ -74,10 +74,13 @@ internal void Complete(Operation declaringOperation, bool seal) foreach (var selection in _selections) { - selection.Complete(declaringOperation, this); + selection.Complete(this, seal); } - _flags |= Flags.Sealed; + if (seal) + { + _flags |= Flags.Sealed; + } } /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs index ce8e84a3630..e10abc1e2a5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs @@ -36,7 +36,7 @@ public async Task ExecuteAsync( var operation = requestContext.GetOperation(); var selectionSet = operation.RootSelectionSet; - if (selectionSet.Selections.Count != 1) + if (selectionSet.Selections.Length != 1) { throw SubscriptionExecutor_SubscriptionsMustHaveOneField(); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs index 441f034c9e7..112df731c60 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs @@ -91,7 +91,7 @@ private async ValueTask TryExecuteAsync(CancellationToken cancellationToke // signal that this resolver task has errors and shall end. if (Selection.Arguments.HasErrors) { - foreach (var argument in Selection.Arguments) + foreach (var argument in Selection.Arguments.ArgumentValues) { if (argument.HasError) { @@ -157,12 +157,13 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat return; } - if (_selection.IsList && _selection.HasStreamDirective(_operationContext.IncludeFlags)) - { - var stream = postProcessor.ToStreamResultAsync(result, cancellationToken); - _context.Result = await CreateStreamResultAsync(stream).ConfigureAwait(false); - return; - } + // TODO: DEFER + // if (_selection.IsList && _selection.HasStreamDirective(_operationContext.IncludeFlags)) + // { + // var stream = postProcessor.ToStreamResultAsync(result, cancellationToken); + // _context.Result = await CreateStreamResultAsync(stream).ConfigureAwait(false); + // return; + // } _context.Result = await postProcessor.ToCompletionResultAsync(result, cancellationToken).ConfigureAwait(false); } @@ -199,8 +200,10 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat if (next) { + // TODO : DEFER // if the stream has more items than the initial requested items then we will // defer the rest of the stream. + /* _operationContext.DeferredScheduler.Register( new DeferredStream( Selection, @@ -211,6 +214,7 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat enumerator, _context.ScopedContextData), _context.ParentResult); + */ } return list; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs index b6203dc5395..a5d30fe42a4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs @@ -9,7 +9,7 @@ internal sealed partial class ResolverTask /// public void Initialize( OperationContext operationContext, - ISelection selection, + Selection selection, ObjectResult parentResult, int responseIndex, object? parent, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs index 21a20cc2830..4b19453a6e7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs @@ -10,7 +10,7 @@ internal sealed partial class ResolverTask(ObjectPool objectPool) private readonly List _taskBuffer = []; private readonly Dictionary _args = new(StringComparer.Ordinal); private OperationContext _operationContext = null!; - private ISelection _selection = null!; + private Selection _selection = null!; private ExecutionTaskStatus _completionStatus = ExecutionTaskStatus.Completed; private Task? _task; @@ -32,7 +32,7 @@ internal sealed partial class ResolverTask(ObjectPool objectPool) /// /// Gets the selection for which a resolver is executed. /// - internal ISelection Selection => _selection; + internal Selection Selection => _selection; /// public ExecutionTaskKind Kind @@ -73,8 +73,4 @@ public void BeginExecute(CancellationToken cancellationToken) Status = ExecutionTaskStatus.Running; _task = ExecuteAsync(cancellationToken); } - - /// - public Task WaitForCompletionAsync(CancellationToken cancellationToken) - => _task ?? Task.CompletedTask; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index 46066fe111b..973ef1e29e5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -1,6 +1,5 @@ using System.Collections.Immutable; using System.Diagnostics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using HotChocolate.Types; using static HotChocolate.Execution.Processing.PathHelper; @@ -16,13 +15,14 @@ static ResolverTaskFactory() { } public static ObjectResult EnqueueResolverTasks( OperationContext operationContext, - ISelectionSet selectionSet, + SelectionSet selectionSet, object? parent, Path path, IImmutableDictionary scopedContext, ObjectResult? parentResult = null) { - var selectionsCount = selectionSet.Selections.Count; + var selections = selectionSet.Selections; + var selectionsCount = selections.Length; var responseIndex = selectionsCount; parentResult ??= operationContext.Result.RentObject(selectionsCount); var scheduler = operationContext.Scheduler; @@ -34,8 +34,6 @@ public static ObjectResult EnqueueResolverTasks( try { - ref var selectionSpace = ref ((SelectionSet)selectionSet).GetSelectionsReference(); - // we are iterating reverse so that in the case of a mutation the first // synchronous root selection is executed first, since the work scheduler // is using two stacks one for parallel work and one for synchronous work. @@ -44,7 +42,7 @@ public static ObjectResult EnqueueResolverTasks( // guarantees while executing efficient. for (var i = selectionsCount - 1; i >= 0; i--) { - ref var selection = ref Unsafe.Add(ref selectionSpace, i); + var selection = selections[i]; if (final || selection.IsIncluded(includeFlags)) { @@ -69,17 +67,6 @@ public static ObjectResult EnqueueResolverTasks( scheduler.Register(CollectionsMarshal.AsSpan(bufferedTasks)); } - if (selectionSet.Fragments.Count > 0) - { - TryHandleDeferredFragments( - operationContext, - selectionSet, - scopedContext, - path, - parent, - parentResult); - } - return parentResult; } finally @@ -144,10 +131,11 @@ public static ResolverTask EnqueueElementTasks( ResultData parentResult, int parentIndex, object parent, - ISelectionSet selectionSet) + SelectionSet selectionSet) { var responseIndex = 0; - var selectionsCount = selectionSet.Selections.Count; + var selections = selectionSet.Selections; + var selectionsCount = selections.Length; var operationContext = context.OperationContext; var result = operationContext.Result.RentObject(selectionsCount); var includeFlags = operationContext.IncludeFlags; @@ -155,10 +143,7 @@ public static ResolverTask EnqueueElementTasks( result.SetParent(parentResult, parentIndex); - ref var selection = ref ((SelectionSet)selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref selection, selectionsCount); - - while (Unsafe.IsAddressLessThan(ref selection, ref end)) + foreach (var selection in selections) { if (result.IsInvalidated) { @@ -167,7 +152,7 @@ public static ResolverTask EnqueueElementTasks( if (!final && !selection.IsIncluded(includeFlags)) { - goto NEXT; + continue; } if (selection.Strategy is SelectionExecutionStrategy.Pure) @@ -190,20 +175,6 @@ public static ResolverTask EnqueueElementTasks( responseIndex++, context.ResolverContext.ScopedContextData)); } - -NEXT: - selection = ref Unsafe.Add(ref selection, 1)!; - } - - if (selectionSet.Fragments.Count > 0) - { - TryHandleDeferredFragments( - operationContext, - selectionSet, - context.ResolverContext.ScopedContextData, - CreatePathFromContext(result), - parent, - result); } return result.IsInvalidated ? null : result; @@ -211,7 +182,7 @@ public static ResolverTask EnqueueElementTasks( private static void ResolveAndCompleteInline( ValueCompletionContext context, - ISelection selection, + Selection selection, int responseIndex, ObjectType parentType, object parent, @@ -332,34 +303,6 @@ private static void CommitValue( } } - private static void TryHandleDeferredFragments( - OperationContext operationContext, - ISelectionSet selectionSet, - IImmutableDictionary scopedContext, - Path path, - object? parent, - ObjectResult parentResult) - { - var fragments = selectionSet.Fragments; - var includeFlags = operationContext.IncludeFlags; - - for (var i = 0; i < fragments.Count; i++) - { - var fragment = fragments[i]; - if (!fragment.IsConditional || fragment.IsIncluded(includeFlags)) - { - operationContext.DeferredScheduler.Register( - new DeferredFragment( - fragment, - fragment.GetLabel(operationContext.Variables), - path, - parent, - scopedContext), - parentResult); - } - } - } - private sealed class NoOpExecutionTask(OperationContext context) : ExecutionTask { protected override IExecutionTaskContext Context { get; } = context; diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 2d0e7d9066a..a16f3d639cd 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -195,6 +195,18 @@ OperationContext.cs + + + ResolverTask.cs + + + + ResolverTask.cs + + + + ResolverTask.cs + diff --git a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/OperationParameterExpressionBuilder.cs b/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/OperationParameterExpressionBuilder.cs index 06cc6ce1d09..0598c766c67 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/OperationParameterExpressionBuilder.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/OperationParameterExpressionBuilder.cs @@ -1,13 +1,14 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Internal; namespace HotChocolate.Resolvers.Expressions.Parameters; internal sealed class OperationParameterExpressionBuilder() - : LambdaParameterExpressionBuilder(ctx => ctx.Operation, isPure: true) + : LambdaParameterExpressionBuilder(ctx => ctx.Operation, isPure: true) , IParameterBindingFactory , IParameterBinding { @@ -15,10 +16,12 @@ public override ArgumentKind Kind => ArgumentKind.Operation; public override bool CanHandle(ParameterInfo parameter) - => typeof(IOperation) == parameter.ParameterType; + => typeof(IOperation) == parameter.ParameterType + || typeof(Operation) == parameter.ParameterType; public bool CanHandle(ParameterDescriptor parameter) - => typeof(IOperation) == parameter.Type; + => typeof(IOperation) == parameter.Type + || typeof(Operation) == parameter.Type; public IParameterBinding Create(ParameterDescriptor parameter) => this; @@ -27,6 +30,6 @@ public T Execute(IResolverContext context) { Debug.Assert(typeof(IOperation).IsAssignableFrom(typeof(T))); var operation = context.Operation; - return Unsafe.As(ref operation); + return Unsafe.As(ref operation); } } From a96af9a67125c4246358b3cb8c03d7459a75aead Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 1 Dec 2025 23:34:54 +0100 Subject: [PATCH 14/42] wip --- .../src/Authorization/AuthorizeMiddleware.cs | 2 +- .../ErrorBuilderExtensions.cs | 3 +- ...fsetPaginationResolverContextExtensions.cs | 7 +- .../Processing/FieldSelectionNode.cs | 14 + .../Execution/Processing/IncludeCondition.cs | 153 ++ .../Processing/IncludeConditionCollection.cs | 50 + .../Execution/Processing/OperationCompiler.cs | 208 --- .../Processing/OperationContext.Execution.cs | 2 +- .../Processing/OperationContextOwner.cs | 7 +- .../Types/Execution/Processing/Selection.cs | 13 - .../Processing/Tasks/ResolverTaskFactory.cs | 2 +- .../Execution/Processing/Utf8StringCache.cs | 15 + .../Core/src/Types/HotChocolate.Types.csproj | 10 +- .../Core/src/Validation/ErrorHelper.cs | 1295 ++++++++--------- 14 files changed, 849 insertions(+), 932 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/FieldSelectionNode.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/IncludeConditionCollection.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Utf8StringCache.cs diff --git a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs index 0a5aa008ea1..e7de30d536b 100644 --- a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs +++ b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs @@ -69,7 +69,7 @@ private void SetError( .SetMessage(AuthorizeMiddleware_NoDefaultPolicy) .SetCode(ErrorCodes.Authentication.NoDefaultPolicy) .SetPath(context.Path) - .AddLocation(context.Selection.SyntaxNode) + .AddLocations(context.Selection.SyntaxNodes) .Build(), AuthorizeResult.PolicyNotFound => ErrorBuilder.New() diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs index 9c4d6c88050..eb9d4a2843b 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Globalization; using HotChocolate.Language; @@ -40,7 +41,7 @@ public ErrorBuilder SetInputPath(Path inputPath) /// The format of the message. /// The arguments for the message. /// The error builder. - public ErrorBuilder SetMessage(string format, params object[] args) + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, params object?[] args) { ArgumentNullException.ThrowIfNull(builder); ArgumentException.ThrowIfNullOrEmpty(format); diff --git a/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs index 63f5829a6a9..089dccdd442 100644 --- a/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types.OffsetPagination/Extensions/OffsetPaginationResolverContextExtensions.cs @@ -23,13 +23,8 @@ public static bool IsTotalCountSelected(this IResolverContext context) var selectionSet = context.Selection.DeclaringOperation.GetSelectionSet(context.Selection, objectType); foreach (var selection in selectionSet.Selections) - { )) - - } - - for (var i = 0; i < selections.Count; i++) { - if (selections[i].Field.Name is OffsetPagingFieldNames.TotalCount) + if (selection.Field.Name is OffsetPagingFieldNames.TotalCount) { return true; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/FieldSelectionNode.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/FieldSelectionNode.cs new file mode 100644 index 00000000000..f5964f13f64 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/FieldSelectionNode.cs @@ -0,0 +1,14 @@ +using HotChocolate.Language; + +namespace HotChocolate.Execution.Processing; + +/// +/// Represents a field selection node with its path include flags. +/// +/// +/// The syntax node that represents the field selection. +/// +/// +/// The flags that must be all set for this selection to be included. +/// +public sealed record FieldSelectionNode(FieldNode Node, ulong PathIncludeFlags); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs new file mode 100644 index 00000000000..f59672de25a --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeCondition.cs @@ -0,0 +1,153 @@ +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Language; +using HotChocolate.Types; + +namespace HotChocolate.Execution.Processing; + +internal readonly struct IncludeCondition : IEquatable +{ + private readonly string? _skip; + private readonly string? _include; + + public IncludeCondition(string? skip, string? include) + { + _skip = skip; + _include = include; + } + + public string? Skip => _skip; + + public string? Include => _include; + + public bool IsIncluded(IVariableValueCollection variableValues) + { + if (_skip is not null) + { + if (!variableValues.TryGetValue(_skip, out var value)) + { + throw new InvalidOperationException($"The variable {_skip} has an invalid value."); + } + + if (value.Value) + { + return false; + } + } + + if (_include is not null) + { + if (!variableValues.TryGetValue(_include, out var value)) + { + throw new InvalidOperationException($"The variable {_include} has an invalid value."); + } + + if (!value.Value) + { + return false; + } + } + + return true; + } + + public bool Equals(IncludeCondition other) + => string.Equals(Skip, other.Skip, StringComparison.Ordinal) + && string.Equals(Include, other.Include, StringComparison.Ordinal); + + public override bool Equals([NotNullWhen(true)] object? obj) + => obj is IncludeCondition other && Equals(other); + + public override int GetHashCode() + => HashCode.Combine(Skip, Include); + + public static bool TryCreate(FieldNode field, out IncludeCondition includeCondition) + => TryCreate(field.Directives, out includeCondition); + + public static bool TryCreate(InlineFragmentNode inlineFragment, out IncludeCondition includeCondition) + => TryCreate(inlineFragment.Directives, out includeCondition); + + private static bool TryCreate(IReadOnlyList directives, out IncludeCondition includeCondition) + { + string? skip = null; + string? include = null; + + if (directives.Count == 0) + { + includeCondition = default; + return false; + } + + if (directives.Count == 1) + { + TryParseDirective(directives[0], ref skip, ref include); + if (TryCreateIncludeCondition(out includeCondition)) + { + return true; + } + } + + if (directives.Count == 2) + { + TryParseDirective(directives[0], ref skip, ref include); + TryParseDirective(directives[1], ref skip, ref include); + return TryCreateIncludeCondition(out includeCondition); + } + + if (directives.Count == 3) + { + TryParseDirective(directives[0], ref skip, ref include); + TryParseDirective(directives[1], ref skip, ref include); + + if (skip is not null && include is not null) + { + includeCondition = new IncludeCondition(skip, include); + return true; + } + + TryParseDirective(directives[2], ref skip, ref include); + return TryCreateIncludeCondition(out includeCondition); + } + + for (var i = 0; i < directives.Count; i++) + { + TryParseDirective(directives[i], ref skip, ref include); + + if (skip is not null && include is not null) + { + includeCondition = new IncludeCondition(skip, include); + return true; + } + } + + includeCondition = default; + return false; + + bool TryCreateIncludeCondition(out IncludeCondition includeCondition) + { + if (skip is not null || include is not null) + { + includeCondition = new IncludeCondition(skip, include); + return true; + } + + includeCondition = default; + return false; + } + } + + private static void TryParseDirective(DirectiveNode directive, ref string? skip, ref string? include) + { + if (directive.Name.Value.Equals(DirectiveNames.Skip.Name, StringComparison.Ordinal) + && directive.Arguments.Count == 1 + && directive.Arguments[0].Value is VariableNode skipVariable) + { + skip = skipVariable.Name.Value; + } + else if (directive.Name.Value.Equals(DirectiveNames.Include.Name, StringComparison.Ordinal) + && directive.Arguments.Count == 1 + && directive.Arguments[0].Value is VariableNode includeVariable) + { + include = includeVariable.Name.Value; + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeConditionCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeConditionCollection.cs new file mode 100644 index 00000000000..f9cbbdd292f --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/IncludeConditionCollection.cs @@ -0,0 +1,50 @@ +using System.Collections; + +namespace HotChocolate.Execution.Processing; + +internal class IncludeConditionCollection : ICollection +{ + private readonly OrderedDictionary _dictionary = []; + + public IncludeCondition this[int index] + => _dictionary.GetAt(index).Key; + + public int Count => _dictionary.Count; + + public bool IsReadOnly => false; + + public bool Add(IncludeCondition item) + { + if (_dictionary.Count == 64) + { + throw new InvalidOperationException( + "The maximum number of include conditions has been reached."); + } + + return _dictionary.TryAdd(item, _dictionary.Count); + } + + void ICollection.Add(IncludeCondition item) + => Add(item); + + public bool Remove(IncludeCondition item) + => throw new InvalidOperationException("This is an add only collection."); + + void ICollection.Clear() + => throw new InvalidOperationException("This is an add only collection."); + + public bool Contains(IncludeCondition item) + => _dictionary.ContainsKey(item); + + public int IndexOf(IncludeCondition item) + => _dictionary.GetValueOrDefault(item, -1); + + public void CopyTo(IncludeCondition[] array, int arrayIndex) + => _dictionary.Keys.CopyTo(array, arrayIndex); + + public IEnumerator GetEnumerator() + => _dictionary.Keys.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 33caee22385..e83d352bbb0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -1,6 +1,4 @@ using System.Buffers; -using System.Collections; -using System.Diagnostics.CodeAnalysis; using HotChocolate.Fusion.Rewriters; using HotChocolate.Language; using HotChocolate.Language.Visitors; @@ -436,209 +434,3 @@ public void Register(object element, int id) } } } - -/// -/// Represents a field selection node with its path include flags. -/// -/// -/// The syntax node that represents the field selection. -/// -/// -/// The flags that must be all set for this selection to be included. -/// -public sealed record FieldSelectionNode(FieldNode Node, ulong PathIncludeFlags); - -internal class IncludeConditionCollection : ICollection -{ - private readonly OrderedDictionary _dictionary = []; - - public IncludeCondition this[int index] - => _dictionary.GetAt(index).Key; - - public int Count => _dictionary.Count; - - public bool IsReadOnly => false; - - public bool Add(IncludeCondition item) - { - if (_dictionary.Count == 64) - { - throw new InvalidOperationException( - "The maximum number of include conditions has been reached."); - } - - return _dictionary.TryAdd(item, _dictionary.Count); - } - - void ICollection.Add(IncludeCondition item) - => Add(item); - - public bool Remove(IncludeCondition item) - => throw new InvalidOperationException("This is an add only collection."); - - void ICollection.Clear() - => throw new InvalidOperationException("This is an add only collection."); - - public bool Contains(IncludeCondition item) - => _dictionary.ContainsKey(item); - - public int IndexOf(IncludeCondition item) - => _dictionary.GetValueOrDefault(item, -1); - - public void CopyTo(IncludeCondition[] array, int arrayIndex) - => _dictionary.Keys.CopyTo(array, arrayIndex); - - public IEnumerator GetEnumerator() - => _dictionary.Keys.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); -} - -internal readonly struct IncludeCondition : IEquatable -{ - private readonly string? _skip; - private readonly string? _include; - - public IncludeCondition(string? skip, string? include) - { - _skip = skip; - _include = include; - } - - public string? Skip => _skip; - - public string? Include => _include; - - public bool IsIncluded(IVariableValueCollection variableValues) - { - if (_skip is not null) - { - if (!variableValues.TryGetValue(_skip, out var value)) - { - throw new InvalidOperationException($"The variable {_skip} has an invalid value."); - } - - if (value.Value) - { - return false; - } - } - - if (_include is not null) - { - if (!variableValues.TryGetValue(_include, out var value)) - { - throw new InvalidOperationException($"The variable {_include} has an invalid value."); - } - - if (!value.Value) - { - return false; - } - } - - return true; - } - - public bool Equals(IncludeCondition other) - => string.Equals(Skip, other.Skip, StringComparison.Ordinal) - && string.Equals(Include, other.Include, StringComparison.Ordinal); - - public override bool Equals([NotNullWhen(true)] object? obj) - => obj is IncludeCondition other && Equals(other); - - public override int GetHashCode() - => HashCode.Combine(Skip, Include); - - public static bool TryCreate(FieldNode field, out IncludeCondition includeCondition) - => TryCreate(field.Directives, out includeCondition); - - public static bool TryCreate(InlineFragmentNode inlineFragment, out IncludeCondition includeCondition) - => TryCreate(inlineFragment.Directives, out includeCondition); - - private static bool TryCreate(IReadOnlyList directives, out IncludeCondition includeCondition) - { - string? skip = null; - string? include = null; - - if (directives.Count == 0) - { - includeCondition = default; - return false; - } - - if (directives.Count == 1) - { - TryParseDirective(directives[0], ref skip, ref include); - if (TryCreateIncludeCondition(out includeCondition)) - { - return true; - } - } - - if (directives.Count == 2) - { - TryParseDirective(directives[0], ref skip, ref include); - TryParseDirective(directives[1], ref skip, ref include); - return TryCreateIncludeCondition(out includeCondition); - } - - if (directives.Count == 3) - { - TryParseDirective(directives[0], ref skip, ref include); - TryParseDirective(directives[1], ref skip, ref include); - - if (skip is not null && include is not null) - { - includeCondition = new IncludeCondition(skip, include); - return true; - } - - TryParseDirective(directives[2], ref skip, ref include); - return TryCreateIncludeCondition(out includeCondition); - } - - for (var i = 0; i < directives.Count; i++) - { - TryParseDirective(directives[i], ref skip, ref include); - - if (skip is not null && include is not null) - { - includeCondition = new IncludeCondition(skip, include); - return true; - } - } - - includeCondition = default; - return false; - - bool TryCreateIncludeCondition(out IncludeCondition includeCondition) - { - if (skip is not null || include is not null) - { - includeCondition = new IncludeCondition(skip, include); - return true; - } - - includeCondition = default; - return false; - } - } - - private static void TryParseDirective(DirectiveNode directive, ref string? skip, ref string? include) - { - if (directive.Name.Value.Equals(DirectiveNames.Skip.Name, StringComparison.Ordinal) - && directive.Arguments.Count == 1 - && directive.Arguments[0].Value is VariableNode skipVariable) - { - skip = skipVariable.Name.Value; - } - else if (directive.Name.Value.Equals(DirectiveNames.Include.Name, StringComparison.Ordinal) - && directive.Arguments.Count == 1 - && directive.Arguments[0].Value is VariableNode includeVariable) - { - include = includeVariable.Name.Value; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs index 6e74fb6e5ea..3fca2464889 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs @@ -43,7 +43,7 @@ public RequestContext RequestContext } public ResolverTask CreateResolverTask( - ISelection selection, + Selection selection, object? parent, ObjectResult parentResult, int responseIndex, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs index ae26c204bad..c0aa82e3049 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs @@ -4,12 +4,15 @@ namespace HotChocolate.Execution.Processing; /// +/// /// The operation context owner abstracts the interaction of resolving of -/// an instance from its pool and returning to to +/// an instance from its pool and returning to /// the pool through the implementation of . -/// +/// +/// /// In some cases its desirable to not call dispose and abandon a pooled /// . +/// /// internal sealed class OperationContextOwner : IDisposable { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index f4538b26dfe..cd95444549b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -1,7 +1,4 @@ using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Text; -using HotChocolate.Caching.Memory; using HotChocolate.Execution.Properties; using HotChocolate.Language; using HotChocolate.Resolvers; @@ -267,13 +264,3 @@ public Sealed( } } } - -internal static class Utf8StringCache -{ - private static readonly Encoding s_utf8 = Encoding.UTF8; - private static readonly Cache s_cache = new(capacity: 4 * 1024); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] GetUtf8String(string s) - => s_cache.GetOrCreate(s, static k => s_utf8.GetBytes(k)); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index 973ef1e29e5..420df73c557 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -78,7 +78,7 @@ public static ObjectResult EnqueueResolverTasks( public static ResolverTask EnqueueElementTasks( OperationContext operationContext, - ISelection selection, + Selection selection, object? parent, Path path, int index, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Utf8StringCache.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Utf8StringCache.cs new file mode 100644 index 00000000000..330f0c33daf --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Utf8StringCache.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using System.Text; +using HotChocolate.Caching.Memory; + +namespace HotChocolate.Execution.Processing; + +internal static class Utf8StringCache +{ + private static readonly Encoding s_utf8 = Encoding.UTF8; + private static readonly Cache s_cache = new(capacity: 4 * 1024); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] GetUtf8String(string s) + => s_cache.GetOrCreate(s, static k => s_utf8.GetBytes(k)); +} diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index a16f3d639cd..7b3d5a23453 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -46,7 +46,6 @@ - @@ -65,19 +64,18 @@ - - - - - + + + + diff --git a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs index 415369aa554..daaadbe780f 100644 --- a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs @@ -6,763 +6,672 @@ namespace HotChocolate.Validation; internal static class ErrorHelper { - public static IError VariableNotUsed( - this DocumentValidatorContext context, - OperationDefinitionNode node, - IEnumerable unusedVariables) - { - return ErrorBuilder.New() - .SetMessage( - "The following variables were not used: " - + $"{string.Join(", ", unusedVariables)}.") - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-All-Variables-Used") - .Build(); - } - - public static IError VariableNotDeclared( - this DocumentValidatorContext context, - OperationDefinitionNode node, - IEnumerable usedVariables) - { - return ErrorBuilder.New() - .SetMessage( - "The following variables were not declared: " - + $"{string.Join(", ", usedVariables)}.") - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-All-Variable-Uses-Defined") - .Build(); - } - - public static IError OneOfVariableIsNotCompatible( - this DocumentValidatorContext context, - VariableNode variable, - VariableDefinitionNode variableDefinition) - { - var variableName = variableDefinition.Variable.Name.Value; - - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_OneOfVariableIsNotCompatible, - variableName) - .AddLocation(variable) - .SetPath(context.CreateErrorPath()) - .SetExtension("variable", variableName) - .SpecifiedBy("sec-All-Variable-Usages-are-Allowed") - .Build(); - } - - public static IError VariableIsNotCompatible( - this DocumentValidatorContext context, - VariableNode variable, - VariableDefinitionNode variableDefinition) - { - var variableName = variableDefinition.Variable.Name.Value; - - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_VariableIsNotCompatible, - variableName) - .AddLocation(variable) - .SetPath(context.CreateErrorPath()) - .SetExtension("variable", variableName) - .SetExtension("variableType", variableDefinition.Type.ToString()) - .SetExtension("locationType", context.Types.Peek().FullTypeName()) - .SpecifiedBy("sec-All-Variable-Usages-are-Allowed") - .Build(); - } - - public static IError DirectiveNotValidInLocation( - this DocumentValidatorContext context, - DirectiveNode node) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_DirectiveNotValidInLocation) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-Directives-Are-In-Valid-Locations") - .Build(); - } - - public static IError DirectiveNotSupported( - this DocumentValidatorContext context, - DirectiveNode node) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_DirectiveNotSupported, - node.Name.Value) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-Directives-Are-Defined") - .Build(); - } - - public static IError DirectiveMustBeUniqueInLocation( - this DocumentValidatorContext context, - DirectiveNode node) => - ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_DirectiveMustBeUniqueInLocation) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-Directives-Are-Unique-Per-Location") - .Build(); - - public static IError TypeSystemDefinitionNotAllowed( - this DocumentValidatorContext context, - IDefinitionNode node) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_TypeSystemDefinitionNotAllowed) - .AddLocation(node) - .SpecifiedBy("sec-Executable-Definitions") - .Build(); - } - - public static IError UnionFieldError( - this DocumentValidatorContext context, - SelectionSetNode node, - IUnionTypeDefinition type) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_UnionFieldError) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("type", type.Name) - .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") - .Build(); - } - - public static IError FieldDoesNotExist( - this DocumentValidatorContext context, - FieldNode node, - IComplexTypeDefinition outputType) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_FieldDoesNotExist, - node.Name.Value, outputType.Name) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("type", outputType.Name) - .SetExtension("field", node.Name.Value) - .SetExtension("responseName", (node.Alias ?? node.Name).Value) - .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") - .Build(); - } - - public static IError LeafFieldsCannotHaveSelections( - this DocumentValidatorContext context, - FieldNode node, - IComplexTypeDefinition declaringType, - IType fieldType) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_LeafFieldsCannotHaveSelections, - node.Name.Value, - fieldType.FullTypeName()) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("declaringType", declaringType.Name) - .SetExtension("field", node.Name.Value) - .SetExtension("type", fieldType.FullTypeName()) - .SetExtension("responseName", (node.Alias ?? node.Name).Value) - .SpecifiedBy("sec-Leaf-Field-Selections") - .Build(); - } - - public static IError ArgumentValueIsNotCompatible( - this DocumentValidatorContext context, - ArgumentNode node, - IInputType locationType, - IValueNode value) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_ArgumentValueIsNotCompatible) - .AddLocation(value) - .SetPath(context.CreateErrorPath()) - .SetExtension("argument", node.Name.Value) - .SetExtension("argumentValue", value.ToString()) - .SetExtension("locationType", locationType.FullTypeName()) - .SpecifiedBy("sec-Values-of-Correct-Type") - .Build(); - } - - public static IError FieldValueIsNotCompatible( - this DocumentValidatorContext context, - IInputValueDefinition field, - IInputType locationType, - IValueNode valueNode) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FieldValueIsNotCompatible, field.Name) - .AddLocation(valueNode) - .SetExtension("fieldName", field.Name) - .SetExtension("fieldType", field.Type.FullTypeName()) - .SetExtension("locationType", locationType.FullTypeName()) - .SetPath(context.CreateErrorPath()) - .SpecifiedBy("sec-Values-of-Correct-Type") - .Build(); - } - - public static IError VariableDefaultValueIsNotCompatible( - this DocumentValidatorContext context, - VariableDefinitionNode node, - IInputType locationType, - IValueNode valueNode) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_VariableDefaultValueIsNotCompatible, - node.Variable.Name.Value) - .AddLocation(valueNode) - .SetPath(context.CreateErrorPath()) - .SetExtension("variable", node.Variable.Name.Value) - .SetExtension("variableType", node.Type.ToString()) - .SetExtension("locationType", locationType.FullTypeName()) - .SpecifiedBy("sec-Values-of-Correct-Type") + public static IError SkipAndIncludeNotAllowedOnSubscriptionRootField( + ISelectionNode selection) + => ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_SkipAndIncludeNotAllowedOnSubscriptionRootField) + .AddLocation(selection) + .SpecifiedBy("sec-Single-Root-Field", rfc: 860) .Build(); - } - public static IError NoSelectionOnCompositeField( - this DocumentValidatorContext context, - FieldNode node, - IComplexTypeDefinition declaringType, - IType fieldType) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_NoSelectionOnCompositeField, - node.Name.Value, - fieldType.ToTypeNode().ToString()) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("declaringType", declaringType.Name) - .SetExtension("field", node.Name.Value) - .SetExtension("type", fieldType.FullTypeName()) - .SetExtension("responseName", (node.Alias ?? node.Name).Value) - .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") + public static IError DeferAndStreamNotAllowedOnMutationOrSubscriptionRoot( + ISelectionNode selection) + => ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_DeferAndStreamNotAllowedOnMutationOrSubscriptionRoot) + .AddLocation(selection) + .SpecifiedBy("sec-Defer-And-Stream-Directives-Are-Used-On-Valid-Root-Field") .Build(); - } - public static IError NoSelectionOnRootType( - this DocumentValidatorContext context, - OperationDefinitionNode node, - IType fieldType) + extension(DocumentValidatorContext context) { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_NoSelectionOnRootType, - node.Name?.Value ?? "Unnamed") - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("operation", node.Name?.Value ?? "Unnamed") - .SetExtension("type", fieldType.FullTypeName()) - .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") - .Build(); - } + public IError VariableNotUsed(OperationDefinitionNode node, + IEnumerable unusedVariables) + { + return ErrorBuilder.New() + .SetMessage( + "The following variables were not used: " + + $"{string.Join(", ", unusedVariables)}.") + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-All-Variables-Used") + .Build(); + } - public static IError FieldIsRequiredButNull( - this DocumentValidatorContext context, - ISyntaxNode node, - string fieldName) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FieldIsRequiredButNull, fieldName) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("field", fieldName) - .SpecifiedBy("sec-Input-Object-Required-Fields") - .Build(); - } + public IError VariableNotDeclared(OperationDefinitionNode node, + IEnumerable usedVariables) + { + return ErrorBuilder.New() + .SetMessage( + "The following variables were not declared: " + + $"{string.Join(", ", usedVariables)}.") + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-All-Variable-Uses-Defined") + .Build(); + } - public static IError FieldsAreNotMergeable( - this DocumentValidatorContext context, - FieldInfo fieldA, - FieldInfo fieldB) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FieldsAreNotMergeable) - .AddLocation(fieldA.SyntaxNode) - .AddLocation(fieldB.SyntaxNode) - .SetExtension("declaringTypeA", fieldA.DeclaringType.NamedType().Name) - .SetExtension("declaringTypeB", fieldB.DeclaringType.NamedType().Name) - .SetExtension("fieldA", fieldA.SyntaxNode.Name.Value) - .SetExtension("fieldB", fieldB.SyntaxNode.Name.Value) - .SetExtension("typeA", fieldA.Type.FullTypeName()) - .SetExtension("typeB", fieldB.Type.FullTypeName()) - .SetExtension("responseNameA", fieldA.ResponseName) - .SetExtension("responseNameB", fieldB.ResponseName) - .SpecifiedBy("sec-Field-Selection-Merging") - .Build(); - } + public IError OneOfVariableIsNotCompatible(VariableNode variable, + VariableDefinitionNode variableDefinition) + { + var variableName = variableDefinition.Variable.Name.Value; - public static IError OperationNotSupported( - this DocumentValidatorContext context, - OperationType operationType) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_OperationNotSupported, - operationType) - .Build(); - } + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_OneOfVariableIsNotCompatible, + variableName) + .AddLocation(variable) + .SetPath(context.CreateErrorPath()) + .SetExtension("variable", variableName) + .SpecifiedBy("sec-All-Variable-Usages-are-Allowed") + .Build(); + } - public static IError FragmentNameNotUnique( - this DocumentValidatorContext context, - FragmentDefinitionNode fragmentDefinition) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_FragmentNameNotUnique, - fragmentDefinition.Name.Value) - .AddLocation(fragmentDefinition) - .SetExtension("fragment", fragmentDefinition.Name.Value) - .SpecifiedBy("sec-Fragment-Name-Uniqueness") - .Build(); - } + public IError VariableIsNotCompatible(VariableNode variable, + VariableDefinitionNode variableDefinition) + { + var variableName = variableDefinition.Variable.Name.Value; - public static IError FragmentNotUsed( - this DocumentValidatorContext context, - FragmentDefinitionNode fragmentDefinition) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_FragmentNotUsed, - fragmentDefinition.Name.Value) - .AddLocation(fragmentDefinition) - .SetPath(context.CreateErrorPath()) - .SetExtension("fragment", fragmentDefinition.Name.Value) - .SpecifiedBy("sec-Fragments-Must-Be-Used") - .Build(); - } + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_VariableIsNotCompatible, + variableName) + .AddLocation(variable) + .SetPath(context.CreateErrorPath()) + .SetExtension("variable", variableName) + .SetExtension("variableType", variableDefinition.Type.ToString()) + .SetExtension("locationType", context.Types.Peek().FullTypeName()) + .SpecifiedBy("sec-All-Variable-Usages-are-Allowed") + .Build(); + } - public static IError FragmentCycleDetected( - this DocumentValidatorContext context, - FragmentSpreadNode fragmentSpread) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FragmentCycleDetected) - .AddLocation(fragmentSpread) - .SetPath(context.CreateErrorPath()) - .SetExtension("fragment", fragmentSpread.Name.Value) - .SpecifiedBy("sec-Fragment-spreads-must-not-form-cycles") - .Build(); - } + public IError DirectiveNotValidInLocation(DirectiveNode node) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_DirectiveNotValidInLocation) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-Directives-Are-In-Valid-Locations") + .Build(); + } - public static IError FragmentDoesNotExist( - this DocumentValidatorContext context, - FragmentSpreadNode fragmentSpread) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_FragmentDoesNotExist, - fragmentSpread.Name.Value) - .AddLocation(fragmentSpread) - .SetPath(context.CreateErrorPath()) - .SetExtension("fragment", fragmentSpread.Name.Value) - .SpecifiedBy("sec-Fragment-spread-target-defined") - .Build(); - } + public IError DirectiveNotSupported(DirectiveNode node) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_DirectiveNotSupported, + node.Name.Value) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-Directives-Are-Defined") + .Build(); + } - public static IError FragmentNotPossible( - this DocumentValidatorContext context, - ISyntaxNode node, - ITypeDefinition typeCondition, - ITypeDefinition parentType) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FragmentNotPossible) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("typeCondition", typeCondition.Name) - .SetExtension("selectionSetType", parentType.Name) - .SetFragmentName(node) - .SpecifiedBy("sec-Fragment-spread-is-possible") - .Build(); - } + public IError DirectiveMustBeUniqueInLocation(DirectiveNode node) => + ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_DirectiveMustBeUniqueInLocation) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-Directives-Are-Unique-Per-Location") + .Build(); - public static IError FragmentTypeConditionUnknown( - this DocumentValidatorContext context, - ISyntaxNode node, - NamedTypeNode typeCondition) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_FragmentTypeConditionUnknown, - typeCondition.Name.Value) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("typeCondition", typeCondition.Name.Value) - .SetFragmentName(node) - .SpecifiedBy("sec-Fragment-Spread-Type-Existence") - .Build(); - } + public IError TypeSystemDefinitionNotAllowed(IDefinitionNode node) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_TypeSystemDefinitionNotAllowed) + .AddLocation(node) + .SpecifiedBy("sec-Executable-Definitions") + .Build(); + } - public static IError FragmentOnlyCompositeType( - this DocumentValidatorContext context, - ISyntaxNode node, - ITypeDefinition type) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_FragmentOnlyCompositeType) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("typeCondition", type.FullTypeName()) - .SetFragmentName(node) - .SpecifiedBy("sec-Fragments-On-Composite-Types") - .Build(); - } + public IError UnionFieldError(SelectionSetNode node, + IUnionTypeDefinition type) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_UnionFieldError) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("type", type.Name) + .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") + .Build(); + } - public static IError InputFieldAmbiguous( - this DocumentValidatorContext context, - ObjectFieldNode field) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_InputFieldAmbiguous, field.Name.Value) - .AddLocation(field) - .SetPath(context.CreateErrorPath()) - .SetExtension("field", field.Name.Value) - .SpecifiedBy("sec-Input-Object-Field-Uniqueness") - .Build(); - } + public IError FieldDoesNotExist(FieldNode node, + IComplexTypeDefinition outputType) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_FieldDoesNotExist, + node.Name.Value, outputType.Name) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("type", outputType.Name) + .SetExtension("field", node.Name.Value) + .SetExtension("responseName", (node.Alias ?? node.Name).Value) + .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") + .Build(); + } - public static IError InputFieldDoesNotExist( - this DocumentValidatorContext context, - ObjectFieldNode field) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_InputFieldDoesNotExist, - field.Name.Value) - .AddLocation(field) - .SetPath(context.CreateErrorPath()) - .SetExtension("field", field.Name.Value) - .SpecifiedBy("sec-Input-Object-Field-Names") - .Build(); - } + public IError LeafFieldsCannotHaveSelections(FieldNode node, + IComplexTypeDefinition declaringType, + IType fieldType) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_LeafFieldsCannotHaveSelections, + node.Name.Value, + fieldType.FullTypeName()) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("declaringType", declaringType.Name) + .SetExtension("field", node.Name.Value) + .SetExtension("type", fieldType.FullTypeName()) + .SetExtension("responseName", (node.Alias ?? node.Name).Value) + .SpecifiedBy("sec-Leaf-Field-Selections") + .Build(); + } - public static IError InputFieldRequired( - this DocumentValidatorContext context, - ISyntaxNode node, - string fieldName) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_InputFieldRequired, fieldName) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("field", fieldName) - .SpecifiedBy("sec-Input-Object-Required-Fields") - .Build(); - } + public IError ArgumentValueIsNotCompatible(ArgumentNode node, + IInputType locationType, + IValueNode value) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_ArgumentValueIsNotCompatible) + .AddLocation(value) + .SetPath(context.CreateErrorPath()) + .SetExtension("argument", node.Name.Value) + .SetExtension("argumentValue", value.ToString()) + .SetExtension("locationType", locationType.FullTypeName()) + .SpecifiedBy("sec-Values-of-Correct-Type") + .Build(); + } - public static IError OperationNameNotUnique( - this DocumentValidatorContext context, - OperationDefinitionNode operation, - string operationName) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_OperationNameNotUnique, - operationName) - .AddLocation(operation) - .SetExtension("operation", operationName) - .SpecifiedBy("sec-Operation-Name-Uniqueness") - .Build(); - } + public IError FieldValueIsNotCompatible(IInputValueDefinition field, + IInputType locationType, + IValueNode valueNode) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FieldValueIsNotCompatible, field.Name) + .AddLocation(valueNode) + .SetExtension("fieldName", field.Name) + .SetExtension("fieldType", field.Type.FullTypeName()) + .SetExtension("locationType", locationType.FullTypeName()) + .SetPath(context.CreateErrorPath()) + .SpecifiedBy("sec-Values-of-Correct-Type") + .Build(); + } - public static IError OperationAnonymousMoreThanOne( - this DocumentValidatorContext context, - OperationDefinitionNode operation, - int operations) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_OperationAnonymousMoreThanOne) - .AddLocation(operation) - .SetExtension("operations", operations) - .SpecifiedBy("sec-Lone-Anonymous-Operation") - .Build(); - } + public IError VariableDefaultValueIsNotCompatible(VariableDefinitionNode node, + IInputType locationType, + IValueNode valueNode) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_VariableDefaultValueIsNotCompatible, + node.Variable.Name.Value) + .AddLocation(valueNode) + .SetPath(context.CreateErrorPath()) + .SetExtension("variable", node.Variable.Name.Value) + .SetExtension("variableType", node.Type.ToString()) + .SetExtension("locationType", locationType.FullTypeName()) + .SpecifiedBy("sec-Values-of-Correct-Type") + .Build(); + } - public static IError VariableNotInputType( - this DocumentValidatorContext context, - VariableDefinitionNode node, - string variableName) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_VariableNotInputType, variableName) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("variable", variableName) - .SetExtension("variableType", node.Type.ToString()) - .SpecifiedBy("sec-Variables-Are-Input-Types") - .Build(); - } + public IError NoSelectionOnCompositeField(FieldNode node, + IComplexTypeDefinition declaringType, + IType fieldType) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_NoSelectionOnCompositeField, + node.Name.Value, + fieldType.ToTypeNode().ToString()) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("declaringType", declaringType.Name) + .SetExtension("field", node.Name.Value) + .SetExtension("type", fieldType.FullTypeName()) + .SetExtension("responseName", (node.Alias ?? node.Name).Value) + .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") + .Build(); + } - public static IError VariableNameNotUnique( - this DocumentValidatorContext context, - VariableDefinitionNode node, - string variableName) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_VariableNameNotUnique) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension("variable", variableName) - .SetExtension("variableType", node.Type.ToString()) - .SpecifiedBy("sec-Variable-Uniqueness") - .Build(); - } + public IError NoSelectionOnRootType(OperationDefinitionNode node, + IType fieldType) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_NoSelectionOnRootType, + node.Name?.Value ?? "Unnamed") + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("operation", node.Name?.Value ?? "Unnamed") + .SetExtension("type", fieldType.FullTypeName()) + .SpecifiedBy("sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types") + .Build(); + } - public static IError ArgumentNotUnique( - this DocumentValidatorContext context, - ArgumentNode node, - SchemaCoordinate? field = null, - IDirectiveDefinition? directive = null) - { - var builder = ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_ArgumentNotUnique) - .AddLocation(node) - .SetPath(context.CreateErrorPath()); + public IError FieldIsRequiredButNull(ISyntaxNode node, + string fieldName) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FieldIsRequiredButNull, fieldName) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("field", fieldName) + .SpecifiedBy("sec-Input-Object-Required-Fields") + .Build(); + } - if (field.HasValue) + public IError FieldsAreNotMergeable(FieldInfo fieldA, + FieldInfo fieldB) { - builder - .SetExtension("type", field.Value.Name) - .SetExtension("field", field.Value.MemberName); + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FieldsAreNotMergeable) + .AddLocation(fieldA.SyntaxNode) + .AddLocation(fieldB.SyntaxNode) + .SetExtension("declaringTypeA", fieldA.DeclaringType.NamedType().Name) + .SetExtension("declaringTypeB", fieldB.DeclaringType.NamedType().Name) + .SetExtension("fieldA", fieldA.SyntaxNode.Name.Value) + .SetExtension("fieldB", fieldB.SyntaxNode.Name.Value) + .SetExtension("typeA", fieldA.Type.FullTypeName()) + .SetExtension("typeB", fieldB.Type.FullTypeName()) + .SetExtension("responseNameA", fieldA.ResponseName) + .SetExtension("responseNameB", fieldB.ResponseName) + .SpecifiedBy("sec-Field-Selection-Merging") + .Build(); } - if (directive is not null) + public IError OperationNotSupported(OperationType operationType) { - builder.SetExtension("directive", directive.Name); + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_OperationNotSupported, + operationType) + .Build(); } - return builder - .SetExtension("argument", node.Name.Value) - .SpecifiedBy("sec-Argument-Uniqueness") - .Build(); - } + public IError FragmentNameNotUnique(FragmentDefinitionNode fragmentDefinition) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_FragmentNameNotUnique, + fragmentDefinition.Name.Value) + .AddLocation(fragmentDefinition) + .SetExtension("fragment", fragmentDefinition.Name.Value) + .SpecifiedBy("sec-Fragment-Name-Uniqueness") + .Build(); + } - public static IError ArgumentRequired( - this DocumentValidatorContext context, - ISyntaxNode node, - string argumentName, - SchemaCoordinate? field = null, - IDirectiveDefinition? directive = null) - { - var builder = ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_ArgumentRequired, argumentName) - .AddLocation(node) - .SetPath(context.CreateErrorPath()); + public IError FragmentNotUsed(FragmentDefinitionNode fragmentDefinition) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_FragmentNotUsed, + fragmentDefinition.Name.Value) + .AddLocation(fragmentDefinition) + .SetPath(context.CreateErrorPath()) + .SetExtension("fragment", fragmentDefinition.Name.Value) + .SpecifiedBy("sec-Fragments-Must-Be-Used") + .Build(); + } - if (field.HasValue) + public IError FragmentCycleDetected(FragmentSpreadNode fragmentSpread) { - builder - .SetExtension("type", field.Value.Name) - .SetExtension("field", field.Value.MemberName); + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FragmentCycleDetected) + .AddLocation(fragmentSpread) + .SetPath(context.CreateErrorPath()) + .SetExtension("fragment", fragmentSpread.Name.Value) + .SpecifiedBy("sec-Fragment-spreads-must-not-form-cycles") + .Build(); } - if (directive is not null) + public IError FragmentDoesNotExist(FragmentSpreadNode fragmentSpread) { - builder.SetExtension("directive", directive.Name); + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_FragmentDoesNotExist, + fragmentSpread.Name.Value) + .AddLocation(fragmentSpread) + .SetPath(context.CreateErrorPath()) + .SetExtension("fragment", fragmentSpread.Name.Value) + .SpecifiedBy("sec-Fragment-spread-target-defined") + .Build(); } - return builder - .SetExtension("argument", argumentName) - .SpecifiedBy("sec-Required-Arguments") - .Build(); - } + public IError FragmentNotPossible(ISyntaxNode node, + ITypeDefinition typeCondition, + ITypeDefinition parentType) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FragmentNotPossible) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("typeCondition", typeCondition.Name) + .SetExtension("selectionSetType", parentType.Name) + .SetFragmentName(node) + .SpecifiedBy("sec-Fragment-spread-is-possible") + .Build(); + } - public static IError ArgumentDoesNotExist( - this DocumentValidatorContext context, - ArgumentNode node, - SchemaCoordinate? field = null, - IDirectiveDefinition? directive = null) - { - var builder = ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_ArgumentDoesNotExist, node.Name.Value) - .AddLocation(node) - .SetPath(context.CreateErrorPath()); + public IError FragmentTypeConditionUnknown(ISyntaxNode node, + NamedTypeNode typeCondition) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_FragmentTypeConditionUnknown, + typeCondition.Name.Value) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("typeCondition", typeCondition.Name.Value) + .SetFragmentName(node) + .SpecifiedBy("sec-Fragment-Spread-Type-Existence") + .Build(); + } - if (field.HasValue) + public IError FragmentOnlyCompositeType(ISyntaxNode node, + ITypeDefinition type) { - builder - .SetExtension("type", field.Value.Name) - .SetExtension("field", field.Value.MemberName); + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_FragmentOnlyCompositeType) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("typeCondition", type.FullTypeName()) + .SetFragmentName(node) + .SpecifiedBy("sec-Fragments-On-Composite-Types") + .Build(); } - if (directive is not null) + public IError InputFieldAmbiguous(ObjectFieldNode field) { - builder.SetExtension("directive", directive.Name); + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_InputFieldAmbiguous, field.Name.Value) + .AddLocation(field) + .SetPath(context.CreateErrorPath()) + .SetExtension("field", field.Name.Value) + .SpecifiedBy("sec-Input-Object-Field-Uniqueness") + .Build(); } - return builder - .SetExtension("argument", node.Name.Value) - .SpecifiedBy("sec-Required-Arguments") - .Build(); - } + public IError InputFieldDoesNotExist(ObjectFieldNode field) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_InputFieldDoesNotExist, + field.Name.Value) + .AddLocation(field) + .SetPath(context.CreateErrorPath()) + .SetExtension("field", field.Name.Value) + .SpecifiedBy("sec-Input-Object-Field-Names") + .Build(); + } - public static IError SubscriptionSingleRootField( - this DocumentValidatorContext context, - OperationDefinitionNode operation) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_SubscriptionSingleRootField) - .AddLocation(operation) - .SpecifiedBy("sec-Single-root-field") - .Build(); - } + public IError InputFieldRequired(ISyntaxNode node, + string fieldName) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_InputFieldRequired, fieldName) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("field", fieldName) + .SpecifiedBy("sec-Input-Object-Required-Fields") + .Build(); + } - public static IError SubscriptionNoTopLevelIntrospectionField( - this DocumentValidatorContext context, - OperationDefinitionNode operation) - { - return ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_SubscriptionNoTopLevelIntrospectionField) - .AddLocation(operation) - .SpecifiedBy("sec-Single-root-field") - .Build(); - } + public IError OperationNameNotUnique(OperationDefinitionNode operation, + string operationName) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_OperationNameNotUnique, + operationName) + .AddLocation(operation) + .SetExtension("operation", operationName) + .SpecifiedBy("sec-Operation-Name-Uniqueness") + .Build(); + } - public static IError MaxExecutionDepth( - this DocumentValidatorContext context, - OperationDefinitionNode operation, - int allowedExecutionDepth, - int detectedExecutionDepth) - { - return ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_MaxExecutionDepth, - detectedExecutionDepth, allowedExecutionDepth) - .AddLocation(operation) - .SetExtension("allowedExecutionDepth", allowedExecutionDepth) - .SetExtension("detectedExecutionDepth", detectedExecutionDepth) - .Build(); - } + public IError OperationAnonymousMoreThanOne(OperationDefinitionNode operation, + int operations) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_OperationAnonymousMoreThanOne) + .AddLocation(operation) + .SetExtension("operations", operations) + .SpecifiedBy("sec-Lone-Anonymous-Operation") + .Build(); + } - public static IError IntrospectionNotAllowed( - this DocumentValidatorContext context, - FieldNode field, - string? customErrorMessage) - { - var message = customErrorMessage ?? Resources.ErrorHelper_IntrospectionNotAllowed; + public IError VariableNotInputType(VariableDefinitionNode node, + string variableName) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_VariableNotInputType, variableName) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("variable", variableName) + .SetExtension("variableType", node.Type.ToString()) + .SpecifiedBy("sec-Variables-Are-Input-Types") + .Build(); + } - return ErrorBuilder.New() - .SetMessage(message) - .AddLocation(field) - .SetExtension(nameof(field), field.Name) - .SetCode(ErrorCodes.Validation.IntrospectionNotAllowed) - .Build(); - } + public IError VariableNameNotUnique(VariableDefinitionNode node, + string variableName) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_VariableNameNotUnique) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension("variable", variableName) + .SetExtension("variableType", node.Type.ToString()) + .SpecifiedBy("sec-Variable-Uniqueness") + .Build(); + } - public static IError OneOfMustHaveExactlyOneField( - this DocumentValidatorContext context, - ISyntaxNode node, - IInputObjectTypeDefinition type) - => ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_OneOfMustHaveExactlyOneField, type.Name) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetExtension(nameof(type), type.Name) - .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) - .Build(); + public IError ArgumentNotUnique(ArgumentNode node, + SchemaCoordinate? field = null, + IDirectiveDefinition? directive = null) + { + var builder = ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_ArgumentNotUnique) + .AddLocation(node) + .SetPath(context.CreateErrorPath()); + + if (field.HasValue) + { + builder + .SetExtension("type", field.Value.Name) + .SetExtension("field", field.Value.MemberName); + } + + if (directive is not null) + { + builder.SetExtension("directive", directive.Name); + } + + return builder + .SetExtension("argument", node.Name.Value) + .SpecifiedBy("sec-Argument-Uniqueness") + .Build(); + } - public static IError OneOfVariablesMustBeNonNull( - this DocumentValidatorContext context, - ISyntaxNode node, - SchemaCoordinate fieldCoordinate, - string variableName) - => ErrorBuilder.New() - .SetMessage( - Resources.ErrorHelper_OneOfVariablesMustBeNonNull, - variableName, - fieldCoordinate.MemberName!, - fieldCoordinate.Name) - .AddLocation(node) - .SetPath(context.CreateErrorPath()) - .SetCoordinate(fieldCoordinate) - .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) - .Build(); + public IError ArgumentRequired(ISyntaxNode node, + string argumentName, + SchemaCoordinate? field = null, + IDirectiveDefinition? directive = null) + { + var builder = ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_ArgumentRequired, argumentName) + .AddLocation(node) + .SetPath(context.CreateErrorPath()); + + if (field.HasValue) + { + builder + .SetExtension("type", field.Value.Name) + .SetExtension("field", field.Value.MemberName); + } + + if (directive is not null) + { + builder.SetExtension("directive", directive.Name); + } + + return builder + .SetExtension("argument", argumentName) + .SpecifiedBy("sec-Required-Arguments") + .Build(); + } - public static IError SkipAndIncludeNotAllowedOnSubscriptionRootField( - ISelectionNode selection) - => ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_SkipAndIncludeNotAllowedOnSubscriptionRootField) - .AddLocation(selection) - .SpecifiedBy("sec-Single-Root-Field", rfc: 860) - .Build(); + public IError ArgumentDoesNotExist(ArgumentNode node, + SchemaCoordinate? field = null, + IDirectiveDefinition? directive = null) + { + var builder = ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_ArgumentDoesNotExist, node.Name.Value) + .AddLocation(node) + .SetPath(context.CreateErrorPath()); + + if (field.HasValue) + { + builder + .SetExtension("type", field.Value.Name) + .SetExtension("field", field.Value.MemberName); + } + + if (directive is not null) + { + builder.SetExtension("directive", directive.Name); + } + + return builder + .SetExtension("argument", node.Name.Value) + .SpecifiedBy("sec-Required-Arguments") + .Build(); + } - public static IError DeferAndStreamNotAllowedOnMutationOrSubscriptionRoot( - ISelectionNode selection) - => ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_DeferAndStreamNotAllowedOnMutationOrSubscriptionRoot) - .AddLocation(selection) - .SpecifiedBy("sec-Defer-And-Stream-Directives-Are-Used-On-Valid-Root-Field") - .Build(); + public IError SubscriptionSingleRootField(OperationDefinitionNode operation) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_SubscriptionSingleRootField) + .AddLocation(operation) + .SpecifiedBy("sec-Single-root-field") + .Build(); + } - public static IError DeferAndStreamDuplicateLabel( - this DocumentValidatorContext context, - ISyntaxNode selection, - string label) - => ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_DeferAndStreamDuplicateLabel) - .AddLocation(selection) - .SpecifiedBy("sec-Defer-And-Stream-Directive-Labels-Are-Unique") - .SetExtension(nameof(label), label) - .SetPath(context.CreateErrorPath()) - .Build(); + public IError SubscriptionNoTopLevelIntrospectionField(OperationDefinitionNode operation) + { + return ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_SubscriptionNoTopLevelIntrospectionField) + .AddLocation(operation) + .SpecifiedBy("sec-Single-root-field") + .Build(); + } - public static IError DeferAndStreamLabelIsVariable( - this DocumentValidatorContext context, - ISyntaxNode selection, - string variable) - => ErrorBuilder.New() - .SetMessage(Resources.ErrorHelper_DeferAndStreamLabelIsVariable) - .AddLocation(selection) - .SpecifiedBy("sec-Defer-And-Stream-Directive-Labels-Are-Unique") - .SetExtension(nameof(variable), $"${variable}") - .SetPath(context.CreateErrorPath()) - .Build(); + public IError MaxExecutionDepth(OperationDefinitionNode operation, + int allowedExecutionDepth, + int detectedExecutionDepth) + { + return ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_MaxExecutionDepth, + detectedExecutionDepth, allowedExecutionDepth) + .AddLocation(operation) + .SetExtension("allowedExecutionDepth", allowedExecutionDepth) + .SetExtension("detectedExecutionDepth", detectedExecutionDepth) + .Build(); + } - public static IError StreamOnNonListField( - this DocumentValidatorContext context, - ISyntaxNode selection) - => ErrorBuilder.New() - .SetMessage("@stream directive is only valid on list fields.") - .AddLocation(selection) - .SpecifiedBy("sec-Stream-Directives-Are-Used-On-List-Fields") - .SetPath(context.CreateErrorPath()) - .Build(); + public IError IntrospectionNotAllowed(FieldNode field, + string? customErrorMessage) + { + var message = customErrorMessage ?? Resources.ErrorHelper_IntrospectionNotAllowed; + + return ErrorBuilder.New() + .SetMessage(message) + .AddLocation(field) + .SetExtension(nameof(field), field.Name) + .SetCode(ErrorCodes.Validation.IntrospectionNotAllowed) + .Build(); + } - public static void ReportMaxIntrospectionDepthOverflow( - this DocumentValidatorContext context, - ISyntaxNode selection) - { - context.FatalErrorDetected = true; - context.ReportError( - ErrorBuilder.New() - .SetMessage("Maximum allowed introspection depth exceeded.") - .SetCode(ErrorCodes.Validation.MaxIntrospectionDepthOverflow) + public IError OneOfMustHaveExactlyOneField(ISyntaxNode node, + IInputObjectTypeDefinition type) + => ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_OneOfMustHaveExactlyOneField, type.Name) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetExtension(nameof(type), type.Name) + .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) + .Build(); + + public IError OneOfVariablesMustBeNonNull(ISyntaxNode node, + SchemaCoordinate fieldCoordinate, + string variableName) + => ErrorBuilder.New() + .SetMessage( + Resources.ErrorHelper_OneOfVariablesMustBeNonNull, + variableName, + fieldCoordinate.MemberName!, + fieldCoordinate.Name) + .AddLocation(node) + .SetPath(context.CreateErrorPath()) + .SetCoordinate(fieldCoordinate) + .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) + .Build(); + + public IError DeferAndStreamDuplicateLabel(ISyntaxNode selection, + string label) + => ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_DeferAndStreamDuplicateLabel) .AddLocation(selection) + .SpecifiedBy("sec-Defer-And-Stream-Directive-Labels-Are-Unique") + .SetExtension(nameof(label), label) .SetPath(context.CreateErrorPath()) - .Build()); - } + .Build(); - public static void ReportMaxCoordinateCycleDepthOverflow( - this DocumentValidatorContext context, - ISyntaxNode selection) - { - context.FatalErrorDetected = true; + public IError DeferAndStreamLabelIsVariable(ISyntaxNode selection, + string variable) + => ErrorBuilder.New() + .SetMessage(Resources.ErrorHelper_DeferAndStreamLabelIsVariable) + .AddLocation(selection) + .SpecifiedBy("sec-Defer-And-Stream-Directive-Labels-Are-Unique") + .SetExtension(nameof(variable), $"${variable}") + .SetPath(context.CreateErrorPath()) + .Build(); - context.ReportError( - ErrorBuilder.New() - .SetMessage("Maximum allowed coordinate cycle depth was exceeded.") - .SetCode(ErrorCodes.Validation.MaxCoordinateCycleDepthOverflow) + public IError StreamOnNonListField(ISyntaxNode selection) + => ErrorBuilder.New() + .SetMessage("@stream directive is only valid on list fields.") .AddLocation(selection) + .SpecifiedBy("sec-Stream-Directives-Are-Used-On-List-Fields") .SetPath(context.CreateErrorPath()) - .Build()); + .Build(); + + public void ReportMaxIntrospectionDepthOverflow(ISyntaxNode selection) + { + context.FatalErrorDetected = true; + context.ReportError( + ErrorBuilder.New() + .SetMessage("Maximum allowed introspection depth exceeded.") + .SetCode(ErrorCodes.Validation.MaxIntrospectionDepthOverflow) + .AddLocation(selection) + .SetPath(context.CreateErrorPath()) + .Build()); + } + + public void ReportMaxCoordinateCycleDepthOverflow(ISyntaxNode selection) + { + context.FatalErrorDetected = true; + + context.ReportError( + ErrorBuilder.New() + .SetMessage("Maximum allowed coordinate cycle depth was exceeded.") + .SetCode(ErrorCodes.Validation.MaxCoordinateCycleDepthOverflow) + .AddLocation(selection) + .SetPath(context.CreateErrorPath()) + .Build()); + } } } From 1d42995b1c4665dc24719eb75e26f17a1c106691 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 2 Dec 2025 12:12:49 +0100 Subject: [PATCH 15/42] wip --- .../src/Caching/QueryCacheMiddleware.cs | 3 +- .../src/Authorization/AuthorizeMiddleware.cs | 6 +- .../ErrorBuilderExtensions.cs | 23 +- .../Execution.Projections/ExpressionCache.cs | 86 -- ...otChocolateExecutionSelectionExtensions.cs | 18 +- .../Core/src/Features/IFeatureCollection.cs | 23 +- .../Core/src/Types/Execution/ErrorHelper.cs | 22 +- .../Processing/ISelectionVariants.cs | 49 - .../Processing/MiddlewareContext.Global.cs | 2 + .../Processing/MiddlewareContext.Pure.cs | 2 + .../Processing/MiddlewareContext.Selection.cs | 1 - .../Types/Execution/Processing/Operation.cs | 10 +- .../Execution/Processing/OperationCompiler.cs | 8 +- .../OperationFeatureCollection.Selections.cs | 84 + .../Processing/OperationFeatureCollection.cs | 4 +- .../Execution/Processing/OperationPrinter.cs | 238 --- .../Types/Execution/Processing/Selection.cs | 96 +- .../Processing/SelectionFeatureCollection.cs | 44 + .../Execution/Processing/SelectionSet.cs | 43 +- .../SubscriptionExecutor.Subscription.cs | 7 +- .../Processing/Tasks/ResolverTask.Execute.cs | 6 +- .../Processing/Tasks/ResolverTask.Pooling.cs | 1 + .../Processing/Tasks/ResolverTaskFactory.cs | 2 +- .../Processing/ValueCompletion.Leaf.cs | 6 +- .../Processing/ValueCompletion.List.cs | 6 +- .../Execution/Processing/ValueCompletion.cs | 6 +- .../Extensions/ErrorBuilderExtensions.cs | 20 + .../Extensions/ResolverContextExtensions.cs | 1348 ++++++++--------- .../Core/src/Types/HotChocolate.Types.csproj | 16 + .../Resolvers/DefaultResolverCompiler.cs | 1 - .../FieldSyntaxParameterExpressionBuilder.cs | 32 - .../SelectionParameterExpressionBuilder.cs | 9 +- .../src/Types/Resolvers/IResolverContext.cs | 5 + .../Resolvers/ParameterBindingResolver.cs | 1 - .../Types/Text/Json/ResultDocument.WriteTo.cs | 22 +- .../src/Types/Text/Json/ResultDocument.cs | 5 +- .../DirectiveCollectionExtensions.cs | 257 ---- .../Types/Pagination/PagingMiddleware.cs | 2 +- .../Types/Types/Relay/NodeFieldResolvers.cs | 8 +- .../Core/src/Types/Utilities/ErrorHelper.cs | 9 +- .../IsProjectedProjectionOptimizer.cs | 9 +- .../Visitor/IProjectionOptimizer.cs | 2 +- .../Execution/Nodes/Selection.cs | 18 + 43 files changed, 1064 insertions(+), 1496 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionVariants.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs create mode 100644 src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs delete mode 100644 src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/FieldSyntaxParameterExpressionBuilder.cs delete mode 100644 src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveCollectionExtensions.cs diff --git a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs index 266b4011184..190acf51ae9 100644 --- a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs +++ b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs @@ -30,8 +30,7 @@ public async ValueTask InvokeAsync(RequestContext context) } if (!context.TryGetOperation(out var operation) - || !operation.ContextData.TryGetValue(ExecutionContextData.CacheControlHeaderValue, out var value) - || value is not CacheControlHeaderValue cacheControlHeaderValue) + || !operation.Features.TryGet(out var cacheControlHeaderValue)) { return; } diff --git a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs index e7de30d536b..38f27393a8e 100644 --- a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs +++ b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs @@ -69,7 +69,7 @@ private void SetError( .SetMessage(AuthorizeMiddleware_NoDefaultPolicy) .SetCode(ErrorCodes.Authentication.NoDefaultPolicy) .SetPath(context.Path) - .AddLocations(context.Selection.SyntaxNodes) + .AddLocations(context.Selection) .Build(), AuthorizeResult.PolicyNotFound => ErrorBuilder.New() @@ -78,7 +78,7 @@ private void SetError( _directive.Policy!) .SetCode(ErrorCodes.Authentication.PolicyNotFound) .SetPath(context.Path) - .AddLocation(context.Selection.SyntaxNode) + .AddLocations(context.Selection) .Build(), _ => ErrorBuilder.New() @@ -88,7 +88,7 @@ private void SetError( ? ErrorCodes.Authentication.NotAuthorized : ErrorCodes.Authentication.NotAuthenticated) .SetPath(context.Path) - .AddLocation(context.Selection.SyntaxNode) + .AddLocations(context.Selection) .Build() }; } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs index eb9d4a2843b..7b13fee3b11 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs @@ -35,17 +35,36 @@ public ErrorBuilder SetInputPath(Path inputPath) return builder.SetExtension(nameof(inputPath), inputPath); } + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, object? arg) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg)); + } + /// /// Sets the message of the error. /// /// The format of the message. /// The arguments for the message. /// The error builder. - public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, params object?[] args) + public ErrorBuilder SetMessage( + [StringSyntax("CompositeFormat")] string format, +#if NET10_0_OR_GREATER + params ReadOnlySpan args) +#else + params object[] args) +#endif { ArgumentNullException.ThrowIfNull(builder); ArgumentException.ThrowIfNullOrEmpty(format); - ArgumentNullException.ThrowIfNull(args); return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, args)); } diff --git a/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs b/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs deleted file mode 100644 index 17d66d918ec..00000000000 --- a/src/HotChocolate/Core/src/Execution.Projections/ExpressionCache.cs +++ /dev/null @@ -1,86 +0,0 @@ -// ReSharper disable InconsistentlySynchronizedField -using System.Collections.Concurrent; -using System.Diagnostics.CodeAnalysis; -using System.Linq.Expressions; -using GreenDonut.Data; -using HotChocolate.Execution.Processing; - -namespace HotChocolate.Execution.Projections; - -internal sealed class ExpressionCache -{ - private readonly object _writeLock = new(); - private readonly ConcurrentDictionary _cache = new(); - - public bool TryGetExpression( - Selection selection, - [NotNullWhen(true)] out Expression>? expression) - { - if (_cache.TryGetValue(selection.Id, out var cachedExpression) - && cachedExpression is Expression> casted) - { - expression = casted; - return true; - } - - expression = null; - return false; - } - - public Expression> GetOrCreateExpression( - Selection selection, - SelectionExpressionBuilder expressionBuilder) - { - if (!TryGetExpression(selection, out var expression)) - { - lock (_writeLock) - { - if (!TryGetExpression(selection, out expression)) - { - expression = expressionBuilder.BuildExpression(selection); - _cache.TryAdd(selection.Id, expression); - } - } - } - - return expression; - } - - public Expression> GetOrCreateExpression( - Selection selection, - ISelectorBuilder expressionBuilder) - { - if (!TryGetExpression(selection, out var expression)) - { - lock (_writeLock) - { - if (!TryGetExpression(selection, out expression)) - { - expression = expressionBuilder.TryCompile()!; - _cache.TryAdd(selection.Id, expression); - } - } - } - - return expression; - } - - public Expression> GetOrCreateNodeExpression( - Selection selection, - SelectionExpressionBuilder expressionBuilder) - { - if (!TryGetExpression(selection, out var expression)) - { - lock (_writeLock) - { - if (!TryGetExpression(selection, out expression)) - { - expression = expressionBuilder.BuildNodeExpression(selection); - _cache.TryAdd(selection.Id, expression); - } - } - } - - return expression; - } -} diff --git a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs index 6c7740745af..652dedfb075 100644 --- a/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Projections/Extensions/HotChocolateExecutionSelectionExtensions.cs @@ -105,11 +105,7 @@ public static Expression> AsSelector( private static bool TryGetExpression( Selection selection, [NotNullWhen(true)] out Expression>? expression) - { - var features = selection.DeclaringOperation.Features; - var cache = features.GetOrSetSafe(); - return cache.TryGetExpression(selection, out expression); - } + => selection.Features.TryGet(out expression); private static int GetConnectionSelections(Selection selection, Span buffer) { @@ -181,18 +177,12 @@ file static class Extensions extension(Selection selection) { public Expression> GetOrCreateExpression() - => selection.DeclaringOperation.Features - .GetOrSetSafe() - .GetOrCreateExpression(selection, s_builder); + => selection.Features.GetOrSetSafe(() => s_builder.BuildExpression(selection)); public Expression> GetOrCreateExpression(ISelectorBuilder expressionBuilder) - => selection.DeclaringOperation.Features - .GetOrSetSafe() - .GetOrCreateExpression(selection, expressionBuilder); + => selection.Features.GetOrSetSafe(() => expressionBuilder.TryCompile()!); public Expression> GetOrCreateNodeExpression() - => selection.DeclaringOperation.Features - .GetOrSetSafe() - .GetOrCreateNodeExpression(selection, s_builder); + => selection.Features.GetOrSetSafe(() => s_builder.BuildNodeExpression(selection)); } } diff --git a/src/HotChocolate/Core/src/Features/IFeatureCollection.cs b/src/HotChocolate/Core/src/Features/IFeatureCollection.cs index 1e6f6654470..ee319b7b841 100644 --- a/src/HotChocolate/Core/src/Features/IFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Features/IFeatureCollection.cs @@ -36,7 +36,25 @@ public interface IFeatureCollection : IEnumerable> /// /// The feature key. /// The requested feature, or null if it is not present. - TFeature? Get(); + TFeature? Get() + { + if (typeof(TFeature).IsValueType) + { + var feature = this[typeof(TFeature)]; + if (feature is null && Nullable.GetUnderlyingType(typeof(TFeature)) is null) + { + throw new InvalidOperationException( + $"{typeof(TFeature).FullName} does not exist in the feature collection " + + "and because it is a struct the method can't return null. " + + $"Use 'featureCollection[typeof({typeof(TFeature).FullName})] is not null' " + + "to check if the feature exists."); + } + + return (TFeature?)feature; + } + + return (TFeature?)this[typeof(TFeature)]; + } /// /// Tries to retrieve the requested feature from the collection. @@ -55,5 +73,6 @@ public interface IFeatureCollection : IEnumerable> /// /// The feature key. /// The feature value. - void Set(TFeature? instance); + void Set(TFeature? instance) + => this[typeof(TFeature)] = instance; } diff --git a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs index 1de37cf2a30..5ed2a9d615d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs @@ -32,11 +32,11 @@ public static IError ArgumentValueIsInvalid( public static IError InvalidLeafValue( GraphQLException exception, - FieldNode field, + Selection selection, Path path) { return ErrorBuilder.FromError(exception.Errors[0]) - .TryAddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.CannotSerializeLeafValue) .Build(); @@ -44,12 +44,12 @@ public static IError InvalidLeafValue( public static IError UnexpectedLeafValueSerializationError( Exception exception, - FieldNode field, + Selection selection, Path path) { return ErrorBuilder .FromException(exception) - .AddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.CannotSerializeLeafValue) .Build(); @@ -85,24 +85,24 @@ public static IError UnexpectedErrorWhileResolvingAbstractType( public static IError ListValueIsNotSupported( Type listType, - FieldNode field, + Selection selection, Path path) { return ErrorBuilder.New() .SetMessage(ErrorHelper_ListValueIsNotSupported_Message, listType.FullName!) - .AddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.ListTypeNotSupported) .Build(); } public static IError UnexpectedValueCompletionError( - FieldNode field, + Selection selection, Path path) { return ErrorBuilder.New() .SetMessage(ErrorHelper_UnexpectedValueCompletionError_Message) - .AddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.ListTypeNotSupported) .Build(); @@ -137,16 +137,16 @@ public static IOperationResult StateInvalidForOperationExecution() => .Build()); public static IError ValueCompletion_CouldNotResolveAbstractType( - FieldNode field, + Selection selection, Path path, object result) => ErrorBuilder.New() .SetMessage( ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message, result.GetType().FullName ?? result.GetType().Name, - field.Name) + selection.ResponseName) .SetPath(path) - .AddLocation(field) + .AddLocations(selection) .Build(); public static IOperationResult OperationKindNotAllowed() => diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionVariants.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionVariants.cs deleted file mode 100644 index 19d60e8bb67..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ISelectionVariants.cs +++ /dev/null @@ -1,49 +0,0 @@ -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents all the selection set variants of a field. -/// -public interface ISelectionVariants -{ - /// - /// Gets the operation unique id for this variant. - /// - int Id { get; } - - /// - /// Gets the operation that declares this variant. - /// - IOperation DeclaringOperation { get; } - - /// - /// Gets all the possible return types of the field to which this variant belongs to. - /// - IEnumerable GetPossibleTypes(); - - /// - /// Evaluates if the specified type context is a possible type for this variant. - /// - /// - /// The type context to evaluate. - /// - /// - /// Returns true if the specified type context is a possible type for this variant; - /// - bool IsPossibleType(ObjectType typeContext); - - /// - /// Gets the selection set for the specified field return type. - /// - /// - /// The field return type. - /// - /// - /// Returns the selection set for the specified field return type. - /// - /// - /// Invalid field return type. - /// - ISelectionSet GetSelectionSet(ObjectType typeContext); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs index 9211f4d4c0e..d1ba41b2545 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs @@ -33,6 +33,8 @@ public IServiceProvider Services public IVariableValueCollection Variables => _operationContext.Variables; + public ulong IncludeFlags => _operationContext.IncludeFlags; + public CancellationToken RequestAborted { get; private set; } public bool HasCleanupTasks => _cleanupTasks.Count > 0; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs index 20c1d467e6f..896dd713716 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs @@ -65,6 +65,8 @@ public void Clear() public Path Path => PathHelper.CreatePathFromContext(_selection, _parentResult, -1); + public ulong IncludeFlags => parentContext.IncludeFlags; + public CancellationToken RequestAborted => parentContext.RequestAborted; public void ReportError(string errorMessage) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 6efa2b63cac..88ac8f0e8d5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -1,5 +1,4 @@ using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; using HotChocolate.Resolvers; using HotChocolate.Types; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 4c440b5b1c0..10151268f48 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -29,6 +29,7 @@ public sealed class Operation : IOperation internal Operation( string id, string hash, + DocumentNode document, OperationDefinitionNode definition, ObjectType rootType, Schema schema, @@ -41,6 +42,7 @@ internal Operation( { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentException.ThrowIfNullOrWhiteSpace(hash); + ArgumentNullException.ThrowIfNull(document); ArgumentNullException.ThrowIfNull(definition); ArgumentNullException.ThrowIfNull(rootType); ArgumentNullException.ThrowIfNull(schema); @@ -51,6 +53,7 @@ internal Operation( Id = id; Hash = hash; + Document = document; Definition = definition; RootType = rootType; Schema = schema; @@ -80,6 +83,11 @@ internal Operation( /// public string? Name => Definition.Name?.Value; + /// + /// Gets the normalized operation document. + /// + public DocumentNode Document { get; } + /// /// Gets the syntax node representing the operation definition. /// @@ -259,5 +267,5 @@ internal Selection GetSelectionById(int id) internal SelectionSet GetSelectionSetById(int id) => Unsafe.As(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_elementsById), id)); - public override string ToString() => OperationPrinter.Print(this); + public override string ToString() => Definition.ToString(indented: true); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index e83d352bbb0..ee24611434a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -29,12 +29,15 @@ public OperationCompiler( _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); } - public Operation Compile(string id, string hash, OperationDefinitionNode operationDefinition) + public Operation Compile( + string id, + string hash, + OperationDefinitionNode operationDefinition) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentNullException.ThrowIfNull(operationDefinition); - var document = new DocumentNode(new IDefinitionNode[] { operationDefinition }); + var document = new DocumentNode([operationDefinition]); document = _documentRewriter.RewriteDocument(document); operationDefinition = (OperationDefinitionNode)document.Definitions[0]; @@ -68,6 +71,7 @@ public Operation Compile(string id, string hash, OperationDefinitionNode operati return new Operation( id, hash, + document, operationDefinition, rootType, _schema, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs new file mode 100644 index 00000000000..22cda22d024 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs @@ -0,0 +1,84 @@ +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; + +namespace HotChocolate.Execution.Processing; + +[SuppressMessage("ReSharper", "NonAtomicCompoundOperator")] +public sealed partial class OperationFeatureCollection +{ + internal bool TryGet(int selectionId, [NotNullWhen(true)] out TFeature? feature) + { + if (_selectionFeatures.TryGetValue((selectionId, typeof(TFeature)), out var result) + && result is TFeature f) + { + feature = f; + return true; + } + + feature = default; + return false; + } + + internal object? this[int selectionId, Type featureType] + { + get + { + ArgumentOutOfRangeException.ThrowIfLessThan(selectionId, 0); + ArgumentNullException.ThrowIfNull(featureType); + + return _selectionFeatures.GetValueOrDefault((selectionId, featureType)); + } + set + { + ArgumentOutOfRangeException.ThrowIfLessThan(selectionId, 0); + ArgumentNullException.ThrowIfNull(featureType); + + lock (_writeLock) + { + if (value == null) + { + _selectionFeatures = _selectionFeatures.Remove((selectionId, featureType)); + _containerRevision++; + return; + } + + _selectionFeatures = _selectionFeatures.SetItem((selectionId, featureType), value); + _containerRevision++; + } + } + } + + internal TFeature GetOrSetSafe(int selectionId, Func factory) + { + ArgumentNullException.ThrowIfNull(factory); + + if (!TryGet(selectionId, out var feature)) + { + lock (_writeLock) + { + if (!TryGet(selectionId, out feature)) + { + feature = factory(); + this[selectionId, typeof(TFeature)] = feature; + } + } + } + + return feature; + } + + internal IEnumerable> GetFeatures(int selectionId) + { + foreach (var ((id, type), value) in _selectionFeatures) + { + if (selectionId == id) + { + yield return new KeyValuePair(type, value); + } + } + } + + internal bool HasFeatures(int selectionId) + => !_selectionFeatures.IsEmpty + && _selectionFeatures.Keys.Any(t => t.Item1 == selectionId); +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs index 553e910d594..69972333267 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Execution.Processing; [SuppressMessage("ReSharper", "NonAtomicCompoundOperator")] -public sealed class OperationFeatureCollection : IFeatureCollection +public sealed partial class OperationFeatureCollection : IFeatureCollection { #if NET9_0_OR_GREATER private readonly Lock _writeLock = new(); @@ -15,8 +15,10 @@ public sealed class OperationFeatureCollection : IFeatureCollection #endif #if NET10_0_OR_GREATER private ImmutableDictionary _features = []; + private ImmutableDictionary<(int, Type), object> _selectionFeatures = []; #else private ImmutableDictionary _features = ImmutableDictionary.Empty; + private ImmutableDictionary<(int, Type), object> _selectionFeatures = ImmutableDictionary<(int, Type), object>.Empty; #endif private volatile int _containerRevision; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs deleted file mode 100644 index 22c45421c45..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationPrinter.cs +++ /dev/null @@ -1,238 +0,0 @@ -using HotChocolate.Language; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -/// -/// This operation printer is made for testing purposes. -/// -internal static class OperationPrinter -{ - public static string Print(Operation operation) - { - var directives = operation.Definition.Directives; - - if (operation.IncludeConditions.Count > 0) - { - var temp = operation.Definition.Directives.ToList(); - directives = temp; - - for (var i = 0; i < operation.IncludeConditions.Count; i++) - { - var includeCondition = operation.IncludeConditions[i]; - long flag = 2 ^ i; - - var arguments = new List { new("flag", new IntValueNode(flag)) }; - - if (includeCondition.Skip is BooleanValueNode) - { - arguments.Add(new ArgumentNode("skip", includeCondition.Skip)); - } - - if (includeCondition.Include is BooleanValueNode) - { - arguments.Add(new ArgumentNode("include", includeCondition.Include)); - } - - temp.Add(new DirectiveNode("includeCondition", arguments)); - } - } - - var definitions = new List(); - var context = new PrintContext(operation, operation.SelectionVariants[0], definitions); - - var selectionSet = Visit(context); - - var operationDefinition = new OperationDefinitionNode( - operation.Definition.Location, - operation.Definition.Name, - operation.Definition.Description, - operation.Definition.Operation, - operation.Definition.VariableDefinitions, - directives, - selectionSet); - definitions.Insert(0, operationDefinition); - - return new DocumentNode(definitions).ToString(); - } - - private static SelectionSetNode Visit(PrintContext context) - { - var fragments = new List(); - - foreach (var objectType in context.SelectionVariants.GetPossibleTypes()) - { - var typeContext = objectType; - var selectionSet = context.SelectionVariants.GetSelectionSet(typeContext); - var selections = new List(); - - fragments.Add(new InlineFragmentNode( - null, - new NamedTypeNode(typeContext.Name), - Array.Empty(), - CreateSelectionSet(context, selectionSet, selections))); - - foreach (var fragment in selectionSet.Fragments) - { - if (context.GetOrCreateFragmentName(fragment.SelectionSet.Id, out var fragmentName)) - { - var index = context.Definitions.Count; - context.Definitions.Add(null!); - - context.Definitions[index] = - new FragmentDefinitionNode( - null, - new(fragmentName), - description: null, - Array.Empty(), - new NamedTypeNode(typeContext.Name), - Array.Empty(), - CreateSelectionSet(context, fragment.SelectionSet, [])); - } - - selections.Add( - new FragmentSpreadNode( - null, - new(fragmentName), - new[] { new DirectiveNode("defer") })); - } - } - - return new SelectionSetNode(fragments); - } - - private static SelectionSetNode CreateSelectionSet( - PrintContext context, - ISelectionSet selectionSet, - List selections) - { - foreach (var selection in selectionSet.Selections) - { - var selectionSetId = ((Selection)selection).SelectionSetId; - SelectionSetNode? selectionSetNode = null; - - if (selection.SelectionSet is not null) - { - var childSelectionSet = context.Operation.SelectionVariants[selectionSetId]; - selectionSetNode = Visit(context.Branch(childSelectionSet)); - } - - selections.Add(CreateSelection(selection, selectionSetNode)); - } - - return new SelectionSetNode(selections); - } - - private static FieldNode CreateSelection( - ISelection selection, - SelectionSetNode? selectionSet) - { - var directives = new List(); - - if (selection.IsConditional) - { - directives.Add(new DirectiveNode("conditional")); - } - - directives.Add(CreateExecutionInfo(selection)); - - return new FieldNode( - null, - selection.SyntaxNode.Name, - selection.SyntaxNode.Alias, - directives, - selection.SyntaxNode.Arguments, - selectionSet); - } - - private static DirectiveNode CreateExecutionInfo(ISelection selection) - { - var arguments = new ArgumentNode[selection.IsInternal ? 4 : 3]; - arguments[0] = new ArgumentNode("id", new IntValueNode(selection.Id)); - arguments[1] = new ArgumentNode("kind", new EnumValueNode(selection.Strategy)); - - if (selection.Type.IsListType()) - { - if (selection.Type.NamedType().IsLeafType()) - { - arguments[2] = new ArgumentNode("type", new EnumValueNode("LEAF_LIST")); - } - else - { - arguments[2] = new ArgumentNode("type", new EnumValueNode("COMPOSITE_LIST")); - } - } - else if (selection.Type.IsCompositeType()) - { - arguments[2] = new ArgumentNode("type", new EnumValueNode("COMPOSITE")); - } - else if (selection.Type.IsLeafType()) - { - arguments[2] = new ArgumentNode("type", new EnumValueNode("LEAF")); - } - - if (selection.IsInternal) - { - arguments[3] = new ArgumentNode("internal", BooleanValueNode.True); - } - - return new DirectiveNode("__execute", arguments); - } - - private sealed class PrintContext - { - private readonly GlobalState _state; - - public PrintContext( - Operation operation, - ISelectionVariants selectionVariants, - List definitions) - { - Operation = operation; - SelectionVariants = selectionVariants; - Definitions = definitions; - _state = new(); - } - - private PrintContext( - Operation operation, - ISelectionVariants selectionVariants, - List definitions, - GlobalState state) - { - Operation = operation; - SelectionVariants = selectionVariants; - Definitions = definitions; - _state = state; - } - - public Operation Operation { get; } - - public ISelectionVariants SelectionVariants { get; } - - public List Definitions { get; } - - public bool GetOrCreateFragmentName(int selectionSetId, out string fragmentName) - { - if (!_state.FragmentNames.TryGetValue(selectionSetId, out var name)) - { - name = $"Fragment_{_state.FragmentId++}"; - _state.FragmentNames.Add(selectionSetId, name); - fragmentName = name; - return true; - } - - fragmentName = name; - return false; - } - - public PrintContext Branch(ISelectionVariants selectionVariants) - => new(Operation, selectionVariants, Definitions, _state); - - private sealed class GlobalState - { - public int FragmentId; - public readonly Dictionary FragmentNames = []; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index cd95444549b..b782c6cf467 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -1,5 +1,5 @@ -using System.Diagnostics; using HotChocolate.Execution.Properties; +using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Resolvers; using HotChocolate.Types; @@ -9,7 +9,7 @@ namespace HotChocolate.Execution.Processing; /// /// Represents a field selection during execution. /// -public class Selection : ISelection +public sealed class Selection : ISelection, IFeatureProvider { private static readonly ArgumentMap s_emptyArguments = ArgumentMap.Empty; private readonly FieldSelectionNode[] _syntaxNodes; @@ -24,9 +24,9 @@ internal Selection( FieldSelectionNode[] syntaxNodes, ulong[] includeFlags, bool isInternal, - ArgumentMap? arguments = null, - FieldDelegate? resolverPipeline = null, - PureFieldDelegate? pureResolver = null) + ArgumentMap? arguments, + FieldDelegate? resolverPipeline, + PureFieldDelegate? pureResolver) { ArgumentNullException.ThrowIfNull(field); @@ -71,42 +71,84 @@ internal Selection( internal ReadOnlySpan Utf8ResponseName => _utf8ResponseName; + /// public bool IsInternal => (_flags & Flags.Internal) == Flags.Internal; + /// public bool IsConditional => _includeFlags.Length > 0; + /// + /// Gets a value indicating whether this selection returns a list type. + /// public bool IsList => (_flags & Flags.List) == Flags.List; + /// public bool IsLeaf => (_flags & Flags.Leaf) == Flags.Leaf; /// - /// Defines if this selection has child selections. + /// Gets a value indicating whether this selection has child selections. /// public bool HasSelections => !IsLeaf; + /// + /// Gets the field definition from the schema that this selection targets. + /// public ObjectField Field { get; } /// IOutputFieldDefinition ISelection.Field => Field; + /// public IType Type => Field.Type; + /// + /// Gets the object type that declares the field being selected. + /// public ObjectType DeclaringType => Field.DeclaringType; + /// + /// Gets the selection set that contains this selection. + /// public SelectionSet DeclaringSelectionSet { get; private set; } = null!; + /// ISelectionSet ISelection.DeclaringSelectionSet => DeclaringSelectionSet; + /// + /// Gets the operation that contains this selection. + /// public Operation DeclaringOperation => DeclaringSelectionSet.DeclaringOperation; + /// + /// Gets the selection features. + /// + public SelectionFeatureCollection Features => new(DeclaringOperation.Features, Id); + + IFeatureCollection IFeatureProvider.Features => Features; + + /// + /// Gets the arguments that were provided to this field selection. + /// public ArgumentMap Arguments { get; } + /// + /// Gets the execution strategy for this selection. + /// public SelectionExecutionStrategy Strategy { get; private set; } + /// + /// Gets the resolver pipeline delegate for this selection. + /// public FieldDelegate? ResolverPipeline { get; private set; } + /// + /// Gets the pure resolver delegate for this selection. + /// public PureFieldDelegate? PureResolver { get; private set; } + /// + /// Gets the syntax nodes that contributed to this selection. + /// public ReadOnlySpan SyntaxNodes => _syntaxNodes; IEnumerable ISelection.GetSyntaxNodes() @@ -117,6 +159,17 @@ IEnumerable ISelection.GetSyntaxNodes() } } + /// + /// Determines whether this selection should be skipped based on conditional flags. + /// + /// The conditional inclusion flags. + /// + /// true if this selection should be included; otherwise, false. + /// + public bool IsSkipped(ulong includeFlags) + => IsIncluded(includeFlags); + + /// public bool IsIncluded(ulong includeFlags) { if (_includeFlags.Length == 0) @@ -232,35 +285,4 @@ private enum Flags Stream = 8, Leaf = 16 } - - internal sealed class Sealed : Selection - { - public Sealed( - int id, - ObjectType declaringType, - ObjectField field, - IType type, - FieldNode syntaxNode, - string responseName, - ArgumentMap? arguments = null, - ulong[]? includeConditions = null, - bool isInternal = false, - bool isParallelExecutable = true, - FieldDelegate? resolverPipeline = null, - PureFieldDelegate? pureResolver = null) : base( - id, - declaringType, - field, - type, - syntaxNode, - responseName, - arguments, - includeConditions, - isInternal, - isParallelExecutable, - resolverPipeline, - pureResolver) - { - } - } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs new file mode 100644 index 00000000000..c122ee84ae3 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using HotChocolate.Features; + +namespace HotChocolate.Execution.Processing; + +public readonly struct SelectionFeatureCollection : IFeatureCollection +{ + private readonly OperationFeatureCollection _parent; + private readonly int _selectionId; + + internal SelectionFeatureCollection(OperationFeatureCollection parent, int selectionId) + { + _parent = parent; + _selectionId = selectionId; + } + + public bool IsReadOnly => _parent.IsReadOnly; + + public bool IsEmpty => !_parent.HasFeatures(_selectionId); + + public int Revision => _parent.Revision; + + public object? this[Type key] + { + get => _parent[_selectionId, key]; + set => _parent[_selectionId, key] = value; + } + + public bool TryGet([NotNullWhen(true)] out TFeature? feature) + => _parent.TryGet(_selectionId, out feature); + + public TFeature GetOrSetSafe() where TFeature : new() + => GetOrSetSafe(static () => new TFeature()); + + internal TFeature GetOrSetSafe(Func factory) + => _parent.GetOrSetSafe(_selectionId, factory); + + public IEnumerator> GetEnumerator() + => _parent.GetFeatures(_selectionId).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 39af1b52e5a..46cce24dd61 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -1,4 +1,5 @@ using System.Collections.Frozen; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using HotChocolate.Types; @@ -17,7 +18,7 @@ public sealed class SelectionSet : ISelectionSet private readonly SelectionLookup _utf8ResponseNameLookup; private Flags _flags; - public SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, bool isConditional) + internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, bool isConditional) { ArgumentNullException.ThrowIfNull(selections); @@ -63,6 +64,36 @@ public SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, IEnumerable ISelectionSet.GetSelections() => _selections; + /// + /// Tries to resolve a selection by name. + /// + /// + /// The selection response name. + /// + /// + /// The resolved selection. + /// + /// + /// Returns true if the selection was successfully resolved. + /// + public bool TryGetSelection(string responseName, [NotNullWhen(true)] out Selection? selection) + => _responseNameLookup.TryGetValue(responseName, out selection); + + /// + /// Tries to resolve a selection by name. + /// + /// + /// The selection response name. + /// + /// + /// The resolved selection. + /// + /// + /// Returns true if the selection was successfully resolved. + /// + public bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out Selection? selection) + => _utf8ResponseNameLookup.TryGetSelection(utf8ResponseName, out selection); + internal void Complete(Operation declaringOperation, bool seal) { if ((_flags & Flags.Sealed) == Flags.Sealed) @@ -83,16 +114,6 @@ internal void Complete(Operation declaringOperation, bool seal) } } - /// - /// Returns a reference to the 0th element of the underlying selections array. - /// If the selections array is empty, returns a reference to the location where the 0th element - /// would have been stored. Such a reference may or may not be null. - /// It can be used for pinning but must never be de-referenced. - /// This is only meant for use by the execution engine. - /// - internal ref Selection GetSelectionsReference() - => ref MemoryMarshal.GetReference(_selections.AsSpan()); - [Flags] private enum Flags { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs index 5d0609fafb7..ef15af5a215 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs @@ -3,7 +3,6 @@ using HotChocolate.Execution.Internal; using HotChocolate.Fetching; using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.ObjectPool; namespace HotChocolate.Execution.Processing; @@ -20,7 +19,7 @@ private sealed class Subscription : ISubscription, IAsyncDisposable private IDisposable? _subscriptionScope; private readonly RequestContext _requestContext; private readonly ObjectType _subscriptionType; - private readonly ISelectionSet _rootSelections; + private readonly SelectionSet _rootSelections; private readonly Func _resolveQueryRootValue; private ISourceStream _sourceStream = null!; private object? _cachedRootValue; @@ -33,7 +32,7 @@ private Subscription( QueryExecutor queryExecutor, RequestContext requestContext, ObjectType subscriptionType, - ISelectionSet rootSelections, + SelectionSet rootSelections, Func resolveQueryRootValue, IExecutionDiagnosticEvents diagnosticEvents) { @@ -85,7 +84,7 @@ public static async ValueTask SubscribeAsync( QueryExecutor queryExecutor, RequestContext requestContext, ObjectType subscriptionType, - ISelectionSet rootSelections, + SelectionSet rootSelections, Func resolveQueryRootValue, IExecutionDiagnosticEvents diagnosticsEvents) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs index 112df731c60..0ffe890c8a2 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs @@ -1,6 +1,5 @@ using HotChocolate.Execution.Internal; using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; using System.Runtime.InteropServices; namespace HotChocolate.Execution.Processing.Tasks; @@ -168,6 +167,8 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat _context.Result = await postProcessor.ToCompletionResultAsync(result, cancellationToken).ConfigureAwait(false); } + // TODO : DEFER + /* private async ValueTask> CreateStreamResultAsync(IAsyncEnumerable stream) { var streamDirective = _selection.GetStreamDirective(_context.Variables)!; @@ -203,7 +204,6 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat // TODO : DEFER // if the stream has more items than the initial requested items then we will // defer the rest of the stream. - /* _operationContext.DeferredScheduler.Register( new DeferredStream( Selection, @@ -214,7 +214,6 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat enumerator, _context.ScopedContextData), _context.ParentResult); - */ } return list; @@ -230,6 +229,7 @@ private async ValueTask ExecuteResolverPipelineAsync(CancellationToken cancellat } } } + */ /// /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs index a5d30fe42a4..5bd5f9edf88 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs @@ -40,6 +40,7 @@ internal bool Reset() Next = null; Previous = null; State = null; + _task = null; _taskBuffer.Clear(); _args.Clear(); return true; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index 420df73c557..c54b36a56f5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -251,7 +251,7 @@ private static void ResolveAndCompleteInline( private static void CompleteInline( OperationContext operationContext, MiddlewareContext resolverContext, - ISelection selection, + Selection selection, IType type, int responseIndex, ObjectResult parentResult, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs index b5adb3b5674..a2866256f59 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs @@ -9,7 +9,7 @@ internal static partial class ValueCompletion { private static object? CompleteLeafValue( ValueCompletionContext context, - ISelection selection, + Selection selection, IType type, ResultData parent, int index, @@ -34,13 +34,13 @@ internal static partial class ValueCompletion catch (SerializationException ex) { var errorPath = CreatePathFromContext(selection, parent, index); - var error = InvalidLeafValue(ex, selection.SyntaxNode, errorPath); + var error = InvalidLeafValue(ex, selection, errorPath); operationContext.ReportError(error, resolverContext, selection); } catch (Exception ex) { var errorPath = CreatePathFromContext(selection, parent, index); - var error = UnexpectedLeafValueSerializationError(ex, selection.SyntaxNode, errorPath); + var error = UnexpectedLeafValueSerializationError(ex, selection, errorPath); operationContext.ReportError(error, resolverContext, selection); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs index 4608d697f24..cfa0ba15099 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs @@ -10,7 +10,7 @@ internal static partial class ValueCompletion { private static object? CompleteListValue( ValueCompletionContext context, - ISelection selection, + Selection selection, IType type, ResultData parent, int index, @@ -114,7 +114,7 @@ internal static partial class ValueCompletion } var errorPath = CreatePathFromContext(selection, parent, index); - var error = ListValueIsNotSupported(result.GetType(), selection.SyntaxNode, errorPath); + var error = ListValueIsNotSupported(result.GetType(), selection, errorPath); operationContext.ReportError(error, resolverContext, selection); return null; @@ -122,7 +122,7 @@ internal static partial class ValueCompletion private static bool TryCompleteElement( ValueCompletionContext context, - ISelection selection, + Selection selection, IType elementType, bool isLeafType, ListResult list, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs index a18286305d3..3eb8a859f72 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs @@ -8,7 +8,7 @@ internal static partial class ValueCompletion { public static object? Complete( ValueCompletionContext context, - ISelection selection, + Selection selection, ResultData parent, int index, object? result) @@ -16,7 +16,7 @@ internal static partial class ValueCompletion public static object? Complete( ValueCompletionContext context, - ISelection selection, + Selection selection, IType type, ResultData parent, int index, @@ -51,7 +51,7 @@ internal static partial class ValueCompletion } var errorPath = CreatePathFromContext(selection, parent, index); - var error = UnexpectedValueCompletionError(selection.SyntaxNode, errorPath); + var error = UnexpectedValueCompletionError(selection, errorPath); context.OperationContext.ReportError(error, context.ResolverContext, selection); return null; } diff --git a/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs new file mode 100644 index 00000000000..7a6362d85c2 --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using HotChocolate.Execution.Processing; + +namespace HotChocolate; + +internal static class ErrorBuilderExtensions +{ + public static ErrorBuilder AddLocations(this ErrorBuilder errorBuilder, Selection selection) + { + Debug.Assert(errorBuilder is not null); + Debug.Assert(selection is not null); + + foreach (var syntaxNode in selection.SyntaxNodes) + { + errorBuilder.AddLocation(syntaxNode.Node); + } + + return errorBuilder; + } +} diff --git a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs index 8936dc920b4..29c5d692654 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs @@ -8,779 +8,750 @@ namespace HotChocolate; public static class ResolverContextExtensions { - /// - /// Gets the global state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the global state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T? GetGlobalStateOrDefault( - this IResolverContext context, - string name) + extension(IResolverContext context) { - ArgumentNullException.ThrowIfNull(context); + /// + /// Gets the global state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the global state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T? GetGlobalStateOrDefault(string name) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + if (context.ContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } + + return default; } - if (context.ContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the global state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The default value. + /// The type of the state. + /// + /// Returns the global state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T GetGlobalStateOrDefault(string name, + T defaultValue) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return default; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the global state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The default value. - /// The type of the state. - /// - /// Returns the global state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T GetGlobalStateOrDefault( - this IResolverContext context, - string name, - T defaultValue) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + return defaultValue; } - if (context.ContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the global state for the specified , + /// or throws if the state does not exist. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the global state for the specified . + /// + public T GetGlobalState(string name) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return defaultValue; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the global state for the specified , - /// or throws if the state does not exist. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the global state for the specified . - /// - public static T GetGlobalState( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ContextData.TryGetValue(name, out var value) && value is T typedValue) + { + return typedValue; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + throw new ArgumentException( + string.Format(ResolverContextExtensions_ContextData_KeyNotFound, name)); } - if (context.ContextData.TryGetValue(name, out var value) && value is T typedValue) + /// + /// Gets the scoped state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the scoped state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T? GetScopedStateOrDefault(string name) { - return typedValue; - } + ArgumentNullException.ThrowIfNull(context); - throw new ArgumentException( - string.Format(ResolverContextExtensions_ContextData_KeyNotFound, name)); - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the scoped state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the scoped state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T? GetScopedStateOrDefault( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ScopedContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + return default; } - if (context.ScopedContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the scoped state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The default value. + /// The type of the state. + /// + /// Returns the scoped state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T GetScopedStateOrDefault(string name, + T defaultValue) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return default; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the scoped state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The default value. - /// The type of the state. - /// - /// Returns the scoped state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T GetScopedStateOrDefault( - this IResolverContext context, - string name, - T defaultValue) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ScopedContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + return defaultValue; } - if (context.ScopedContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the scoped state for the specified , + /// or throws if the state does not exist. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the scoped state for the specified . + /// + public T GetScopedState(string name) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return defaultValue; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the scoped state for the specified , - /// or throws if the state does not exist. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the scoped state for the specified . - /// - public static T GetScopedState( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ScopedContextData.TryGetValue(name, out var value) + && value is T typedValue) + { + return typedValue; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + throw new ArgumentException( + string.Format(ResolverContextExtensions_ScopedContextData_KeyNotFound, name)); } - if (context.ScopedContextData.TryGetValue(name, out var value) - && value is T typedValue) + /// + /// Gets the local state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the local state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T? GetLocalStateOrDefault(string name) { - return typedValue; - } + ArgumentNullException.ThrowIfNull(context); - throw new ArgumentException( - string.Format(ResolverContextExtensions_ScopedContextData_KeyNotFound, name)); - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the local state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the local state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T? GetLocalStateOrDefault( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.LocalContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + return default; } - if (context.LocalContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the local state for the specified , + /// or a default value if the state could not be resolved. + /// + /// The name of the state. + /// The default value. + /// The type of the state. + /// + /// Returns the local state for the specified + /// or the default value of , if the state + /// could not be found or cast to . + /// + public T GetLocalStateOrDefault(string name, + T defaultValue) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return default; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the local state for the specified , - /// or a default value if the state could not be resolved. - /// - /// The resolver context. - /// The name of the state. - /// The default value. - /// The type of the state. - /// - /// Returns the local state for the specified - /// or the default value of , if the state - /// could not be found or cast to . - /// - public static T GetLocalStateOrDefault( - this IResolverContext context, - string name, - T defaultValue) - { - ArgumentNullException.ThrowIfNull(context); + if (context.LocalContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + return defaultValue; } - if (context.LocalContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Gets the local state for the specified , + /// or throws if the state does not exist. + /// + /// The name of the state. + /// The type of the state. + /// + /// Returns the local state for the specified . + /// + public T GetLocalState(string name) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - return defaultValue; - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the local state for the specified , - /// or throws if the state does not exist. - /// - /// The resolver context. - /// The name of the state. - /// The type of the state. - /// - /// Returns the local state for the specified . - /// - public static T GetLocalState( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.LocalContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + throw new ArgumentException( + string.Format(ResolverContextExtensions_LocalContextData_KeyNotFound, name)); } - if (context.LocalContextData.TryGetValue(name, out var value) - && value is T casted) + /// + /// Sets the global state for + /// to the specified . + /// State set previously using the same + /// will be overwritten. + /// + /// The name of the state. + /// The new state value. + /// The type of the state. + public void SetGlobalState(string name, + T value) { - return casted; - } + ArgumentNullException.ThrowIfNull(context); - throw new ArgumentException( - string.Format(ResolverContextExtensions_LocalContextData_KeyNotFound, name)); - } - - /// - /// Sets the global state for - /// to the specified . - /// State set previously using the same - /// will be overwritten. - /// - /// The resolver context. - /// The name of the state. - /// The new state value. - /// The type of the state. - public static void SetGlobalState( - this IResolverContext context, - string name, - T value) - { - ArgumentNullException.ThrowIfNull(context); + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + context.ContextData[name] = value; } - context.ContextData[name] = value; - } - - /// - /// Sets the scoped state for - /// to the specified . - /// State set previously using the same - /// will be overwritten. - /// - /// The resolver context. - /// The name of the state. - /// The new state value. - /// The type of the state. - public static void SetScopedState( - this IResolverContext context, - string name, - T value) - { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) + /// + /// Sets the scoped state for + /// to the specified . + /// State set previously using the same + /// will be overwritten. + /// + /// The name of the state. + /// The new state value. + /// The type of the state. + public void SetScopedState(string name, + T value) { - throw String_NullOrEmpty(nameof(name)); - } - - context.ScopedContextData = context.ScopedContextData.SetItem(name, value); - } + ArgumentNullException.ThrowIfNull(context); - /// - /// Sets the local state for - /// to the specified . - /// State set previously using the same - /// will be overwritten. - /// - /// The resolver context. - /// The name of the state. - /// The new state value. - /// The type of the state. - public static void SetLocalState( - this IResolverContext context, - string name, - T value) - { - ArgumentNullException.ThrowIfNull(context); + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + context.ScopedContextData = context.ScopedContextData.SetItem(name, value); } - context.LocalContextData = context.LocalContextData.SetItem(name, value); - } - - /// - /// Gets or sets the global state for the specified . - /// - /// The resolver context. - /// The name of the state. - /// - /// A function that receives the name of the state as an argument - /// and returns the new state value that should be set. - /// - /// The type of the state. - /// - /// The existing state for the specified , - /// or the newly created state using the function. - /// - public static T GetOrSetGlobalState( - this IResolverContext context, - string name, - Func createValue) - { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) + /// + /// Sets the local state for + /// to the specified . + /// State set previously using the same + /// will be overwritten. + /// + /// The name of the state. + /// The new state value. + /// The type of the state. + public void SetLocalState(string name, + T value) { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(createValue); + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (context.ContextData.TryGetValue(name, out var value) - && value is T casted) - { - return casted; + context.LocalContextData = context.LocalContextData.SetItem(name, value); } - var newValue = createValue(name); - SetGlobalState(context, name, newValue); - return newValue; - } - - /// - /// Gets or sets the scoped state for the specified . - /// - /// The resolver context. - /// The name of the state. - /// - /// A function that receives the name of the state as an argument - /// and returns the new state value that should be set. - /// - /// The type of the state. - /// - /// The existing state for the specified , - /// or the newly created state using the function. - /// - public static T GetOrSetScopedState( - this IResolverContext context, - string name, - Func createValue) - { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) + /// + /// Gets or sets the global state for the specified . + /// + /// The name of the state. + /// + /// A function that receives the name of the state as an argument + /// and returns the new state value that should be set. + /// + /// The type of the state. + /// + /// The existing state for the specified , + /// or the newly created state using the function. + /// + public T GetOrSetGlobalState(string name, + Func createValue) { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(createValue); + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (context.ScopedContextData.TryGetValue(name, out var value) - && value is T casted) - { - return casted; - } + ArgumentNullException.ThrowIfNull(createValue); - var newValue = createValue(name); - SetScopedState(context, name, newValue); - return newValue; - } + if (context.ContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - /// - /// Gets or sets the local state for the specified . - /// - /// The resolver context. - /// The name of the state. - /// - /// A function that receives the name of the state as an argument - /// and returns the new state value that should be set. - /// - /// The type of the state. - /// - /// The existing state for the specified , - /// or the newly created state using the function. - /// - public static T GetOrSetLocalState( - this IResolverContext context, - string name, - Func createValue) - { - ArgumentNullException.ThrowIfNull(context); + var newValue = createValue(name); + SetGlobalState(context, name, newValue); + return newValue; + } + + /// + /// Gets or sets the scoped state for the specified . + /// + /// The name of the state. + /// + /// A function that receives the name of the state as an argument + /// and returns the new state value that should be set. + /// + /// The type of the state. + /// + /// The existing state for the specified , + /// or the newly created state using the function. + /// + public T GetOrSetScopedState(string name, + Func createValue) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentNullException.ThrowIfNull(createValue); - ArgumentNullException.ThrowIfNull(createValue); + if (context.ScopedContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (context.LocalContextData.TryGetValue(name, out var value) - && value is T casted) - { - return casted; - } + var newValue = createValue(name); + SetScopedState(context, name, newValue); + return newValue; + } + + /// + /// Gets or sets the local state for the specified . + /// + /// The name of the state. + /// + /// A function that receives the name of the state as an argument + /// and returns the new state value that should be set. + /// + /// The type of the state. + /// + /// The existing state for the specified , + /// or the newly created state using the function. + /// + public T GetOrSetLocalState(string name, + Func createValue) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - var newValue = createValue(name); - SetLocalState(context, name, newValue); - return newValue; - } + ArgumentNullException.ThrowIfNull(createValue); - /// - /// Removes the scoped state set for the specified . - /// - /// The resolver context. - /// The name of the state. - public static void RemoveScopedState( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); + if (context.LocalContextData.TryGetValue(name, out var value) + && value is T casted) + { + return casted; + } - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); + var newValue = createValue(name); + SetLocalState(context, name, newValue); + return newValue; } - context.ScopedContextData = context.ScopedContextData.Remove(name); - } - - /// - /// Removes the local state set for the specified . - /// - /// The resolver context. - /// The name of the state. - public static void RemoveLocalState( - this IResolverContext context, - string name) - { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) + /// + /// Removes the scoped state set for the specified . + /// + /// The name of the state. + public void RemoveScopedState(string name) { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentNullException.ThrowIfNull(context); - context.LocalContextData = context.LocalContextData.Remove(name); - } + if (string.IsNullOrEmpty(name)) + { + throw String_NullOrEmpty(nameof(name)); + } - /// - /// Gets the event message. - /// - /// The resolver context. - /// The type of the event message. - /// The event message. - public static T GetEventMessage(this IResolverContext context) - { - ArgumentNullException.ThrowIfNull(context); + context.ScopedContextData = context.ScopedContextData.Remove(name); + } - if (context.ScopedContextData.TryGetValue( - WellKnownContextData.EventMessage, - out var value) && value is { }) + /// + /// Removes the local state set for the specified . + /// + /// The name of the state. + public void RemoveLocalState(string name) { - if (value is T casted) + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrEmpty(name)) { - return casted; + throw String_NullOrEmpty(nameof(name)); } - throw EventMessage_InvalidCast(typeof(T), value.GetType()); + context.LocalContextData = context.LocalContextData.Remove(name); } - throw EventMessage_NotFound(); - } + /// + /// Gets the event message. + /// + /// The type of the event message. + /// The event message. + public T GetEventMessage() + { + ArgumentNullException.ThrowIfNull(context); - /// - /// Gets the user for this request. - /// - /// - /// The resolver context. - /// - /// - /// Returns the user for this request. - /// - public static ClaimsPrincipal? GetUser(this IResolverContext context) - => context.GetGlobalStateOrDefault(nameof(ClaimsPrincipal)); - - /// - /// Checks if a field is selected in the current selection set. - /// - /// - /// The resolver context. - /// - /// - /// The name of the field that shall be checked. - /// - /// - /// true if the field is selected; otherwise, false. - /// - /// - /// is null. - /// - /// - /// is null or whitespace. - /// - public static bool IsSelected(this IResolverContext context, string fieldName) - { - ArgumentNullException.ThrowIfNull(context); + if (context.ScopedContextData.TryGetValue( + WellKnownContextData.EventMessage, + out var value) && value is { }) + { + if (value is T casted) + { + return casted; + } - if (string.IsNullOrWhiteSpace(fieldName)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName)); - } + throw EventMessage_InvalidCast(typeof(T), value.GetType()); + } - var namedType = context.Selection.Type.NamedType(); + throw EventMessage_NotFound(); + } + + /// + /// Gets the user for this request. + /// + /// + /// Returns the user for this request. + /// + public ClaimsPrincipal? GetUser() + => context.GetGlobalStateOrDefault(nameof(ClaimsPrincipal)); + + /// + /// Checks if a field is selected in the current selection set. + /// + /// + /// The name of the field that shall be checked. + /// + /// + /// true if the field is selected; otherwise, false. + /// + /// + /// is null. + /// + /// + /// is null or whitespace. + /// + public bool IsSelected(string fieldName) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrWhiteSpace(fieldName)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName)); + } - if (!namedType.IsCompositeType()) - { - return false; - } + var namedType = context.Selection.Type.NamedType(); - if (namedType.IsAbstractType()) - { - foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) + if (!namedType.IsCompositeType()) { - var selections = context.GetSelections(possibleType, context.Selection); + return false; + } - for (var i = 0; i < selections.Count; i++) + if (namedType.IsAbstractType()) + { + foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) { - if (selections[i].Field.Name.Equals(fieldName)) + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); + + foreach(var selection in selectionSet.Selections) { - return true; + if (selection.IsIncluded(includeFlags) + && selection.Field.Name.Equals(fieldName)) + { + return true; + } } } } - } - else - { - var selections = context.GetSelections((ObjectType)namedType, context.Selection); - - for (var i = 0; i < selections.Count; i++) + else { - if (selections[i].Field.Name.Equals(fieldName)) + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); + + foreach(var selection in selectionSet.Selections) { - return true; + if (selection.IsIncluded(includeFlags) + && selection.Field.Name.Equals(fieldName)) + { + return true; + } } } - } - - return false; - } - /// - /// Checks if a field is selected in the current selection set. - /// - /// - /// The resolver context. - /// - /// - /// The name of the first field that shall be checked. - /// - /// - /// The name of the second field that shall be checked. - /// - /// - /// - /// is null. - /// - /// - /// is null or whitespace or - /// is null or whitespace. - /// - public static bool IsSelected(this IResolverContext context, string fieldName1, string fieldName2) - { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrWhiteSpace(fieldName1)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName1)); + return false; } - if (string.IsNullOrWhiteSpace(fieldName2)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName2)); - } + /// + /// Checks if a field is selected in the current selection set. + /// + /// + /// The name of the first field that shall be checked. + /// + /// + /// The name of the second field that shall be checked. + /// + /// + /// + /// is null. + /// + /// + /// is null or whitespace or + /// is null or whitespace. + /// + public bool IsSelected(string fieldName1, string fieldName2) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrWhiteSpace(fieldName1)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName1)); + } - var namedType = context.Selection.Type.NamedType(); + if (string.IsNullOrWhiteSpace(fieldName2)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName2)); + } - if (!namedType.IsCompositeType()) - { - return false; - } + var namedType = context.Selection.Type.NamedType(); - if (namedType.IsAbstractType()) - { - foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) + if (!namedType.IsCompositeType()) { - var selections = context.GetSelections(possibleType, context.Selection); + return false; + } - for (var i = 0; i < selections.Count; i++) + if (namedType.IsAbstractType()) + { + foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) { - var selection = selections[i]; + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - if (selection.Field.Name.Equals(fieldName1) || selection.Field.Name.Equals(fieldName2)) + foreach(var selection in selectionSet.Selections) { - return true; + if (selection.IsSkipped(includeFlags)) + { + continue; + } + + if (selection.Field.Name.Equals(fieldName1) || selection.Field.Name.Equals(fieldName2)) + { + return true; + } } } } - } - else - { - var selections = context.GetSelections((ObjectType)namedType, context.Selection); - - for (var i = 0; i < selections.Count; i++) + else { - var selection = selections[i]; + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - if (selection.Field.Name.Equals(fieldName1) || selection.Field.Name.Equals(fieldName2)) + foreach(var selection in selectionSet.Selections) { - return true; + if (selection.IsSkipped(includeFlags)) + { + continue; + } + + if (selection.Field.Name.Equals(fieldName1) || selection.Field.Name.Equals(fieldName2)) + { + return true; + } } } - } - return false; - } + return false; + } - /// - /// Checks if a field is selected in the current selection set. - /// - /// - /// The resolver context. - /// - /// - /// The name of the first field that shall be checked. - /// - /// - /// The name of the second field that shall be checked. - /// - /// - /// The name of the third field that shall be checked. - /// - /// - /// - /// is null. - /// - /// - /// is null or whitespace or - /// is null or whitespace or - /// is null or whitespace. - /// - public static bool IsSelected( - this IResolverContext context, - string fieldName1, - string fieldName2, - string fieldName3) - { - ArgumentNullException.ThrowIfNull(context); + /// + /// Checks if a field is selected in the current selection set. + /// + /// + /// The name of the first field that shall be checked. + /// + /// + /// The name of the second field that shall be checked. + /// + /// + /// The name of the third field that shall be checked. + /// + /// + /// + /// is null. + /// + /// + /// is null or whitespace or + /// is null or whitespace or + /// is null or whitespace. + /// + public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) + { + ArgumentNullException.ThrowIfNull(context); + + if (string.IsNullOrWhiteSpace(fieldName1)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName1)); + } - if (string.IsNullOrWhiteSpace(fieldName1)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName1)); - } + if (string.IsNullOrWhiteSpace(fieldName2)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName2)); + } - if (string.IsNullOrWhiteSpace(fieldName2)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName2)); - } + if (string.IsNullOrWhiteSpace(fieldName3)) + { + throw new ArgumentException( + ResolverContextExtensions_IsSelected_FieldNameEmpty, + nameof(fieldName3)); + } - if (string.IsNullOrWhiteSpace(fieldName3)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName3)); - } + var namedType = context.Selection.Type.NamedType(); - var namedType = context.Selection.Type.NamedType(); + if (!namedType.IsCompositeType()) + { + return false; + } - if (!namedType.IsCompositeType()) - { - return false; - } + if (namedType.IsAbstractType()) + { + foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) + { + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - if (namedType.IsAbstractType()) - { - foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) + foreach(var selection in selectionSet.Selections) + { + if (selection.IsSkipped(includeFlags)) + { + continue; + } + + if (selection.Field.Name.Equals(fieldName1) + || selection.Field.Name.Equals(fieldName2) + || selection.Field.Name.Equals(fieldName3)) + { + return true; + } + } + } + } + else { - var selections = context.GetSelections(possibleType, context.Selection); + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - for (var i = 0; i < selections.Count; i++) + foreach(var selection in selectionSet.Selections) { - var selection = selections[i]; + if (selection.IsSkipped(includeFlags)) + { + continue; + } if (selection.Field.Name.Equals(fieldName1) || selection.Field.Name.Equals(fieldName2) @@ -790,83 +761,66 @@ public static bool IsSelected( } } } + + return false; } - else + + /// + /// Checks if a field is selected in the current selection set. + /// + /// + /// The names of the fields that shall be checked. + /// + /// + /// + /// is null or + /// is null. + /// + public bool IsSelected(ISet fieldNames) { - var selections = context.GetSelections((ObjectType)namedType, context.Selection); + ArgumentNullException.ThrowIfNull(context); + ArgumentNullException.ThrowIfNull(fieldNames); + + var namedType = context.Selection.Type.NamedType(); - for (var i = 0; i < selections.Count; i++) + if (!namedType.IsCompositeType()) { - var selection = selections[i]; + return false; + } - if (selection.Field.Name.Equals(fieldName1) - || selection.Field.Name.Equals(fieldName2) - || selection.Field.Name.Equals(fieldName3)) + if (namedType.IsAbstractType()) + { + foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) { - return true; + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); + + foreach(var selection in selectionSet.Selections) + { + if (selection.IsIncluded(includeFlags) + && fieldNames.Contains(selection.Field.Name)) + { + return true; + } + } } } - } - - return false; - } - - /// - /// Checks if a field is selected in the current selection set. - /// - /// - /// The resolver context. - /// - /// - /// The names of the fields that shall be checked. - /// - /// - /// - /// is null or - /// is null. - /// - public static bool IsSelected( - this IResolverContext context, - ISet fieldNames) - { - ArgumentNullException.ThrowIfNull(context); - ArgumentNullException.ThrowIfNull(fieldNames); - - var namedType = context.Selection.Type.NamedType(); - - if (!namedType.IsCompositeType()) - { - return false; - } - - if (namedType.IsAbstractType()) - { - foreach (var possibleType in context.Schema.GetPossibleTypes(namedType)) + else { - var selections = context.GetSelections(possibleType, context.Selection); + var includeFlags = context.IncludeFlags; + var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - for (var i = 0; i < selections.Count; i++) + foreach(var selection in selectionSet.Selections) { - if (fieldNames.Contains(selections[i].Field.Name)) + if (selection.IsIncluded(includeFlags) + && fieldNames.Contains(selection.Field.Name)) { return true; } } } - } - else - { - var selections = context.GetSelections((ObjectType)namedType, context.Selection); - for (var i = 0; i < selections.Count; i++) - { - if (fieldNames.Contains(selections[i].Field.Name)) - { - return true; - } - } + return false; } - - return false; } } diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 7b3d5a23453..a36c9b2e24c 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -205,6 +205,22 @@ ResolverTask.cs + + + ValueCompletion.cs + + + + ValueCompletion.cs + + + + ValueCompletion.cs + + + + OperationFeatureCollection.cs + diff --git a/src/HotChocolate/Core/src/Types/Resolvers/DefaultResolverCompiler.cs b/src/HotChocolate/Core/src/Types/Resolvers/DefaultResolverCompiler.cs index c661a27188c..e4f509b19cd 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/DefaultResolverCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/DefaultResolverCompiler.cs @@ -86,7 +86,6 @@ public DefaultResolverCompiler( expressionBuilders.Add(new ResolverContextParameterExpressionBuilder()); expressionBuilders.Add(new SchemaParameterExpressionBuilder()); expressionBuilders.Add(new SelectionParameterExpressionBuilder()); - expressionBuilders.Add(new FieldSyntaxParameterExpressionBuilder()); expressionBuilders.Add(new ObjectTypeParameterExpressionBuilder()); expressionBuilders.Add(new OperationDefinitionParameterExpressionBuilder()); expressionBuilders.Add(new OperationParameterExpressionBuilder()); diff --git a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/FieldSyntaxParameterExpressionBuilder.cs b/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/FieldSyntaxParameterExpressionBuilder.cs deleted file mode 100644 index cc1d1fe29ec..00000000000 --- a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/FieldSyntaxParameterExpressionBuilder.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Diagnostics; -using System.Reflection; -using System.Runtime.CompilerServices; -using HotChocolate.Internal; -using HotChocolate.Language; - -namespace HotChocolate.Resolvers.Expressions.Parameters; - -internal sealed class FieldSyntaxParameterExpressionBuilder() - : LambdaParameterExpressionBuilder(ctx => ctx.Selection.SyntaxNode, isPure: true) - , IParameterBindingFactory - , IParameterBinding -{ - public override ArgumentKind Kind - => ArgumentKind.FieldSyntax; - - public override bool CanHandle(ParameterInfo parameter) - => typeof(FieldNode) == parameter.ParameterType; - - public bool CanHandle(ParameterDescriptor parameter) - => typeof(FieldNode) == parameter.Type; - - public IParameterBinding Create(ParameterDescriptor parameter) - => this; - - public T Execute(IResolverContext context) - { - Debug.Assert(typeof(T) == typeof(FieldNode)); - var syntaxNode = context.Selection.SyntaxNode; - return Unsafe.As(ref syntaxNode); - } -} diff --git a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/SelectionParameterExpressionBuilder.cs b/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/SelectionParameterExpressionBuilder.cs index b6a3903611f..2ce5729ad9b 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/SelectionParameterExpressionBuilder.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/Expressions/Parameters/SelectionParameterExpressionBuilder.cs @@ -2,6 +2,7 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Internal; @@ -16,10 +17,12 @@ public override ArgumentKind Kind => ArgumentKind.Selection; public override bool CanHandle(ParameterInfo parameter) - => typeof(ISelection).IsAssignableFrom(parameter.ParameterType); + => typeof(ISelection).IsAssignableFrom(parameter.ParameterType) + || typeof(Selection).IsAssignableFrom(parameter.ParameterType); public bool CanHandle(ParameterDescriptor parameter) - => typeof(ISelection).IsAssignableFrom(parameter.Type); + => typeof(ISelection).IsAssignableFrom(parameter.Type) + || typeof(Selection).IsAssignableFrom(parameter.Type); public override Expression Build(ParameterExpressionBuilderContext context) => Expression.Convert(base.Build(context), context.Parameter.ParameterType); @@ -31,6 +34,6 @@ public T Execute(IResolverContext context) { Debug.Assert(typeof(T) == typeof(ISelection)); var selection = context.Selection; - return Unsafe.As(ref selection); + return Unsafe.As(ref selection); } } diff --git a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs index 5eef2e5429d..7a055e474f2 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/IResolverContext.cs @@ -44,6 +44,11 @@ public interface IResolverContext : IHasContextData, IFeatureProvider /// Path Path { get; } + /// + /// Gets the selection include flags. + /// + ulong IncludeFlags { get; } + /// /// Gets the previous (parent) resolver result. /// diff --git a/src/HotChocolate/Core/src/Types/Resolvers/ParameterBindingResolver.cs b/src/HotChocolate/Core/src/Types/Resolvers/ParameterBindingResolver.cs index 4c0e43d9cd7..e4b3eafd3fa 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/ParameterBindingResolver.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/ParameterBindingResolver.cs @@ -45,7 +45,6 @@ public ParameterBindingResolver( bindingFactories.Add(new ResolverContextParameterExpressionBuilder()); bindingFactories.Add(new SchemaParameterExpressionBuilder()); bindingFactories.Add(new SelectionParameterExpressionBuilder()); - bindingFactories.Add(new FieldSyntaxParameterExpressionBuilder()); bindingFactories.Add(new ObjectTypeParameterExpressionBuilder()); bindingFactories.Add(new OperationDefinitionParameterExpressionBuilder()); bindingFactories.Add(new OperationParameterExpressionBuilder()); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs index 869b8c26d26..9246b7aca06 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -16,7 +16,7 @@ public void WriteTo(IBufferWriter writer, bool indented = false) internal ref struct RawJsonFormatter(ResultDocument document, IBufferWriter writer, bool indented) { - private int _indentLevel = 0; + private int _indentation = 0; public void Write() { @@ -25,7 +25,7 @@ public void Write() if (indented) { WriteNewLine(); - _indentLevel++; + _indentation++; } if (document._errors?.Count > 0) @@ -117,7 +117,7 @@ public void Write() if (indented) { - _indentLevel--; + _indentation--; WriteNewLine(); WriteIndent(); } @@ -144,12 +144,12 @@ public void WriteValue(Cursor cursor, DbRow row) switch (tokenType) { case ElementTokenType.StartObject - when (ElementFlags.SourceResult & row.Flags) != ElementFlags.SourceResult: + when (ElementFlags.IsObject & row.Flags) != ElementFlags.IsObject: WriteObject(cursor, row); break; case ElementTokenType.StartArray - when (ElementFlags.SourceResult & row.Flags) != ElementFlags.SourceResult: + when (ElementFlags.IsList & row.Flags) != ElementFlags.IsList: WriteArray(cursor, row); break; @@ -167,7 +167,7 @@ public void WriteValue(Cursor cursor, DbRow row) break; default: - document.WriteRawValueTo(writer, row, _indentLevel, indented); + document.WriteRawValueTo(writer, row, _indentation, indented); break; } } @@ -183,7 +183,7 @@ private void WriteObject(Cursor start, DbRow startRow) if (indented && current < end) { - _indentLevel++; + _indentation++; } var first = true; @@ -234,7 +234,7 @@ private void WriteObject(Cursor start, DbRow startRow) if (indented && !first) { - _indentLevel--; + _indentation--; WriteNewLine(); WriteIndent(); } @@ -253,7 +253,7 @@ private void WriteArray(Cursor start, DbRow startRow) if (indented && current < end) { - _indentLevel++; + _indentation++; } var first = true; @@ -279,7 +279,7 @@ private void WriteArray(Cursor start, DbRow startRow) if (indented && end > start + 1) { - _indentLevel--; + _indentation--; WriteNewLine(); WriteIndent(); } @@ -293,7 +293,7 @@ private void WriteArray(Cursor start, DbRow startRow) [MethodImpl(MethodImplOptions.AggressiveInlining)] private readonly void WriteIndent() { - var indentSize = _indentLevel * 2; + var indentSize = _indentation * 2; if (indentSize > 0) { var span = writer.GetSpan(indentSize); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index da69ffbf89d..d4fae9588fc 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -335,7 +335,7 @@ internal void Invalidate(Cursor current) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteRawValueTo(IBufferWriter writer, DbRow row) + private void WriteRawValueTo(IBufferWriter writer, DbRow row, int indentation, bool indented) { switch (row.TokenType) { @@ -360,6 +360,7 @@ private void WriteRawValueTo(IBufferWriter writer, DbRow row) WriteLocalDataTo(writer, row.Location, row.SizeOrLength); return; + // TODO : We need to handle any types. default: throw new NotSupportedException(); } @@ -738,7 +739,7 @@ private void WriteEmptyProperty(Cursor parent, ISelection selection) flags |= ElementFlags.IsList; } - if (selection.Type.IsCompositeType()) + if (selection.Type.NamedType().IsCompositeType()) { flags |= ElementFlags.IsObject; } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveCollectionExtensions.cs deleted file mode 100644 index b9646781854..00000000000 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveCollectionExtensions.cs +++ /dev/null @@ -1,257 +0,0 @@ -using HotChocolate.Execution; -using HotChocolate.Execution.Processing; -using HotChocolate.Language; -using HotChocolate.Utilities; -using ThrowHelper = HotChocolate.Utilities.ThrowHelper; - -// ReSharper disable once CheckNamespace -namespace HotChocolate.Types; - -public static class DirectiveCollectionExtensions -{ - public static T? SingleOrDefault(this DirectiveCollection directives) where T : notnull - { - foreach (var directive in directives) - { - if (typeof(T).IsAssignableFrom(directive.Type.RuntimeType)) - { - return directive.ToValue(); - } - } - - return default; - } - - internal static IValueNode? SkipValue(this IReadOnlyList directives) - { - var directive = directives.GetSkipDirectiveNode(); - - if (directive is null) - { - return null; - } - - return directive.GetArgumentValue(DirectiveNames.Skip.Arguments.If, BooleanValueNode.True) - ?? throw ThrowHelper.MissingIfArgument(directive); - } - - internal static IValueNode? IncludeValue(this IReadOnlyList directives) - { - var directive = directives.GetIncludeDirectiveNode(); - - if (directive is null) - { - return null; - } - - return directive.GetArgumentValue(DirectiveNames.Include.Arguments.If, BooleanValueNode.True) - ?? throw ThrowHelper.MissingIfArgument(directive); - } - - internal static bool IsDeferrable(this InlineFragmentNode fragmentNode) - => fragmentNode.Directives.IsDeferrable(); - - internal static bool IsDeferrable(this FragmentSpreadNode fragmentSpreadNode) - => fragmentSpreadNode.Directives.IsDeferrable(); - - internal static bool IsDeferrable(this IReadOnlyList directives) - { - var directive = directives.GetDeferDirectiveNode(); - var ifValue = directive?.GetArgumentValue(DirectiveNames.Defer.Arguments.If, BooleanValueNode.True); - - // a fragment is not deferrable if we do not find a defer directive or - // if the `if`-argument of the defer directive is a bool literal with a false value. - return directive is not null && ifValue is not { Value: false }; - } - - internal static DirectiveNode? GetSkipDirectiveNode( - this IReadOnlyList directives) - => GetDirectiveNode(directives, DirectiveNames.Skip.Name); - - internal static DirectiveNode? GetIncludeDirectiveNode( - this IReadOnlyList directives) - => GetDirectiveNode(directives, DirectiveNames.Include.Name); - - internal static DeferDirective? GetDeferDirective( - this IReadOnlyList directives, - IVariableValueCollection variables) - { - var directiveNode = GetDirectiveNode(directives, DirectiveNames.Defer.Name); - - if (directiveNode is not null) - { - var @if = true; - string? label = null; - - foreach (var argument in directiveNode.Arguments) - { - switch (argument.Name.Value) - { - case DirectiveNames.Defer.Arguments.If: - @if = argument.Value switch - { - VariableNode variable => !variables.GetBooleanValue(variable.Name.Value) ?? true, - BooleanValueNode b => b.Value, - _ => true - }; - break; - - case DirectiveNames.Defer.Arguments.Label: - label = argument.Value switch - { - VariableNode variable => variables.GetStringValue(variable.Name.Value), - StringValueNode b => b.Value, - _ => null - }; - break; - } - } - - return new DeferDirective(@if, label); - } - - return null; - } - - private static bool? GetBooleanValue(this IVariableValueCollection variables, string variableName) - => variables.TryGetValue(variableName, out BooleanValueNode? value) ? value.Value : null; - - private static string? GetStringValue(this IVariableValueCollection variables, string variableName) - => variables.TryGetValue(variableName, out StringValueNode? value) ? value.Value : null; - - private static int? GetIntValue(this IVariableValueCollection variables, string variableName) - => variables.TryGetValue(variableName, out IntValueNode? value) ? value.ToInt32() : null; - - internal static StreamDirective? GetStreamDirective( - this ISelection selection, - IVariableValueCollection variables) => - selection.SyntaxNode.GetStreamDirective(variables); - - internal static StreamDirective? GetStreamDirective( - this FieldNode fieldNode, - IVariableValueCollection variables) - { - var directiveNode = GetDirectiveNode(fieldNode.Directives, DirectiveNames.Stream.Name); - - if (directiveNode is not null) - { - var @if = true; - string? label = null; - var initialCount = 0; - - foreach (var argument in directiveNode.Arguments) - { - switch (argument.Name.Value) - { - case DirectiveNames.Stream.Arguments.If: - @if = argument.Value switch - { - VariableNode variable => !variables.GetBooleanValue(variable.Name.Value) ?? true, - BooleanValueNode b => b.Value, - _ => true - }; - break; - - case DirectiveNames.Stream.Arguments.Label: - label = argument.Value switch - { - VariableNode variable => variables.GetStringValue(variable.Name.Value), - StringValueNode b => b.Value, - _ => null - }; - break; - - case DirectiveNames.Stream.Arguments.InitialCount: - initialCount = argument.Value switch - { - VariableNode variable => variables.GetIntValue(variable.Name.Value) ?? 0, - IntValueNode b => b.ToInt32(), - _ => 0 - }; - break; - } - } - - return new StreamDirective(@if, initialCount, label); - } - - return null; - } - - internal static bool StreamDirectiveEquals( - this DirectiveNode streamA, - DirectiveNode streamB) - { - var argsA = CreateStreamArgs(streamA); - var argsB = CreateStreamArgs(streamB); - - return SyntaxComparer.BySyntax.Equals(argsA.If, argsB.If) - && SyntaxComparer.BySyntax.Equals(argsA.InitialCount, argsB.InitialCount) - && SyntaxComparer.BySyntax.Equals(argsA.Label, argsB.Label); - } - - private static StreamArgs CreateStreamArgs(DirectiveNode directiveNode) - { - var args = new StreamArgs(); - - for (var i = 0; i < directiveNode.Arguments.Count; i++) - { - var argument = directiveNode.Arguments[i]; - - switch (argument.Name.Value) - { - case DirectiveNames.Stream.Arguments.If: - args.If = argument.Value; - break; - - case DirectiveNames.Stream.Arguments.Label: - args.Label = argument.Value; - break; - - case DirectiveNames.Stream.Arguments.InitialCount: - args.InitialCount = argument.Value; - break; - } - } - - return args; - } - - internal static DirectiveNode? GetDeferDirectiveNode( - this IHasDirectives container) => - GetDirectiveNode(container.Directives, DirectiveNames.Defer.Name); - - internal static DirectiveNode? GetDeferDirectiveNode( - this IReadOnlyList directives) => - GetDirectiveNode(directives, DirectiveNames.Defer.Name); - - private static DirectiveNode? GetDirectiveNode( - this IReadOnlyList directives, - string name) - { - if (directives.Count == 0) - { - return null; - } - - for (var i = 0; i < directives.Count; i++) - { - var directive = directives[i]; - - if (directive.Name.Value.EqualsOrdinal(name)) - { - return directive; - } - } - return null; - } - - private ref struct StreamArgs - { - public IValueNode? If { get; set; } - - public IValueNode? Label { get; set; } - - public IValueNode? InitialCount { get; set; } - } -} diff --git a/src/HotChocolate/Core/src/Types/Types/Pagination/PagingMiddleware.cs b/src/HotChocolate/Core/src/Types/Types/Pagination/PagingMiddleware.cs index f84b093f38f..94bee128925 100644 --- a/src/HotChocolate/Core/src/Types/Types/Pagination/PagingMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Types/Pagination/PagingMiddleware.cs @@ -46,7 +46,7 @@ public async ValueTask InvokeAsync(IMiddlewareContext context) { errors[i] = ErrorBuilder .FromError(ex.Errors[i]) - .AddLocations(context.Selection.SyntaxNodes) + .AddLocations(context.Selection) .SetPath(context.Path) .Build(); } diff --git a/src/HotChocolate/Core/src/Types/Types/Relay/NodeFieldResolvers.cs b/src/HotChocolate/Core/src/Types/Types/Relay/NodeFieldResolvers.cs index ca32579e62b..c188213f885 100644 --- a/src/HotChocolate/Core/src/Types/Types/Relay/NodeFieldResolvers.cs +++ b/src/HotChocolate/Core/src/Types/Types/Relay/NodeFieldResolvers.cs @@ -40,7 +40,7 @@ public static async ValueTask ResolveSingleNodeAsync( ErrorHelper.Relay_NoNodeResolver( typeName, context.Path, - context.Selection.SyntaxNodes)); + context.Selection)); context.Result = null; } @@ -64,7 +64,7 @@ public static async ValueTask ResolveManyNodeAsync( { context.ReportError( ErrorHelper.FetchedToManyNodesAtOnce( - context.Selection.SyntaxNodes, + context.Selection, context.Path, maxAllowedNodes, list.Items.Count)); @@ -100,7 +100,7 @@ public static async ValueTask ResolveManyNodeAsync( ErrorHelper.Relay_NoNodeResolver( typeName, context.Path, - context.Selection.SyntaxNodes)); + context.Selection)); } } @@ -183,7 +183,7 @@ public static async ValueTask ResolveManyNodeAsync( ErrorHelper.Relay_NoNodeResolver( typeName, context.Path, - context.Selection.SyntaxNodes)); + context.Selection)); } context.Result = results; diff --git a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs index df07ef5efbe..7c90512ef9d 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs @@ -1,4 +1,5 @@ using System.Globalization; +using HotChocolate.Execution.Processing; using HotChocolate.Language; using HotChocolate.Properties; using HotChocolate.Types; @@ -452,11 +453,11 @@ public static ISchemaError NoSchemaTypesAllowedAsRuntimeType( .SetTypeSystemObject(type) .Build(); - public static IError Relay_NoNodeResolver(string typeName, Path path, IReadOnlyList fieldNodes) + public static IError Relay_NoNodeResolver(string typeName, Path path, Selection selection) => ErrorBuilder.New() .SetMessage(ErrorHelper_Relay_NoNodeResolver, typeName) .SetPath(path) - .AddLocations(fieldNodes) + .AddLocations(selection) .Build(); public static ISchemaError NodeResolver_MustHaveExactlyOneIdArg( @@ -494,7 +495,7 @@ public static ISchemaError NodeResolverMissing( .Build(); public static IError FetchedToManyNodesAtOnce( - IReadOnlyList fieldNodes, + Selection selection, Path path, int maxAllowedNodes, int requestNodes) @@ -503,7 +504,7 @@ public static IError FetchedToManyNodesAtOnce( ErrorHelper_FetchedToManyNodesAtOnce, maxAllowedNodes, requestNodes) - .AddLocations(fieldNodes) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.FetchedToManyNodesAtOnce) .Build(); diff --git a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs index 4739c744624..feab6327d5f 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs @@ -1,20 +1,19 @@ using HotChocolate.Execution.Processing; using HotChocolate.Language; -using HotChocolate.Types; namespace HotChocolate.Data.Projections.Handlers; public class IsProjectedProjectionOptimizer : IProjectionOptimizer { - public bool CanHandle(ISelection field) => - field.DeclaringType is ObjectType objectType - && objectType.Features.Get()?.AlwaysProjectedFields.Length > 0; + public bool CanHandle(Selection field) + => field.DeclaringType is { } objectType + && objectType.Features.Get()?.AlwaysProjectedFields.Length > 0; public Selection RewriteSelection( SelectionSetOptimizerContext context, Selection selection) { - if (context.Type is not ObjectType type + if (context.Type is not { } type || !type.Features.TryGet(out ProjectionTypeFeature? feature)) { return selection; diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs index 4222ab7f8e2..53d5cfc8c2d 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs @@ -11,7 +11,7 @@ public interface IProjectionOptimizer /// /// The selection to test for /// Returns true if the selection can be handled - bool CanHandle(ISelection selection); + bool CanHandle(Selection selection); /// /// Rewrites a selection. In case nothing is rewritten, the diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/Selection.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/Selection.cs index c951df63810..dcdca53e219 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/Selection.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/Selection.cs @@ -5,6 +5,9 @@ namespace HotChocolate.Fusion.Execution.Nodes; +/// +/// Represents a field selection during execution in the Fusion execution engine. +/// public sealed class Selection : ISelection { private readonly FieldSelectionNode[] _syntaxNodes; @@ -44,26 +47,40 @@ public Selection( _utf8ResponseName = Utf8StringCache.GetUtf8String(responseName); } + /// public int Id { get; } + /// public string ResponseName { get; } internal ReadOnlySpan Utf8ResponseName => _utf8ResponseName; + /// public bool IsInternal => (_flags & Flags.Internal) == Flags.Internal; + /// public bool IsConditional => _includeFlags.Length > 0; + /// public bool IsLeaf => (_flags & Flags.Leaf) == Flags.Leaf; + /// public IOutputFieldDefinition Field { get; } + /// public IType Type => Field.Type; + /// + /// Gets the selection set that contains this selection. + /// public SelectionSet DeclaringSelectionSet { get; private set; } = null!; + /// ISelectionSet ISelection.DeclaringSelectionSet => DeclaringSelectionSet; + /// + /// Gets the syntax nodes that contributed to this selection. + /// public ReadOnlySpan SyntaxNodes => _syntaxNodes; internal ResolveFieldValue? Resolver => Field.Features.Get(); @@ -76,6 +93,7 @@ IEnumerable ISelection.GetSyntaxNodes() } } + /// public bool IsIncluded(ulong includeFlags) { if (_includeFlags.Length == 0) From fbb3ff7a4cac76270da57ed44d042e92ade0ac72 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 2 Dec 2025 12:16:32 +0100 Subject: [PATCH 16/42] wip --- .../Core/src/Validation/ErrorHelper.cs | 93 +++++++++---------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs index daaadbe780f..45f730d958c 100644 --- a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs @@ -24,7 +24,8 @@ public static IError DeferAndStreamNotAllowedOnMutationOrSubscriptionRoot( extension(DocumentValidatorContext context) { - public IError VariableNotUsed(OperationDefinitionNode node, + public IError VariableNotUsed( + OperationDefinitionNode node, IEnumerable unusedVariables) { return ErrorBuilder.New() @@ -37,7 +38,8 @@ public IError VariableNotUsed(OperationDefinitionNode node, .Build(); } - public IError VariableNotDeclared(OperationDefinitionNode node, + public IError VariableNotDeclared( + OperationDefinitionNode node, IEnumerable usedVariables) { return ErrorBuilder.New() @@ -50,7 +52,8 @@ public IError VariableNotDeclared(OperationDefinitionNode node, .Build(); } - public IError OneOfVariableIsNotCompatible(VariableNode variable, + public IError OneOfVariableIsNotCompatible( + VariableNode variable, VariableDefinitionNode variableDefinition) { var variableName = variableDefinition.Variable.Name.Value; @@ -66,7 +69,8 @@ public IError OneOfVariableIsNotCompatible(VariableNode variable, .Build(); } - public IError VariableIsNotCompatible(VariableNode variable, + public IError VariableIsNotCompatible( + VariableNode variable, VariableDefinitionNode variableDefinition) { var variableName = variableDefinition.Variable.Name.Value; @@ -123,8 +127,7 @@ public IError TypeSystemDefinitionNotAllowed(IDefinitionNode node) .Build(); } - public IError UnionFieldError(SelectionSetNode node, - IUnionTypeDefinition type) + public IError UnionFieldError(SelectionSetNode node, IUnionTypeDefinition type) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_UnionFieldError) @@ -135,8 +138,7 @@ public IError UnionFieldError(SelectionSetNode node, .Build(); } - public IError FieldDoesNotExist(FieldNode node, - IComplexTypeDefinition outputType) + public IError FieldDoesNotExist(FieldNode node, IComplexTypeDefinition outputType) { return ErrorBuilder.New() .SetMessage( @@ -151,7 +153,8 @@ public IError FieldDoesNotExist(FieldNode node, .Build(); } - public IError LeafFieldsCannotHaveSelections(FieldNode node, + public IError LeafFieldsCannotHaveSelections( + FieldNode node, IComplexTypeDefinition declaringType, IType fieldType) { @@ -170,7 +173,8 @@ public IError LeafFieldsCannotHaveSelections(FieldNode node, .Build(); } - public IError ArgumentValueIsNotCompatible(ArgumentNode node, + public IError ArgumentValueIsNotCompatible( + ArgumentNode node, IInputType locationType, IValueNode value) { @@ -185,7 +189,8 @@ public IError ArgumentValueIsNotCompatible(ArgumentNode node, .Build(); } - public IError FieldValueIsNotCompatible(IInputValueDefinition field, + public IError FieldValueIsNotCompatible( + IInputValueDefinition field, IInputType locationType, IValueNode valueNode) { @@ -200,7 +205,8 @@ public IError FieldValueIsNotCompatible(IInputValueDefinition field, .Build(); } - public IError VariableDefaultValueIsNotCompatible(VariableDefinitionNode node, + public IError VariableDefaultValueIsNotCompatible( + VariableDefinitionNode node, IInputType locationType, IValueNode valueNode) { @@ -217,7 +223,8 @@ public IError VariableDefaultValueIsNotCompatible(VariableDefinitionNode node, .Build(); } - public IError NoSelectionOnCompositeField(FieldNode node, + public IError NoSelectionOnCompositeField( + FieldNode node, IComplexTypeDefinition declaringType, IType fieldType) { @@ -236,8 +243,7 @@ public IError NoSelectionOnCompositeField(FieldNode node, .Build(); } - public IError NoSelectionOnRootType(OperationDefinitionNode node, - IType fieldType) + public IError NoSelectionOnRootType(OperationDefinitionNode node, IType fieldType) { return ErrorBuilder.New() .SetMessage( @@ -251,8 +257,7 @@ public IError NoSelectionOnRootType(OperationDefinitionNode node, .Build(); } - public IError FieldIsRequiredButNull(ISyntaxNode node, - string fieldName) + public IError FieldIsRequiredButNull(ISyntaxNode node, string fieldName) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_FieldIsRequiredButNull, fieldName) @@ -263,8 +268,7 @@ public IError FieldIsRequiredButNull(ISyntaxNode node, .Build(); } - public IError FieldsAreNotMergeable(FieldInfo fieldA, - FieldInfo fieldB) + public IError FieldsAreNotMergeable(FieldInfo fieldA, FieldInfo fieldB) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_FieldsAreNotMergeable) @@ -340,7 +344,8 @@ public IError FragmentDoesNotExist(FragmentSpreadNode fragmentSpread) .Build(); } - public IError FragmentNotPossible(ISyntaxNode node, + public IError FragmentNotPossible( + ISyntaxNode node, ITypeDefinition typeCondition, ITypeDefinition parentType) { @@ -355,8 +360,7 @@ public IError FragmentNotPossible(ISyntaxNode node, .Build(); } - public IError FragmentTypeConditionUnknown(ISyntaxNode node, - NamedTypeNode typeCondition) + public IError FragmentTypeConditionUnknown(ISyntaxNode node, NamedTypeNode typeCondition) { return ErrorBuilder.New() .SetMessage( @@ -370,8 +374,7 @@ public IError FragmentTypeConditionUnknown(ISyntaxNode node, .Build(); } - public IError FragmentOnlyCompositeType(ISyntaxNode node, - ITypeDefinition type) + public IError FragmentOnlyCompositeType(ISyntaxNode node, ITypeDefinition type) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_FragmentOnlyCompositeType) @@ -407,8 +410,7 @@ public IError InputFieldDoesNotExist(ObjectFieldNode field) .Build(); } - public IError InputFieldRequired(ISyntaxNode node, - string fieldName) + public IError InputFieldRequired(ISyntaxNode node, string fieldName) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_InputFieldRequired, fieldName) @@ -419,8 +421,7 @@ public IError InputFieldRequired(ISyntaxNode node, .Build(); } - public IError OperationNameNotUnique(OperationDefinitionNode operation, - string operationName) + public IError OperationNameNotUnique(OperationDefinitionNode operation, string operationName) { return ErrorBuilder.New() .SetMessage( @@ -432,8 +433,7 @@ public IError OperationNameNotUnique(OperationDefinitionNode operation, .Build(); } - public IError OperationAnonymousMoreThanOne(OperationDefinitionNode operation, - int operations) + public IError OperationAnonymousMoreThanOne(OperationDefinitionNode operation, int operations) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_OperationAnonymousMoreThanOne) @@ -443,8 +443,7 @@ public IError OperationAnonymousMoreThanOne(OperationDefinitionNode operation, .Build(); } - public IError VariableNotInputType(VariableDefinitionNode node, - string variableName) + public IError VariableNotInputType(VariableDefinitionNode node, string variableName) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_VariableNotInputType, variableName) @@ -456,8 +455,7 @@ public IError VariableNotInputType(VariableDefinitionNode node, .Build(); } - public IError VariableNameNotUnique(VariableDefinitionNode node, - string variableName) + public IError VariableNameNotUnique(VariableDefinitionNode node, string variableName) { return ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_VariableNameNotUnique) @@ -469,7 +467,8 @@ public IError VariableNameNotUnique(VariableDefinitionNode node, .Build(); } - public IError ArgumentNotUnique(ArgumentNode node, + public IError ArgumentNotUnique( + ArgumentNode node, SchemaCoordinate? field = null, IDirectiveDefinition? directive = null) { @@ -496,7 +495,8 @@ public IError ArgumentNotUnique(ArgumentNode node, .Build(); } - public IError ArgumentRequired(ISyntaxNode node, + public IError ArgumentRequired( + ISyntaxNode node, string argumentName, SchemaCoordinate? field = null, IDirectiveDefinition? directive = null) @@ -524,7 +524,8 @@ public IError ArgumentRequired(ISyntaxNode node, .Build(); } - public IError ArgumentDoesNotExist(ArgumentNode node, + public IError ArgumentDoesNotExist( + ArgumentNode node, SchemaCoordinate? field = null, IDirectiveDefinition? directive = null) { @@ -569,7 +570,8 @@ public IError SubscriptionNoTopLevelIntrospectionField(OperationDefinitionNode o .Build(); } - public IError MaxExecutionDepth(OperationDefinitionNode operation, + public IError MaxExecutionDepth( + OperationDefinitionNode operation, int allowedExecutionDepth, int detectedExecutionDepth) { @@ -583,8 +585,7 @@ public IError MaxExecutionDepth(OperationDefinitionNode operation, .Build(); } - public IError IntrospectionNotAllowed(FieldNode field, - string? customErrorMessage) + public IError IntrospectionNotAllowed(FieldNode field, string? customErrorMessage) { var message = customErrorMessage ?? Resources.ErrorHelper_IntrospectionNotAllowed; @@ -596,8 +597,7 @@ public IError IntrospectionNotAllowed(FieldNode field, .Build(); } - public IError OneOfMustHaveExactlyOneField(ISyntaxNode node, - IInputObjectTypeDefinition type) + public IError OneOfMustHaveExactlyOneField(ISyntaxNode node, IInputObjectTypeDefinition type) => ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_OneOfMustHaveExactlyOneField, type.Name) .AddLocation(node) @@ -606,7 +606,8 @@ public IError OneOfMustHaveExactlyOneField(ISyntaxNode node, .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) .Build(); - public IError OneOfVariablesMustBeNonNull(ISyntaxNode node, + public IError OneOfVariablesMustBeNonNull( + ISyntaxNode node, SchemaCoordinate fieldCoordinate, string variableName) => ErrorBuilder.New() @@ -621,8 +622,7 @@ public IError OneOfVariablesMustBeNonNull(ISyntaxNode node, .SpecifiedBy("sec-All-Variable-Usages-Are-Allowed", rfc: 825) .Build(); - public IError DeferAndStreamDuplicateLabel(ISyntaxNode selection, - string label) + public IError DeferAndStreamDuplicateLabel(ISyntaxNode selection, string label) => ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_DeferAndStreamDuplicateLabel) .AddLocation(selection) @@ -631,8 +631,7 @@ public IError DeferAndStreamDuplicateLabel(ISyntaxNode selection, .SetPath(context.CreateErrorPath()) .Build(); - public IError DeferAndStreamLabelIsVariable(ISyntaxNode selection, - string variable) + public IError DeferAndStreamLabelIsVariable(ISyntaxNode selection, string variable) => ErrorBuilder.New() .SetMessage(Resources.ErrorHelper_DeferAndStreamLabelIsVariable) .AddLocation(selection) From cd27228b90310d8d3ec57473bb7a260e3fa85dfb Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 2 Dec 2025 21:16:12 +0100 Subject: [PATCH 17/42] wip --- .../Core/src/Types/Execution/Processing/Operation.cs | 7 ++----- .../Core/src/Types/Execution/Processing/SelectionSet.cs | 1 - .../Core/src/Validation/HotChocolate.Validation.csproj | 1 - .../Optimizers/QueryablePagingProjectionOptimizer.cs | 7 +++---- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 10151268f48..78631edb320 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -1,12 +1,9 @@ using System.Collections.Concurrent; -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Types; -using static HotChocolate.Execution.Properties.Resources; -using static HotChocolate.Execution.ThrowHelper; namespace HotChocolate.Execution.Processing; @@ -68,7 +65,7 @@ internal Operation( rootSelectionSet.Complete(this, seal: isFinal); } - /// + /// /// Gets the internal unique identifier for this operation. /// public string Id { get; } @@ -191,7 +188,7 @@ public SelectionSet GetSelectionSet(Selection selection, IObjectTypeDefinition t _includeConditions, ref _elementsById, ref _lastId); - selectionSet.Complete(this, seal: _isFinal); + selectionSet.Complete(this, seal: _isFinal); _selectionSets.TryAdd(key, selectionSet); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 46cce24dd61..7c0cc5c51db 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -1,6 +1,5 @@ using System.Collections.Frozen; using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; using System.Text; using HotChocolate.Types; diff --git a/src/HotChocolate/Core/src/Validation/HotChocolate.Validation.csproj b/src/HotChocolate/Core/src/Validation/HotChocolate.Validation.csproj index 5b35cede164..1195b619af7 100644 --- a/src/HotChocolate/Core/src/Validation/HotChocolate.Validation.csproj +++ b/src/HotChocolate/Core/src/Validation/HotChocolate.Validation.csproj @@ -4,7 +4,6 @@ HotChocolate.Validation HotChocolate.Validation HotChocolate.Validation - diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs index 9182d19349d..c6ad38ed3ff 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs @@ -26,10 +26,9 @@ public Selection RewriteSelection( if (context.Type.NamedType() is not IPageType pageType) { - throw ThrowHelper - .PagingProjectionOptimizer_NotAPagingField( - selection.DeclaringType, - selection.Field); + throw ThrowHelper.PagingProjectionOptimizer_NotAPagingField( + selection.DeclaringType, + selection.Field); } var selections = CollectSelection(context); From 01e428470fc46a145964fc64099f8154fefccece Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 3 Dec 2025 09:45:29 +0100 Subject: [PATCH 18/42] wip --- .../src/Authorization/AuthorizeMiddleware.cs | 2 +- .../ErrorBuilderExtensions.cs | 82 ++++++++++++++++++- .../Core/src/Validation/ErrorHelper.cs | 2 +- 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs index 38f27393a8e..62f998fee96 100644 --- a/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs +++ b/src/HotChocolate/Core/src/Authorization/AuthorizeMiddleware.cs @@ -75,7 +75,7 @@ private void SetError( => ErrorBuilder.New() .SetMessage( AuthorizeMiddleware_PolicyNotFound, - _directive.Policy!) + _directive.Policy) .SetCode(ErrorCodes.Authentication.PolicyNotFound) .SetPath(context.Path) .AddLocations(context.Selection) diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs index 7b13fee3b11..c269b159a40 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/ErrorBuilderExtensions.cs @@ -39,14 +39,90 @@ public ErrorBuilder SetInputPath(Path inputPath) /// Sets the message of the error. /// /// The format of the message. - /// The argument for the message. + /// The argument for the message. /// The error builder. - public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, object? arg) + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, object? arg1) { ArgumentNullException.ThrowIfNull(builder); ArgumentException.ThrowIfNullOrEmpty(format); - return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg)); + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1)); + } + + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The first argument for the message. + /// The second argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, object? arg1, object? arg2) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1, arg2)); + } + + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The first argument for the message. + /// The second argument for the message. + /// The third argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, object? arg1, object? arg2, object? arg3) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1, arg2, arg3)); + } + + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, string? arg1) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1)); + } + + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The first argument for the message. + /// The second argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, string? arg1, string? arg2) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1, arg2)); + } + + /// + /// Sets the message of the error. + /// + /// The format of the message. + /// The first argument for the message. + /// The second argument for the message. + /// The third argument for the message. + /// The error builder. + public ErrorBuilder SetMessage([StringSyntax("CompositeFormat")] string format, string? arg1, string? arg2, string? arg3) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentException.ThrowIfNullOrEmpty(format); + + return builder.SetMessage(string.Format(CultureInfo.InvariantCulture, format, arg1, arg2, arg3)); } /// diff --git a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs index 45f730d958c..eefd5dfed09 100644 --- a/src/HotChocolate/Core/src/Validation/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Validation/ErrorHelper.cs @@ -614,7 +614,7 @@ public IError OneOfVariablesMustBeNonNull( .SetMessage( Resources.ErrorHelper_OneOfVariablesMustBeNonNull, variableName, - fieldCoordinate.MemberName!, + fieldCoordinate.MemberName, fieldCoordinate.Name) .AddLocation(node) .SetPath(context.CreateErrorPath()) From 50a3a78cec48303648b810b691958e11fb775ef9 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 10:34:28 +0100 Subject: [PATCH 19/42] wip --- .../Core/src/Types/Execution/ErrorHelper.cs | 10 +- .../Types/Execution/Processing/Operation.cs | 12 +- .../Execution/Processing/OperationCompiler.cs | 102 +++++++- .../OperationCompilerOptimizerHelper.cs | 22 +- .../OperationFeatureCollection.Selections.cs | 48 +++- .../Processing/OperationOptimizerContext.cs | 45 +--- .../Types/Execution/Processing/Selection.cs | 14 +- .../Processing/SelectionFeatureCollection.cs | 46 ++++ .../Execution/Processing/SelectionSet.cs | 14 +- .../SelectionSetOptimizerContext.cs | 111 ++++----- .../Processing/ValueCompletion.Object.cs | 10 +- .../Types/Execution/RequestExecutorManager.cs | 3 +- .../Core/src/Types/Execution/ThrowHelper.cs | 6 + .../Extensions/ResolverContextExtensions.cs | 230 ++++-------------- .../Types/Pagination/ConnectionFlagsHelper.cs | 89 ++++--- .../Core/src/Types/Utilities/ThrowHelper.cs | 9 +- .../Processing/OperationCompilerTests.cs | 2 +- .../QueryablePagingProjectionOptimizer.cs | 2 +- .../IsProjectedProjectionOptimizer.cs | 2 +- 19 files changed, 370 insertions(+), 407 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs index 5ed2a9d615d..abcb9c0ca53 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs @@ -57,12 +57,12 @@ public static IError UnexpectedLeafValueSerializationError( public static IError UnableToResolveTheAbstractType( string typeName, - FieldNode field, + Selection selection, Path path) { return ErrorBuilder.New() .SetMessage(ErrorHelper_UnableToResolveTheAbstractType_Message, typeName) - .AddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.CannotResolveAbstractType) .Build(); @@ -71,12 +71,12 @@ public static IError UnableToResolveTheAbstractType( public static IError UnexpectedErrorWhileResolvingAbstractType( Exception exception, string typeName, - FieldNode field, + Selection selection, Path path) { return ErrorBuilder.New() .SetMessage(ErrorHelper_UnableToResolveTheAbstractType_Message, typeName) - .AddLocation(field) + .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.CannotResolveAbstractType) .SetException(exception) @@ -89,7 +89,7 @@ public static IError ListValueIsNotSupported( Path path) { return ErrorBuilder.New() - .SetMessage(ErrorHelper_ListValueIsNotSupported_Message, listType.FullName!) + .SetMessage(ErrorHelper_ListValueIsNotSupported_Message, listType.FullName) .AddLocations(selection) .SetPath(path) .SetCode(ErrorCodes.Execution.ListTypeNotSupported) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index 78631edb320..c88f27dda86 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -19,7 +19,6 @@ public sealed class Operation : IOperation private readonly OperationCompiler _compiler; private readonly IncludeConditionCollection _includeConditions; private readonly OperationFeatureCollection _features; - private readonly bool _isFinal; private object[] _elementsById; private int _lastId; @@ -33,9 +32,9 @@ internal Operation( SelectionSet rootSelectionSet, OperationCompiler compiler, IncludeConditionCollection includeConditions, + OperationFeatureCollection features, int lastId, - object[] elementsById, - bool isFinal) + object[] elementsById) { ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentException.ThrowIfNullOrWhiteSpace(hash); @@ -59,10 +58,7 @@ internal Operation( _includeConditions = includeConditions; _lastId = lastId; _elementsById = elementsById; - _isFinal = isFinal; - - _features = new OperationFeatureCollection(); - rootSelectionSet.Complete(this, seal: isFinal); + _features = features; } /// @@ -183,12 +179,12 @@ public SelectionSet GetSelectionSet(Selection selection, IObjectTypeDefinition t { selectionSet = _compiler.CompileSelectionSet( + this, selection, objectType, _includeConditions, ref _elementsById, ref _lastId); - selectionSet.Complete(this, seal: _isFinal); _selectionSets.TryAdd(key, selectionSet); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index ee24611434a..2565aa7b5fd 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -1,4 +1,6 @@ using System.Buffers; +using System.Collections.Immutable; +using System.Runtime.InteropServices; using HotChocolate.Fusion.Rewriters; using HotChocolate.Language; using HotChocolate.Language.Visitors; @@ -11,6 +13,7 @@ internal sealed partial class OperationCompiler { private readonly Schema _schema; private readonly ObjectPool>> _fieldsPool; + private readonly OperationCompilerOptimizers _optimizers; private readonly DocumentRewriter _documentRewriter; private readonly InputParser _inputValueParser; private static readonly ArrayPool s_objectArrayPool = ArrayPool.Shared; @@ -18,7 +21,8 @@ internal sealed partial class OperationCompiler public OperationCompiler( Schema schema, InputParser inputValueParser, - ObjectPool>> fieldsPool) + ObjectPool>> fieldsPool, + OperationCompilerOptimizers optimizers) { ArgumentNullException.ThrowIfNull(schema); ArgumentNullException.ThrowIfNull(fieldsPool); @@ -27,6 +31,7 @@ public OperationCompiler( _inputValueParser = inputValueParser; _fieldsPool = fieldsPool; _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); + _optimizers = optimizers; } public Operation Compile( @@ -64,11 +69,12 @@ public Operation Compile( fields, rootType, compilationContext, + _optimizers.SelectionSetOptimizers, ref lastId); compilationContext.Register(selectionSet, selectionSet.Id); - return new Operation( + var operation = new Operation( id, hash, document, @@ -76,11 +82,24 @@ public Operation Compile( rootType, _schema, selectionSet, - this, + compiler: this, includeConditions, + compilationContext.Features, lastId, - compilationContext.ElementsById, - isFinal: true); // todo : add the interceptors back + compilationContext.ElementsById); + + selectionSet.Complete(operation); + + if (_optimizers.OperationOptimizers.Length > 0) + { + var context = new OperationOptimizerContext(operation); + foreach (var optimizer in _optimizers.OperationOptimizers) + { + optimizer.OptimizeOperation(context); + } + } + + return operation; } finally { @@ -89,13 +108,16 @@ public Operation Compile( } internal SelectionSet CompileSelectionSet( + Operation operation, Selection selection, ObjectType objectType, IncludeConditionCollection includeConditions, ref object[] elementsById, ref int lastId) { - var compilationContext = new CompilationContext(elementsById); + var compilationContext = new CompilationContext(elementsById, operation.Features); + var optimizers = OperationCompilerOptimizerHelper.GetOptimizers(selection); + var fields = _fieldsPool.Get(); fields.Clear(); @@ -126,9 +148,10 @@ internal SelectionSet CompileSelectionSet( } } - var selectionSet = BuildSelectionSet(fields, objectType, compilationContext, ref lastId); + var selectionSet = BuildSelectionSet(fields, objectType, compilationContext, optimizers, ref lastId); compilationContext.Register(selectionSet, selectionSet.Id); elementsById = compilationContext.ElementsById; + selectionSet.Complete(operation); return selectionSet; } finally @@ -193,6 +216,7 @@ private SelectionSet BuildSelectionSet( OrderedDictionary> fieldMap, ObjectType typeContext, CompilationContext compilationContext, + ImmutableArray optimizers, ref int lastId) { var i = 0; @@ -263,6 +287,11 @@ private SelectionSet BuildSelectionSet( fieldDelegate, pureFieldDelegate); + if (optimizers.Length > 0) + { + selection.Features.SetSafe(optimizers); + } + // Register the selection in the elements array compilationContext.Register(selection, selection.Id); selections[i++] = selection; @@ -273,6 +302,53 @@ private SelectionSet BuildSelectionSet( } } + // if there are no optimizers registered for this selection we exit early. + if (optimizers.Length == 0) + { + return new SelectionSet(selectionSetId, typeContext, selections, isConditional); + } + + var current = ImmutableCollectionsMarshal.AsImmutableArray(selections); + var rewritten = current; + + var optimizerContext = new SelectionSetOptimizerContext( + selectionSetId, + typeContext, + ref rewritten, + compilationContext.Features, + ref lastId, + _schema, + CreateFieldPipeline); + + foreach (var optimizer in optimizers) + { + optimizer.OptimizeSelectionSet(optimizerContext); + } + + // If `rewritten` is still the same instance as `current`, + // the optimizers did not change the selections array. + // This mean we can simply construct the SelectionSet. + if (current == rewritten) + { + return new SelectionSet(selectionSetId, typeContext, selections, isConditional); + } + + if (current.Length < rewritten.Length) + { + for (var j = current.Length; j < rewritten.Length; j++) + { + var selection = rewritten[j]; + + if (optimizers.Length > 0) + { + selection.Features.SetSafe(optimizers); + } + + compilationContext.Register(selection, selection.Id); + } + } + + selections = ImmutableCollectionsMarshal.AsArray(rewritten)!; return new SelectionSet(selectionSetId, typeContext, selections, isConditional); } @@ -418,12 +494,20 @@ protected override ISyntaxVisitorAction Enter( } } - private class CompilationContext(object[] elementsById) + private class CompilationContext { - private object[] _elementsById = elementsById; + private object[] _elementsById; + + public CompilationContext(object[] elementsById, OperationFeatureCollection? features = null) + { + _elementsById = elementsById; + Features = features ?? new OperationFeatureCollection(); + } public object[] ElementsById => _elementsById; + public OperationFeatureCollection Features { get; } + public void Register(object element, int id) { if (id >= _elementsById.Length) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs index 4a9ed3b2d8e..43b1bd835e7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizerHelper.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Execution.Processing; /// -/// This helper class allows adding optimizers to context data or retrieve optimizers from context data. +/// This helper class allows to register optimizers with a field configuration. /// internal static class OperationCompilerOptimizerHelper { @@ -33,8 +33,20 @@ private static void RegisterOptimizerInternal( } } - public static bool TryGetOptimizers( - IFeatureProvider featureProvider, - out ImmutableArray optimizers) - => featureProvider.Features.TryGet(out optimizers); + public static ImmutableArray GetOptimizers(Selection selection) + { + var optimizers = ImmutableArray.Empty; + + if (selection.Features.TryGet>(out var selectionOptimizers)) + { + optimizers = selectionOptimizers; + } + + if (selection.Field.Features.TryGet>(out var fieldOptimizers)) + { + optimizers = optimizers.AddRange(fieldOptimizers); + } + + return optimizers; + } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs index 22cda22d024..bb718cc5eb7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.Selections.cs @@ -6,19 +6,6 @@ namespace HotChocolate.Execution.Processing; [SuppressMessage("ReSharper", "NonAtomicCompoundOperator")] public sealed partial class OperationFeatureCollection { - internal bool TryGet(int selectionId, [NotNullWhen(true)] out TFeature? feature) - { - if (_selectionFeatures.TryGetValue((selectionId, typeof(TFeature)), out var result) - && result is TFeature f) - { - feature = f; - return true; - } - - feature = default; - return false; - } - internal object? this[int selectionId, Type featureType] { get @@ -48,6 +35,19 @@ internal bool TryGet(int selectionId, [NotNullWhen(true)] out TFeature } } + internal bool TryGet(int selectionId, [NotNullWhen(true)] out TFeature? feature) + { + if (_selectionFeatures.TryGetValue((selectionId, typeof(TFeature)), out var result) + && result is TFeature f) + { + feature = f; + return true; + } + + feature = default; + return false; + } + internal TFeature GetOrSetSafe(int selectionId, Func factory) { ArgumentNullException.ThrowIfNull(factory); @@ -67,6 +67,28 @@ internal TFeature GetOrSetSafe(int selectionId, Func factory return feature; } + internal TFeature GetOrSetSafe( + int selectionId, + Func factory, + TContext context) + { + ArgumentNullException.ThrowIfNull(factory); + + if (!TryGet(selectionId, out var feature)) + { + lock (_writeLock) + { + if (!TryGet(selectionId, out feature)) + { + feature = factory(context); + this[selectionId, typeof(TFeature)] = feature; + } + } + } + + return feature; + } + internal IEnumerable> GetFeatures(int selectionId) { foreach (var ((id, type), value) in _selectionFeatures) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs index 4aaabec22ae..c2f721a968a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationOptimizerContext.cs @@ -10,60 +10,17 @@ namespace HotChocolate.Execution.Processing; /// public readonly ref struct OperationOptimizerContext { - private readonly CreateFieldPipeline _createFieldPipeline; - /// /// Initializes a new instance of /// internal OperationOptimizerContext( - Operation operation, - Dictionary contextData, - CreateFieldPipeline createFieldPipeline) + Operation operation) { Operation = operation; - ContextData = contextData; - _createFieldPipeline = createFieldPipeline; } /// /// Gets the operation. /// public Operation Operation { get; } - - /// - /// The context data dictionary can be used by middleware components and - /// resolvers to store and retrieve data during execution. - /// - public IDictionary ContextData { get; } - - /// - /// Sets the resolvers on the specified . - /// - /// - /// The selection to set the resolvers on. - /// - /// - /// The async resolver pipeline. - /// - /// - /// The pure resolver. - /// - public void SetResolver( - Selection selection, - FieldDelegate? resolverPipeline = null, - PureFieldDelegate? pureResolver = null) - => selection.SetResolvers(resolverPipeline, pureResolver); - - /// - /// Allows to compile the field resolver pipeline for a field. - /// - /// The field. - /// The selection of the field. - /// - /// Returns a representing the field resolver pipeline. - /// - public FieldDelegate CompileResolverPipeline( - ObjectField field, - FieldNode fieldSelection) - => _createFieldPipeline(Operation.Schema, field, fieldSelection); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index b782c6cf467..cef3f42b1cd 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -16,6 +16,7 @@ public sealed class Selection : ISelection, IFeatureProvider private readonly ulong[] _includeFlags; private readonly byte[] _utf8ResponseName; private Flags _flags; + private SelectionSet? _declaringSelectionSet; internal Selection( int id, @@ -109,7 +110,8 @@ internal Selection( /// /// Gets the selection set that contains this selection. /// - public SelectionSet DeclaringSelectionSet { get; private set; } = null!; + public SelectionSet DeclaringSelectionSet + => _declaringSelectionSet ?? throw ThrowHelper.Selection_NotFullyInitialized(); /// ISelectionSet ISelection.DeclaringSelectionSet => DeclaringSelectionSet; @@ -240,7 +242,7 @@ internal void SetResolvers( /// /// Completes the selection without sealing it. /// - internal void Complete(SelectionSet selectionSet, bool seal) + internal void Complete(SelectionSet selectionSet) { ArgumentNullException.ThrowIfNull(selectionSet); @@ -249,12 +251,8 @@ internal void Complete(SelectionSet selectionSet, bool seal) throw new InvalidOperationException("Selection is already sealed."); } - DeclaringSelectionSet = selectionSet; - - if (seal) - { - _flags |= Flags.Sealed; - } + _declaringSelectionSet = selectionSet; + _flags |= Flags.Sealed; } private SelectionExecutionStrategy InferStrategy( diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs index c122ee84ae3..b1fe6773b6e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs @@ -4,6 +4,11 @@ namespace HotChocolate.Execution.Processing; +/// +/// Represents a collection of features associated with a specific selection +/// within a GraphQL operation. This struct provides a view into the parent +/// scoped to a single selection. +/// public readonly struct SelectionFeatureCollection : IFeatureCollection { private readonly OperationFeatureCollection _parent; @@ -15,27 +20,68 @@ internal SelectionFeatureCollection(OperationFeatureCollection parent, int selec _selectionId = selectionId; } + /// + /// Gets a value indicating whether this feature collection is read-only. + /// public bool IsReadOnly => _parent.IsReadOnly; + /// + /// Gets a value indicating whether this selection has no features. + /// public bool IsEmpty => !_parent.HasFeatures(_selectionId); + /// + /// Gets the revision number of the underlying feature collection. + /// public int Revision => _parent.Revision; + /// + /// Gets or sets a feature by its type. + /// + /// The type of the feature. + /// The feature instance, or null if not found. public object? this[Type key] { get => _parent[_selectionId, key]; set => _parent[_selectionId, key] = value; } + /// + /// Sets a feature instance for this selection. + /// + /// The type of the feature. + /// The feature instance to set, or null to remove. + /// This method is thread-safe. + public void SetSafe(TFeature? instance) + => this[typeof(TFeature)] = instance; + + /// + /// Tries to get a feature of the specified type. + /// + /// The type of the feature. + /// + /// When this method returns, contains the feature if found; otherwise, null. + /// + /// true if the feature was found; otherwise, false. public bool TryGet([NotNullWhen(true)] out TFeature? feature) => _parent.TryGet(_selectionId, out feature); + /// + /// Gets an existing feature or creates and sets a new instance using the default constructor. + /// + /// The type of the feature. + /// The existing or newly created feature instance. + /// This method is thread-safe. public TFeature GetOrSetSafe() where TFeature : new() => GetOrSetSafe(static () => new TFeature()); internal TFeature GetOrSetSafe(Func factory) => _parent.GetOrSetSafe(_selectionId, factory); + internal TFeature GetOrSetSafe(Func factory, TContext context) + => _parent.GetOrSetSafe(_selectionId, factory, context); + + /// public IEnumerator> GetEnumerator() => _parent.GetFeatures(_selectionId).GetEnumerator(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 7c0cc5c51db..228f15f6261 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -16,6 +16,7 @@ public sealed class SelectionSet : ISelectionSet private readonly FrozenDictionary _responseNameLookup; private readonly SelectionLookup _utf8ResponseNameLookup; private Flags _flags; + private Operation? _declaringOperation; internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, bool isConditional) { @@ -52,7 +53,7 @@ internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections /// /// Gets the declaring operation. /// - public Operation DeclaringOperation { get; private set; } = null!; + public Operation DeclaringOperation => _declaringOperation ?? throw ThrowHelper.SelectionSet_NotFullyInitialized(); IOperation ISelectionSet.DeclaringOperation => DeclaringOperation; @@ -93,24 +94,21 @@ public bool TryGetSelection(string responseName, [NotNullWhen(true)] out Selecti public bool TryGetSelection(ReadOnlySpan utf8ResponseName, [NotNullWhen(true)] out Selection? selection) => _utf8ResponseNameLookup.TryGetSelection(utf8ResponseName, out selection); - internal void Complete(Operation declaringOperation, bool seal) + internal void Complete(Operation declaringOperation) { if ((_flags & Flags.Sealed) == Flags.Sealed) { throw new InvalidOperationException("Selection set is already sealed."); } - DeclaringOperation = declaringOperation; + _declaringOperation = declaringOperation; foreach (var selection in _selections) { - selection.Complete(this, seal); + selection.Complete(this); } - if (seal) - { - _flags |= Flags.Sealed; - } + _flags |= Flags.Sealed; } [Flags] diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs index a7beac3cfaa..afb94e02f92 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs @@ -1,6 +1,9 @@ +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using HotChocolate.Language; using HotChocolate.Resolvers; using HotChocolate.Types; +using HotChocolate.Utilities; namespace HotChocolate.Execution.Processing; @@ -8,66 +11,67 @@ namespace HotChocolate.Execution.Processing; /// The optimizer provides helper methods /// to optimize a . /// -public readonly ref struct SelectionSetOptimizerContext +public ref struct SelectionSetOptimizerContext { - private readonly OperationCompiler _compiler; - private readonly OperationCompiler.CompilerContext _compilerContext; - private readonly Dictionary _selectionLookup; - private readonly CreateFieldPipeline _createFieldPipeline; - + private readonly int _selectionSetId; + private readonly ref ImmutableArray _selections; + private readonly OperationFeatureCollection _features; + private readonly ref int _lastSelectionId; + private readonly Func _createFieldPipeline; + private Dictionary? _selectionMap; /// /// Initializes a new instance of /// internal SelectionSetOptimizerContext( - OperationCompiler compiler, - OperationCompiler.CompilerContext compilerContext, - Dictionary selectionLookup, - Dictionary contextData, - CreateFieldPipeline createFieldPipeline, - SelectionPath path) + int selectionSetId, + ObjectType typeContext, + ref ImmutableArray selections, + OperationFeatureCollection features, + ref int lastSelectionId, + Schema schema, + Func createFieldPipeline) { - _compiler = compiler; - _compilerContext = compilerContext; - _selectionLookup = selectionLookup; + _selectionSetId = selectionSetId; + _selections = ref selections; + _features = features; + _lastSelectionId = ref lastSelectionId; _createFieldPipeline = createFieldPipeline; - ContextData = contextData; - Path = path; + TypeContext = typeContext; + Schema = schema; } /// /// Gets the schema for which the query is compiled. /// - public Schema Schema - => _compilerContext.Schema; + public Schema Schema { get; } /// /// Gets the type context of the current selection-set. /// - public ObjectType Type - => _compilerContext.Type; + public ObjectType TypeContext { get; } - /// - /// Gets the selections of this selection set. - /// - public IReadOnlyDictionary Selections - => _compilerContext.Fields; + public bool ContainsField(string fieldName) + => _selections.Any(t => t.Field.Name.EqualsOrdinal(fieldName)); - /// - /// The context data dictionary can be used by middleware components and - /// resolvers to store and retrieve data during execution. - /// - public IDictionary ContextData { get; } + public bool ContainsResponseName(string responseName) + { + _selectionMap ??= _selections.ToDictionary(t => t.ResponseName); + return _selectionMap.ContainsKey(responseName); + } - /// - /// Gets the current selection path. - /// - public SelectionPath Path { get; } + public bool TryGetSelection(string responseName, [MaybeNullWhen(false)] out Selection value) + { + _selectionMap ??= _selections.ToDictionary(t => t.ResponseName); + return _selectionMap.TryGetValue(responseName, out value); + } + + public SelectionFeatureCollection Features => new(_features, _selectionSetId); /// /// Gets the next operation unique selection id. /// - public int GetNextSelectionId() - => _compiler.GetNextSelectionId(); + public int NewSelectionId() + => ++_lastSelectionId; /// /// Sets the resolvers on the specified . @@ -99,20 +103,21 @@ public FieldDelegate CompileResolverPipeline(ObjectField field, FieldNode select => _createFieldPipeline(Schema, field, selection); /// - /// Adds an additional selection for internal purposes. + /// Adds a selection for internal purposes. /// - /// - /// The new optimized selection. + /// + /// The internal selection. /// /// - /// is null. + /// is null. /// - public void AddSelection(Selection newSelection) + public void AddSelection(Selection internalSelection) { - ArgumentNullException.ThrowIfNull(newSelection); + ArgumentNullException.ThrowIfNull(internalSelection); - _compilerContext.Fields.Add(newSelection.ResponseName, newSelection); - _compiler.RegisterNewSelection(newSelection); + _selectionMap ??= _selections.ToDictionary(t => t.ResponseName); + _selectionMap.Add(internalSelection.ResponseName, internalSelection); + _selections = _selections.Add(internalSelection); } /// @@ -132,19 +137,15 @@ public void ReplaceSelection(Selection newSelection) { ArgumentNullException.ThrowIfNull(newSelection); - if (!_compilerContext.Fields.TryGetValue( - newSelection.ResponseName, - out var currentSelection)) + _selectionMap ??= _selections.ToDictionary(t => t.ResponseName); + + if (!_selectionMap.TryGetValue(newSelection.ResponseName, out var currentSelection)) { throw new ArgumentException($"The `{newSelection.ResponseName}` does not exist."); } - _compilerContext.Fields[newSelection.ResponseName] = newSelection; - - if (_selectionLookup.TryGetValue(currentSelection, out var selectionSetInfos)) - { - _selectionLookup.Remove(currentSelection); - _selectionLookup.Add(newSelection, selectionSetInfos); - } + _selectionMap[newSelection.ResponseName] = newSelection; + var index = _selections.IndexOf(currentSelection); + _selections = _selections.SetItem(index, newSelection); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs index 4c940e97cd1..522a3698743 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs @@ -11,7 +11,7 @@ internal static partial class ValueCompletion { private static ObjectResult? CompleteCompositeValue( ValueCompletionContext context, - ISelection selection, + Selection selection, IType type, ResultData parent, int index, @@ -34,14 +34,14 @@ internal static partial class ValueCompletion } var errorPath = CreatePathFromContext(selection, parent, index); - var error = ValueCompletion_CouldNotResolveAbstractType(selection.SyntaxNode, errorPath, result); + var error = ValueCompletion_CouldNotResolveAbstractType(selection, errorPath, result); operationContext.ReportError(error, context.ResolverContext, selection); return null; } private static bool TryResolveObjectType( ValueCompletionContext context, - ISelection selection, + Selection selection, IType fieldType, ResultData parent, int index, @@ -76,7 +76,7 @@ private static bool TryResolveObjectType( var error = UnableToResolveTheAbstractType( fieldType.Print(), - selection.SyntaxNode, + selection, CreatePathFromContext(selection, parent, index)); context.OperationContext.ReportError(error, context.ResolverContext, selection); } @@ -85,7 +85,7 @@ private static bool TryResolveObjectType( var error = UnexpectedErrorWhileResolvingAbstractType( ex, fieldType.Print(), - selection.SyntaxNode, + selection, CreatePathFromContext(selection, parent, index)); context.OperationContext.ReportError(error, context.ResolverContext, selection); } diff --git a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs index c26e30ec3db..a3ebe5b7ee4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs +++ b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs @@ -275,7 +275,8 @@ await typeModuleChangeMonitor.ConfigureAsync(context, cancellationToken) static sp => new OperationCompiler( sp.GetRequiredService(), sp.GetRequiredService(), - sp.GetRequiredService>>>())); + sp.GetRequiredService>>>(), + sp.GetRequiredService())); serviceCollection.AddSingleton( static _ => new DefaultObjectPoolProvider()); diff --git a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs index a9b8ebe2e4e..d2ac4820927 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs @@ -6,6 +6,12 @@ namespace HotChocolate.Execution; internal static class ThrowHelper { + public static InvalidOperationException SelectionSet_NotFullyInitialized() + => new InvalidOperationException("The selection set is not fully initialized."); + + public static InvalidOperationException Selection_NotFullyInitialized() + => new InvalidOperationException("The selection is not fully initialized."); + public static GraphQLException VariableIsNotAnInputType( VariableDefinitionNode variableDefinition) { diff --git a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs index 29c5d692654..9a886885497 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs @@ -23,12 +23,7 @@ public static class ResolverContextExtensions /// public T? GetGlobalStateOrDefault(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ContextData.TryGetValue(name, out var value) && value is T casted) @@ -51,15 +46,9 @@ public static class ResolverContextExtensions /// or the default value of , if the state /// could not be found or cast to . /// - public T GetGlobalStateOrDefault(string name, - T defaultValue) + public T GetGlobalStateOrDefault(string name, T defaultValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ContextData.TryGetValue(name, out var value) && value is T casted) @@ -81,12 +70,7 @@ public T GetGlobalStateOrDefault(string name, /// public T GetGlobalState(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ContextData.TryGetValue(name, out var value) && value is T typedValue) { @@ -110,12 +94,7 @@ public T GetGlobalState(string name) /// public T? GetScopedStateOrDefault(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ScopedContextData.TryGetValue(name, out var value) && value is T casted) @@ -138,15 +117,9 @@ public T GetGlobalState(string name) /// or the default value of , if the state /// could not be found or cast to . /// - public T GetScopedStateOrDefault(string name, - T defaultValue) + public T GetScopedStateOrDefault(string name, T defaultValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ScopedContextData.TryGetValue(name, out var value) && value is T casted) @@ -168,12 +141,7 @@ public T GetScopedStateOrDefault(string name, /// public T GetScopedState(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.ScopedContextData.TryGetValue(name, out var value) && value is T typedValue) @@ -198,12 +166,7 @@ public T GetScopedState(string name) /// public T? GetLocalStateOrDefault(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.LocalContextData.TryGetValue(name, out var value) && value is T casted) @@ -226,15 +189,9 @@ public T GetScopedState(string name) /// or the default value of , if the state /// could not be found or cast to . /// - public T GetLocalStateOrDefault(string name, - T defaultValue) + public T GetLocalStateOrDefault(string name, T defaultValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.LocalContextData.TryGetValue(name, out var value) && value is T casted) @@ -256,12 +213,7 @@ public T GetLocalStateOrDefault(string name, /// public T GetLocalState(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } + ArgumentException.ThrowIfNullOrEmpty(name); if (context.LocalContextData.TryGetValue(name, out var value) && value is T casted) @@ -282,16 +234,9 @@ public T GetLocalState(string name) /// The name of the state. /// The new state value. /// The type of the state. - public void SetGlobalState(string name, - T value) + public void SetGlobalState(string name, T value) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); context.ContextData[name] = value; } @@ -304,16 +249,9 @@ public void SetGlobalState(string name, /// The name of the state. /// The new state value. /// The type of the state. - public void SetScopedState(string name, - T value) + public void SetScopedState(string name, T value) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); context.ScopedContextData = context.ScopedContextData.SetItem(name, value); } @@ -326,16 +264,9 @@ public void SetScopedState(string name, /// The name of the state. /// The new state value. /// The type of the state. - public void SetLocalState(string name, - T value) + public void SetLocalState(string name, T value) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); context.LocalContextData = context.LocalContextData.SetItem(name, value); } @@ -352,16 +283,9 @@ public void SetLocalState(string name, /// The existing state for the specified , /// or the newly created state using the function. /// - public T GetOrSetGlobalState(string name, - Func createValue) + public T GetOrSetGlobalState(string name, Func createValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); ArgumentNullException.ThrowIfNull(createValue); if (context.ContextData.TryGetValue(name, out var value) @@ -388,16 +312,9 @@ public T GetOrSetGlobalState(string name, /// The existing state for the specified , /// or the newly created state using the function. /// - public T GetOrSetScopedState(string name, - Func createValue) + public T GetOrSetScopedState(string name, Func createValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); ArgumentNullException.ThrowIfNull(createValue); if (context.ScopedContextData.TryGetValue(name, out var value) @@ -424,16 +341,9 @@ public T GetOrSetScopedState(string name, /// The existing state for the specified , /// or the newly created state using the function. /// - public T GetOrSetLocalState(string name, - Func createValue) + public T GetOrSetLocalState(string name, Func createValue) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); ArgumentNullException.ThrowIfNull(createValue); if (context.LocalContextData.TryGetValue(name, out var value) @@ -453,13 +363,7 @@ public T GetOrSetLocalState(string name, /// The name of the state. public void RemoveScopedState(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); context.ScopedContextData = context.ScopedContextData.Remove(name); } @@ -469,13 +373,7 @@ public void RemoveScopedState(string name) /// The name of the state. public void RemoveLocalState(string name) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrEmpty(name)) - { - throw String_NullOrEmpty(nameof(name)); - } - + ArgumentException.ThrowIfNullOrEmpty(name); context.LocalContextData = context.LocalContextData.Remove(name); } @@ -486,8 +384,6 @@ public void RemoveLocalState(string name) /// The event message. public T GetEventMessage() { - ArgumentNullException.ThrowIfNull(context); - if (context.ScopedContextData.TryGetValue( WellKnownContextData.EventMessage, out var value) && value is { }) @@ -521,22 +417,12 @@ public T GetEventMessage() /// /// true if the field is selected; otherwise, false. /// - /// - /// is null. - /// /// /// is null or whitespace. /// public bool IsSelected(string fieldName) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrWhiteSpace(fieldName)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName)); - } + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName); var namedType = context.Selection.Type.NamedType(); @@ -589,31 +475,17 @@ public bool IsSelected(string fieldName) /// /// The name of the second field that shall be checked. /// - /// - /// - /// is null. - /// + /// + /// true if one of the fields is selected; otherwise, false. + /// /// /// is null or whitespace or /// is null or whitespace. /// public bool IsSelected(string fieldName1, string fieldName2) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrWhiteSpace(fieldName1)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName1)); - } - - if (string.IsNullOrWhiteSpace(fieldName2)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName2)); - } + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName1); + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName2); var namedType = context.Selection.Type.NamedType(); @@ -677,10 +549,9 @@ public bool IsSelected(string fieldName1, string fieldName2) /// /// The name of the third field that shall be checked. /// - /// - /// - /// is null. - /// + /// + /// true if one of the fields is selected; otherwise, false. + /// /// /// is null or whitespace or /// is null or whitespace or @@ -688,28 +559,9 @@ public bool IsSelected(string fieldName1, string fieldName2) /// public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) { - ArgumentNullException.ThrowIfNull(context); - - if (string.IsNullOrWhiteSpace(fieldName1)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName1)); - } - - if (string.IsNullOrWhiteSpace(fieldName2)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName2)); - } - - if (string.IsNullOrWhiteSpace(fieldName3)) - { - throw new ArgumentException( - ResolverContextExtensions_IsSelected_FieldNameEmpty, - nameof(fieldName3)); - } + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName1); + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName2); + ArgumentException.ThrowIfNullOrWhiteSpace(fieldName3); var namedType = context.Selection.Type.NamedType(); @@ -771,14 +623,14 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) /// /// The names of the fields that shall be checked. /// - /// + /// + /// true if one of the fields is selected; otherwise, false. + /// /// - /// is null or /// is null. /// public bool IsSelected(ISet fieldNames) { - ArgumentNullException.ThrowIfNull(context); ArgumentNullException.ThrowIfNull(fieldNames); var namedType = context.Selection.Type.NamedType(); diff --git a/src/HotChocolate/Core/src/Types/Types/Pagination/ConnectionFlagsHelper.cs b/src/HotChocolate/Core/src/Types/Types/Pagination/ConnectionFlagsHelper.cs index ce5b2eecdd7..9bce97065b6 100644 --- a/src/HotChocolate/Core/src/Types/Types/Pagination/ConnectionFlagsHelper.cs +++ b/src/HotChocolate/Core/src/Types/Types/Pagination/ConnectionFlagsHelper.cs @@ -12,71 +12,66 @@ namespace HotChocolate.Types.Pagination; /// public static class ConnectionFlagsHelper { - private const string KeyFormat = "HotChocolate.Types.Pagination.ConnectionFlags_{0}"; private static readonly ConcurrentDictionary s_parsedSelectionSets = new(); /// /// Gets the connection flags from the current resolver context. /// public static ConnectionFlags GetConnectionFlags(IResolverContext context) + => context.Selection.Features.GetOrSetSafe(CreateConnectionFlags, context); + + private static ConnectionFlags CreateConnectionFlags(IResolverContext context) { - return context.Operation.GetOrAddState( - string.Format(KeyFormat, context.Selection.Id), - static (_, ctx) => - { - if (ctx.Selection.Field is ObjectField field - && !field.Flags.HasFlag(CoreFieldFlags.Connection)) - { - return ConnectionFlags.None; - } + if (context.Selection.Field.Flags.HasFlag(CoreFieldFlags.Connection)) + { + return ConnectionFlags.None; + } - var options = PagingHelper.GetPagingOptions(ctx.Schema, ctx.Selection.Field); + var connectionFlags = ConnectionFlags.None; - var connectionFlags = ConnectionFlags.None; + if (context.IsSelected("edges")) + { + connectionFlags |= ConnectionFlags.Edges; + } - if (ctx.IsSelected("edges")) - { - connectionFlags |= ConnectionFlags.Edges; - } + if (context.IsSelected("nodes")) + { + connectionFlags |= ConnectionFlags.Nodes; + } - if (ctx.IsSelected("nodes")) - { - connectionFlags |= ConnectionFlags.Nodes; - } + if (context.IsSelected("totalCount")) + { + connectionFlags |= ConnectionFlags.TotalCount; + } + + var options = PagingHelper.GetPagingOptions(context.Schema, context.Selection.Field); + + if (options.PageInfoFields.Count > 0 + || ((options.EnableRelativeCursors ?? PagingDefaults.EnableRelativeCursors) + && options.RelativeCursorFields.Count > 0)) + { + var startSelections = context.Select(); + var selectionContext = new IsSelectedContext(context.Schema, startSelections); - if (ctx.IsSelected("totalCount")) + if (options.PageInfoFields.Count > 0) + { + if (ArePatternsMatched(startSelections, selectionContext, options.PageInfoFields)) { - connectionFlags |= ConnectionFlags.TotalCount; + connectionFlags |= ConnectionFlags.PageInfo; } + } - if (options.PageInfoFields.Count > 0 - || ((options.EnableRelativeCursors ?? PagingDefaults.EnableRelativeCursors) - && options.RelativeCursorFields.Count > 0)) + if ((options.EnableRelativeCursors ?? PagingDefaults.EnableRelativeCursors) + && options.RelativeCursorFields.Count > 0) + { + if (ArePatternsMatched(startSelections, selectionContext, options.RelativeCursorFields)) { - var startSelections = ctx.Select(); - var selectionContext = new IsSelectedContext(ctx.Schema, startSelections); - - if (options.PageInfoFields.Count > 0) - { - if (ArePatternsMatched(startSelections, selectionContext, options.PageInfoFields)) - { - connectionFlags |= ConnectionFlags.PageInfo; - } - } - - if ((options.EnableRelativeCursors ?? PagingDefaults.EnableRelativeCursors) - && options.RelativeCursorFields.Count > 0) - { - if (ArePatternsMatched(startSelections, selectionContext, options.RelativeCursorFields)) - { - connectionFlags |= ConnectionFlags.RelativeCursor; - } - } + connectionFlags |= ConnectionFlags.RelativeCursor; } + } + } - return connectionFlags; - }, - context); + return connectionFlags; } private static bool ArePatternsMatched( diff --git a/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs index 97b079fc8fe..60b2676dcda 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs @@ -12,11 +12,6 @@ namespace HotChocolate.Utilities; internal static class ThrowHelper { - public static ArgumentException String_NullOrEmpty(string parameterName) => - new ArgumentException( - $"'{parameterName}' cannot be null or empty", - parameterName); - public static GraphQLException EventMessage_InvalidCast( Type expectedType, Type messageType) => @@ -24,8 +19,8 @@ public static GraphQLException EventMessage_InvalidCast( ErrorBuilder.New() .SetMessage( ThrowHelper_EventMessage_InvalidCast, - messageType.FullName!, - expectedType.FullName!) + messageType.FullName, + expectedType.FullName) .Build()); public static GraphQLException EventMessage_NotFound() => diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs index ca9bd53c437..1274cf5d887 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs @@ -1441,7 +1441,7 @@ public void OptimizeSelectionSet(SelectionSetOptimizerContext context) var bazPipeline = context.CompileResolverPipeline(baz, bazSelection); var compiledSelection = new Selection( - context.GetNextSelectionId(), + context.NewSelectionId(), context.Type, baz, baz.Type, diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs index c6ad38ed3ff..d75c48d9c51 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs @@ -68,7 +68,7 @@ private Selection CreateCombinedSelection( context.CompileResolverPipeline(nodesField, combinedField); return new Selection.Sealed( - context.GetNextSelectionId(), + context.NewSelectionId(), declaringType, nodesField, nodesField.Type, diff --git a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs index feab6327d5f..c89ef8cbfe2 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs @@ -50,7 +50,7 @@ public Selection RewriteSelection( var nodesPipeline = context.CompileResolverPipeline(nodesField, nodesFieldNode); var compiledSelection = new Selection.Sealed( - context.GetNextSelectionId(), + context.NewSelectionId(), context.Type, nodesField, nodesField.Type, From 45ed184b524cf8b5a5e5821b69da9378860ce74b Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 11:14:34 +0100 Subject: [PATCH 20/42] align extension argument validation --- ...uestExecutorServiceCollectionExtensions.cs | 6 --- .../ObjectPoolProviderExtensions.cs | 5 +-- .../SchemaBuilderExtensions.Resolvers.cs | 44 ++----------------- .../src/Types/Extensions/SchemaExtensions.cs | 16 ------- .../DataLoaderResolverContextExtensions.cs | 2 - .../src/Types/Internal/TypeInfoExtensions.cs | 1 - .../Directives/InternalDirectiveExtensions.cs | 10 +---- .../Directives/LookupDirectiveExtensions.cs | 5 +-- .../Directives/RequireDescriptorExtensions.cs | 5 --- .../ShareableDirectiveExtensions.cs | 13 +----- .../Configurations/BindableListExtensions.cs | 6 +-- .../ArgumentDescriptorExtensions.cs | 3 -- .../DirectiveTypeDescriptorExtensions.cs | 5 --- .../InputObjectTypeDescriptorExtensions.cs | 29 ++---------- .../InterfaceTypeDescriptorExtensions.cs | 5 --- .../ObjectFieldDescriptorExtensions.cs | 20 --------- .../ObjectTypeDescriptorExtensions.cs | 2 - .../Types/Types/Extensions/TypeExtensions.cs | 13 +----- .../Extensions/NodeTypeFeatureExtensions.cs | 3 -- .../Extensions/RelayIdFieldExtensions.cs | 21 --------- .../Core/src/Types/Types/TypeNamePrinter.cs | 2 - .../src/Types/Utilities/ReflectionUtils.cs | 24 ++-------- 22 files changed, 17 insertions(+), 223 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs index d78ec74851f..1c77312e894 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs @@ -25,8 +25,6 @@ public static class RequestExecutorServiceCollectionExtensions /// The . public static IServiceCollection AddGraphQLCore(this IServiceCollection services) { - ArgumentNullException.ThrowIfNull(services); - services.AddOptions(); services.TryAddSingleton(); @@ -109,8 +107,6 @@ public static IRequestExecutorBuilder AddGraphQL( this IServiceCollection services, string? schemaName = null) { - ArgumentNullException.ThrowIfNull(services); - services.AddGraphQLCore(); schemaName ??= ISchemaDefinition.DefaultName; return CreateBuilder(services, schemaName); @@ -133,8 +129,6 @@ public static IRequestExecutorBuilder AddGraphQL( this IRequestExecutorBuilder builder, string? schemaName = null) { - ArgumentNullException.ThrowIfNull(builder); - schemaName ??= ISchemaDefinition.DefaultName; return CreateBuilder(builder.Services, schemaName); } diff --git a/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs index 5a4feb791b5..771e393a38c 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ObjectPoolProviderExtensions.cs @@ -8,8 +8,5 @@ internal static class ObjectPoolProviderExtensions { public static ObjectPool>> CreateFieldMapPool( this ObjectPoolProvider provider) - { - ArgumentNullException.ThrowIfNull(provider); - return provider.Create(new FieldMapPooledObjectPolicy()); - } + => provider.Create(new FieldMapPooledObjectPolicy()); } diff --git a/src/HotChocolate/Core/src/Types/Extensions/SchemaBuilderExtensions.Resolvers.cs b/src/HotChocolate/Core/src/Types/Extensions/SchemaBuilderExtensions.Resolvers.cs index c1de2f430d9..15961ae8f91 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/SchemaBuilderExtensions.Resolvers.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/SchemaBuilderExtensions.Resolvers.cs @@ -33,9 +33,7 @@ public static ISchemaBuilder AddResolver( FieldResolverDelegate resolver, Type? resultType = null) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverConfigInternal(builder, fieldCoordinate, resolver, resultType); } @@ -63,9 +61,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal( builder, typeName, @@ -97,11 +93,8 @@ public static ISchemaBuilder AddResolver( string fieldName, Func> resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - - return AddResolverInternal(builder, typeName, fieldName, - ctx => resolver(ctx)); + return AddResolverInternal(builder, typeName, fieldName, ctx => resolver(ctx)); } /// @@ -128,9 +121,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, ctx => new ValueTask(resolver(ctx))); } @@ -159,9 +150,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func> resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, async ctx => await resolver(ctx).ConfigureAwait(false)); } @@ -190,9 +179,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, _ => new ValueTask(resolver())); } @@ -221,9 +208,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func> resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, _ => resolver()); } @@ -251,9 +236,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, _ => new ValueTask(resolver())); } @@ -282,9 +265,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func> resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal( builder, typeName, @@ -318,9 +299,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, ctx => new ValueTask(resolver(ctx, ctx.RequestAborted))); } @@ -349,9 +328,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal(builder, typeName, fieldName, ctx => new ValueTask(resolver(ctx, ctx.RequestAborted))); } @@ -380,9 +357,7 @@ public static ISchemaBuilder AddResolver( string fieldName, Func> resolver) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolver); - return AddResolverInternal( builder, typeName, @@ -415,12 +390,8 @@ public static ISchemaBuilder AddResolver( string typeName, string fieldName, object? constantResult) - { - ArgumentNullException.ThrowIfNull(builder); - - return AddResolverInternal(builder, typeName, fieldName, + => AddResolverInternal(builder, typeName, fieldName, _ => new ValueTask(constantResult)); - } /// /// Adds a resolver delegate that returns a constant result. @@ -445,12 +416,8 @@ public static ISchemaBuilder AddResolver( string typeName, string fieldName, TResult constantResult) - { - ArgumentNullException.ThrowIfNull(builder); - - return AddResolverInternal(builder, typeName, fieldName, + => AddResolverInternal(builder, typeName, fieldName, _ => new ValueTask(constantResult)); - } /// /// Adds a resolver delegate for a specific field. @@ -473,7 +440,6 @@ public static ISchemaBuilder AddResolver( Type resolverType, string? typeName = null) { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(resolverType); if (resolverType is { IsClass: true, IsAbstract: false, IsPublic: true } or @@ -519,8 +485,6 @@ public static ISchemaBuilder AddResolver( public static ISchemaBuilder AddRootResolver(this ISchemaBuilder builder, Type resolverType) { - ArgumentNullException.ThrowIfNull(builder); - if (resolverType is { IsClass: true } or { IsInterface: true }) { foreach (var property in resolverType.GetProperties()) @@ -542,9 +506,7 @@ public static ISchemaBuilder AddRootResolver(this ISchemaBuilder builder) public static ISchemaBuilder AddRootResolver(this ISchemaBuilder builder, T root) where T : class { - ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(root); - InitializeResolverTypeInterceptor(builder); var feature = builder.Features.GetRequired(); feature.RootInstance = root; diff --git a/src/HotChocolate/Core/src/Types/Extensions/SchemaExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/SchemaExtensions.cs index fa8a39f604a..e66dbf29e1c 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/SchemaExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/SchemaExtensions.cs @@ -44,9 +44,6 @@ public static class SchemaExtensions /// true if a type system member was found with the given /// ; otherwise, false. /// - /// - /// is null. - /// public static bool TryGetMember( this Schema schema, string coordinateString, @@ -77,16 +74,11 @@ public static bool TryGetMember( /// true if a type system member was found with the given /// ; otherwise, false. /// - /// - /// is null. - /// public static bool TryGetMember( this Schema schema, SchemaCoordinate coordinate, [NotNullWhen(true)] out ITypeSystemMember? member) { - ArgumentNullException.ThrowIfNull(schema); - if (coordinate.OfDirective) { if (schema.DirectiveTypes.TryGetDirective(coordinate.Name, out var directive)) @@ -178,9 +170,6 @@ public static bool TryGetMember( /// /// Returns the resolved type system member. /// - /// - /// is null. - /// /// /// The has invalid syntax. /// @@ -205,9 +194,6 @@ public static ITypeSystemMember GetMember( /// /// Returns the resolved type system member. /// - /// - /// is null. - /// /// /// Unable to resolve a type system member with the /// specified . @@ -216,8 +202,6 @@ public static ITypeSystemMember GetMember( this Schema schema, SchemaCoordinate coordinate) { - ArgumentNullException.ThrowIfNull(schema); - if (coordinate.OfDirective) { if (schema.DirectiveTypes.TryGetDirective(coordinate.Name, out var directive)) diff --git a/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs index 6acc7d516d7..b2487a09c38 100644 --- a/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Fetching/Extensions/DataLoaderResolverContextExtensions.cs @@ -12,8 +12,6 @@ public static class DataLoaderResolverContextExtensions public static T DataLoader(this IResolverContext context) where T : IDataLoader { - ArgumentNullException.ThrowIfNull(context); - var services = context.RequestServices; var reg = services.GetRequiredService(); return reg.GetDataLoader(); diff --git a/src/HotChocolate/Core/src/Types/Internal/TypeInfoExtensions.cs b/src/HotChocolate/Core/src/Types/Internal/TypeInfoExtensions.cs index 4d74b04267f..cd40ef9723d 100644 --- a/src/HotChocolate/Core/src/Types/Internal/TypeInfoExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Internal/TypeInfoExtensions.cs @@ -33,7 +33,6 @@ internal static IType CreateType(this ITypeInfo typeInfo, ITypeDefinition typeDe /// public static TypeReference CreateTypeReference(this ITypeInfo typeInfo, NamedTypeNode namedType) { - ArgumentNullException.ThrowIfNull(typeInfo); ArgumentNullException.ThrowIfNull(namedType); ITypeNode type = namedType; diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/InternalDirectiveExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/InternalDirectiveExtensions.cs index 5568f9d79e6..a98a9ba00f6 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/InternalDirectiveExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/InternalDirectiveExtensions.cs @@ -26,10 +26,7 @@ public static class InternalDirectiveExtensions /// /// public static IObjectTypeDescriptor Internal(this IObjectTypeDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - return descriptor.Directive(Composite.Internal.Instance); - } + => descriptor.Directive(Composite.Internal.Instance); /// /// @@ -52,8 +49,5 @@ public static IObjectTypeDescriptor Internal(this IObjectTypeDescriptor descript /// /// public static IObjectFieldDescriptor Internal(this IObjectFieldDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - return descriptor.Directive(Composite.Internal.Instance); - } + => descriptor.Directive(Composite.Internal.Instance); } diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/LookupDirectiveExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/LookupDirectiveExtensions.cs index d8990b5ce08..69d988acb54 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/LookupDirectiveExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/LookupDirectiveExtensions.cs @@ -23,8 +23,5 @@ public static class LookupDirectiveExtensions /// /// public static IObjectFieldDescriptor Lookup(this IObjectFieldDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - return descriptor.Directive(Composite.Lookup.Instance); - } + => descriptor.Directive(Composite.Lookup.Instance); } diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/RequireDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/RequireDescriptorExtensions.cs index 4dd41df7462..1b9865e740e 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/RequireDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/RequireDescriptorExtensions.cs @@ -23,16 +23,11 @@ public static class RequireDescriptorExtensions /// The argument descriptor. /// The field selection map. /// The argument descriptor with the @require directive applied. - /// - /// The is null. - /// /// /// The syntax used in the parameter is invalid. /// public static IArgumentDescriptor Require(this IArgumentDescriptor descriptor, string field) { - ArgumentNullException.ThrowIfNull(descriptor); - IValueSelectionNode valueSelection; try diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/ShareableDirectiveExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/ShareableDirectiveExtensions.cs index 9fa833ee517..93d5eb8846a 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Directives/ShareableDirectiveExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Directives/ShareableDirectiveExtensions.cs @@ -46,15 +46,10 @@ public static class ShareableDirectiveExtensions /// fields of the type sharable. /// /// The object type descriptor with the directive applied. - /// - /// The is null. - /// public static IObjectTypeDescriptor Shareable( this IObjectTypeDescriptor descriptor, bool scoped = false) { - ArgumentNullException.ThrowIfNull(descriptor); - if (scoped) { // The @sharable directive on a type is meant as a helper to apply it to all fields within its scope. @@ -117,12 +112,6 @@ public static IObjectTypeDescriptor Shareable( /// /// The object field descriptor. /// The object field descriptor with the directive applied. - /// - /// The is null. - /// public static IObjectFieldDescriptor Shareable(this IObjectFieldDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - return descriptor.Directive(Composite.Shareable.Instance); - } + => descriptor.Directive(Composite.Shareable.Instance); } diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/BindableListExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/BindableListExtensions.cs index e23c9d3d122..87684e4dc06 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/BindableListExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/BindableListExtensions.cs @@ -3,9 +3,5 @@ namespace HotChocolate.Types.Descriptors.Configurations; public static class BindableListExtensions { public static bool IsImplicitBinding(this IBindableList list) - { - ArgumentNullException.ThrowIfNull(list); - - return list.BindingBehavior == BindingBehavior.Implicit; - } + => list.BindingBehavior == BindingBehavior.Implicit; } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/ArgumentDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/ArgumentDescriptorExtensions.cs index 8c355e36286..8fa5fc4408b 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/ArgumentDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/ArgumentDescriptorExtensions.cs @@ -23,7 +23,6 @@ public static class ArgumentDescriptorExtensions /// Returns the input field descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -33,9 +32,7 @@ public static IArgumentDescriptor DefaultValueSyntax( this IArgumentDescriptor descriptor, [StringSyntax("graphql")] string syntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(syntax); - var value = Utf8GraphQLParser.Syntax.ParseValueLiteral(syntax); return descriptor.DefaultValue(value); } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveTypeDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveTypeDescriptorExtensions.cs index a657798315e..50c86c59cfa 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveTypeDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/DirectiveTypeDescriptorExtensions.cs @@ -9,9 +9,7 @@ public static IDirectiveTypeDescriptor Ignore( this IDirectiveTypeDescriptor descriptor, Expression> property) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(property); - descriptor.Argument(property).Ignore(); return descriptor; } @@ -29,7 +27,6 @@ public static IDirectiveTypeDescriptor Ignore( /// Returns the directive argument descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -39,9 +36,7 @@ public static IDirectiveArgumentDescriptor Type( this IDirectiveArgumentDescriptor descriptor, string typeSyntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(typeSyntax); - return descriptor.Type(Utf8GraphQLParser.Syntax.ParseTypeReference(typeSyntax)); } } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/InputObjectTypeDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/InputObjectTypeDescriptorExtensions.cs index cbe781a1857..50bdd7826db 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/InputObjectTypeDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/InputObjectTypeDescriptorExtensions.cs @@ -25,16 +25,13 @@ public static class InputObjectTypeDescriptorExtensions /// Returns the descriptor for configuration chaining. /// /// - /// The is null or - /// the is null. + /// The is null. /// public static IInputObjectTypeDescriptor Ignore( this IInputObjectTypeDescriptor descriptor, Expression> property) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(property); - descriptor.Field(property).Ignore(); return descriptor; } @@ -49,15 +46,8 @@ public static IInputObjectTypeDescriptor Ignore( /// /// Returns the descriptor for configuration chaining. /// - /// - /// The is null. - /// public static IInputObjectTypeDescriptor OneOf(this IInputObjectTypeDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - - return descriptor.Directive(DirectiveNames.OneOf.Name); - } + => descriptor.Directive(DirectiveNames.OneOf.Name); /// /// Defines an input object type as a OneOf input object type @@ -72,16 +62,9 @@ public static IInputObjectTypeDescriptor OneOf(this IInputObjectTypeDescriptor d /// /// Returns the descriptor for configuration chaining. /// - /// - /// The is null. - /// public static IInputObjectTypeDescriptor OneOf( this IInputObjectTypeDescriptor descriptor) - { - ArgumentNullException.ThrowIfNull(descriptor); - - return descriptor.Directive(DirectiveNames.OneOf.Name); - } + => descriptor.Directive(DirectiveNames.OneOf.Name); /// /// Specifies the type of an input field with GraphQL SDL type syntax. @@ -96,7 +79,6 @@ public static IInputObjectTypeDescriptor OneOf( /// Returns the input field descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -106,9 +88,7 @@ public static IInputFieldDescriptor Type( this IInputFieldDescriptor descriptor, string typeSyntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(typeSyntax); - return descriptor.Type(Utf8GraphQLParser.Syntax.ParseTypeReference(typeSyntax)); } @@ -125,7 +105,6 @@ public static IInputFieldDescriptor Type( /// Returns the input field descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -135,9 +114,7 @@ public static IInputFieldDescriptor DefaultValueSyntax( this IInputFieldDescriptor descriptor, [StringSyntax("graphql")] string syntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(syntax); - var value = Utf8GraphQLParser.Syntax.ParseValueLiteral(syntax); return descriptor.DefaultValue(value); } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/InterfaceTypeDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/InterfaceTypeDescriptorExtensions.cs index 58223d2e9f4..ce65ff90a3b 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/InterfaceTypeDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/InterfaceTypeDescriptorExtensions.cs @@ -9,9 +9,7 @@ public static IInterfaceTypeDescriptor Ignore( this IInterfaceTypeDescriptor descriptor, Expression> propertyOrMethod) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(propertyOrMethod); - descriptor.Field(propertyOrMethod).Ignore(); return descriptor; } @@ -29,7 +27,6 @@ public static IInterfaceTypeDescriptor Ignore( /// Returns the interface field descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -39,9 +36,7 @@ public static IInterfaceFieldDescriptor Type( this IInterfaceFieldDescriptor descriptor, string typeSyntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(typeSyntax); - return descriptor.Type(Utf8GraphQLParser.Syntax.ParseTypeReference(typeSyntax)); } } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectFieldDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectFieldDescriptorExtensions.cs index 8a2e3c96d49..708ff4b135d 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectFieldDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectFieldDescriptorExtensions.cs @@ -14,8 +14,6 @@ public static class ObjectFieldDescriptorExtensions /// public static IObjectFieldDescriptor Serial(this IObjectFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - descriptor.Extend().OnBeforeCreate(c => c.IsParallelExecutable = false); return descriptor; } @@ -26,8 +24,6 @@ public static IObjectFieldDescriptor Serial(this IObjectFieldDescriptor descript /// public static IObjectFieldDescriptor Parallel(this IObjectFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - descriptor.Extend().OnBeforeCreate(c => c.IsParallelExecutable = true); return descriptor; } @@ -45,7 +41,6 @@ public static IObjectFieldDescriptor Parallel(this IObjectFieldDescriptor descri /// Returns the object field descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -55,9 +50,7 @@ public static IObjectFieldDescriptor Type( this IObjectFieldDescriptor descriptor, string typeSyntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(typeSyntax); - return descriptor.Type(Utf8GraphQLParser.Syntax.ParseTypeReference(typeSyntax)); } @@ -74,7 +67,6 @@ public static IObjectFieldDescriptor Type( /// Returns the argument descriptor for configuration chaining. /// /// - /// is null. /// is null. /// /// @@ -84,9 +76,7 @@ public static IArgumentDescriptor Type( this IArgumentDescriptor descriptor, string typeSyntax) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(typeSyntax); - return descriptor.Type(Utf8GraphQLParser.Syntax.ParseTypeReference(typeSyntax)); } @@ -99,14 +89,9 @@ public static IArgumentDescriptor Type( /// /// Returns the object field descriptor for configuration chaining. /// - /// - /// is null. - /// public static IObjectFieldDescriptor UseRequestScope( this IObjectFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - descriptor.Extend().Configuration.DependencyInjectionScope = DependencyInjectionScope.Request; return descriptor; } @@ -120,14 +105,9 @@ public static IObjectFieldDescriptor UseRequestScope( /// /// Returns the object field descriptor for configuration chaining. /// - /// - /// is null. - /// public static IObjectFieldDescriptor UseResolverScope( this IObjectFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - descriptor.Extend().Configuration.DependencyInjectionScope = DependencyInjectionScope.Resolver; return descriptor; } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectTypeDescriptorExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectTypeDescriptorExtensions.cs index 4aad269bb55..e80c9ff6d31 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectTypeDescriptorExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectTypeDescriptorExtensions.cs @@ -12,9 +12,7 @@ public static IObjectTypeDescriptor Ignore( this IObjectTypeDescriptor descriptor, Expression> propertyOrMethod) { - ArgumentNullException.ThrowIfNull(descriptor); ArgumentNullException.ThrowIfNull(propertyOrMethod); - descriptor.Field(propertyOrMethod).Ignore(); return descriptor; } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs index eac5e96bdf8..4751b4964cf 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs @@ -11,8 +11,6 @@ public static class TypeExtensions { internal static IInputType EnsureInputType(this IType type) { - ArgumentNullException.ThrowIfNull(type); - if (type.NamedType() is not IInputType) { throw InputTypeExpected(type); @@ -23,8 +21,6 @@ internal static IInputType EnsureInputType(this IType type) internal static IOutputType EnsureOutputType(this IType type) { - ArgumentNullException.ThrowIfNull(type); - if (type.NamedType() is not IOutputType) { throw OutputTypeExpected(type); @@ -34,16 +30,10 @@ internal static IOutputType EnsureOutputType(this IType type) } public static string TypeName(this IType type) - { - ArgumentNullException.ThrowIfNull(type); - - return type.NamedType().Name; - } + => type.NamedType().Name; public static Type ToRuntimeType(this IType type) { - ArgumentNullException.ThrowIfNull(type); - if (type.IsListType()) { var elementType = ToRuntimeType(type.ElementType()); @@ -94,7 +84,6 @@ public static ITypeNode RenameName(this ITypeNode typeNode, string name) public static bool IsInstanceOfType(this IInputType type, IValueNode literal) { - ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(literal); while (true) diff --git a/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/NodeTypeFeatureExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/NodeTypeFeatureExtensions.cs index 1fa86b4ecea..e7486276a7a 100644 --- a/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/NodeTypeFeatureExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/NodeTypeFeatureExtensions.cs @@ -15,8 +15,6 @@ internal static class NodeTypeFeatureExtensions /// True if the node resolver was found, false otherwise. public static bool TryGetNodeResolver(this ObjectType type, [NotNullWhen(true)] out NodeResolverInfo? nodeResolver) { - ArgumentNullException.ThrowIfNull(type); - if (type.Features.TryGet(out var feature) && feature.NodeResolver is not null) { nodeResolver = feature.NodeResolver; @@ -39,7 +37,6 @@ public static void SetNodeResolver( this ObjectType type, NodeResolverInfo nodeResolver) { - ArgumentNullException.ThrowIfNull(type); ArgumentNullException.ThrowIfNull(nodeResolver); var feature = type.Features.Get(); diff --git a/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/RelayIdFieldExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/RelayIdFieldExtensions.cs index c7319f40361..fb39ff1f0d8 100644 --- a/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/RelayIdFieldExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Relay/Extensions/RelayIdFieldExtensions.cs @@ -67,10 +67,7 @@ public static IInputFieldDescriptor ID( this IInputFieldDescriptor descriptor, string? typeName = null) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor, typeName); - return descriptor; } @@ -80,10 +77,7 @@ public static IInputFieldDescriptor ID( /// public static IInputFieldDescriptor ID(this IInputFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor); - return descriptor; } @@ -96,10 +90,7 @@ public static IArgumentDescriptor ID( this IArgumentDescriptor descriptor, string? typeName = null) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor, typeName); - return descriptor; } @@ -109,10 +100,7 @@ public static IArgumentDescriptor ID( /// public static IArgumentDescriptor ID(this IArgumentDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor); - return descriptor; } @@ -125,10 +113,7 @@ public static IObjectFieldDescriptor ID( this IObjectFieldDescriptor descriptor, string? typeName = null) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor, typeName); - return descriptor; } @@ -138,10 +123,7 @@ public static IObjectFieldDescriptor ID( /// public static IObjectFieldDescriptor ID(this IObjectFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor); - return descriptor; } @@ -149,10 +131,7 @@ public static IObjectFieldDescriptor ID(this IObjectFieldDescriptor descripto /// the descriptor public static IInterfaceFieldDescriptor ID(this IInterfaceFieldDescriptor descriptor) { - ArgumentNullException.ThrowIfNull(descriptor); - RelayIdFieldHelpers.ApplyIdToField(descriptor); - return descriptor; } } diff --git a/src/HotChocolate/Core/src/Types/Types/TypeNamePrinter.cs b/src/HotChocolate/Core/src/Types/Types/TypeNamePrinter.cs index 39ff7debc72..aff5cae7b6c 100644 --- a/src/HotChocolate/Core/src/Types/Types/TypeNamePrinter.cs +++ b/src/HotChocolate/Core/src/Types/Types/TypeNamePrinter.cs @@ -8,8 +8,6 @@ public static class TypeNamePrinter private static string Print(IType type, int count) { - ArgumentNullException.ThrowIfNull(type); - if (count > MaxTypeDepth) { throw new InvalidOperationException( diff --git a/src/HotChocolate/Core/src/Types/Utilities/ReflectionUtils.cs b/src/HotChocolate/Core/src/Types/Utilities/ReflectionUtils.cs index 73e4ec4aab7..7cb3f36bd38 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ReflectionUtils.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ReflectionUtils.cs @@ -15,11 +15,7 @@ public static class ReflectionUtils public static MemberInfo TryExtractMember( this Expression> memberExpression, bool allowStatic = false) - { - ArgumentNullException.ThrowIfNull(memberExpression); - - return TryExtractMemberInternal(UnwrapFunc(memberExpression), allowStatic); - } + => TryExtractMemberInternal(UnwrapFunc(memberExpression), allowStatic); internal static MemberInfo TryExtractCallMember( this Expression expression) @@ -56,20 +52,12 @@ public static MethodInfo ExtractMethod( public static MemberInfo ExtractMember( this Expression> memberExpression, bool allowStatic = false) - { - ArgumentNullException.ThrowIfNull(memberExpression); - - return ExtractMemberInternal(UnwrapAction(memberExpression), allowStatic); - } + => ExtractMemberInternal(UnwrapAction(memberExpression), allowStatic); public static MemberInfo ExtractMember( this Expression> memberExpression, bool allowStatic = false) - { - ArgumentNullException.ThrowIfNull(memberExpression); - - return ExtractMemberInternal(UnwrapFunc(memberExpression), allowStatic); - } + => ExtractMemberInternal(UnwrapFunc(memberExpression), allowStatic); private static MemberInfo ExtractMemberInternal( Expression expression, @@ -184,13 +172,9 @@ private static bool IsStaticMethod(MethodInfo method) => method.IsStatic; public static string GetTypeName(this Type type) - { - ArgumentNullException.ThrowIfNull(type); - - return type.IsGenericType + => type.IsGenericType ? CreateGenericTypeName(type) : CreateTypeName(type, type.Name); - } private static string CreateGenericTypeName(Type type) { From be3c2a5bdc36d1bafd587f9f8959cd4e4ea8af95 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 21:57:05 +0100 Subject: [PATCH 21/42] wip --- .../CacheControlConstraintsOptimizer.cs | 16 +-- .../src/Caching/ImmutableCacheConstraints.cs | 12 +++ .../src/Caching/QueryCacheMiddleware.cs | 11 +-- .../Processing/OperationFeatureCollection.cs | 13 ++- .../Types/Execution/Processing/Selection.cs | 99 ++++++++++++++++++- .../Processing/SelectionFeatureCollection.cs | 28 ++++++ .../SelectionSetOptimizerContext.cs | 8 ++ .../Core/src/Types/HotChocolate.Types.csproj | 3 +- .../Extensions/FilterFeatureExtensions.cs | 4 +- .../HotChocolateDataQueryableExtensions.cs | 16 ++- .../Data/src/Data/HotChocolate.Data.csproj | 1 + ...gingArgumentsParameterExpressionBuilder.cs | 2 +- .../Projections/Context/ISelectedField.cs | 4 +- .../Data/Projections/Context/SelectedField.cs | 29 +++--- .../ProjectionProviderDescriptorExtensions.cs | 1 + .../Convention/IProjectionFieldInterceptor.cs | 2 +- .../IProjectionFieldInterceptor`1.cs | 4 +- .../ProjectionInterceptorCombinator.cs | 6 +- .../Convention/ProjectionProvider.cs | 5 +- .../Convention/ProjectionSelection.cs | 23 ----- .../ProjectionSelectionExtensions.cs | 12 +++ .../Handlers/ProjectionFieldHandler.cs | 16 +-- .../Handlers/ProjectionFieldWrapper.cs | 14 +-- .../QueryableProjectionFieldHandler.cs | 6 +- .../QueryableProjectionHandlerBase.cs | 4 +- .../QueryableProjectionListHandler.cs | 8 +- .../QueryableProjectionScalarHandler.cs | 6 +- .../Interceptor/QueryableFilterInterceptor.cs | 11 +-- .../Interceptor/QueryableSortInterceptor.cs | 18 ++-- .../QueryableTakeHandlerInterceptor.cs | 6 +- .../QueryableFilterProjectionOptimizer.cs | 2 +- .../QueryablePagingProjectionOptimizer.cs | 51 +++++----- .../QueryableSortProjectionOptimizer.cs | 6 +- .../Expressions/QueryableProjectionContext.cs | 22 +++-- .../Expressions/QueryableProjectionVisitor.cs | 6 +- ...ojectionObjectFieldDescriptorExtensions.cs | 49 +++------ .../Extensions/SelectionFlagsExtensions.cs | 16 +-- .../Data/Projections/IProjectionSelection.cs | 8 -- .../Projections/ISelectionVisitorContext.cs | 13 ++- .../IsProjectedProjectionOptimizer.cs | 33 +++---- .../Optimizers/NodeSelectionSetOptimizer.cs | 4 +- .../src/Data/Projections/ProjectionFeature.cs | 5 - .../Data/Projections/ProjectionOptimizer.cs | 6 +- .../Data/Projections/ProjectionTypeFeature.cs | 6 ++ .../Projections/ProjectionTypeInterceptor.cs | 1 + .../src/Data/Projections/ProjectionVisitor.cs | 66 ++++++------- .../src/Data/Projections/SelectionVisitor.cs | 4 +- .../Projections/SelectionVisitorContext.cs | 10 +- .../Data/Projections/SelectionVisitor`1.cs | 76 +++++++------- .../Visitor/IProjectionFieldHandler.cs | 9 +- .../Visitor/IProjectionFieldHandler~1.cs | 16 ++- .../Projections/Visitor/ProjectionScope.cs | 7 +- .../Visitor/ProjectionVisitorContext.cs | 9 +- ...SortingContextResolverContextExtensions.cs | 2 +- .../Extensions/SortingFeatureExtensions.cs | 29 +++--- .../src/Diagnostics/ActivityEnricher.cs | 10 +- .../Fusion.Execution.Benchmarks.csproj | 1 + .../GraphQLQueryBenchmark.cs | 9 +- ...bProjectionProviderDescriptorExtensions.cs | 1 + .../HotChocolate.Utilities.Buffers.csproj | 1 + 60 files changed, 480 insertions(+), 386 deletions(-) delete mode 100644 src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelection.cs create mode 100644 src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelectionExtensions.cs delete mode 100644 src/HotChocolate/Data/src/Data/Projections/IProjectionSelection.cs create mode 100644 src/HotChocolate/Data/src/Data/Projections/ProjectionTypeFeature.cs diff --git a/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs b/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs index 2fa588c8518..a12a2c80b87 100644 --- a/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs +++ b/src/HotChocolate/Caching/src/Caching/CacheControlConstraintsOptimizer.cs @@ -38,20 +38,8 @@ public void OptimizeOperation(OperationOptimizerContext context) : null }; - context.ContextData.Add( - ExecutionContextData.CacheControlConstraints, - constraints); - - context.ContextData.Add( - ExecutionContextData.CacheControlHeaderValue, - headerValue); - } - - if (constraints.Vary is { Length: > 0 }) - { - context.ContextData.Add( - ExecutionContextData.VaryHeaderValue, - string.Join(", ", constraints.Vary)); + context.Operation.Features.SetSafe(constraints); + context.Operation.Features.SetSafe(headerValue); } } diff --git a/src/HotChocolate/Caching/src/Caching/ImmutableCacheConstraints.cs b/src/HotChocolate/Caching/src/Caching/ImmutableCacheConstraints.cs index 97472f0697e..91a1f454ef5 100644 --- a/src/HotChocolate/Caching/src/Caching/ImmutableCacheConstraints.cs +++ b/src/HotChocolate/Caching/src/Caching/ImmutableCacheConstraints.cs @@ -16,4 +16,16 @@ internal sealed class ImmutableCacheConstraints( public CacheControlScope Scope { get; } = scope; public ImmutableArray Vary { get; } = vary; + + public string VaryString + { + get + { + field ??= Vary.Length is 0 + ? string.Empty + : string.Join(", ", Vary); + + return field; + } + } } diff --git a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs index 190acf51ae9..889d3476e28 100644 --- a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs +++ b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs @@ -30,7 +30,8 @@ public async ValueTask InvokeAsync(RequestContext context) } if (!context.TryGetOperation(out var operation) - || !operation.Features.TryGet(out var cacheControlHeaderValue)) + || !operation.Features.TryGet(out var headerValue) + || !operation.Features.TryGet(out var constraints)) { return; } @@ -45,13 +46,11 @@ operationResult.ContextData is not null ? new ExtensionData(operationResult.ContextData) : []; - contextData.Add(ExecutionContextData.CacheControlHeaderValue, cacheControlHeaderValue); + contextData.Add(ExecutionContextData.CacheControlHeaderValue, headerValue); - if (operation.ContextData.TryGetValue(ExecutionContextData.VaryHeaderValue, out var varyValue) - && varyValue is string varyHeaderValue - && !string.IsNullOrEmpty(varyHeaderValue)) + if (constraints.Vary.Length > 0) { - contextData.Add(ExecutionContextData.VaryHeaderValue, varyHeaderValue); + contextData.Add(ExecutionContextData.VaryHeaderValue, constraints.Vary); } context.Result = operationResult.WithContextData(contextData); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs index 69972333267..dfbf1426fb2 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationFeatureCollection.cs @@ -123,11 +123,14 @@ public bool TryGet([NotNullWhen(true)] out TFeature? feature) return false; } - /// - public void Set(TFeature? instance) - { - this[typeof(TFeature)] = instance; - } + /// + /// Sets a feature instance for this selection. + /// + /// The type of the feature. + /// The feature instance to set, or null to remove. + /// This method is thread-safe. + public void SetSafe(TFeature? instance) + => this[typeof(TFeature)] = instance; /// public IEnumerator> GetEnumerator() diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index cef3f42b1cd..d47b00eb706 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -24,10 +24,10 @@ internal Selection( ObjectField field, FieldSelectionNode[] syntaxNodes, ulong[] includeFlags, - bool isInternal, - ArgumentMap? arguments, - FieldDelegate? resolverPipeline, - PureFieldDelegate? pureResolver) + bool isInternal = false, + ArgumentMap? arguments = null, + FieldDelegate? resolverPipeline = null, + PureFieldDelegate? pureResolver = null) { ArgumentNullException.ThrowIfNull(field); @@ -41,6 +41,7 @@ internal Selection( Id = id; ResponseName = responseName; Field = field; + Type = field.Type; Arguments = arguments ?? s_emptyArguments; ResolverPipeline = resolverPipeline; PureResolver = pureResolver; @@ -64,6 +65,34 @@ internal Selection( _utf8ResponseName = Utf8StringCache.GetUtf8String(responseName); } + private Selection( + int id, + string responseName, + byte[] utf8ResponseName, + ObjectField field, + IType type, + FieldSelectionNode[] syntaxNodes, + ulong[] includeFlags, + Flags flags, + ArgumentMap? arguments, + SelectionExecutionStrategy strategy, + FieldDelegate? resolverPipeline, + PureFieldDelegate? pureResolver) + { + Id = id; + ResponseName = responseName; + Field = field; + Type = type; + Arguments = arguments ?? s_emptyArguments; + ResolverPipeline = resolverPipeline; + PureResolver = pureResolver; + Strategy = strategy; + _syntaxNodes = syntaxNodes; + _includeFlags = includeFlags; + _flags = flags; + _utf8ResponseName = utf8ResponseName; + } + /// public int Id { get; } @@ -100,7 +129,7 @@ internal Selection( IOutputFieldDefinition ISelection.Field => Field; /// - public IType Type => Field.Type; + public IType Type { get; } /// /// Gets the object type that declares the field being selected. @@ -161,6 +190,28 @@ IEnumerable ISelection.GetSyntaxNodes() } } + /// + /// Gets the selection set for this selection resolved against the specified object type. + /// + /// + /// The object type context to resolve the selection set against. + /// + /// + /// The selection set containing the child selections for the specified type context. + /// + /// + /// Thrown when this selection is a leaf selection (scalar or enum) which does not have child selections. + /// + public SelectionSet GetSelectionSet(ObjectType typeContext) + { + if (IsLeaf) + { + throw new InvalidOperationException("Leaf selections do not have a selection set."); + } + + return DeclaringOperation.GetSelectionSet(this, typeContext); + } + /// /// Determines whether this selection should be skipped based on conditional flags. /// @@ -215,6 +266,44 @@ public bool IsIncluded(ulong includeFlags) return false; } + public Selection WithField(ObjectField field) + { + ArgumentNullException.ThrowIfNull(field); + + return new Selection( + Id, + ResponseName, + _utf8ResponseName, + field, + field.Type, + _syntaxNodes, + _includeFlags, + _flags, + Arguments, + Strategy, + ResolverPipeline, + PureResolver); + } + + public Selection WithType(IType type) + { + ArgumentNullException.ThrowIfNull(type); + + return new Selection( + Id, + ResponseName, + _utf8ResponseName, + Field, + type, + _syntaxNodes, + _includeFlags, + _flags, + Arguments, + Strategy, + ResolverPipeline, + PureResolver); + } + public override string ToString() { if (SyntaxNodes[0].Node.Alias is not null) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs index b1fe6773b6e..f14458099ba 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs @@ -46,6 +46,34 @@ public object? this[Type key] set => _parent[_selectionId, key] = value; } + /// + /// Gets a feature of the specified type. + /// + /// The type of the feature. + /// The feature instance, or null if not found. + /// + /// Thrown when is a non-nullable value type and the feature does not exist. + /// + public TFeature? Get() + { + if (typeof(TFeature).IsValueType) + { + var feature = this[typeof(TFeature)]; + if (feature is null && Nullable.GetUnderlyingType(typeof(TFeature)) is null) + { + throw new InvalidOperationException( + $"{typeof(TFeature).FullName} does not exist in the feature collection " + + "and because it is a struct the method can't return null. " + + $"Use 'featureCollection[typeof({typeof(TFeature).FullName})] is not null' " + + "to check if the feature exists."); + } + + return (TFeature?)feature; + } + + return (TFeature?)this[typeof(TFeature)]; + } + /// /// Sets a feature instance for this selection. /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs index afb94e02f92..c956a0fa9a0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs @@ -50,6 +50,8 @@ internal SelectionSetOptimizerContext( /// public ObjectType TypeContext { get; } + public ImmutableArray Selections => _selections; + public bool ContainsField(string fieldName) => _selections.Any(t => t.Field.Name.EqualsOrdinal(fieldName)); @@ -65,6 +67,12 @@ public bool TryGetSelection(string responseName, [MaybeNullWhen(false)] out Sele return _selectionMap.TryGetValue(responseName, out value); } + public Selection GetSelection(string responseName) + { + _selectionMap ??= _selections.ToDictionary(t => t.ResponseName); + return _selectionMap[responseName]; + } + public SelectionFeatureCollection Features => new(_features, _selectionSetId); /// diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index a36c9b2e24c..d17deed0210 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -35,8 +35,7 @@ - - + diff --git a/src/HotChocolate/Data/src/Data/Filters/Extensions/FilterFeatureExtensions.cs b/src/HotChocolate/Data/src/Data/Filters/Extensions/FilterFeatureExtensions.cs index e1873fe3f38..cb7cde8e8da 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Extensions/FilterFeatureExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Extensions/FilterFeatureExtensions.cs @@ -15,7 +15,7 @@ public static class FilterFeatureExtensions /// true if the selection has a filtering enabled; /// otherwise, false. /// - public static bool HasFilterFeature(this ISelection selection) + public static bool HasFilterFeature(this Selection selection) { ArgumentNullException.ThrowIfNull(selection); @@ -30,7 +30,7 @@ public static bool HasFilterFeature(this ISelection selection) /// The filter feature from the selection; /// otherwise, null. /// - public static FilterFeature? GetFilterFeature(this ISelection selection) + public static FilterFeature? GetFilterFeature(this Selection selection) { ArgumentNullException.ThrowIfNull(selection); diff --git a/src/HotChocolate/Data/src/Data/Filters/Extensions/HotChocolateDataQueryableExtensions.cs b/src/HotChocolate/Data/src/Data/Filters/Extensions/HotChocolateDataQueryableExtensions.cs index d48cdbd9598..7d7fb6188ab 100644 --- a/src/HotChocolate/Data/src/Data/Filters/Extensions/HotChocolateDataQueryableExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Filters/Extensions/HotChocolateDataQueryableExtensions.cs @@ -1,5 +1,6 @@ using HotChocolate.Data.Filters; using HotChocolate.Data.Sorting; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; // ReSharper disable once CheckNamespace @@ -7,7 +8,7 @@ namespace System.Linq; /// /// Provides extension methods to integrate -/// with and . +/// with and . /// public static class HotChocolateDataQueryableExtensions { @@ -27,13 +28,11 @@ public static class HotChocolateDataQueryableExtensions /// Returns a queryable that has the selection applied. /// /// - /// Throws if is null or if is null. + /// Throws if is null. /// - public static IQueryable Select(this IQueryable queryable, ISelection selection) + public static IQueryable Select(this IQueryable queryable, Selection selection) { - ArgumentNullException.ThrowIfNull(queryable); ArgumentNullException.ThrowIfNull(selection); - return queryable.Select(selection.AsSelector()); } @@ -53,13 +52,11 @@ public static IQueryable Select(this IQueryable queryable, ISelection s /// Returns a queryable that has the filter applied. /// /// - /// Throws if is null or if is null. + /// Throws if is null. /// public static IQueryable Where(this IQueryable queryable, IFilterContext filter) { - ArgumentNullException.ThrowIfNull(queryable); ArgumentNullException.ThrowIfNull(filter); - var predicate = filter.AsPredicate(); return predicate is null ? queryable : queryable.Where(predicate); } @@ -80,11 +77,10 @@ public static IQueryable Where(this IQueryable queryable, IFilterContex /// Returns a queryable that has the sorting applied. /// /// - /// Throws if is null or if is null. + /// Throws if is null. /// public static IQueryable Order(this IQueryable queryable, ISortingContext sorting) { - ArgumentNullException.ThrowIfNull(queryable); ArgumentNullException.ThrowIfNull(sorting); var sortDefinition = sorting.AsSortDefinition(); diff --git a/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj b/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj index f5f21fbc643..a8f0d569b50 100644 --- a/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj +++ b/src/HotChocolate/Data/src/Data/HotChocolate.Data.csproj @@ -12,6 +12,7 @@ + diff --git a/src/HotChocolate/Data/src/Data/PagingArgumentsParameterExpressionBuilder.cs b/src/HotChocolate/Data/src/Data/PagingArgumentsParameterExpressionBuilder.cs index 0bba80e0794..a9ad284273b 100644 --- a/src/HotChocolate/Data/src/Data/PagingArgumentsParameterExpressionBuilder.cs +++ b/src/HotChocolate/Data/src/Data/PagingArgumentsParameterExpressionBuilder.cs @@ -42,6 +42,6 @@ private static PagingArguments MapArguments(IResolverContext context) private static PagingArguments MapArguments(CursorPagingArguments arguments, bool includeTotalCount) => new(arguments.First, arguments.After, arguments.Last, arguments.Before, includeTotalCount); - private static bool IncludeTotalCount(ISelection selection) + private static bool IncludeTotalCount(Selection selection) => selection.Field.Features.Get()?.IncludeTotalCount is true; } diff --git a/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs b/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs index a2c98a8aa24..048cf55079b 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Context/ISelectedField.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Data.Projections.Context; /// /// Represents a field that is selected in a query in the context of an operation. /// -/// The difference between and is that +/// The difference between and is that /// is specific to the current request/operation and not cached. This /// makes it possible to recursively iterate through the selected fields by calling /// . @@ -35,7 +35,7 @@ public interface ISelectedField /// Gets the field selection for which a field resolver is /// being executed. /// - ISelection Selection { get; } + Selection Selection { get; } /// /// Gets the field on which the field resolver is being executed. diff --git a/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs b/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs index 3f47dc6b21a..825c0c0db55 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Context/SelectedField.cs @@ -1,3 +1,4 @@ +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Resolvers; using HotChocolate.Types; @@ -13,14 +14,14 @@ public sealed class SelectedField : ISelectedField /// /// Creates a new instance of /// - internal SelectedField(IResolverContext resolverContext, ISelection selection) + internal SelectedField(IResolverContext resolverContext, Selection selection) { _resolverContext = resolverContext; Selection = selection; } /// - public ISelection Selection { get; } + public Selection Selection { get; } /// public IOutputFieldDefinition Field => Selection.Field; @@ -36,21 +37,21 @@ public IReadOnlyList GetFields( ObjectType? type = null, bool allowInternals = false) { - var fields = GetFieldSelections(type, allowInternals); + var selections = GetSelections(type, allowInternals); - if (fields is null) + if (selections is null) { return []; } - var finalFields = new SelectedField[fields.Count]; + var selectedFields = new List(); - for (var i = 0; i < fields.Count; i++) + foreach (var selection in selections) { - finalFields[i] = new SelectedField(_resolverContext, fields[i]); + selectedFields.Add(new SelectedField(_resolverContext, selection)); } - return finalFields; + return selectedFields; } /// @@ -59,16 +60,16 @@ public bool IsSelected( ObjectType? type = null, bool allowInternals = false) { - var fields = GetFieldSelections(type, allowInternals); + var selections = GetSelections(type, allowInternals); - if (fields is null) + if (selections is null) { return false; } - for (var i = 0; i < fields.Count; i++) + foreach (var selection in selections) { - if (fields[i].Field.Name == fieldName) + if (selection.Field.Name == fieldName) { return true; } @@ -77,13 +78,13 @@ public bool IsSelected( return false; } - private IReadOnlyList? GetFieldSelections( + private SelectionEnumerator? GetSelections( ObjectType? type = null, bool allowInternals = false) { var namedType = Field.Type.NamedType(); - if (Selection.SelectionSet is null) + if (Selection.IsLeaf) { return null; } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/Extensions/ProjectionProviderDescriptorExtensions.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/Extensions/ProjectionProviderDescriptorExtensions.cs index 536e7fa6047..03dca1a4cf9 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/Extensions/ProjectionProviderDescriptorExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/Extensions/ProjectionProviderDescriptorExtensions.cs @@ -1,6 +1,7 @@ using HotChocolate.Data.Projections; using HotChocolate.Data.Projections.Expressions.Handlers; using HotChocolate.Data.Projections.Handlers; +using HotChocolate.Data.Projections.Optimizers; namespace HotChocolate.Data; diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs index f20404790c6..5643a3e185a 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs @@ -11,5 +11,5 @@ public interface IProjectionFieldInterceptor /// /// The selection to test for /// Returns true if the selection can be handled - bool CanHandle(ISelection selection); + bool CanHandle(Selection selection); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor`1.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor`1.cs index a83fe0cde84..607cf11369e 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor`1.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor`1.cs @@ -14,7 +14,7 @@ public interface IProjectionFieldInterceptor /// The current selection void BeforeProjection( TContext context, - ISelection selection); + Selection selection); /// /// This method is called after the enter and leave methods of a @@ -24,5 +24,5 @@ void BeforeProjection( /// The current selection void AfterProjection( TContext context, - ISelection selection); + Selection selection); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionInterceptorCombinator.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionInterceptorCombinator.cs index 2fbac715201..72064262abc 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionInterceptorCombinator.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionInterceptorCombinator.cs @@ -20,11 +20,11 @@ public ProjectionInterceptorCombinator( _next = next; } - public bool CanHandle(ISelection selection) => true; + public bool CanHandle(Selection selection) => true; public void BeforeProjection( T context, - ISelection selection) + Selection selection) { if (_current is IProjectionFieldInterceptor currentHandler) { @@ -37,7 +37,7 @@ public void BeforeProjection( } } - public void AfterProjection(T context, ISelection selection) + public void AfterProjection(T context, Selection selection) { if (_next is IProjectionFieldInterceptor nextHandler) { diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs index f74cea5be9d..0ea678db3a1 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionProvider.cs @@ -154,9 +154,8 @@ public Selection RewriteSelection( } } - return ProjectionSelection.From( - selection, - fieldHandler); + selection.Features.SetSafe(fieldHandler); + return selection; } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelection.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelection.cs deleted file mode 100644 index de4997ce000..00000000000 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelection.cs +++ /dev/null @@ -1,23 +0,0 @@ -using HotChocolate.Execution.Processing; - -namespace HotChocolate.Data.Projections; - -public class ProjectionSelection - : Selection - , IProjectionSelection -{ - public ProjectionSelection( - IProjectionFieldHandler handler, - Selection selection) - : base(selection) - { - Handler = handler; - } - - public IProjectionFieldHandler Handler { get; } - - public static ProjectionSelection From( - Selection selection, - IProjectionFieldHandler handler) => - new(handler, selection); -} diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelectionExtensions.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelectionExtensions.cs new file mode 100644 index 00000000000..fc66246730e --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/ProjectionSelectionExtensions.cs @@ -0,0 +1,12 @@ +using HotChocolate.Execution.Processing; +using HotChocolate.Features; + +namespace HotChocolate.Data.Projections; + +public static class ProjectionSelectionExtensions +{ + extension(Selection selection) + { + public IProjectionFieldHandler? ProjectionHandler { get => selection.Features.Get(); } + } +} diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldHandler.cs index c9fb8e6c66c..967b3dfeacc 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldHandler.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; /// -/// A handler that can intersect a and optimize the selection set for +/// A handler that can intersect a and optimize the selection set for /// projections. /// public abstract class ProjectionFieldHandler @@ -23,35 +23,35 @@ public virtual IProjectionFieldHandler Wrap(IProjectionFieldInterceptor intercep } /// - public abstract bool CanHandle(ISelection selection); + public abstract bool CanHandle(Selection selection); /// - public virtual T OnBeforeEnter(T context, ISelection selection) => context; + public virtual T OnBeforeEnter(T context, Selection selection) => context; /// public abstract bool TryHandleEnter( T context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action); /// public virtual T OnAfterEnter( T context, - ISelection selection, + Selection selection, ISelectionVisitorAction action) => context; /// - public virtual T OnBeforeLeave(T context, ISelection selection) => context; + public virtual T OnBeforeLeave(T context, Selection selection) => context; /// public abstract bool TryHandleLeave( T context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action); /// public virtual T OnAfterLeave( T context, - ISelection selection, + Selection selection, ISelectionVisitorAction action) => context; } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldWrapper.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldWrapper.cs index af0626e2e02..62bde2f0f59 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldWrapper.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/ProjectionFieldWrapper.cs @@ -19,33 +19,33 @@ public ProjectionFieldWrapper( _interceptor = interceptor; } - public bool CanHandle(ISelection selection) => + public bool CanHandle(Selection selection) => _handler.CanHandle(selection); public IProjectionFieldHandler Wrap(IProjectionFieldInterceptor interceptor) => _handler.Wrap(new ProjectionInterceptorCombinator(_interceptor, interceptor)); - public T OnBeforeEnter(T context, ISelection selection) => + public T OnBeforeEnter(T context, Selection selection) => _handler.OnBeforeEnter(context, selection); public bool TryHandleEnter( T context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { _interceptor.BeforeProjection(context, selection); return _handler.TryHandleEnter(context, selection, out action); } - public T OnAfterEnter(T context, ISelection selection, ISelectionVisitorAction result) => + public T OnAfterEnter(T context, Selection selection, ISelectionVisitorAction result) => _handler.OnAfterEnter(context, selection, result); - public T OnBeforeLeave(T context, ISelection selection) => + public T OnBeforeLeave(T context, Selection selection) => _handler.OnBeforeLeave(context, selection); public bool TryHandleLeave( T context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { _handler.TryHandleLeave(context, selection, out action); @@ -53,6 +53,6 @@ public bool TryHandleLeave( return action is not null; } - public T OnAfterLeave(T context, ISelection selection, ISelectionVisitorAction result) => + public T OnAfterLeave(T context, Selection selection, ISelectionVisitorAction result) => _handler.OnAfterLeave(context, selection, result); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs index 4851a43e156..dc13c5b0c68 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs @@ -9,13 +9,13 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; public class QueryableProjectionFieldHandler : QueryableProjectionHandlerBase { - public override bool CanHandle(ISelection selection) => + public override bool CanHandle(Selection selection) => selection.Field.Member is { } && selection.SelectionSet is not null; public override bool TryHandleEnter( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; @@ -48,7 +48,7 @@ public override bool TryHandleEnter( public override bool TryHandleLeave( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionHandlerBase.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionHandlerBase.cs index 2b45b6b5c1d..44937250621 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionHandlerBase.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionHandlerBase.cs @@ -8,7 +8,7 @@ public abstract class QueryableProjectionHandlerBase { public override bool TryHandleEnter( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { action = SelectionVisitor.Continue; @@ -17,7 +17,7 @@ public override bool TryHandleEnter( public override bool TryHandleLeave( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { action = SelectionVisitor.Continue; diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionListHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionListHandler.cs index b2bd688a0b9..9466a674a2c 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionListHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionListHandler.cs @@ -9,13 +9,13 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; public class QueryableProjectionListHandler : QueryableProjectionHandlerBase { - public override bool CanHandle(ISelection selection) => + public override bool CanHandle(Selection selection) => selection.Field.Member is { } && (selection.IsList || selection.IsMemberIsList()); public override QueryableProjectionContext OnBeforeEnter( QueryableProjectionContext context, - ISelection selection) + Selection selection) { var field = selection.Field; if (field.Member is PropertyInfo { CanWrite: true }) @@ -30,7 +30,7 @@ public override QueryableProjectionContext OnBeforeEnter( public override bool TryHandleEnter( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; @@ -58,7 +58,7 @@ public override bool TryHandleEnter( public override bool TryHandleLeave( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs index 7d5be358f91..594df9df6c3 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs @@ -8,13 +8,13 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; public class QueryableProjectionScalarHandler : QueryableProjectionHandlerBase { - public override bool CanHandle(ISelection selection) => + public override bool CanHandle(Selection selection) => selection.Field.Member is { } && selection.SelectionSet is null; public override bool TryHandleEnter( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { if (selection.Field.Member is PropertyInfo { CanWrite: true }) @@ -29,7 +29,7 @@ public override bool TryHandleEnter( public override bool TryHandleLeave( QueryableProjectionContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableFilterInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableFilterInterceptor.cs index 3fba65b481a..ce707b212db 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableFilterInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableFilterInterceptor.cs @@ -14,21 +14,20 @@ namespace HotChocolate.Data.Projections.Handlers; public class QueryableFilterInterceptor : IProjectionFieldInterceptor { - public bool CanHandle(ISelection selection) => + public bool CanHandle(Selection selection) => selection.Field.Member is PropertyInfo propertyInfo && propertyInfo.CanWrite && selection.HasFilterFeature(); public void BeforeProjection( QueryableProjectionContext context, - ISelection selection) + Selection selection) { - var field = selection.Field; var filterFeature = selection.GetFilterFeature(); if (filterFeature is not null - && context.Selection.Count > 0 - && context.Selection.Peek().Arguments.TryCoerceArguments(context.ResolverContext, out var coercedArgs) + && context.Selections.Count > 0 + && context.Selections.Peek().Arguments.TryCoerceArguments(context.ResolverContext, out var coercedArgs) && coercedArgs.TryGetValue(filterFeature.ArgumentName, out var argumentValue) && argumentValue.Type is IFilterInputType filterInputType && argumentValue.ValueLiteral is { } valueNode and not NullValueNode) @@ -64,7 +63,7 @@ public void BeforeProjection( } } - public void AfterProjection(QueryableProjectionContext context, ISelection selection) + public void AfterProjection(QueryableProjectionContext context, Selection selection) { } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs index 3898b8ac62a..2953c81bf7a 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs @@ -4,7 +4,7 @@ using HotChocolate.Data.Projections.Expressions.Handlers; using HotChocolate.Data.Sorting; using HotChocolate.Data.Sorting.Expressions; -using HotChocolate.Execution.Internal; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Language; using HotChocolate.Types; @@ -15,20 +15,20 @@ namespace HotChocolate.Data.Projections.Handlers; public class QueryableSortInterceptor : IProjectionFieldInterceptor { - public bool CanHandle(ISelection selection) => - selection.Field.Member is PropertyInfo propertyInfo - && propertyInfo.CanWrite - && selection.HasSortingFeature(); + public bool CanHandle(Selection selection) + => selection.Field.Member is PropertyInfo propertyInfo + && propertyInfo.CanWrite + && selection.HasSortingFeature; public void BeforeProjection( QueryableProjectionContext context, - ISelection selection) + Selection selection) { var field = selection.Field; if (field.Features.TryGet(out SortingFeature? feature) - && context.Selection.Count > 0 - && context.Selection.Peek().Arguments.TryCoerceArguments(context.ResolverContext, out var coercedArgs) + && context.Selections.Count > 0 + && context.Selections.Peek().Arguments.TryCoerceArguments(context.ResolverContext, out var coercedArgs) && coercedArgs.TryGetValue(feature.ArgumentName, out var argumentValue) && argumentValue.Type is ListType lt && lt.ElementType is NonNullType nn @@ -51,7 +51,7 @@ public void BeforeProjection( } } - public void AfterProjection(QueryableProjectionContext context, ISelection selection) + public void AfterProjection(QueryableProjectionContext context, Selection selection) { } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableTakeHandlerInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableTakeHandlerInterceptor.cs index 540f0d2da23..5b50413b9fa 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableTakeHandlerInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableTakeHandlerInterceptor.cs @@ -20,13 +20,13 @@ protected QueryableTakeHandlerInterceptor(SelectionFlags selectionFlags, int tak _take = take; } - public bool CanHandle(ISelection selection) => + public bool CanHandle(Selection selection) => selection.Field.Member is PropertyInfo { CanWrite: true } && selection.IsSelectionFlags(_selectionFlags); public void BeforeProjection( QueryableProjectionContext context, - ISelection selection) + Selection selection) { if (selection.IsSelectionFlags(_selectionFlags)) { @@ -42,7 +42,7 @@ public void BeforeProjection( public void AfterProjection( QueryableProjectionContext context, - ISelection selection) + Selection selection) { } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs index 59bfd237377..286acd8f250 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs @@ -8,7 +8,7 @@ namespace HotChocolate.Data.Projections.Handlers; public sealed class QueryableFilterProjectionOptimizer : IProjectionOptimizer { - public bool CanHandle(ISelection field) + public bool CanHandle(Selection field) => field.Field.Member is { } && field.HasFilterFeature(); public Selection RewriteSelection( diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs index d75c48d9c51..7b4ef8f5ef2 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Data.Projections.Handlers; public sealed class QueryablePagingProjectionOptimizer : IProjectionOptimizer { - public bool CanHandle(ISelection field) => + public bool CanHandle(Selection field) => field.DeclaringType is IPageType && field.Field.Name is "edges" or "items" or "nodes"; @@ -19,12 +19,12 @@ public Selection RewriteSelection( { // The selection optimizer will also process the field we just added // we have to avoid processing this field twice. - if (context.Selections.ContainsKey(CombinedEdgeField)) + if (context.ContainsResponseName(CombinedEdgeField)) { return selection; } - if (context.Type.NamedType() is not IPageType pageType) + if (context.TypeContext is not IPageType pageType) { throw ThrowHelper.PagingProjectionOptimizer_NotAPagingField( selection.DeclaringType, @@ -48,7 +48,7 @@ public Selection RewriteSelection( private Selection CreateCombinedSelection( SelectionSetOptimizerContext context, - ISelection selection, + Selection selection, ObjectType declaringType, IPageType pageType, IReadOnlyList selections) @@ -110,20 +110,22 @@ private static void CollectSelectionOfEdges( SelectionSetOptimizerContext context, List selections) { - if (context.Selections.Values.FirstOrDefault( - x => x.Field.Name == "edges") is { } edgeSelection) + if (context.Selections.FirstOrDefault(t => t.Field.Name == "edges") is { } edgeSelection) { - foreach (var edgeSubField in edgeSelection.SelectionSet!.Selections) + foreach (var fieldNode in edgeSelection.SyntaxNodes) { - if (edgeSubField is FieldNode edgeSubFieldNode - && edgeSubFieldNode.Name.Value is "node" - && edgeSubFieldNode.SelectionSet?.Selections is not null) + foreach (var edgeSubField in fieldNode.Node.SelectionSet!.Selections) { - foreach (var nodeField in edgeSubFieldNode.SelectionSet.Selections) + if (edgeSubField is FieldNode edgeSubFieldNode + && edgeSubFieldNode.Name.Value is "node" + && edgeSubFieldNode.SelectionSet?.Selections is not null) { - selections.Add( - s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? + foreach (var nodeField in edgeSubFieldNode.SelectionSet.Selections) + { + selections.Add( + s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? throw new SyntaxNodeCannotBeNullException(nodeField)); + } } } } @@ -134,14 +136,16 @@ private static void CollectSelectionOfItems( SelectionSetOptimizerContext context, List selections) { - if (context.Selections.Values - .FirstOrDefault(x => x.Field.Name == "items") is { } itemSelection) + if (context.Selections.FirstOrDefault(x => x.Field.Name == "items") is { } itemSelection) { - foreach (var nodeField in itemSelection.SelectionSet!.Selections) + foreach (var fieldNode in itemSelection.SyntaxNodes) { - selections.Add( - s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? + foreach (var nodeField in fieldNode.Node.SelectionSet!.Selections) + { + selections.Add( + s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? throw new SyntaxNodeCannotBeNullException(nodeField)); + } } } } @@ -150,13 +154,16 @@ private static void CollectSelectionOfNodes( SelectionSetOptimizerContext context, List selections) { - if (context.Selections.Values.FirstOrDefault(x => x.Field.Name == "nodes") is { } nodeSelection) + if (context.Selections.FirstOrDefault(x => x.Field.Name == "nodes") is { } nodeSelection) { - foreach (var nodeField in nodeSelection.SelectionSet!.Selections) + foreach (var fieldNode in nodeSelection.SyntaxNodes) { - selections.Add( - s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? + foreach (var nodeField in fieldNode.Node.SelectionSet!.Selections) + { + selections.Add( + s_cloneSelectionSetRewriter.Rewrite(nodeField) ?? throw new SyntaxNodeCannotBeNullException(nodeField)); + } } } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs index c242f3373cb..d8e2e96e6a1 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableSortProjectionOptimizer.cs @@ -7,8 +7,8 @@ namespace HotChocolate.Data.Projections.Handlers; public sealed class QueryableSortProjectionOptimizer : IProjectionOptimizer { - public bool CanHandle(ISelection field) - => field.Field.Member is { } && field.HasSortingFeature(); + public bool CanHandle(Selection field) + => field.Field.Member is { } && field.HasSortingFeature; public Selection RewriteSelection( SelectionSetOptimizerContext context, @@ -16,7 +16,7 @@ public Selection RewriteSelection( { var resolverPipeline = selection.ResolverPipeline ?? - context.CompileResolverPipeline(selection.Field, selection.SyntaxNode); + context.CompileResolverPipeline(selection.Field, selection.SyntaxNodes[0].Node); static FieldDelegate WrappedPipeline(FieldDelegate next) => ctx => diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionContext.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionContext.cs index 4d09ce1d3c8..a700222c976 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionContext.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionContext.cs @@ -4,15 +4,17 @@ namespace HotChocolate.Data.Projections.Expressions; -public class QueryableProjectionContext( - IResolverContext context, - IOutputType initialType, - Type runtimeType, - bool inMemory) - : ProjectionVisitorContext( - context, - initialType, - new QueryableProjectionScope(runtimeType, "_s1")) +public class QueryableProjectionContext : ProjectionVisitorContext { - public bool InMemory { get; } = inMemory; + public QueryableProjectionContext( + IResolverContext context, + IOutputType initialType, + Type runtimeType, + bool inMemory) + : base(context, initialType, new QueryableProjectionScope(runtimeType, "_s1")) + { + InMemory = inMemory; + } + + public bool InMemory { get; } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs index a2a9adce4e8..5db151a404d 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionVisitor.cs @@ -10,7 +10,7 @@ public class QueryableProjectionVisitor : ProjectionVisitor(IProjectionConvention convention) => new ProjectionQueryBuilder(convention.CreateBuilder()); - private static Selection UnwrapMutationPayloadSelection(ISelectionSet selectionSet, ObjectField field) + private static Selection UnwrapMutationPayloadSelection(SelectionSet selectionSet, ObjectField field) { - ref var selection = ref Unsafe.As(selectionSet).GetSelectionsReference(); - ref var end = ref Unsafe.Add(ref selection, selectionSet.Selections.Count); - - while (Unsafe.IsAddressLessThan(ref selection, ref end)) + foreach (var selection in selectionSet.Selections) { if (ReferenceEquals(selection.Field, field)) { return selection; } - - selection = ref Unsafe.Add(ref selection, 1)!; } throw new InvalidOperationException( @@ -226,12 +220,12 @@ public void Prepare(IMiddlewareContext context) && objectType.RuntimeType != typeof(object)) { var fieldProxy = new ObjectField(context.Selection.Field, objectType); - var selection = CreateProxySelection(context.Selection, fieldProxy); + var selection = context.Selection.WithField(fieldProxy); context = new MiddlewareContextProxy(context, selection, objectType); } //for use case when projection is used with Mutation Conventions - else if (context.Operation.Type is OperationType.Mutation + else if (context.Operation.Kind is OperationType.Mutation && context.Selection.Type.NamedType() is ObjectType mutationPayloadType && mutationPayloadType.Features.TryGet(out MutationPayloadInfo? mutationInfo)) { @@ -254,7 +248,7 @@ public void Apply(IMiddlewareContext context) private sealed class MiddlewareContextProxy( IMiddlewareContext context, - ISelection selection, + Selection selection, ObjectType objectType) : IMiddlewareContext { @@ -266,16 +260,18 @@ private sealed class MiddlewareContextProxy( public ObjectType ObjectType { get; } = objectType; - public IOperation Operation => _context.Operation; + public Operation Operation => _context.Operation; public IOperationResultBuilder OperationResult => _context.OperationResult; - public ISelection Selection { get; } = selection; + public Selection Selection { get; } = selection; public IVariableValueCollection Variables => _context.Variables; public Path Path => _context.Path; + public ulong IncludeFlags => _context.IncludeFlags; + public IServiceProvider RequestServices => _context.RequestServices; public string ResponseName => _context.ResponseName; @@ -336,9 +332,9 @@ public TValueNode ArgumentLiteral(string name) where TValueNode : IV public void ReportError(Exception exception, Action? configure = null) => _context.ReportError(exception, configure); - public IReadOnlyList GetSelections( + public SelectionEnumerator GetSelections( ObjectType typeContext, - ISelection? selection = null, + Selection? selection = null, bool allowInternals = false) => _context.GetSelections(typeContext, selection, allowInternals); @@ -372,27 +368,4 @@ public ArgumentValue ReplaceArgument(string argumentName, ArgumentValue newArgum IResolverContext IResolverContext.Clone() => _context.Clone(); } - - private static Selection.Sealed CreateProxySelection(ISelection selection, ObjectField field) - { - var includeConditionsSource = ((Selection)selection).IncludeConditions; - var includeConditions = new long[includeConditionsSource.Length]; - includeConditionsSource.CopyTo(includeConditions); - - var proxy = new Selection.Sealed(selection.Id, - selection.DeclaringType, - field, - field.Type, - selection.SyntaxNode, - selection.ResponseName, - selection.Arguments, - includeConditions, - selection.IsInternal, - selection.Strategy != SelectionExecutionStrategy.Serial, - selection.ResolverPipeline, - selection.PureResolver); - proxy.SetSelectionSetId(((Selection)selection).SelectionSetId); - proxy.Seal(selection.DeclaringOperation, selection.DeclaringSelectionSet); - return proxy; - } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Extensions/SelectionFlagsExtensions.cs b/src/HotChocolate/Data/src/Data/Projections/Extensions/SelectionFlagsExtensions.cs index 9869506075d..2a3d70a5010 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Extensions/SelectionFlagsExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Extensions/SelectionFlagsExtensions.cs @@ -15,10 +15,8 @@ public static class SelectionFlagsExtensions /// The selection. /// /// true if the field has a first or default middleware; otherwise, false. - public static bool IsFirstOrDefault(this ISelection selection) + public static bool IsFirstOrDefault(this Selection selection) { - ArgumentNullException.ThrowIfNull(selection); - var flags = selection.Field.Features.Get() ?? SelectionFlags.None; return (flags & SelectionFlags.FirstOrDefault) == SelectionFlags.FirstOrDefault; } @@ -29,10 +27,8 @@ public static bool IsFirstOrDefault(this ISelection selection) /// The selection. /// /// true if the field has a single or default middleware; otherwise, false. - public static bool IsSingleOrDefault(this ISelection selection) + public static bool IsSingleOrDefault(this Selection selection) { - ArgumentNullException.ThrowIfNull(selection); - var flags = selection.Field.Features.Get() ?? SelectionFlags.None; return (flags & SelectionFlags.SingleOrDefault) == SelectionFlags.SingleOrDefault; } @@ -43,10 +39,8 @@ public static bool IsSingleOrDefault(this ISelection selection) /// The selection. /// /// true if the field is a list; otherwise, false. - public static bool IsMemberIsList(this ISelection selection) + public static bool IsMemberIsList(this Selection selection) { - ArgumentNullException.ThrowIfNull(selection); - var flags = selection.Field.Features.Get() ?? SelectionFlags.None; return (flags & SelectionFlags.MemberIsList) == SelectionFlags.MemberIsList; } @@ -58,10 +52,8 @@ public static bool IsMemberIsList(this ISelection selection) /// The flags. /// /// true if the specified are set on the field; otherwise, false. - public static bool IsSelectionFlags(this ISelection selection, SelectionFlags flags) + public static bool IsSelectionFlags(this Selection selection, SelectionFlags flags) { - ArgumentNullException.ThrowIfNull(selection); - var actualFlags = selection.Field.Features.Get() ?? SelectionFlags.None; return (actualFlags & flags) == flags; } diff --git a/src/HotChocolate/Data/src/Data/Projections/IProjectionSelection.cs b/src/HotChocolate/Data/src/Data/Projections/IProjectionSelection.cs deleted file mode 100644 index f1201812a9e..00000000000 --- a/src/HotChocolate/Data/src/Data/Projections/IProjectionSelection.cs +++ /dev/null @@ -1,8 +0,0 @@ -using HotChocolate.Execution.Processing; - -namespace HotChocolate.Data.Projections; - -public interface IProjectionSelection : ISelection -{ - IProjectionFieldHandler Handler { get; } -} diff --git a/src/HotChocolate/Data/src/Data/Projections/ISelectionVisitorContext.cs b/src/HotChocolate/Data/src/Data/Projections/ISelectionVisitorContext.cs index a9f81f88691..3986a83d9a6 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ISelectionVisitorContext.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ISelectionVisitorContext.cs @@ -6,9 +6,18 @@ namespace HotChocolate.Data.Projections; public interface ISelectionVisitorContext { - Stack Selection { get; } + ulong IncludeFlags => ResolverContext.IncludeFlags; - Stack ResolvedType { get; } + Operation Operation => ResolverContext.Operation; + + Stack Selections { get; } + + Stack ResolvedTypes { get; } IResolverContext ResolverContext { get; } + + SelectionEnumerator GetSelections( + ObjectType typeContext, + Selection? selection = null, + bool allowInternals = false); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs index c89ef8cbfe2..36a108fe8a9 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Optimizers/IsProjectedProjectionOptimizer.cs @@ -1,7 +1,7 @@ using HotChocolate.Execution.Processing; using HotChocolate.Language; -namespace HotChocolate.Data.Projections.Handlers; +namespace HotChocolate.Data.Projections.Optimizers; public class IsProjectedProjectionOptimizer : IProjectionOptimizer { @@ -13,8 +13,7 @@ public Selection RewriteSelection( SelectionSetOptimizerContext context, Selection selection) { - if (context.Type is not { } type - || !type.Features.TryGet(out ProjectionTypeFeature? feature)) + if (!context.TypeContext.Features.TryGet(out ProjectionTypeFeature? feature)) { return selection; } @@ -22,41 +21,39 @@ public Selection RewriteSelection( for (var i = 0; i < feature.AlwaysProjectedFields.Length; i++) { var alias = "__projection_alias_" + i; - var alwaysProjectedField = feature.AlwaysProjectedFields[i]; + var fieldName = feature.AlwaysProjectedFields[i]; // if the field is already in the selection set we do not need to project it - if (context.Selections.TryGetValue(alwaysProjectedField, out var field) - && field.Field.Name == alwaysProjectedField) + if (context.TryGetSelection(fieldName, out var otherSelection) + && otherSelection.Field.Name == fieldName) { continue; } // if the field is already added as an alias we do not need to add it - if (context.Selections.TryGetValue(alias, out field) - && field.Field.Name == alwaysProjectedField) + if (context.TryGetSelection(alias, out otherSelection) + && otherSelection.Field.Name == fieldName) { continue; } - var nodesField = type.Fields[alwaysProjectedField]; - var nodesFieldNode = new FieldNode( + var field = context.TypeContext.Fields[fieldName]; + var fieldNode = new FieldNode( null, - new NameNode(alwaysProjectedField), + new NameNode(fieldName), new NameNode(alias), [], [], null); - var nodesPipeline = context.CompileResolverPipeline(nodesField, nodesFieldNode); + var nodesPipeline = context.CompileResolverPipeline(field, fieldNode); - var compiledSelection = new Selection.Sealed( + var compiledSelection = new Selection( context.NewSelectionId(), - context.Type, - nodesField, - nodesField.Type, - nodesFieldNode, alias, - arguments: selection.Arguments, + field, + [new FieldSelectionNode(fieldNode, 0)], + [], isInternal: true, resolverPipeline: nodesPipeline); diff --git a/src/HotChocolate/Data/src/Data/Projections/Optimizers/NodeSelectionSetOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Optimizers/NodeSelectionSetOptimizer.cs index 75be2f45836..a386eb80d27 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Optimizers/NodeSelectionSetOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Optimizers/NodeSelectionSetOptimizer.cs @@ -1,13 +1,13 @@ using HotChocolate.Execution.Processing; using HotChocolate.Types.Relay; -namespace HotChocolate.Data.Projections; +namespace HotChocolate.Data.Projections.Optimizers; internal sealed class NodeSelectionSetOptimizer(ISelectionSetOptimizer optimizer) : ISelectionSetOptimizer { public void OptimizeSelectionSet(SelectionSetOptimizerContext context) { - if (context.Type.Features.TryGet(out var feature) + if (context.TypeContext.Features.TryGet(out var feature) && feature.NodeResolver is { } nodeResolverInfo && nodeResolverInfo.QueryField?.HasProjectionMiddleware() == true) { diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionFeature.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionFeature.cs index 27a92191716..baa0ce03083 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ProjectionFeature.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionFeature.cs @@ -1,10 +1,5 @@ -using System.Collections.Immutable; - namespace HotChocolate.Data.Projections; public record ProjectionFeature( bool AlwaysProjected = false, bool HasProjectionMiddleware = false); - -public record ProjectionTypeFeature( - ImmutableArray AlwaysProjectedFields); diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs index 2030c3d416a..6e6d1fe04bd 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionOptimizer.cs @@ -8,16 +8,16 @@ internal sealed class ProjectionOptimizer(IProjectionProvider provider) public void OptimizeSelectionSet(SelectionSetOptimizerContext context) { var processedSelections = new HashSet(); - while (!processedSelections.SetEquals(context.Selections.Keys)) + while (!processedSelections.SetEquals(context.Selections.Select(t => t.ResponseName))) { - var selectionToProcess = new HashSet(context.Selections.Keys); + var selectionToProcess = new HashSet(context.Selections.Select(t => t.ResponseName)); selectionToProcess.ExceptWith(processedSelections); foreach (var responseName in selectionToProcess) { var rewrittenSelection = provider.RewriteSelection( context, - context.Selections[responseName]); + context.GetSelection(responseName)); context.ReplaceSelection(rewrittenSelection); diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeFeature.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeFeature.cs new file mode 100644 index 00000000000..4e2b61e1c7e --- /dev/null +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeFeature.cs @@ -0,0 +1,6 @@ +using System.Collections.Immutable; + +namespace HotChocolate.Data.Projections; + +public record ProjectionTypeFeature( + ImmutableArray AlwaysProjectedFields); diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeInterceptor.cs index 1724e17488b..0136708102a 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionTypeInterceptor.cs @@ -1,4 +1,5 @@ using HotChocolate.Configuration; +using HotChocolate.Data.Projections.Optimizers; using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Types; diff --git a/src/HotChocolate/Data/src/Data/Projections/ProjectionVisitor.cs b/src/HotChocolate/Data/src/Data/Projections/ProjectionVisitor.cs index c50346ddd28..c10436726a2 100644 --- a/src/HotChocolate/Data/src/Data/Projections/ProjectionVisitor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/ProjectionVisitor.cs @@ -14,16 +14,15 @@ public virtual void Visit(TContext context) Visit(context, context.ResolverContext.Selection); } - public virtual void Visit(TContext context, ISelection selection) + public virtual void Visit(TContext context, Selection selection) { - context.Selection.Push(selection); + context.Selections.Push(selection); Visit(selection.Field, context); } - protected override TContext OnBeforeLeave(ISelection selection, TContext localContext) + protected override TContext OnBeforeLeave(Selection selection, TContext localContext) { - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler) + if (selection.ProjectionHandler is IProjectionFieldHandler handler) { return handler.OnBeforeLeave(localContext, selection); } @@ -32,12 +31,11 @@ protected override TContext OnBeforeLeave(ISelection selection, TContext localCo } protected override TContext OnAfterLeave( - ISelection selection, + Selection selection, TContext localContext, ISelectionVisitorAction result) { - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler) + if (selection.ProjectionHandler is IProjectionFieldHandler handler) { return handler.OnAfterLeave(localContext, selection, result); } @@ -46,12 +44,11 @@ protected override TContext OnAfterLeave( } protected override TContext OnAfterEnter( - ISelection selection, + Selection selection, TContext localContext, ISelectionVisitorAction result) { - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler) + if (selection.ProjectionHandler is IProjectionFieldHandler handler) { return handler.OnAfterEnter(localContext, selection, result); } @@ -59,10 +56,9 @@ protected override TContext OnAfterEnter( return localContext; } - protected override TContext OnBeforeEnter(ISelection selection, TContext context) + protected override TContext OnBeforeEnter(Selection selection, TContext context) { - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler) + if (selection.ProjectionHandler is IProjectionFieldHandler handler) { return handler.OnBeforeEnter(context, selection); } @@ -71,17 +67,13 @@ protected override TContext OnBeforeEnter(ISelection selection, TContext context } protected override ISelectionVisitorAction Enter( - ISelection selection, + Selection selection, TContext context) { base.Enter(selection, context); - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler - && handler.TryHandleEnter( - context, - selection, - out var handlerResult)) + if (selection.ProjectionHandler is IProjectionFieldHandler handler + && handler.TryHandleEnter(context, selection, out var handlerResult)) { return handlerResult; } @@ -90,17 +82,13 @@ protected override ISelectionVisitorAction Enter( } protected override ISelectionVisitorAction Leave( - ISelection selection, + Selection selection, TContext context) { base.Leave(selection, context); - if (selection is IProjectionSelection projectionSelection - && projectionSelection.Handler is IProjectionFieldHandler handler - && handler.TryHandleLeave( - context, - selection, - out var handlerResult)) + if (selection.ProjectionHandler is IProjectionFieldHandler handler + && handler.TryHandleLeave(context, selection, out var handlerResult)) { return handlerResult; } @@ -108,7 +96,7 @@ protected override ISelectionVisitorAction Leave( return SkipAndLeave; } - protected override ISelectionVisitorAction Visit(ISelection selection, TContext context) + protected override ISelectionVisitorAction Visit(Selection selection, TContext context) { if (selection.Field.IsNotProjected()) { @@ -120,21 +108,29 @@ protected override ISelectionVisitorAction Visit(ISelection selection, TContext protected override ISelectionVisitorAction Visit(IOutputFieldDefinition field, TContext context) { - if (context.Selection.Count > 1 && field.IsNotProjected()) + if (context.Selections.Count > 1 && field.IsNotProjected()) { return Skip; } if (field.Type.NamedType() is IPageType and ObjectType pageType - && context.Selection.Peek() is { } pagingFieldSelection) + && context.Selections.Peek() is { } pagingFieldSelection) { - var selections = context.ResolverContext.GetSelections(pageType, pagingFieldSelection, true); + var includeFlags = context.IncludeFlags; + var selections = context.Operation.GetSelectionSet(pagingFieldSelection, pageType).Selections; - for (var index = selections.Count - 1; index >= 0; index--) + for (var i = selections.Length - 1; i >= 0; i--) { - if (selections[index] is { ResponseName: CombinedEdgeField } selection) + var selection = selections[i]; + + if (selection.IsSkipped(includeFlags)) + { + continue; + } + + if (selection is { ResponseName: CombinedEdgeField }) { - context.Selection.Push(selection); + context.Selections.Push(selection); return base.Visit(selection.Field, context); } diff --git a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor.cs b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor.cs index b851405ab16..3b8520b7461 100644 --- a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor.cs @@ -1,12 +1,12 @@ namespace HotChocolate.Data.Projections; -public class SelectionVisitor +public abstract class SelectionVisitor { /// /// The visitor default action. /// /// - protected virtual ISelectionVisitorAction DefaultAction => Continue; + protected ISelectionVisitorAction DefaultAction => Continue; /// /// Ends traversing the graph. diff --git a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitorContext.cs b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitorContext.cs index 2fb0e328214..016c478ec86 100644 --- a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitorContext.cs +++ b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitorContext.cs @@ -7,11 +7,17 @@ namespace HotChocolate.Data.Projections; public class SelectionVisitorContext(IResolverContext context) : ISelectionVisitorContext { - public Stack Selection { get; } = new(); + public Stack Selections { get; } = new(); public Stack SelectionSetNodes { get; } = new(); - public Stack ResolvedType { get; } = new(); + public Stack ResolvedTypes { get; } = new(); public IResolverContext ResolverContext { get; } = context; + + public SelectionEnumerator GetSelections( + ObjectType typeContext, + Selection? selection = null, + bool allowInternals = false) + => ResolverContext.GetSelections(typeContext, selection, allowInternals); } diff --git a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor`1.cs b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor`1.cs index 8ca14d0bfaf..00f814fdb9c 100644 --- a/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor`1.cs +++ b/src/HotChocolate/Data/src/Data/Projections/SelectionVisitor`1.cs @@ -3,9 +3,7 @@ namespace HotChocolate.Data.Projections; -public class SelectionVisitor - : SelectionVisitor - where TContext : ISelectionVisitorContext +public class SelectionVisitor : SelectionVisitor where TContext : ISelectionVisitorContext { protected virtual ISelectionVisitorAction Visit( IOutputFieldDefinition field, @@ -15,16 +13,15 @@ protected virtual ISelectionVisitorAction Visit( var result = Enter(field, localContext); localContext = OnAfterEnter(field, localContext, result); - if (result.Kind == SelectionVisitorActionKind.Continue) + if (result.Kind is SelectionVisitorActionKind.Continue) { - if (VisitChildren(field, context).Kind == SelectionVisitorActionKind.Break) + if (VisitChildren(field, context).Kind is SelectionVisitorActionKind.Break) { return Break; } } - if (result.Kind == SelectionVisitorActionKind.Continue - || result.Kind == SelectionVisitorActionKind.SkipAndLeave) + if (result.Kind is SelectionVisitorActionKind.Continue or SelectionVisitorActionKind.SkipAndLeave) { localContext = OnBeforeLeave(field, localContext); result = Leave(field, localContext); @@ -36,42 +33,41 @@ protected virtual ISelectionVisitorAction Visit( protected virtual TContext OnBeforeLeave( IOutputFieldDefinition field, - TContext localContext) => - localContext; + TContext localContext) + => localContext; protected virtual TContext OnAfterLeave( IOutputFieldDefinition field, TContext localContext, - ISelectionVisitorAction result) => - localContext; + ISelectionVisitorAction result) + => localContext; protected virtual TContext OnAfterEnter( IOutputFieldDefinition field, TContext localContext, - ISelectionVisitorAction result) => - localContext; + ISelectionVisitorAction result) + => localContext; protected virtual TContext OnBeforeEnter( IOutputFieldDefinition field, - TContext context) => - context; + TContext context) + => context; protected virtual ISelectionVisitorAction Visit( - ISelection selection, + Selection selection, TContext context) { var localContext = OnBeforeEnter(selection, context); var result = Enter(selection, localContext); localContext = OnAfterEnter(selection, localContext, result); - if (result.Kind == SelectionVisitorActionKind.Continue + if (result.Kind is SelectionVisitorActionKind.Continue && VisitChildren(selection, context).Kind == SelectionVisitorActionKind.Break) { return Break; } - if (result.Kind == SelectionVisitorActionKind.Continue - || result.Kind == SelectionVisitorActionKind.SkipAndLeave) + if (result.Kind is SelectionVisitorActionKind.Continue or SelectionVisitorActionKind.SkipAndLeave) { localContext = OnBeforeLeave(selection, localContext); result = Leave(selection, localContext); @@ -82,31 +78,31 @@ protected virtual ISelectionVisitorAction Visit( } protected virtual TContext OnBeforeLeave( - ISelection selection, + Selection selection, TContext localContext) => localContext; protected virtual TContext OnAfterLeave( - ISelection selection, + Selection selection, TContext localContext, ISelectionVisitorAction result) => localContext; protected virtual TContext OnAfterEnter( - ISelection selection, + Selection selection, TContext localContext, ISelectionVisitorAction result) => localContext; protected virtual TContext OnBeforeEnter( - ISelection selection, + Selection selection, TContext context) => context; protected virtual ISelectionVisitorAction VisitChildren(IOutputFieldDefinition field, TContext context) { var type = field.Type; - var selection = context.Selection.Peek(); + var selection = context.Selections.Peek(); var namedType = type.NamedType(); if (namedType.IsAbstractType()) @@ -133,19 +129,24 @@ protected virtual ISelectionVisitorAction VisitChildren(IOutputFieldDefinition f protected virtual ISelectionVisitorAction VisitObjectType( IOutputFieldDefinition field, ObjectType objectType, - ISelection selection, + Selection selection, TContext context) { - context.ResolvedType.Push(field.Type.NamedType().IsAbstractType() ? objectType : null); + context.ResolvedTypes.Push(field.Type.NamedType().IsAbstractType() ? objectType : null); try { - var selections = context.ResolverContext.GetSelections(objectType, selection, true); + var selectionSet = selection.GetSelectionSet(objectType); + var includeFlags = context.ResolverContext.IncludeFlags; - for (var i = 0; i < selections.Count; i++) + foreach (var childSelection in selectionSet.Selections) { - var result = Visit(selections[i], context); - if (result.Kind is SelectionVisitorActionKind.Break) + if (childSelection.IsSkipped(includeFlags)) + { + continue; + } + + if (Visit(selection, context).Kind is SelectionVisitorActionKind.Break) { return Break; } @@ -153,18 +154,17 @@ protected virtual ISelectionVisitorAction VisitObjectType( } finally { - context.ResolvedType.Pop(); + context.ResolvedTypes.Pop(); } return DefaultAction; } protected virtual ISelectionVisitorAction VisitChildren( - ISelection selection, + Selection selection, TContext context) { - var field = selection.Field; - return Visit(field, context); + return Visit(selection.Field, context); } protected virtual ISelectionVisitorAction Enter( @@ -178,18 +178,18 @@ protected virtual ISelectionVisitorAction Leave( DefaultAction; protected virtual ISelectionVisitorAction Enter( - ISelection selection, + Selection selection, TContext context) { - context.Selection.Push(selection); + context.Selections.Push(selection); return DefaultAction; } protected virtual ISelectionVisitorAction Leave( - ISelection selection, + Selection selection, TContext context) { - context.Selection.Pop(); + context.Selections.Pop(); return DefaultAction; } } diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs index 6edbc0e0d95..14d8dc98451 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs @@ -1,21 +1,22 @@ +using HotChocolate.Execution; using HotChocolate.Execution.Processing; namespace HotChocolate.Data.Projections; /// -/// A handler that can intersect a and optimize the selection set for +/// A handler that can intersect a and optimize the selection set for /// projections. /// public interface IProjectionFieldHandler { /// - /// Tests if this field handle can handle a selection. If it can handle the selection it + /// Tests if this field can handle a selection. If it can handle the selection it /// will be attached to the compiled selection set on the - /// type + /// type /// /// The selection to test for /// Returns true if the selection can be handled - bool CanHandle(ISelection selection); + bool CanHandle(Selection selection); /// /// Wrapped this field handler with a type interceptor diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler~1.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler~1.cs index aa2d9f68e78..64c69b5200e 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler~1.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler~1.cs @@ -4,9 +4,7 @@ namespace HotChocolate.Data.Projections; /// -public interface IProjectionFieldHandler - : IProjectionFieldHandler - where TContext : IProjectionVisitorContext +public interface IProjectionFieldHandler : IProjectionFieldHandler where TContext : IProjectionVisitorContext { /// /// This method is called before the visitor calls @@ -17,7 +15,7 @@ public interface IProjectionFieldHandler /// /// The instance of that is used in TryHandleEnter /// - TContext OnBeforeEnter(TContext context, ISelection selection); + TContext OnBeforeEnter(TContext context, Selection selection); /// /// Tries to apply projection to the field. This method is called after @@ -33,7 +31,7 @@ public interface IProjectionFieldHandler /// If true is returned the action is used for further processing bool TryHandleEnter( TContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action); /// @@ -48,7 +46,7 @@ bool TryHandleEnter( /// TContext OnAfterEnter( TContext context, - ISelection selection, + Selection selection, ISelectionVisitorAction result); /// @@ -60,7 +58,7 @@ TContext OnAfterEnter( /// /// The instance of that is used in TryHandleLeave /// - TContext OnBeforeLeave(TContext context, ISelection selection); + TContext OnBeforeLeave(TContext context, Selection selection); /// /// Tries to apply projection to the field. This method is called after @@ -76,7 +74,7 @@ TContext OnAfterEnter( /// If true is returned the action is used for further processing bool TryHandleLeave( TContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action); /// @@ -91,6 +89,6 @@ bool TryHandleLeave( /// TContext OnAfterLeave( TContext context, - ISelection selection, + Selection selection, ISelectionVisitorAction result); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionScope.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionScope.cs index 106e24f094c..858d8b87ce9 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionScope.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionScope.cs @@ -6,13 +6,8 @@ namespace HotChocolate.Data.Projections; /// The type of the filter configuration public class ProjectionScope { - public ProjectionScope() - { - Instance = new Stack(); - } - /// /// Stores the current instance. In case of an expression this would be x.Foo.Bar /// - public Stack Instance { get; } + public Stack Instance { get; } = []; } diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionVisitorContext.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionVisitorContext.cs index 76bf3664a8f..53b83b233eb 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionVisitorContext.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/ProjectionVisitorContext.cs @@ -4,13 +4,14 @@ namespace HotChocolate.Data.Projections; public abstract class ProjectionVisitorContext - : SelectionVisitorContext, - IProjectionVisitorContext + : SelectionVisitorContext + , IProjectionVisitorContext { protected ProjectionVisitorContext( IResolverContext context, IOutputType initialType, - ProjectionScope projectionScope) : base(context) + ProjectionScope projectionScope) + : base(context) { ArgumentNullException.ThrowIfNull(initialType); @@ -21,7 +22,7 @@ protected ProjectionVisitorContext( public Stack> Scopes { get; } - public Stack Types { get; } = new Stack(); + public Stack Types { get; } = []; public IList Errors { get; } = []; } diff --git a/src/HotChocolate/Data/src/Data/Sorting/Context/SortingContextResolverContextExtensions.cs b/src/HotChocolate/Data/src/Data/Sorting/Context/SortingContextResolverContextExtensions.cs index 50209933f4b..687ba355cce 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Context/SortingContextResolverContextExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Context/SortingContextResolverContextExtensions.cs @@ -16,7 +16,7 @@ public static class SortingContextResolverContextExtensions { ArgumentNullException.ThrowIfNull(context); - var argumentName = context.Selection.GetSortingArgumentName(); + var argumentName = context.Selection.SortingArgumentName; if (string.IsNullOrEmpty(argumentName)) { return null; diff --git a/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortingFeatureExtensions.cs b/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortingFeatureExtensions.cs index caefe88366c..6f46ec06bdc 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortingFeatureExtensions.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/Extensions/SortingFeatureExtensions.cs @@ -7,19 +7,20 @@ namespace HotChocolate.Data.Sorting; /// public static class SortingFeatureExtensions { - /// - /// Gets the sorting argument name from the selection. - /// - /// The selection. - /// The sorting argument name. - public static string? GetSortingArgumentName(this ISelection selection) - => selection.Field.Features.Get()?.ArgumentName; + extension(Selection selection) + { + /// + /// Gets the sorting argument name from the selection. + /// + /// The sorting argument name. + public string? SortingArgumentName + => selection.Field.Features.Get()?.ArgumentName; - /// - /// Checks if the selection has a sorting feature. - /// - /// The selection. - /// True if the selection has a sorting feature, otherwise false. - public static bool HasSortingFeature(this ISelection selection) - => selection.Field.Features.Get() is not null; + /// + /// Checks if the selection has a sorting feature. + /// + /// True if the selection has a sorting feature, otherwise false. + public bool HasSortingFeature + => selection.Field.Features.Get() is not null; + } } diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs b/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs index 531406760fa..988c5231a84 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs @@ -336,7 +336,7 @@ public virtual void EnrichExecuteRequest(RequestContext context, Activity activi activity.SetTag("graphql.document.hash", documentInfo.Hash.Value); activity.SetTag("graphql.document.valid", documentInfo.IsValidated); activity.SetTag("graphql.operation.id", operation?.Id); - activity.SetTag("graphql.operation.kind", operation?.Type); + activity.SetTag("graphql.operation.kind", operation?.Kind); activity.SetTag("graphql.operation.name", operation?.Name); if (_options.IncludeDocument && documentInfo.Document is not null) @@ -351,7 +351,7 @@ public virtual void EnrichExecuteRequest(RequestContext context, Activity activi } } - protected virtual string? CreateOperationDisplayName(RequestContext context, IOperation? operation) + protected virtual string? CreateOperationDisplayName(RequestContext context, Operation? operation) { if (operation is null) { @@ -367,7 +367,7 @@ public virtual void EnrichExecuteRequest(RequestContext context, Activity activi displayName.Append('{'); displayName.Append(' '); - foreach (var selection in rootSelectionSet.Selections.Take(3)) + foreach (var selection in rootSelectionSet.Selections[..3]) { if (displayName.Length > 2) { @@ -377,7 +377,7 @@ public virtual void EnrichExecuteRequest(RequestContext context, Activity activi displayName.Append(selection.ResponseName); } - if (rootSelectionSet.Selections.Count > 3) + if (rootSelectionSet.Selections.Length > 3) { displayName.Append(' '); displayName.Append('.'); @@ -667,6 +667,8 @@ private static ISyntaxNode CreateVariablesNode( items[i] = new ObjectValueNode(fields); } + + return new ListValueNode(items); } throw new InvalidOperationException(); diff --git a/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/Fusion.Execution.Benchmarks.csproj b/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/Fusion.Execution.Benchmarks.csproj index 61d4ec3dfb3..293f667f6ee 100644 --- a/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/Fusion.Execution.Benchmarks.csproj +++ b/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/Fusion.Execution.Benchmarks.csproj @@ -6,6 +6,7 @@ net10.0 true Preview + HotChocolate.Fusion.Execution.Benchmarks diff --git a/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/GraphQLQueryBenchmark.cs b/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/GraphQLQueryBenchmark.cs index 3704e00135e..581d0fc787f 100644 --- a/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/GraphQLQueryBenchmark.cs +++ b/src/HotChocolate/Fusion-vnext/benchmarks/Fusion.Execution.Benchmarks/GraphQLQueryBenchmark.cs @@ -14,6 +14,7 @@ using BenchmarkDotNet.Columns; using BenchmarkDotNet.Exporters.Csv; using BenchmarkDotNet.Exporters; +using HotChocolate.Buffers; namespace Fusion.Execution.Benchmarks; @@ -61,8 +62,12 @@ public async Task GlobalSetup() _transportFewItemsRequest = new TransportGraphQLHttpRequest(fewItems, _requestUri); _transportClient = new TransportClient(_client); - JsonMemory.Return(JsonMemory.Rent()); - MetaDbMemory.Return(MetaDbMemory.Rent()); + JsonMemory.Reconfigure( + static () => new FixedSizeArrayPool( + FixedSizeArrayPoolKinds.JsonMemory, + JsonMemory.BufferSize, + 128, + preAllocate: true)); } [GlobalCleanup] diff --git a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Extensions/MongoDbProjectionProviderDescriptorExtensions.cs b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Extensions/MongoDbProjectionProviderDescriptorExtensions.cs index 6a5714432a8..829ac6daf61 100644 --- a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Extensions/MongoDbProjectionProviderDescriptorExtensions.cs +++ b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Extensions/MongoDbProjectionProviderDescriptorExtensions.cs @@ -1,6 +1,7 @@ using HotChocolate.Data.MongoDb.Projections; using HotChocolate.Data.Projections; using HotChocolate.Data.Projections.Handlers; +using HotChocolate.Data.Projections.Optimizers; namespace HotChocolate.Data; 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 8bde094eee5..b767d7e82a9 100644 --- a/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj +++ b/src/HotChocolate/Utilities/src/Utilities.Buffers/HotChocolate.Utilities.Buffers.csproj @@ -16,6 +16,7 @@ + From 76ff6cc367d00276fb9c7b37e470d06d9b3b7024 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 22:41:23 +0100 Subject: [PATCH 22/42] wip --- .../OperationCompiler.CoerceArgumentValues.cs | 2 +- .../OperationCompiler.CompileResolver.cs | 2 +- .../Execution/Processing/OperationCompiler.cs | 23 ++++++++++++++-- .../Types/Resolvers/SelectionEnumerator.cs | 11 +++++++- .../QueryableCursorPagingProviderTests.cs | 26 +++++++++---------- .../Convention/IProjectionFieldInterceptor.cs | 2 +- .../QueryableProjectionFieldHandler.cs | 5 ++-- .../QueryableProjectionScalarHandler.cs | 5 ++-- .../Interceptor/QueryableSortInterceptor.cs | 2 +- .../QueryableFilterProjectionOptimizer.cs | 2 +- .../QueryablePagingProjectionOptimizer.cs | 18 +++++-------- .../Visitor/IProjectionFieldHandler.cs | 2 +- .../Visitor/IProjectionOptimizer.cs | 2 +- .../Handlers/MongoDbProjectionFieldHandler.cs | 8 +++--- ...QueryableSpatialProjectionScalarHandler.cs | 4 +-- ...ocumentAnalyzer.CollectInputObjectTypes.cs | 4 +-- .../Analyzers/FieldCollector.cs | 9 ++++--- .../Mappers/TypeDescriptorMapper.cs | 5 ++-- 18 files changed, 77 insertions(+), 55 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs index f601fa279a6..bcfc1ce0212 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs @@ -10,7 +10,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler +public sealed partial class OperationCompiler { private ArgumentMap? CoerceArgumentValues( ObjectField field, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs index 372d52fd5b7..ef36b6e2d52 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler +public sealed partial class OperationCompiler { internal static FieldDelegate CreateFieldPipeline(Schema schema, ObjectField field, FieldNode selection) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 2565aa7b5fd..ff196c9d4d4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -9,7 +9,7 @@ namespace HotChocolate.Execution.Processing; -internal sealed partial class OperationCompiler +public sealed partial class OperationCompiler { private readonly Schema _schema; private readonly ObjectPool>> _fieldsPool; @@ -18,7 +18,7 @@ internal sealed partial class OperationCompiler private readonly InputParser _inputValueParser; private static readonly ArrayPool s_objectArrayPool = ArrayPool.Shared; - public OperationCompiler( + internal OperationCompiler( Schema schema, InputParser inputValueParser, ObjectPool>> fieldsPool, @@ -34,6 +34,25 @@ public OperationCompiler( _optimizers = optimizers; } + public static Operation Compile( + string id, + OperationDefinitionNode operationDefinition, + Schema schema) + => Compile(id, id, operationDefinition, schema); + + public static Operation Compile( + string id, + string hash, + OperationDefinitionNode operationDefinition, + Schema schema) + => new OperationCompiler( + schema, + new InputParser(), + new DefaultObjectPool>>( + new DefaultPooledObjectPolicy>>()), + new OperationCompilerOptimizers()) + .Compile(id, hash, operationDefinition); + public Operation Compile( string id, string hash, diff --git a/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs b/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs index aed4577252b..23347abd46b 100644 --- a/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs +++ b/src/HotChocolate/Core/src/Types/Resolvers/SelectionEnumerator.cs @@ -12,7 +12,16 @@ public struct SelectionEnumerator : IEnumerable, IEnumerator + /// Initializes a new instance of + /// + /// + /// The selection set to enumerate on. + /// + /// + /// The include flags representing the selections that shall be included. + /// + public SelectionEnumerator(SelectionSet selectionSet, ulong includeFlags) { _selectionSet = selectionSet; _includeFlags = includeFlags; diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs index 5c417d78101..7555d0f1906 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs @@ -493,7 +493,7 @@ private sealed class MockContext : IResolverContext { private readonly CursorPagingArguments _arguments; - private MockContext(CursorPagingArguments arguments, IOperation operation, ISelection selection) + private MockContext(CursorPagingArguments arguments, Operation operation, Selection selection) { _arguments = arguments; Operation = operation; @@ -519,14 +519,10 @@ public static async Task CreateContextAsync(CursorPagingArgume } """); - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "abc", - document, - document.Definitions.OfType().First(), - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "abc", + document.Definitions.OfType().First(), + schema); return new MockContext(arguments, operation, operation.RootSelectionSet.Selections[0]); } @@ -574,13 +570,13 @@ public void ReportError(Exception exception, Action? configure = n throw new NotImplementedException(); } - public IReadOnlyList GetSelections( + public SelectionEnumerator GetSelections( ObjectType typeContext, - ISelection? selection = null, + Selection? selection = null, bool allowInternals = false) { var selectionSet = Operation.GetSelectionSet(selection ?? Selection, typeContext); - return selectionSet.Selections; + return new SelectionEnumerator(selectionSet, IncludeFlags); } public ISelectionCollection Select() @@ -607,14 +603,16 @@ public IResolverContext Clone() public ObjectType ObjectType => throw new NotImplementedException(); - public IOperation Operation { get; } + public Operation Operation { get; } - public ISelection Selection { get; } + public Selection Selection { get; } public IVariableValueCollection Variables => throw new NotImplementedException(); public Path Path => throw new NotImplementedException(); + public ulong IncludeFlags => 0; + public T Parent() { throw new NotImplementedException(); diff --git a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs index 5643a3e185a..0c455a1e94c 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Convention/IProjectionFieldInterceptor.cs @@ -7,7 +7,7 @@ public interface IProjectionFieldInterceptor /// /// Tests if this interceptor can handle a selection If it can handle the selection it /// will be attached to the compiled selection set on the - /// type + /// type ProjectionSelection. /// /// The selection to test for /// Returns true if the selection can be handled diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs index dc13c5b0c68..96557f400f5 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs @@ -9,9 +9,8 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; public class QueryableProjectionFieldHandler : QueryableProjectionHandlerBase { - public override bool CanHandle(Selection selection) => - selection.Field.Member is { } - && selection.SelectionSet is not null; + public override bool CanHandle(Selection selection) + => selection.Field.Member is not null && !selection.IsLeaf; public override bool TryHandleEnter( QueryableProjectionContext context, diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs index 594df9df6c3..e16fef75060 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionScalarHandler.cs @@ -8,9 +8,8 @@ namespace HotChocolate.Data.Projections.Expressions.Handlers; public class QueryableProjectionScalarHandler : QueryableProjectionHandlerBase { - public override bool CanHandle(Selection selection) => - selection.Field.Member is { } - && selection.SelectionSet is null; + public override bool CanHandle(Selection selection) + => selection.Field.Member is not null && selection.IsLeaf; public override bool TryHandleEnter( QueryableProjectionContext context, diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs index 2953c81bf7a..3051f34d423 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Interceptor/QueryableSortInterceptor.cs @@ -4,7 +4,7 @@ using HotChocolate.Data.Projections.Expressions.Handlers; using HotChocolate.Data.Sorting; using HotChocolate.Data.Sorting.Expressions; -using HotChocolate.Execution; +using HotChocolate.Execution.Internal; using HotChocolate.Execution.Processing; using HotChocolate.Language; using HotChocolate.Types; diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs index 286acd8f250..19eec26c72d 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryableFilterProjectionOptimizer.cs @@ -17,7 +17,7 @@ public Selection RewriteSelection( { var resolverPipeline = selection.ResolverPipeline - ?? context.CompileResolverPipeline(selection.Field, selection.SyntaxNode); + ?? context.CompileResolverPipeline(selection.Field, selection.SyntaxNodes[0].Node); static FieldDelegate WrappedPipeline(FieldDelegate next) => ctx => diff --git a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs index 7b4ef8f5ef2..4026a494ce0 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Expressions/Optimizers/QueryablePagingProjectionOptimizer.cs @@ -9,9 +9,8 @@ namespace HotChocolate.Data.Projections.Handlers; public sealed class QueryablePagingProjectionOptimizer : IProjectionOptimizer { - public bool CanHandle(Selection field) => - field.DeclaringType is IPageType - && field.Field.Name is "edges" or "items" or "nodes"; + public bool CanHandle(Selection field) + => field is { DeclaringType: IPageType, Field.Name: "edges" or "items" or "nodes" }; public Selection RewriteSelection( SelectionSetOptimizerContext context, @@ -37,7 +36,6 @@ public Selection RewriteSelection( CreateCombinedSelection( context, selection, - selection.DeclaringType, pageType, selections); @@ -49,7 +47,6 @@ public Selection RewriteSelection( private Selection CreateCombinedSelection( SelectionSetOptimizerContext context, Selection selection, - ObjectType declaringType, IPageType pageType, IReadOnlyList selections) { @@ -67,15 +64,14 @@ private Selection CreateCombinedSelection( selection.ResolverPipeline ?? context.CompileResolverPipeline(nodesField, combinedField); - return new Selection.Sealed( + return new Selection( context.NewSelectionId(), - declaringType, - nodesField, - nodesField.Type, - combinedField, CombinedEdgeField, - arguments: selection.Arguments, + nodesField, + [new FieldSelectionNode(combinedField, 0)], + [], isInternal: true, + arguments: selection.Arguments, resolverPipeline: nodesPipeline); } diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs index 14d8dc98451..0d939dee70e 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionFieldHandler.cs @@ -12,7 +12,7 @@ public interface IProjectionFieldHandler /// /// Tests if this field can handle a selection. If it can handle the selection it /// will be attached to the compiled selection set on the - /// type + /// type IProjectionSelection. /// /// The selection to test for /// Returns true if the selection can be handled diff --git a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs index 53d5cfc8c2d..1bd4518490d 100644 --- a/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs +++ b/src/HotChocolate/Data/src/Data/Projections/Visitor/IProjectionOptimizer.cs @@ -7,7 +7,7 @@ public interface IProjectionOptimizer /// /// Tests if this optimizer can handle a selection If it can handle the selection it /// will be attached to the compiled selection set on the - /// type + /// type ProjectionSelection. /// /// The selection to test for /// Returns true if the selection can be handled diff --git a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionFieldHandler.cs b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionFieldHandler.cs index b089ef4ca76..92b3f6a017a 100644 --- a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionFieldHandler.cs +++ b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionFieldHandler.cs @@ -9,13 +9,13 @@ public class MongoDbProjectionFieldHandler : MongoDbProjectionHandlerBase { /// - public override bool CanHandle(ISelection selection) => - selection.SelectionSet is not null; + public override bool CanHandle(Selection selection) + => !selection.IsLeaf; /// public override bool TryHandleEnter( MongoDbProjectionVisitorContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; @@ -27,7 +27,7 @@ public override bool TryHandleEnter( /// public override bool TryHandleLeave( MongoDbProjectionVisitorContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { context.Path.Pop(); diff --git a/src/HotChocolate/Spatial/src/Data/Projections/Extensions/Extensions/QueryableSpatialProjectionScalarHandler.cs b/src/HotChocolate/Spatial/src/Data/Projections/Extensions/Extensions/QueryableSpatialProjectionScalarHandler.cs index a2c57a634d5..48fd21c4b2a 100644 --- a/src/HotChocolate/Spatial/src/Data/Projections/Extensions/Extensions/QueryableSpatialProjectionScalarHandler.cs +++ b/src/HotChocolate/Spatial/src/Data/Projections/Extensions/Extensions/QueryableSpatialProjectionScalarHandler.cs @@ -8,9 +8,9 @@ namespace HotChocolate.Data.Projections.Spatial; public class QueryableSpatialProjectionScalarHandler : QueryableProjectionScalarHandler { - public override bool CanHandle(ISelection selection) => + public override bool CanHandle(Selection selection) => selection.Field.Member is not null && typeof(Geometry).IsAssignableFrom(selection.Field.Member.GetReturnType()); - public static new QueryableSpatialProjectionScalarHandler Create(ProjectionProviderContext context) => new(); + public new static QueryableSpatialProjectionScalarHandler Create(ProjectionProviderContext context) => new(); } diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/DocumentAnalyzer.CollectInputObjectTypes.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/DocumentAnalyzer.CollectInputObjectTypes.cs index 4ad3991107b..1ad24060502 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/DocumentAnalyzer.CollectInputObjectTypes.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/DocumentAnalyzer.CollectInputObjectTypes.cs @@ -41,7 +41,7 @@ private static void RegisterInputObjectType( foreach (var inputField in inputObjectType.Fields) { - rename = inputField.Directives.SingleOrDefault(); + rename = inputField.Directives.FirstOrDefault()?.ToValue(); fields.Add(new InputFieldModel( GetClassName(rename?.Name ?? inputField.Name), @@ -55,7 +55,7 @@ inputField.DefaultValue is not null context.RegisterType(inputField.Type.NamedType()); } - rename = inputObjectType.Directives.SingleOrDefault(); + rename = inputObjectType.Directives.FirstOrDefault()?.ToValue(); var typeName = context.ResolveTypeName( GetClassName(rename?.Name ?? inputObjectType.Name)); diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/FieldCollector.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/FieldCollector.cs index e1390615d65..6fdf84008ea 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/FieldCollector.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/FieldCollector.cs @@ -207,9 +207,10 @@ private void ResolveFragmentSpread( if (DoesTypeApply(fragment.TypeCondition, type)) { - var deferDirective = fragmentSpreadSyntax.Directives.GetDeferDirectiveNode(); + // TODO : DEFER + // var deferDirective = fragmentSpreadSyntax.Directives.GetDeferDirectiveNode(); var nodes = new List(); - var fragmentNode = new FragmentNode(fragment, nodes, deferDirective); + var fragmentNode = new FragmentNode(fragment, nodes, null); fragmentNodes.Add(fragmentNode); CollectFields( @@ -232,9 +233,9 @@ private void ResolveInlineFragment( if (DoesTypeApply(fragment.TypeCondition, type)) { - var deferDirective = inlineFragmentSyntax.Directives.GetDeferDirectiveNode(); + // var deferDirective = inlineFragmentSyntax.Directives.GetDeferDirectiveNode(); var nodes = new List(); - var fragmentNode = new FragmentNode(fragment, nodes, deferDirective); + var fragmentNode = new FragmentNode(fragment, nodes, null); fragmentNodes.Add(fragmentNode); CollectFields( diff --git a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Mappers/TypeDescriptorMapper.cs b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Mappers/TypeDescriptorMapper.cs index 4bf5c476ae1..bada4a415c8 100644 --- a/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Mappers/TypeDescriptorMapper.cs +++ b/src/StrawberryShake/CodeGeneration/src/CodeGeneration/Mappers/TypeDescriptorMapper.cs @@ -375,8 +375,9 @@ private static void CollectClassesThatImplementInterface( private static bool IncludeOrSkipDirective(OutputFieldModel field) { - return field.SyntaxNode.Directives.GetIncludeDirectiveNode() is not null - || field.SyntaxNode.Directives.GetSkipDirectiveNode() is not null; + return field.SyntaxNode.Directives.Any( + t => t.Name.Value.Equals(DirectiveNames.Include.Name) + || t.Name.Value.Equals(DirectiveNames.Skip.Name)); } private static void AddProperties( From 9d8eeb9daff3697ad975a2312d3d451810840d09 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 22:41:30 +0100 Subject: [PATCH 23/42] wip --- src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj | 1 + .../AutomaticMocking/MockFieldMiddleware.cs | 2 +- .../Convention/Handlers/MongoDbProjectionHandlerBase.cs | 6 +++--- .../Convention/Handlers/MongoDbProjectionScalarHandler.cs | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index d17deed0210..30ebd2b0c99 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -22,6 +22,7 @@ + diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Tests.Shared/AutomaticMocking/MockFieldMiddleware.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Tests.Shared/AutomaticMocking/MockFieldMiddleware.cs index 617211388ea..bd0251809d2 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Tests.Shared/AutomaticMocking/MockFieldMiddleware.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Tests.Shared/AutomaticMocking/MockFieldMiddleware.cs @@ -312,7 +312,7 @@ private static IError CreateError(IResolverContext context, int? index = null) return ErrorBuilder.New() .SetMessage("Unexpected Execution Error") .SetPath(path) - .AddLocation(context.Selection.SyntaxNode) + .AddLocations(context.Selection) .Build(); } diff --git a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionHandlerBase.cs b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionHandlerBase.cs index b9baa931b05..b38b1abf437 100644 --- a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionHandlerBase.cs +++ b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionHandlerBase.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Data.MongoDb.Projections; /// -/// A handler that can intersect a and optimize the selection set for +/// A handler that can intersect a and optimize the selection set for /// mongodb projections. /// public abstract class MongoDbProjectionHandlerBase @@ -15,7 +15,7 @@ public abstract class MongoDbProjectionHandlerBase /// public override bool TryHandleEnter( MongoDbProjectionVisitorContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { action = SelectionVisitor.Continue; @@ -25,7 +25,7 @@ public override bool TryHandleEnter( /// public override bool TryHandleLeave( MongoDbProjectionVisitorContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { action = SelectionVisitor.Continue; diff --git a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionScalarHandler.cs b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionScalarHandler.cs index e093ef61513..161bcd5aece 100644 --- a/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionScalarHandler.cs +++ b/src/HotChocolate/MongoDb/src/Data/Projections/Convention/Handlers/MongoDbProjectionScalarHandler.cs @@ -10,13 +10,13 @@ public class MongoDbProjectionScalarHandler : MongoDbProjectionHandlerBase { /// - public override bool CanHandle(ISelection selection) => - selection.SelectionSet is null; + public override bool CanHandle(Selection selection) => + selection.IsLeaf; /// public override bool TryHandleEnter( MongoDbProjectionVisitorContext context, - ISelection selection, + Selection selection, [NotNullWhen(true)] out ISelectionVisitorAction? action) { var field = selection.Field; From cdfbd3fa6e96bbee772c24cd2d4aa8efedaa700b Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 23:53:38 +0100 Subject: [PATCH 24/42] wip --- .../Execution/Processing/OperationCompiler.cs | 12 +- .../Execution/Processing/SelectionSet.cs | 15 +- .../SelectionSetOptimizerContext.cs | 7 + .../Extensions/ErrorBuilderExtensions.cs | 21 +- .../Execution.Tests/MiddlewareContextTests.cs | 13 +- .../Processing/OperationCompilerTests.cs | 411 ++++++------------ .../Processing/VisibilityTests.cs | 68 +-- .../Resolvers/ResolverCompilerTests.cs | 136 ++++-- .../Types/Brands/BrandNode.cs | 1 + 9 files changed, 339 insertions(+), 345 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index ff196c9d4d4..1aa47e7467e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -85,6 +85,7 @@ public Operation Compile( includeConditions); var selectionSet = BuildSelectionSet( + SelectionPath.Root, fields, rootType, compilationContext, @@ -167,7 +168,8 @@ internal SelectionSet CompileSelectionSet( } } - var selectionSet = BuildSelectionSet(fields, objectType, compilationContext, optimizers, ref lastId); + var path = selection.DeclaringSelectionSet.Path.Append(selection.ResponseName); + var selectionSet = BuildSelectionSet(path, fields, objectType, compilationContext, optimizers, ref lastId); compilationContext.Register(selectionSet, selectionSet.Id); elementsById = compilationContext.ElementsById; selectionSet.Complete(operation); @@ -232,6 +234,7 @@ private void CollectFields( } private SelectionSet BuildSelectionSet( + SelectionPath path, OrderedDictionary> fieldMap, ObjectType typeContext, CompilationContext compilationContext, @@ -324,7 +327,7 @@ private SelectionSet BuildSelectionSet( // if there are no optimizers registered for this selection we exit early. if (optimizers.Length == 0) { - return new SelectionSet(selectionSetId, typeContext, selections, isConditional); + return new SelectionSet(selectionSetId, path, typeContext, selections, isConditional); } var current = ImmutableCollectionsMarshal.AsImmutableArray(selections); @@ -332,6 +335,7 @@ private SelectionSet BuildSelectionSet( var optimizerContext = new SelectionSetOptimizerContext( selectionSetId, + path, typeContext, ref rewritten, compilationContext.Features, @@ -349,7 +353,7 @@ private SelectionSet BuildSelectionSet( // This mean we can simply construct the SelectionSet. if (current == rewritten) { - return new SelectionSet(selectionSetId, typeContext, selections, isConditional); + return new SelectionSet(selectionSetId, path, typeContext, selections, isConditional); } if (current.Length < rewritten.Length) @@ -368,7 +372,7 @@ private SelectionSet BuildSelectionSet( } selections = ImmutableCollectionsMarshal.AsArray(rewritten)!; - return new SelectionSet(selectionSetId, typeContext, selections, isConditional); + return new SelectionSet(selectionSetId, path, typeContext, selections, isConditional); } private static void CollapseIncludeFlags(List includeFlags) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs index 228f15f6261..b27ea77f5b5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSet.cs @@ -18,7 +18,12 @@ public sealed class SelectionSet : ISelectionSet private Flags _flags; private Operation? _declaringOperation; - internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections, bool isConditional) + internal SelectionSet( + int id, + SelectionPath path, + IObjectTypeDefinition type, + Selection[] selections, + bool isConditional) { ArgumentNullException.ThrowIfNull(selections); @@ -28,6 +33,7 @@ internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections } Id = id; + Path = path; Type = type; _flags = isConditional ? Flags.Conditional : Flags.None; _selections = selections; @@ -40,13 +46,18 @@ internal SelectionSet(int id, IObjectTypeDefinition type, Selection[] selections /// public int Id { get; } + /// + /// Gets the path where this selection set is located within the GraphQL operation document. + /// + public SelectionPath Path { get; } + /// /// Defines if this list needs post-processing for skip and include. /// public bool IsConditional => (_flags & Flags.Conditional) == Flags.Conditional; /// - /// Gets the type that declares this selection set. + /// Gets the type context of this selection set. /// public IObjectTypeDefinition Type { get; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs index c956a0fa9a0..17d94802be4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionSetOptimizerContext.cs @@ -24,6 +24,7 @@ public ref struct SelectionSetOptimizerContext /// internal SelectionSetOptimizerContext( int selectionSetId, + SelectionPath path, ObjectType typeContext, ref ImmutableArray selections, OperationFeatureCollection features, @@ -36,6 +37,7 @@ internal SelectionSetOptimizerContext( _features = features; _lastSelectionId = ref lastSelectionId; _createFieldPipeline = createFieldPipeline; + Path = path; TypeContext = typeContext; Schema = schema; } @@ -45,6 +47,11 @@ internal SelectionSetOptimizerContext( /// public Schema Schema { get; } + /// + /// Gets the path where this selection set is located within the GraphQL operation document. + /// + public SelectionPath Path { get; } + /// /// Gets the type context of the current selection-set. /// diff --git a/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs index 7a6362d85c2..db9ded8259a 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ErrorBuilderExtensions.cs @@ -1,14 +1,27 @@ -using System.Diagnostics; using HotChocolate.Execution.Processing; namespace HotChocolate; -internal static class ErrorBuilderExtensions +/// +/// Provides extension methods for . +/// +public static class ErrorBuilderExtensions { + /// + /// Adds all syntax node locations from a selection to the error builder. + /// + /// + /// The error builder to which locations will be added. + /// + /// + /// The selection containing the syntax nodes whose locations will be added to the error. + /// + /// + /// The for method chaining. + /// public static ErrorBuilder AddLocations(this ErrorBuilder errorBuilder, Selection selection) { - Debug.Assert(errorBuilder is not null); - Debug.Assert(selection is not null); + ArgumentNullException.ThrowIfNull(selection); foreach (var syntaxNode in selection.SyntaxNodes) { diff --git a/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs b/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs index 7d294bf4644..a798cdb7f4f 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs @@ -18,7 +18,7 @@ public async Task AccessVariables() .AddResolver( "Query", "foo", - ctx => ctx.Variables.GetValue("abc")?.Value) + ctx => ctx.Variables.GetValue("abc").Value) .Create(); var request = OperationRequestBuilder.New() @@ -43,7 +43,7 @@ public async Task AccessVariables_Fails_When_Variable_Not_Exists() .AddResolver( "Query", "foo", - ctx => ctx.Variables.GetValue("abc")?.Value) + ctx => ctx.Variables.GetValue("abc").Value) .Create(); var request = OperationRequestBuilder.New() @@ -63,7 +63,7 @@ public async Task AccessVariables_Fails_When_Variable_Not_Exists() public async Task CollectFields() { // arrange - var list = new List(); + var list = new List(); var schema = SchemaBuilder.New() .AddDocumentFromString( @@ -105,7 +105,7 @@ await schema.MakeExecutable().ExecuteAsync( }"); // assert - list.Select(t => t.SyntaxNode.Name.Value).ToList().MatchSnapshot(); + list.Select(t => t.SyntaxNodes[0].Node.Name.Value).ToList().MatchSnapshot(); } [Fact] @@ -627,8 +627,8 @@ public async Task SetResultExtensionData_With_ObjectValue_WhenDeferred() private static void CollectSelections( IResolverContext context, - ISelection selection, - ICollection collected) + Selection selection, + ICollection collected) { if (selection.Type.IsLeafType()) { @@ -644,5 +644,6 @@ private static void CollectSelections( } } + // ReSharper disable once NotAccessedPositionalProperty.Local private record SomeData(string SomeField); } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs index 1274cf5d887..09311f012ba 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs @@ -27,14 +27,10 @@ public void Prepare_One_Field() var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -59,14 +55,10 @@ public void Prepare_Duplicate_Field() document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -91,14 +83,10 @@ public void Prepare_Empty_Operation_SelectionSet() document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -129,14 +117,10 @@ ... on Human { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -172,14 +156,10 @@ fragment def on Human { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -242,14 +222,10 @@ fragment Human3 on Human { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -274,14 +250,10 @@ public void Prepare_Duplicate_Field_With_Skip() var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -308,14 +280,10 @@ public void Field_Does_Not_Exist() // act void Action() { - var compiler = new OperationCompiler(new InputParser()); - compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + OperationCompiler.Compile( + "opid", + operationDefinition, + schema); } // assert @@ -348,14 +316,10 @@ fragment abc on Droid { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -384,14 +348,10 @@ fragment abc on Droid { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -420,14 +380,10 @@ fragment abc on Droid { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -460,14 +416,10 @@ fragment abc on Droid { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -508,14 +460,10 @@ ... @include(if: $v) { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -580,14 +528,10 @@ fragment Human3 on Human { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -622,14 +566,10 @@ ... @include(if: $v) { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -653,14 +593,10 @@ name @include(if: $q) var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -693,14 +629,10 @@ public void Field_Based_Optimizers() var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -728,14 +660,10 @@ ... @defer { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -765,14 +693,10 @@ fragment Foo on Droid { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -802,14 +726,10 @@ friends @include(if: $withFriends) { document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -836,14 +756,10 @@ ... abc var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -858,24 +774,22 @@ public void InlineFragment_SelectionsSet_Empty() .Create(); var document = Utf8GraphQLParser.Parse( - @"query foo($v: Boolean){ - hero(episode: EMPIRE) { - name @include(if: $v) - ... on Droid { } - } - }"); + """ + query foo($v: Boolean){ + hero(episode: EMPIRE) { + name @include(if: $v) + ... on Droid { } + } + } + """); var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -899,14 +813,10 @@ query foo($v: Boolean) { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -929,14 +839,10 @@ public async Task Large_Query_Test() document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -960,14 +866,10 @@ public async Task Crypto_Details_Test() document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1005,14 +907,10 @@ fragment PriceInfo on Asset { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1050,14 +948,10 @@ fragment PriceInfo on Asset { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1096,14 +990,10 @@ fragment PriceInfo on Asset { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1127,14 +1017,10 @@ public async Task Crypto_List_Test() document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1215,14 +1101,10 @@ type OrganizationUnit2 implements OrganizationUnit { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1303,19 +1185,13 @@ type OrganizationUnit2 implements OrganizationUnit { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert - Assert.Equal(29, compiler.Metrics.Selections); - Assert.Equal(7, compiler.Metrics.SelectionSetVariants); - Assert.Equal(4, compiler.Metrics.BacklogMaxSize); + // Note: Metrics are no longer accessible with static method } [Fact] @@ -1352,14 +1228,10 @@ fragment TypeTwoParts on TypeTwo { var operationDefinition = document.Definitions.OfType().Single(); // act - var compiler = new OperationCompiler(new InputParser()); - var operation = compiler.Compile( - new OperationCompilerRequest( - "opid", - document, - operationDefinition, - schema.QueryType, - schema)); + var operation = OperationCompiler.Compile( + "opid", + operationDefinition, + schema); // assert MatchSnapshot(document, operation); @@ -1436,17 +1308,16 @@ public void OptimizeSelectionSet(SelectionSetOptimizerContext context) { if (context.Path is { Name: "bar" }) { - var baz = context.Type.Fields["baz"]; + var baz = context.TypeContext.Fields["baz"]; var bazSelection = Utf8GraphQLParser.Syntax.ParseField("baz { text }"); var bazPipeline = context.CompileResolverPipeline(baz, bazSelection); var compiledSelection = new Selection( context.NewSelectionId(), - context.Type, - baz, - baz.Type, - bazSelection, "someName", + baz, + [new FieldSelectionNode(bazSelection, 0)], + [], isInternal: true, resolverPipeline: bazPipeline); diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/VisibilityTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/VisibilityTests.cs index 2342c35e52c..13a0bee45dd 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/VisibilityTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/VisibilityTests.cs @@ -13,9 +13,10 @@ public void TryExtract_Skip_With_Literal() var field = Utf8GraphQLParser.Syntax.ParseField("field @skip(if: true)"); // act - var includeCondition = IncludeCondition.FromSelection(field); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert + Assert.True(hasIncludeCondition); Assert.False(includeCondition.IsIncluded(variables.Object)); } @@ -27,10 +28,12 @@ public void Equals_Skip_With_Literal_True() var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: true)"); // act - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.True(includeConditionA.Equals(includeConditionB)); } @@ -42,10 +45,12 @@ public void Equals_Skip_With_Variable_True() var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: $a)"); // act - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.True(includeConditionA.Equals(includeConditionB)); } @@ -57,10 +62,12 @@ public void Equals_Skip_With_Literal_False() var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: false)"); // act - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.False(includeConditionA.Equals(includeConditionB)); } @@ -72,10 +79,12 @@ public void Equals_Skip_With_Variable_False() var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: $a)"); // act - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.False(includeConditionA.Equals(includeConditionB)); } @@ -87,10 +96,10 @@ public void TryExtract_False() var field = Utf8GraphQLParser.Syntax.ParseField("field @test(test: true)"); // act - var includeCondition = IncludeCondition.FromSelection(field); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert - Assert.True(includeCondition.IsIncluded(variables.Object)); + Assert.False(hasIncludeCondition); } [Fact] @@ -101,10 +110,10 @@ public void TryExtract_False_2() var field = Utf8GraphQLParser.Syntax.ParseField("field"); // act - var includeCondition = IncludeCondition.FromSelection(field); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert - Assert.True(includeCondition.IsIncluded(variables.Object)); + Assert.False(hasIncludeCondition); } [Fact] @@ -115,9 +124,10 @@ public void TryExtract_True() var field = Utf8GraphQLParser.Syntax.ParseField("field @skip(if: true)"); // act - var includeCondition = IncludeCondition.FromSelection(field); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert + Assert.True(hasIncludeCondition); Assert.False(includeCondition.IsIncluded(variables.Object)); } @@ -128,14 +138,16 @@ public void GetHashCode_Skip_With_Literal_Equal() var fieldA = Utf8GraphQLParser.Syntax.ParseField("fieldA @skip(if: true)"); var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: true)"); - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // act var hashCodeA = includeConditionA.GetHashCode(); var hashCodeB = includeConditionB.GetHashCode(); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.Equal(hashCodeA, hashCodeB); } @@ -146,14 +158,16 @@ public void GetHashCode_Skip_With_Literal_NotEqual() var fieldA = Utf8GraphQLParser.Syntax.ParseField("fieldA @skip(if: true)"); var fieldB = Utf8GraphQLParser.Syntax.ParseField("fieldB @skip(if: false)"); - var includeConditionA = IncludeCondition.FromSelection(fieldA); - var includeConditionB = IncludeCondition.FromSelection(fieldB); + var hasIncludeConditionA = IncludeCondition.TryCreate(fieldA, out var includeConditionA); + var hasIncludeConditionB = IncludeCondition.TryCreate(fieldB, out var includeConditionB); // act var hashCodeA = includeConditionA.GetHashCode(); var hashCodeB = includeConditionB.GetHashCode(); // assert + Assert.True(hasIncludeConditionA); + Assert.True(hasIncludeConditionB); Assert.NotEqual(hashCodeA, hashCodeB); } @@ -164,13 +178,13 @@ public void IsVisible_Skip_Variables_True() var variables = new Mock(); variables.Setup(t => t.GetValue(It.IsAny())).Returns(BooleanValueNode.False); var field = Utf8GraphQLParser.Syntax.ParseField("field @skip(if: $a)"); - var includeCondition = IncludeCondition.FromSelection(field); // act - var visible = includeCondition.IsIncluded(variables.Object); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert - Assert.True(visible); + Assert.True(hasIncludeCondition); + Assert.True(includeCondition.IsIncluded(variables.Object)); } [Fact] @@ -180,13 +194,13 @@ public void IsVisible_Include_Variables_True() var variables = new Mock(); variables.Setup(t => t.GetValue(It.IsAny())).Returns(BooleanValueNode.True); var field = Utf8GraphQLParser.Syntax.ParseField("field @include(if: $a)"); - var includeCondition = IncludeCondition.FromSelection(field); // act - var visible = includeCondition.IsIncluded(variables.Object); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert - Assert.True(visible); + Assert.True(hasIncludeCondition); + Assert.True(includeCondition.IsIncluded(variables.Object)); } [Fact] @@ -195,12 +209,12 @@ public void IsVisible_Include_Literal_True() // arrange var variables = new Mock(); var field = Utf8GraphQLParser.Syntax.ParseField("field @include(if: true)"); - var includeCondition = IncludeCondition.FromSelection(field); // act - var visible = includeCondition.IsIncluded(variables.Object); + var hasIncludeCondition = IncludeCondition.TryCreate(field, out var includeCondition); // assert - Assert.True(visible); + Assert.True(hasIncludeCondition); + Assert.True(includeCondition.IsIncluded(variables.Object)); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs b/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs index 90ee7a94b30..1ae88b29256 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs @@ -467,11 +467,29 @@ public async Task Compile_Arguments_FieldSelection() var resolver = compiler.CompileResolve(member, type).Resolver!; // assert - var selection = new Mock(); + var fieldSyntax = new FieldNode( + null, + new NameNode("foo"), + null, + Array.Empty(), + Array.Empty(), + null); + + var schema = + SchemaBuilder.New() + .AddQueryType(c => c.Name("Query").Field("abc").Resolve("def")) + .Create(); + + var selection = new Selection( + id: 1, + "abc", + schema.Types.GetType("Query").Fields["abc"], + [new FieldSelectionNode(fieldSyntax, 1)], + []); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Selection).Returns(selection.Object); + context.SetupGet(t => t.Selection).Returns(selection); var result = (bool)(await resolver(context.Object))!; Assert.True(result); @@ -491,11 +509,29 @@ public async Task Compile_Arguments_Selection() var pure = compiler.CompileResolve(member, type).PureResolver!; // assert - var selection = new Mock(); + var fieldSyntax = new FieldNode( + null, + new NameNode("foo"), + null, + Array.Empty(), + Array.Empty(), + null); + + var schema = + SchemaBuilder.New() + .AddQueryType(c => c.Name("Query").Field("abc").Resolve("def")) + .Create(); + + var selection = new Selection( + id: 1, + "abc", + schema.Types.GetType("Query").Fields["abc"], + [new FieldSelectionNode(fieldSyntax, 1)], + []); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Selection).Returns(selection.Object); + context.SetupGet(t => t.Selection).Returns(selection); var result = (bool)(await resolver(context.Object))!; Assert.True(result, "Standard Resolver"); @@ -526,12 +562,21 @@ public async Task Compile_Arguments_FieldSyntax() Array.Empty(), null); - var selection = new Mock(); - selection.SetupGet(t => t.SyntaxNode).Returns(fieldSyntax); + var schema = + SchemaBuilder.New() + .AddQueryType(c => c.Name("Query").Field("abc").Resolve("def")) + .Create(); + + var selection = new Selection( + id: 1, + "abc", + schema.Types.GetType("Query").Fields["abc"], + [new FieldSelectionNode(fieldSyntax, 1)], + []); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Selection).Returns(selection.Object); + context.SetupGet(t => t.Selection).Returns(selection); var result = (bool)(await resolver(context.Object))!; Assert.True(result, "Standard Resolver"); @@ -579,24 +624,20 @@ public async Task Compile_Arguments_Operation() var resolver = compiler.CompileResolve(member, type).Resolver!; // assert - var operationDefinition = - new OperationDefinitionNode( - null, - null, - null, - OperationType.Query, - Array.Empty(), - Array.Empty(), - new SelectionSetNode( - null, - Array.Empty())); - - var operation = new Mock(); - operation.Setup(t => t.Definition).Returns(operationDefinition); + var schema = + SchemaBuilder.New() + .AddQueryType(c => c.Name("Query").Field("abc").Resolve("def")) + .Create(); + + var document = Utf8GraphQLParser.Parse("{ abc }"); + var operation = OperationCompiler.Compile( + "abc", + document.Definitions.OfType().First(), + schema); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Operation).Returns(operation.Object); + context.SetupGet(t => t.Operation).Returns(operation); var result = (bool)(await resolver(context.Object))!; Assert.True(result); } @@ -614,6 +655,14 @@ public async Task Compile_Arguments_ObjectField() var resolver = compiler.CompileResolve(member, type).Resolver!; // assert + var fieldSyntax = new FieldNode( + null, + new NameNode("a"), + null, + Array.Empty(), + Array.Empty(), + null); + var schema = SchemaBuilder.New() .AddDocumentFromString("type Query { a: String }") .Use(next => next) @@ -621,12 +670,16 @@ public async Task Compile_Arguments_ObjectField() var queryType = schema.Types.GetType("Query"); - var selection = new Mock(); - selection.SetupGet(t => t.Field).Returns(queryType.Fields.First()); + var selection = new Selection( + id: 1, + "a", + queryType.Fields.First(), + [new FieldSelectionNode(fieldSyntax, 1)], + []); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Selection).Returns(selection.Object); + context.SetupGet(t => t.Selection).Returns(selection); var result = (bool)(await resolver(context.Object))!; Assert.True(result); @@ -645,6 +698,14 @@ public async Task Compile_Arguments_IOutputField() var resolver = compiler.CompileResolve(member, type).Resolver!; // assert + var fieldSyntax = new FieldNode( + null, + new NameNode("a"), + null, + Array.Empty(), + Array.Empty(), + null); + var schema = SchemaBuilder.New() .AddDocumentFromString("type Query { a: String }") .Use(next => next) @@ -652,12 +713,16 @@ public async Task Compile_Arguments_IOutputField() var queryType = schema.Types.GetType("Query"); - var selection = new Mock(); - selection.SetupGet(t => t.Field).Returns(queryType.Fields.First()); + var selection = new Selection( + id: 1, + "a", + queryType.Fields.First(), + [new FieldSelectionNode(fieldSyntax, 1)], + []); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Selection).Returns(selection.Object); + context.SetupGet(t => t.Selection).Returns(selection); var result = (bool)(await resolver(context.Object))!; Assert.True(result); @@ -676,13 +741,20 @@ public async Task Compile_Arguments_Document() var resolver = compiler.CompileResolve(member, type).Resolver!; // assert - var document = new DocumentNode(Array.Empty()); - var operation = new Mock(); - operation.Setup(t => t.Document).Returns(document); + var schema = + SchemaBuilder.New() + .AddQueryType(c => c.Name("Query").Field("abc").Resolve("def")) + .Create(); + + var document = Utf8GraphQLParser.Parse("{ abc }"); + var operation = OperationCompiler.Compile( + "abc", + document.Definitions.OfType().First(), + schema); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); - context.SetupGet(t => t.Operation).Returns(operation.Object); + context.SetupGet(t => t.Operation).Returns(operation); var result = (bool)(await resolver(context.Object))!; Assert.True(result); } diff --git a/src/HotChocolate/Data/test/Data.PostgreSQL.Tests/Types/Brands/BrandNode.cs b/src/HotChocolate/Data/test/Data.PostgreSQL.Tests/Types/Brands/BrandNode.cs index 7eee8c9b14b..122ef0ab407 100644 --- a/src/HotChocolate/Data/test/Data.PostgreSQL.Tests/Types/Brands/BrandNode.cs +++ b/src/HotChocolate/Data/test/Data.PostgreSQL.Tests/Types/Brands/BrandNode.cs @@ -1,6 +1,7 @@ using GreenDonut.Data; using HotChocolate.Data.Models; using HotChocolate.Data.Services; +using HotChocolate.Execution; using HotChocolate.Execution.Processing; using HotChocolate.Types; using HotChocolate.Types.Pagination; From 722e60f5dea17ffe4c7f5ed1774b3b8f4709031a Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Thu, 4 Dec 2025 23:58:48 +0100 Subject: [PATCH 25/42] Fixed middleware --- .../Execution/Pipeline/OperationResolverMiddleware.cs | 9 ++------- .../src/Types/Execution/Processing/OperationCompiler.cs | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs index 9c85a312c1d..0a301750db7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs @@ -9,7 +9,6 @@ internal sealed class OperationResolverMiddleware { private readonly RequestDelegate _next; private readonly OperationCompiler _operationPlanner; - private readonly DocumentRewriter _documentRewriter; private readonly IExecutionDiagnosticEvents _diagnosticEvents; private OperationResolverMiddleware( @@ -25,7 +24,6 @@ private OperationResolverMiddleware( _next = next; _operationPlanner = operationPlanner; - _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); _diagnosticEvents = diagnosticEvents; } @@ -42,13 +40,10 @@ public async ValueTask InvokeAsync(RequestContext context) { using (_diagnosticEvents.CompileOperation(context)) { - // Before we can plan an operation, we must de-fragmentize it and remove static include conditions. - var operationDocument = documentInfo.Document; var operationName = context.Request.OperationName; - operationDocument = _documentRewriter.RewriteDocument(operationDocument, operationName); + var operationDocument = documentInfo.Document; var operationNode = operationDocument.GetOperation(operationName); - // After optimizing the query structure we can begin the planning process. operation = _operationPlanner.Compile( operationId ?? Guid.NewGuid().ToString("N"), documentInfo.Hash.Value, @@ -69,7 +64,7 @@ public static RequestMiddlewareConfiguration Create() (core, next) => { var schema = core.Schema; - var operationCompiler = core.Services.GetRequiredService(); + var operationCompiler = core.SchemaServices.GetRequiredService(); var diagnosticEvents = core.SchemaServices.GetRequiredService(); var middleware = new OperationResolverMiddleware( diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 1aa47e7467e..49a07b7e4e9 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -61,6 +61,7 @@ public Operation Compile( ArgumentException.ThrowIfNullOrWhiteSpace(id); ArgumentNullException.ThrowIfNull(operationDefinition); + // Before we can plan an operation, we must de-fragmentize it and remove static include conditions. var document = new DocumentNode([operationDefinition]); document = _documentRewriter.RewriteDocument(document); operationDefinition = (OperationDefinitionNode)document.Definitions[0]; From 133f6942efba492f489153f7563c745040bbabff Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 5 Dec 2025 14:40:05 +0100 Subject: [PATCH 26/42] wip --- ...estExecutorBuilderExtensions.Convention.cs | 2 +- .../Core/src/Types/Execution/ErrorHelper.cs | 2 +- .../Extensions/ExecutionResultExtensions.cs | 2 +- .../Processing/MiddlewareContext.Arguments.cs | 2 +- .../Types/Execution/Processing/Operation.cs | 2 +- .../OperationCompiler.CoerceArgumentValues.cs | 6 - .../Execution/Processing/OperationCompiler.cs | 2 +- .../Processing/OperationContext.Operation.cs | 2 +- .../Processing/Result/ResultBuilder.cs | 2 +- .../Execution/Processing/RootValueResolver.cs | 3 +- .../Types/Execution/Processing/Selection.cs | 2 +- .../Processing/Tasks/ResolverTask.Pooling.cs | 1 - .../Processing/Tasks/ResolverTask.cs | 4 +- .../Processing/VariableValueOrLiteral.cs | 2 +- .../Types/Execution/RequestExecutorManager.cs | 17 +- .../Core/src/Types/Execution/ThrowHelper.cs | 2 +- .../Types/Fetching/BatchDispatcherResult.cs | 2 +- .../Fetching/ExecutionDataLoaderScope.cs | 3 +- .../Types/Fetching/Utilities/ThrowHelper.cs | 2 +- .../Core/src/Types/HotChocolate.Types.csproj | 23 + .../Properties/FetchingResources.Designer.cs | 34 +- .../Types/Properties/FetchingResources.resx | 112 +---- .../Types/Properties/Resources.Designer.cs | 470 +++++------------- .../Conventions/DescriptorContext.cs | 8 +- .../Execution/FusionRequestExecutorManager.cs | 2 +- 25 files changed, 215 insertions(+), 494 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs index a2c6eab4b96..bc762ba1c1c 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/SchemaRequestExecutorBuilderExtensions.Convention.cs @@ -1,6 +1,6 @@ using HotChocolate; using HotChocolate.Execution.Configuration; -using HotChocolate.Execution.Properties; +using HotChocolate.Properties; using HotChocolate.Types.Descriptors; using static HotChocolate.Execution.ThrowHelper; diff --git a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs index abcb9c0ca53..2507ff251a6 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs @@ -2,7 +2,7 @@ using System.Net; using HotChocolate.Execution.Processing; using HotChocolate.Language; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; namespace HotChocolate.Execution; diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs index 8e0e5c914f2..08931bcac27 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs @@ -3,7 +3,7 @@ using HotChocolate.Buffers; using HotChocolate.Execution; using HotChocolate.Transport.Formatters; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; // ReSharper disable once CheckNamespace namespace HotChocolate; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs index e69ab937ba7..16bca1ca7b7 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs @@ -2,7 +2,7 @@ using HotChocolate.Resolvers; using HotChocolate.Types; using HotChocolate.Utilities; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; using static HotChocolate.Execution.ThrowHelper; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs index c88f27dda86..f62474155e8 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Operation.cs @@ -32,7 +32,7 @@ internal Operation( SelectionSet rootSelectionSet, OperationCompiler compiler, IncludeConditionCollection includeConditions, - OperationFeatureCollection features, + OperationFeatureCollection features, int lastId, object[] elementsById) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs index bcfc1ce0212..62b09006798 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs @@ -1,12 +1,6 @@ -using System.Buffers; -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using HotChocolate.Fusion.Rewriters; using HotChocolate.Language; -using HotChocolate.Language.Visitors; using HotChocolate.Resolvers; using HotChocolate.Types; -using Microsoft.Extensions.ObjectPool; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 49a07b7e4e9..e417997b6ae 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -294,7 +294,7 @@ private SelectionSet BuildSelectionSet( var pureFieldDelegate = TryCreatePureField(_schema, field, first.Node); var arguments = ArgumentMap.Empty; - if (first.Node.Arguments.Count > 0) + if (field.Arguments.Count > 0) { arguments = CoerceArgumentValues(field, first.Node); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs index 8921485ebd5..ab9451f9a43 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Operation.cs @@ -1,4 +1,4 @@ -using HotChocolate.Execution.Properties; +using HotChocolate.Properties; using HotChocolate.Types; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs index 82f764c4804..653ea7c7d95 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs @@ -1,6 +1,6 @@ using System.Buffers; using System.Runtime.CompilerServices; -using HotChocolate.Execution.Properties; +using HotChocolate.Properties; using HotChocolate.Resolvers; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs index eb1c09b379b..d0d6524aa18 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/RootValueResolver.cs @@ -1,6 +1,5 @@ using HotChocolate.Types; -using Microsoft.Extensions.DependencyInjection; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs index d47b00eb706..194fa17715d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Selection.cs @@ -1,4 +1,4 @@ -using HotChocolate.Execution.Properties; +using HotChocolate.Properties; using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Resolvers; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs index 5bd5f9edf88..a5d30fe42a4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs @@ -40,7 +40,6 @@ internal bool Reset() Next = null; Previous = null; State = null; - _task = null; _taskBuffer.Clear(); _args.Clear(); return true; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs index 4b19453a6e7..277a00bd565 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs @@ -1,5 +1,6 @@ using HotChocolate.Execution.Instrumentation; using HotChocolate.Resolvers; +using HotChocolate.Utilities; using Microsoft.Extensions.ObjectPool; namespace HotChocolate.Execution.Processing.Tasks; @@ -12,7 +13,6 @@ internal sealed partial class ResolverTask(ObjectPool objectPool) private OperationContext _operationContext = null!; private Selection _selection = null!; private ExecutionTaskStatus _completionStatus = ExecutionTaskStatus.Completed; - private Task? _task; /// /// Gets or sets the internal execution id. @@ -71,6 +71,6 @@ public ExecutionTaskKind Kind public void BeginExecute(CancellationToken cancellationToken) { Status = ExecutionTaskStatus.Running; - _task = ExecuteAsync(cancellationToken); + ExecuteAsync(cancellationToken).FireAndForget(); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs index 4b82070912f..61844bacb3e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/VariableValueOrLiteral.cs @@ -1,6 +1,6 @@ using HotChocolate.Language; using HotChocolate.Types; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs index a3ebe5b7ee4..56e873af829 100644 --- a/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs +++ b/src/HotChocolate/Core/src/Types/Execution/RequestExecutorManager.cs @@ -35,18 +35,19 @@ internal sealed partial class RequestExecutorManager private readonly IServiceProvider _applicationServices; private readonly EventObservable _events = new(); private readonly ChannelWriter _executorEvictionChannelWriter; + private ulong _version; private bool _disposed; public RequestExecutorManager( IOptionsMonitor optionsMonitor, - IServiceProvider serviceProvider) + IServiceProvider applicationServices) { ArgumentNullException.ThrowIfNull(optionsMonitor); - ArgumentNullException.ThrowIfNull(serviceProvider); + ArgumentNullException.ThrowIfNull(applicationServices); _optionsMonitor = optionsMonitor; - _applicationServices = serviceProvider; + _applicationServices = applicationServices; var executorEvictionChannel = Channel.CreateUnbounded(); _executorEvictionChannelWriter = executorEvictionChannel.Writer; @@ -89,8 +90,9 @@ public async ValueTask GetExecutorAsync( throw new InvalidOperationException($"The requested schema '{schemaName}' does not exist."); } - var registeredExecutor = await CreateRequestExecutorAsync(schemaName, true, cancellationToken) - .ConfigureAwait(false); + var registeredExecutor = + await CreateRequestExecutorAsync(schemaName, true, cancellationToken) + .ConfigureAwait(false); return registeredExecutor.Executor; } @@ -266,7 +268,8 @@ await typeModuleChangeMonitor.ConfigureAsync(context, cancellationToken) serviceCollection.AddSingleton(new SchemaVersionInfo(version)); - serviceCollection.AddSingleton(context.DescriptorContext.TypeConverter); + serviceCollection.AddSingleton( + _ => context.DescriptorContext.TypeConverter); serviceCollection.AddSingleton( static sp => new InputParser(sp.GetRequiredService())); @@ -282,6 +285,8 @@ await typeModuleChangeMonitor.ConfigureAsync(context, cancellationToken) static _ => new DefaultObjectPoolProvider()); serviceCollection.AddSingleton( static sp => sp.GetRequiredService().CreateStringBuilderPool()); + serviceCollection.AddSingleton( + static sp => sp.GetRequiredService().CreateFieldMapPool()); serviceCollection.AddSingleton(executorOptions); serviceCollection.AddSingleton( diff --git a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs index d2ac4820927..81cd8a172c0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs @@ -1,6 +1,6 @@ using HotChocolate.Language; using HotChocolate.Types; -using static HotChocolate.Execution.Properties.Resources; +using static HotChocolate.Properties.Resources; namespace HotChocolate.Execution; diff --git a/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs index 96e1ef89d5b..409662c4ca2 100644 --- a/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs +++ b/src/HotChocolate/Core/src/Types/Fetching/BatchDispatcherResult.cs @@ -1,4 +1,4 @@ -using HotChocolate.Fetching.Properties; +using HotChocolate.Properties; namespace HotChocolate.Fetching; diff --git a/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs b/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs index ebf55abd726..737e035edfc 100644 --- a/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs +++ b/src/HotChocolate/Core/src/Types/Fetching/ExecutionDataLoaderScope.cs @@ -1,8 +1,7 @@ using System.Collections.Concurrent; using GreenDonut; using GreenDonut.DependencyInjection; -using HotChocolate.Fetching.Properties; -using Microsoft.Extensions.DependencyInjection; +using HotChocolate.Properties; namespace HotChocolate.Fetching; diff --git a/src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs index 51281d7e99e..bb7a836dc5f 100644 --- a/src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Fetching/Utilities/ThrowHelper.cs @@ -1,4 +1,4 @@ -using static HotChocolate.Fetching.Properties.FetchingResources; +using static HotChocolate.Properties.FetchingResources; namespace HotChocolate.Fetching.Utilities; diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 30ebd2b0c99..17b5240fe90 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -221,6 +221,24 @@ OperationFeatureCollection.cs + + + RequestExecutorManager.cs + + + + RequestExecutorManager.cs + + + + RequestExecutorManager.cs + + + + True + True + FetchingResources.resx + @@ -322,6 +340,11 @@ ResXFileCodeGenerator TextJsonResources.Designer.cs + + + ResXFileCodeGenerator + FetchingResources.Designer.cs + diff --git a/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs index 83d091f7900..a7beaa7e6ea 100644 --- a/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.Designer.cs @@ -7,34 +7,34 @@ // //------------------------------------------------------------------------------ -namespace HotChocolate.Fetching.Properties { +namespace HotChocolate.Properties { using System; - - + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class FetchingResources { - + private static System.Resources.ResourceManager resourceMan; - + private static System.Globalization.CultureInfo resourceCulture; - + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal FetchingResources() { } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Resources.ResourceManager ResourceManager { get { if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("HotChocolate.Fetching.Properties.FetchingResources", typeof(FetchingResources).Assembly); + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("HotChocolate.Properties.FetchingResources", typeof(FetchingResources).Assembly); resourceMan = temp; } return resourceMan; } } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Globalization.CultureInfo Culture { get { @@ -44,49 +44,49 @@ internal static System.Globalization.CultureInfo Culture { resourceCulture = value; } } - + internal static string DataLoaderRegistry_KeyNullOrEmpty { get { return ResourceManager.GetString("DataLoaderRegistry_KeyNullOrEmpty", resourceCulture); } } - + internal static string DefaultDataLoaderRegistry_GetOrRegister { get { return ResourceManager.GetString("DefaultDataLoaderRegistry_GetOrRegister", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_RegistryIsNull { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_RegistryIsNull", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_UnableToRegister { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_UnableToRegister", resourceCulture); } } - + internal static string ThrowHelper_DataLoader_InvalidType { get { return ResourceManager.GetString("ThrowHelper_DataLoader_InvalidType", resourceCulture); } } - + internal static string BatchDispatcherResult_NoExceptions { get { return ResourceManager.GetString("BatchDispatcherResult_NoExceptions", resourceCulture); diff --git a/src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx index 054ca8f64cb..67e73398d1e 100644 --- a/src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx +++ b/src/HotChocolate/Core/src/Types/Properties/FetchingResources.resx @@ -1,122 +1,24 @@ - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + text/microsoft-resx - 2.0 + 1.3 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + The DataLoader key cannot be null or empty. @@ -136,7 +38,7 @@ Unable to register a DataLoader with your DataLoader registry. - The provided type {0} is not a dataloader + The provided type {0} is not a DataLoader. There must be at least one exception to create an error result. diff --git a/src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs index bf137efe381..89f003a93dd 100644 --- a/src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/Resources.Designer.cs @@ -7,50 +7,36 @@ // //------------------------------------------------------------------------------ -namespace HotChocolate.Execution.Properties { +namespace HotChocolate.Properties { using System; - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HotChocolate.Execution.Properties.Resources", typeof(Resources).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("HotChocolate.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -59,561 +45,375 @@ internal Resources() { } } - /// - /// Looks up a localized string similar to Serial execution tasks cannot be batched.. - /// - internal static string BatchExecutionTask_AddExecutionTask_SerialTasksNotAllowed { + internal static string ThrowHelper_FieldDoesNotExistOnType { get { - return ResourceManager.GetString("BatchExecutionTask_AddExecutionTask_SerialTasksNotAllowed", resourceCulture); + return ResourceManager.GetString("ThrowHelper_FieldDoesNotExistOnType", resourceCulture); } } - /// - /// Looks up a localized string similar to You can only read a response stream once.. - /// - internal static string DeferredResult_ReadResultsAsync_ReadOnlyOnce { + internal static string ObjectBuffer_IsEmpty { get { - return ResourceManager.GetString("DeferredResult_ReadResultsAsync_ReadOnlyOnce", resourceCulture); + return ResourceManager.GetString("ObjectBuffer_IsEmpty", resourceCulture); } } - /// - /// Looks up a localized string similar to Detected a non-null violation in argument `{0}`.. - /// - internal static string ErrorHelper_ArgumentNonNullError_Message { + internal static string ObjectBuffer_IsUsedUp { get { - return ResourceManager.GetString("ErrorHelper_ArgumentNonNullError_Message", resourceCulture); + return ResourceManager.GetString("ObjectBuffer_IsUsedUp", resourceCulture); } } - /// - /// Looks up a localized string similar to The type `{0}` is not supported as list value.. - /// - internal static string ErrorHelper_ListValueIsNotSupported_Message { + internal static string PreparedSelection_ReadOnly { get { - return ResourceManager.GetString("ErrorHelper_ListValueIsNotSupported_Message", resourceCulture); + return ResourceManager.GetString("PreparedSelection_ReadOnly", resourceCulture); } } - /// - /// Looks up a localized string similar to The request exceeded the configured timeout of `{0}`.. - /// - internal static string ErrorHelper_RequestTimeout { + internal static string DeferredResult_ReadResultsAsync_ReadOnlyOnce { get { - return ResourceManager.GetString("ErrorHelper_RequestTimeout", resourceCulture); + return ResourceManager.GetString("DeferredResult_ReadResultsAsync_ReadOnlyOnce", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified root type `{0}` is not supported by this server.. - /// - internal static string ErrorHelper_RootTypeNotFound_Message { + internal static string ErrorHelper_ArgumentNonNullError_Message { get { - return ResourceManager.GetString("ErrorHelper_RootTypeNotFound_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_ArgumentNonNullError_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Either no compiled operation was found or the variables have not been coerced.. - /// - internal static string ErrorHelper_StateInvalidForOperationExecution_Message { + internal static string ErrorHelper_UnableToResolveTheAbstractType_Message { get { - return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationExecution_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_UnableToResolveTheAbstractType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Either no query document exists or the document validation result is invalid.. - /// - internal static string ErrorHelper_StateInvalidForOperationResolver_Message { + internal static string ErrorHelper_ListValueIsNotSupported_Message { get { - return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationResolver_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_ListValueIsNotSupported_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to There is no operation on the context which can be used to coerce variables.. - /// - internal static string ErrorHelper_StateInvalidForOperationVariableCoercion_Message { + internal static string ErrorHelper_UnexpectedValueCompletionError_Message { get { - return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationVariableCoercion_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_UnexpectedValueCompletionError_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Unable to resolve the abstract type `{0}`.. - /// - internal static string ErrorHelper_UnableToResolveTheAbstractType_Message { + internal static string ErrorHelper_RootTypeNotFound_Message { get { - return ResourceManager.GetString("ErrorHelper_UnableToResolveTheAbstractType_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_RootTypeNotFound_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Unexpected error during value completion.. - /// - internal static string ErrorHelper_UnexpectedValueCompletionError_Message { + internal static string ErrorHelper_StateInvalidForOperationResolver_Message { get { - return ResourceManager.GetString("ErrorHelper_UnexpectedValueCompletionError_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationResolver_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Could not resolve the actual object type from `{0}` for the abstract type `{1}`.. - /// - internal static string ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message { + internal static string ErrorHelper_StateInvalidForOperationVariableCoercion_Message { get { - return ResourceManager.GetString("ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message", resourceCulture); + return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationVariableCoercion_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The query cannot be null or empty.. - /// - internal static string ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty { + internal static string ErrorHelper_StateInvalidForOperationExecution_Message { get { - return ResourceManager.GetString("ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty", resourceCulture); + return ResourceManager.GetString("ErrorHelper_StateInvalidForOperationExecution_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Only query results are supported.. - /// - internal static string ExecutionResultExtensions_OnlyQueryResults { + internal static string ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message { get { - return ResourceManager.GetString("ExecutionResultExtensions_OnlyQueryResults", resourceCulture); + return ResourceManager.GetString("ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to There is no argument with the name `{0}`.. - /// - internal static string MiddlewareContext_ReplaceArgument_InvalidKey { + internal static string ThrowHelper_VariableIsNotAnInputType_Message { get { - return ResourceManager.GetString("MiddlewareContext_ReplaceArgument_InvalidKey", resourceCulture); + return ResourceManager.GetString("ThrowHelper_VariableIsNotAnInputType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to It is not allowed to replace the arguments with null.. - /// - internal static string MiddlewareContext_ReplaceArguments_NullNotAllowed { + internal static string ThrowHelper_NonNullVariableIsNull_Message { get { - return ResourceManager.GetString("MiddlewareContext_ReplaceArguments_NullNotAllowed", resourceCulture); + return ResourceManager.GetString("ThrowHelper_NonNullVariableIsNull_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Buffer is full.. - /// - internal static string ObjectBuffer_IsEmpty { + internal static string ThrowHelper_VariableValueInvalidType_Message { get { - return ResourceManager.GetString("ObjectBuffer_IsEmpty", resourceCulture); + return ResourceManager.GetString("ThrowHelper_VariableValueInvalidType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Buffer is used up.. - /// - internal static string ObjectBuffer_IsUsedUp { + internal static string ThrowHelper_VariableNotFound_Message { get { - return ResourceManager.GetString("ObjectBuffer_IsUsedUp", resourceCulture); + return ResourceManager.GetString("ThrowHelper_VariableNotFound_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified selection does not have a selection set.. - /// - internal static string Operation_GetPossibleTypes_NoSelectionSet { + internal static string ThrowHelper_VariableNotOfType_Message { get { - return ResourceManager.GetString("Operation_GetPossibleTypes_NoSelectionSet", resourceCulture); + return ResourceManager.GetString("ThrowHelper_VariableNotOfType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The operation selection set is empty.. - /// - internal static string OperationCompiler_Compile_SelectionSetIsEmpty { + internal static string ThrowHelper_RootTypeNotSupported_Message { get { - return ResourceManager.GetString("OperationCompiler_Compile_SelectionSetIsEmpty", resourceCulture); + return ResourceManager.GetString("ThrowHelper_RootTypeNotSupported_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The document did not contain a fragment definition with the name `{0}`.. - /// - internal static string OperationCompiler_FragmentNotFound { + internal static string ThrowHelper_SubscriptionExecutor_ContextInvalidState_Message { get { - return ResourceManager.GetString("OperationCompiler_FragmentNotFound", resourceCulture); + return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_ContextInvalidState_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The operation compiler only allows for 64 unique include conditions.. - /// - internal static string OperationCompiler_ToManyIncludeConditions { + internal static string ThrowHelper_SubscriptionExecutor_SubscriptionsMustHaveOneField_Message { get { - return ResourceManager.GetString("OperationCompiler_ToManyIncludeConditions", resourceCulture); + return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_SubscriptionsMustHaveOneField_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The query type could not be casted to {0}.. - /// - internal static string OperationContext_GetQueryRoot_InvalidCast { + internal static string ThrowHelper_SubscriptionExecutor_NoSubscribeResolver_Message { get { - return ResourceManager.GetString("OperationContext_GetQueryRoot_InvalidCast", resourceCulture); + return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_NoSubscribeResolver_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The selection is read-only.. - /// - internal static string PreparedSelection_ReadOnly { + internal static string ThrowHelper_ResolverContext_LiteralsNotSupported_Message { get { - return ResourceManager.GetString("PreparedSelection_ReadOnly", resourceCulture); + return ResourceManager.GetString("ThrowHelper_ResolverContext_LiteralsNotSupported_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Invalid fragment id.. - /// - internal static string QueryPlan_InvalidFragmentId { + internal static string ThrowHelper_ResolverContext_CannotConvertArgument_Message { get { - return ResourceManager.GetString("QueryPlan_InvalidFragmentId", resourceCulture); + return ResourceManager.GetString("ThrowHelper_ResolverContext_CannotConvertArgument_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified convention type is not supported.. - /// - internal static string RequestExecutorBuilder_Convention_NotSupported { + internal static string ThrowHelper_ResolverContext_LiteralNotCompatible_Message { get { - return ResourceManager.GetString("RequestExecutorBuilder_Convention_NotSupported", resourceCulture); + return ResourceManager.GetString("ThrowHelper_ResolverContext_LiteralNotCompatible_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Its not allowed to set `items` and `data` at the same time.. - /// - internal static string ResultBuilder_DataAndItemsNotAllowed { + internal static string ThrowHelper_ResolverContext_ArgumentDoesNotExist_Message { get { - return ResourceManager.GetString("ResultBuilder_DataAndItemsNotAllowed", resourceCulture); + return ResourceManager.GetString("ThrowHelper_ResolverContext_ArgumentDoesNotExist_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to A GraphQL result must have data, errors or both.. - /// - internal static string ResultHelper_BuildResult_InvalidResult { + internal static string ThrowHelper_OperationResolverHelper_NoOperationFound_Message { get { - return ResourceManager.GetString("ResultHelper_BuildResult_InvalidResult", resourceCulture); + return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_NoOperationFound_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Unable to create the operation type `{0}` instance. Try adding the following service: `services.AddScoped<{1}>();`. - /// - internal static string RootValueResolver_Resolve_CannotCreateInstance { + internal static string ThrowHelper_OperationResolverHelper_MultipleOperation_Message { get { - return ResourceManager.GetString("RootValueResolver_Resolve_CannotCreateInstance", resourceCulture); + return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_MultipleOperation_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The provided response name must be the same as on the selection.. - /// - internal static string SelectionSetOptimizerContext_AddSelection_ResponseNameNotTheSame { + internal static string ThrowHelper_OperationResolverHelper_InvalidOperationName_Message { get { - return ResourceManager.GetString("SelectionSetOptimizerContext_AddSelection_ResponseNameNotTheSame", resourceCulture); + return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_InvalidOperationName_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The `{0}` is not a valid GraphQL field name.. - /// - internal static string SelectionSetOptimizerContext_InvalidFieldName { + internal static string ThrowHelper_BatchExecutor_CannotSerializeVariable_Message { get { - return ResourceManager.GetString("SelectionSetOptimizerContext_InvalidFieldName", resourceCulture); + return ResourceManager.GetString("ThrowHelper_BatchExecutor_CannotSerializeVariable_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to This SelectionVariants instance is read-only.. - /// - internal static string SelectionVariants_ReadOnly { + internal static string ThrowHelper_CollectVariablesVisitor_NoCompatibleType_Message { get { - return ResourceManager.GetString("SelectionVariants_ReadOnly", resourceCulture); + return ResourceManager.GetString("ThrowHelper_CollectVariablesVisitor_NoCompatibleType_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified type `{0}` is not a possible type to this selection set.. - /// - internal static string SelectionVariants_TypeContextInvalid { + internal static string ThrowHelper_FieldVisibility_ValueNotSupported_Message { get { - return ResourceManager.GetString("SelectionVariants_TypeContextInvalid", resourceCulture); + return ResourceManager.GetString("ThrowHelper_FieldVisibility_ValueNotSupported_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Could not serialize the specified variable `{0}`.. - /// - internal static string ThrowHelper_BatchExecutor_CannotSerializeVariable_Message { + internal static string ThrowHelper_QueryCompiler_CompositeTypeSelectionSet_Message { get { - return ResourceManager.GetString("ThrowHelper_BatchExecutor_CannotSerializeVariable_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_QueryCompiler_CompositeTypeSelectionSet_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Unable to find a compatible input type for the exported object type.. - /// - internal static string ThrowHelper_CollectVariablesVisitor_NoCompatibleType_Message { + internal static string ThrowHelper_OperationExecutionMiddleware_NoBatchDispatcher_Message { get { - return ResourceManager.GetString("ThrowHelper_CollectVariablesVisitor_NoCompatibleType_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_OperationExecutionMiddleware_NoBatchDispatcher_Message", resourceCulture); } } - /// - /// Looks up a localized string similar to Field `{0}` does not exist on type `{1}`.. - /// - internal static string ThrowHelper_FieldDoesNotExistOnType { + internal static string OperationCompiler_Compile_SelectionSetIsEmpty { get { - return ResourceManager.GetString("ThrowHelper_FieldDoesNotExistOnType", resourceCulture); + return ResourceManager.GetString("OperationCompiler_Compile_SelectionSetIsEmpty", resourceCulture); } } - /// - /// Looks up a localized string similar to The skip/include if-argument value has to be a 'Boolean'.. - /// - internal static string ThrowHelper_FieldVisibility_ValueNotSupported_Message { + internal static string ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty { get { - return ResourceManager.GetString("ThrowHelper_FieldVisibility_ValueNotSupported_Message", resourceCulture); + return ResourceManager.GetString("ExecutionRequestExecutorExtensions_ExecuteAsync_QueryCannotBeNullOrEmpty", resourceCulture); } } - /// - /// Looks up a localized string similar to The {0} only supports formatting `IQueryResult`.. - /// - internal static string ThrowHelper_JsonFormatter_ResultNotSupported { + internal static string RequestExecutorBuilder_Convention_NotSupported { get { - return ResourceManager.GetString("ThrowHelper_JsonFormatter_ResultNotSupported", resourceCulture); + return ResourceManager.GetString("RequestExecutorBuilder_Convention_NotSupported", resourceCulture); } } - /// - /// Looks up a localized string similar to Variable `{0}` is required.. - /// - internal static string ThrowHelper_NonNullVariableIsNull_Message { + internal static string RootValueResolver_Resolve_CannotCreateInstance { get { - return ResourceManager.GetString("ThrowHelper_NonNullVariableIsNull_Message", resourceCulture); + return ResourceManager.GetString("RootValueResolver_Resolve_CannotCreateInstance", resourceCulture); } } - /// - /// Looks up a localized string similar to Value for OneOf field {0} must be non-null.. - /// - internal static string ThrowHelper_OneOfFieldMustBeNonNull { + internal static string OperationContext_GetQueryRoot_InvalidCast { get { - return ResourceManager.GetString("ThrowHelper_OneOfFieldMustBeNonNull", resourceCulture); + return ResourceManager.GetString("OperationContext_GetQueryRoot_InvalidCast", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified selection does not have a selection set.. - /// - internal static string ThrowHelper_Operation_NoSelectionSet { + internal static string ErrorHelper_RequestTimeout { get { - return ResourceManager.GetString("ThrowHelper_Operation_NoSelectionSet", resourceCulture); + return ResourceManager.GetString("ErrorHelper_RequestTimeout", resourceCulture); } } - /// - /// Looks up a localized string similar to Make sure that you have registered an IBatchDispatcher with your scoped request services.. - /// - internal static string ThrowHelper_OperationExecutionMiddleware_NoBatchDispatcher_Message { + internal static string ResultHelper_BuildResult_InvalidResult { get { - return ResourceManager.GetString("ThrowHelper_OperationExecutionMiddleware_NoBatchDispatcher_Message", resourceCulture); + return ResourceManager.GetString("ResultHelper_BuildResult_InvalidResult", resourceCulture); } } - /// - /// Looks up a localized string similar to The specified operation `{0}` cannot be found.. - /// - internal static string ThrowHelper_OperationResolverHelper_InvalidOperationName_Message { + internal static string BatchExecutionTask_AddExecutionTask_SerialTasksNotAllowed { get { - return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_InvalidOperationName_Message", resourceCulture); + return ResourceManager.GetString("BatchExecutionTask_AddExecutionTask_SerialTasksNotAllowed", resourceCulture); } } - /// - /// Looks up a localized string similar to The operation name can only be omitted if there is just one operation in a GraphQL document.. - /// - internal static string ThrowHelper_OperationResolverHelper_MultipleOperation_Message { + internal static string QueryPlan_InvalidFragmentId { get { - return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_MultipleOperation_Message", resourceCulture); + return ResourceManager.GetString("QueryPlan_InvalidFragmentId", resourceCulture); } } - /// - /// Looks up a localized string similar to There are no operations in the GraphQL document.. - /// - internal static string ThrowHelper_OperationResolverHelper_NoOperationFound_Message { + internal static string WorkBacklog_NotFullyInitialized { get { - return ResourceManager.GetString("ThrowHelper_OperationResolverHelper_NoOperationFound_Message", resourceCulture); + return ResourceManager.GetString("WorkBacklog_NotFullyInitialized", resourceCulture); } } - /// - /// Looks up a localized string similar to A composite type always needs to specify a selection set.. - /// - internal static string ThrowHelper_QueryCompiler_CompositeTypeSelectionSet_Message { + internal static string ThrowHelper_ResolverContext_CannotCastParent { get { - return ResourceManager.GetString("ThrowHelper_QueryCompiler_CompositeTypeSelectionSet_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_ResolverContext_CannotCastParent", resourceCulture); } } - /// - /// Looks up a localized string similar to There was no argument with the name `{0}` found on the field `{1}`.. - /// - internal static string ThrowHelper_ResolverContext_ArgumentDoesNotExist_Message { + internal static string ExecutionResultExtensions_OnlyQueryResults { get { - return ResourceManager.GetString("ThrowHelper_ResolverContext_ArgumentDoesNotExist_Message", resourceCulture); + return ResourceManager.GetString("ExecutionResultExtensions_OnlyQueryResults", resourceCulture); } } - /// - /// Looks up a localized string similar to The resolver parent type of field `{0}` is `{1}` but the resolver requested the type `{2}`. The resolver was unable to cast the parent type to the requested type.. - /// - internal static string ThrowHelper_ResolverContext_CannotCastParent { + internal static string SelectionVariants_ReadOnly { get { - return ResourceManager.GetString("ThrowHelper_ResolverContext_CannotCastParent", resourceCulture); + return ResourceManager.GetString("SelectionVariants_ReadOnly", resourceCulture); } } - /// - /// Looks up a localized string similar to Unable to convert the value of the argument `{0}` to `{1}`. Check if the requested type is correct or register a custom type converter.. - /// - internal static string ThrowHelper_ResolverContext_CannotConvertArgument_Message { + internal static string OperationCompiler_FragmentNotFound { get { - return ResourceManager.GetString("ThrowHelper_ResolverContext_CannotConvertArgument_Message", resourceCulture); + return ResourceManager.GetString("OperationCompiler_FragmentNotFound", resourceCulture); } } - /// - /// Looks up a localized string similar to The argument literal representation is `{0}` which is not compatible with the request literal type `{1}`.. - /// - internal static string ThrowHelper_ResolverContext_LiteralNotCompatible_Message { + internal static string SelectionSetOptimizerContext_InvalidFieldName { get { - return ResourceManager.GetString("ThrowHelper_ResolverContext_LiteralNotCompatible_Message", resourceCulture); + return ResourceManager.GetString("SelectionSetOptimizerContext_InvalidFieldName", resourceCulture); } } - /// - /// Looks up a localized string similar to The ArgumentValue method on the resolver context only allows for runtime values. If you want to retrieve the argument value as GraphQL literal use the ArgumentLiteral method instead.. - /// - internal static string ThrowHelper_ResolverContext_LiteralsNotSupported_Message { + internal static string OperationCompiler_ToManyIncludeConditions { get { - return ResourceManager.GetString("ThrowHelper_ResolverContext_LiteralsNotSupported_Message", resourceCulture); + return ResourceManager.GetString("OperationCompiler_ToManyIncludeConditions", resourceCulture); } } - /// - /// Looks up a localized string similar to The root type `{0}` is not supported.. - /// - internal static string ThrowHelper_RootTypeNotSupported_Message { + internal static string SelectionVariants_TypeContextInvalid { get { - return ResourceManager.GetString("ThrowHelper_RootTypeNotSupported_Message", resourceCulture); + return ResourceManager.GetString("SelectionVariants_TypeContextInvalid", resourceCulture); } } - /// - /// Looks up a localized string similar to The type {0} was already added.. - /// internal static string ThrowHelper_SelectionSet_TypeAlreadyAdded { get { return ResourceManager.GetString("ThrowHelper_SelectionSet_TypeAlreadyAdded", resourceCulture); } } - /// - /// Looks up a localized string similar to The request context is in an invalid state for subscriptions.. - /// - internal static string ThrowHelper_SubscriptionExecutor_ContextInvalidState_Message { + internal static string ThrowHelper_OneOfFieldMustBeNonNull { get { - return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_ContextInvalidState_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_OneOfFieldMustBeNonNull", resourceCulture); } } - /// - /// Looks up a localized string similar to You must declare a subscribe resolver for subscription fields.. - /// - internal static string ThrowHelper_SubscriptionExecutor_NoSubscribeResolver_Message { + internal static string ThrowHelper_Operation_NoSelectionSet { get { - return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_NoSubscribeResolver_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_Operation_NoSelectionSet", resourceCulture); } } - /// - /// Looks up a localized string similar to Subscription queries must have exactly one root field.. - /// - internal static string ThrowHelper_SubscriptionExecutor_SubscriptionsMustHaveOneField_Message { + internal static string ThrowHelper_JsonFormatter_ResultNotSupported { get { - return ResourceManager.GetString("ThrowHelper_SubscriptionExecutor_SubscriptionsMustHaveOneField_Message", resourceCulture); + return ResourceManager.GetString("ThrowHelper_JsonFormatter_ResultNotSupported", resourceCulture); } } - /// - /// Looks up a localized string similar to Variable `{0}` is not an input type.. - /// - internal static string ThrowHelper_VariableIsNotAnInputType_Message { + internal static string ResultBuilder_DataAndItemsNotAllowed { get { - return ResourceManager.GetString("ThrowHelper_VariableIsNotAnInputType_Message", resourceCulture); + return ResourceManager.GetString("ResultBuilder_DataAndItemsNotAllowed", resourceCulture); } } - /// - /// Looks up a localized string similar to The variable with the name `{0}` does not exist.. - /// - internal static string ThrowHelper_VariableNotFound_Message { + internal static string MiddlewareContext_ReplaceArgument_InvalidKey { get { - return ResourceManager.GetString("ThrowHelper_VariableNotFound_Message", resourceCulture); + return ResourceManager.GetString("MiddlewareContext_ReplaceArgument_InvalidKey", resourceCulture); } } - /// - /// Looks up a localized string similar to The variable with the name `{0}` is not of the requested type `{1}`.. - /// - internal static string ThrowHelper_VariableNotOfType_Message { + internal static string VariableValueOrLiteral_NullNotAllowed { get { - return ResourceManager.GetString("ThrowHelper_VariableNotOfType_Message", resourceCulture); + return ResourceManager.GetString("VariableValueOrLiteral_NullNotAllowed", resourceCulture); } } - /// - /// Looks up a localized string similar to Variable `{0}` got an invalid value.. - /// - internal static string ThrowHelper_VariableValueInvalidType_Message { + internal static string Operation_GetPossibleTypes_NoSelectionSet { get { - return ResourceManager.GetString("ThrowHelper_VariableValueInvalidType_Message", resourceCulture); + return ResourceManager.GetString("Operation_GetPossibleTypes_NoSelectionSet", resourceCulture); } } - /// - /// Looks up a localized string similar to The runtime value can only be null if the literal is also null.. - /// - internal static string VariableValueOrLiteral_NullNotAllowed { + internal static string MiddlewareContext_ReplaceArguments_NullNotAllowed { get { - return ResourceManager.GetString("VariableValueOrLiteral_NullNotAllowed", resourceCulture); + return ResourceManager.GetString("MiddlewareContext_ReplaceArguments_NullNotAllowed", resourceCulture); } } - /// - /// Looks up a localized string similar to The WorkBacklog is not fully initialized.. - /// - internal static string WorkBacklog_NotFullyInitialized { + internal static string SelectionSetOptimizerContext_AddSelection_ResponseNameNotTheSame { get { - return ResourceManager.GetString("WorkBacklog_NotFullyInitialized", resourceCulture); + return ResourceManager.GetString("SelectionSetOptimizerContext_AddSelection_ResponseNameNotTheSame", resourceCulture); } } } diff --git a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs index 8d3a58a703d..a4eaa83a427 100644 --- a/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs +++ b/src/HotChocolate/Core/src/Types/Types/Descriptors/Conventions/DescriptorContext.cs @@ -267,26 +267,26 @@ private TypeDiscoveryHandler[] CreateTypeDiscoveryHandlers() internal static DescriptorContext Create( IReadOnlySchemaOptions? options = null, - IServiceProvider? services = null, + IServiceProvider? schemaServices = null, IFeatureCollection? features = null, SchemaBuilder.LazySchema? schema = null, TypeInterceptor? typeInterceptor = null) => new DescriptorContext( () => options ??= new SchemaOptions(), - services ?? EmptyServiceProvider.Instance, + schemaServices ?? EmptyServiceProvider.Instance, features ?? new FeatureCollection(), schema ?? new SchemaBuilder.LazySchema(), typeInterceptor ?? new AggregateTypeInterceptor()); internal static DescriptorContext Create( Func options, - IServiceProvider services, + IServiceProvider schemaServices, IFeatureCollection? features = null, SchemaBuilder.LazySchema? schema = null, TypeInterceptor? typeInterceptor = null) => new DescriptorContext( options, - services, + schemaServices, features ?? new FeatureCollection(), schema ?? new SchemaBuilder.LazySchema(), typeInterceptor ?? new AggregateTypeInterceptor()); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs index 45e2670f7ce..091741d21e4 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutorManager.cs @@ -560,7 +560,7 @@ private sealed class SchemaDefinitionAccessor public FusionSchemaDefinition Schema { get; set; } = null!; } - public sealed class RequestExecutorRegistration : IAsyncDisposable + private sealed class RequestExecutorRegistration : IAsyncDisposable { private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly CancellationToken _cancellationToken; From 1b44d4591dd370b4ac4fcff484268f6739fe101b Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 5 Dec 2025 19:20:19 +0100 Subject: [PATCH 27/42] wip --- .../Pipeline/OperationResolverMiddleware.cs | 8 +- .../Processing/MiddlewareContext.Global.cs | 17 +-- .../Execution/Processing/OperationCompiler.cs | 26 ++-- .../Extensions/ResolverContextExtensions.cs | 16 +- ...cMethod_Await_Return_ApplicationError.json | 6 - ...ncMethod_Await_Throw_ApplicationError.json | 6 - ...yncMethod_Await_Throw_UnexpectedError.json | 6 - ...ethod_NoAwait_Return_ApplicationError.json | 6 - ...Method_NoAwait_Throw_ApplicationError.json | 6 - ...cMethod_NoAwait_Throw_UnexpectedError.json | 6 - ...haviorTests.Error_Filter_Adds_Details.json | 6 - ...viorTests.Error_On_NonNull_Root_Field.json | 6 - ...ests.Property_Return_ApplicationError.json | 6 - ...Tests.Property_Throw_ApplicationError.json | 6 - ...rTests.Property_Throw_UnexpectedError.json | 6 - ...ts.SyncMethod_Return_ApplicationError.json | 6 - ...sts.SyncMethod_Throw_ApplicationError.json | 6 - ...ests.SyncMethod_Throw_UnexpectedError.json | 6 - ...ErrorHandlerTests.AddClassErrorFilter.json | 6 - ...ViaServiceExtensions_ErrorFilterWorks.json | 6 - ...ViaServiceExtensions_ErrorFilterWorks.json | 6 - ...rTests.AddClassErrorFilterWithFactory.json | 6 - ...ViaServiceExtensions_ErrorFilterWorks.json | 6 - .../ErrorHandlerTests.AddFuncErrorFilter.json | 6 - ...dlerTests.FilterOnlyNullRefExceptions.json | 12 -- ...ests.ReportAggregateError_In_Resolver.json | 12 -- ...ests.UseAggregateError_In_ErrorFilter.json | 12 -- ...HasError_nonnull_list_nonnull_element.json | 6 - ...asError_nonnull_list_nullable_element.json | 6 - ...asError_nullable_list_nonnull_element.json | 6 - ...sError_nullable_list_nullable_element.json | 6 - ...ntIsNull_nonnull_list_nonnull_element.json | 6 - ...tIsNull_nonnull_list_nullable_element.json | 6 - ...tIsNull_nullable_list_nonnull_element.json | 6 - ...IsNull_nullable_list_nullable_element.json | 6 - ...t_NonNullElementHasError_nonnull_prop.json | 6 - ..._NonNullElementHasError_nullable_prop.json | 6 - ...ect_NonNullElementIsNull_nonnull_prop.json | 6 - ...ct_NonNullElementIsNull_nullable_prop.json | 6 - ...ld_ThrowException_When_NotADataLoader.snap | 2 +- ..._To_NonNullArgument_With_DefaultValue.snap | 8 +- .../StarWarsCodeFirstTests.cs | 66 ++++---- .../Processing/OperationCompilerTests.cs | 144 ++++-------------- ...iables_Fails_When_Variable_Not_Exists.snap | 6 - ...s_Delegate_ReplaceWithNull_ShouldFail.snap | 6 - ...sure_Errors_Do_Not_Result_In_Timeouts.snap | 8 +- ...OutputType_ClrValue_CannotBeConverted.snap | 8 +- ...ts.OutputType_ClrValue_CannotBeParsed.snap | 6 - ...t_Item_Returns_Null_Should_Error_Item.snap | 6 - ...m_Throwing_Should_Null_And_Error_Item.snap | 12 -- ...Object_List_Returns_Null_Should_Error.snap | 6 - ..._List_Throwing_Should_Null_FAnd_Error.snap | 6 - ...sync_Object_Returns_Null_Should_Error.snap | 6 - ...Object_Throwing_Should_Null_And_Error.snap | 6 - ...t_Item_Returns_Null_Should_Error_Item.snap | 6 - ...m_Throwing_Should_Null_And_Error_Item.snap | 12 -- ...Scalar_List_Returns_Null_Should_Error.snap | 6 - ...r_List_Throwing_Should_Null_And_Error.snap | 6 - ...sync_Scalar_Returns_Null_Should_Error.snap | 6 - ...Scalar_Throwing_Should_Null_And_Error.snap | 6 - ...t_Item_Returns_Null_Should_Error_Item.snap | 6 - ...m_Throwing_Should_Null_And_Error_Item.snap | 12 -- ...Object_List_Returns_Null_Should_Error.snap | 6 - ..._List_Throwing_Should_Null_FAnd_Error.snap | 6 - ...Pure_Object_Returns_Null_Should_Error.snap | 6 - ...Object_Throwing_Should_Null_And_Error.snap | 6 - ...ner_Return_Null_Should_Null_And_Error.snap | 12 -- ...le_Returns_Null_Should_Null_And_Error.snap | 6 - ...t_Item_Returns_Null_Should_Error_Item.snap | 6 - ...m_Throwing_Should_Null_And_Error_Item.snap | 12 -- ...Scalar_List_Returns_Null_Should_Error.snap | 6 - ...r_List_Throwing_Should_Null_And_Error.snap | 6 - ...Pure_Scalar_Returns_Null_Should_Error.snap | 6 - ...Scalar_Throwing_Should_Null_And_Error.snap | 6 - ...ticNonNullTests.Query_With_Connection.snap | 6 - ...SchemaBuilderExtensions.Resolvers.Tests.cs | 10 +- .../Descriptors/ArgumentDescriptorTests.cs | 2 +- .../DirectiveArgumentDescriptorTests.cs | 2 +- .../Descriptors/InputFieldDescriptorTests.cs | 2 +- .../InterfaceFieldDescriptorTests.cs | 2 +- .../Descriptors/ObjectFieldDescriptorTests.cs | 2 +- .../Types.Tests/Types/DirectiveTypeTests.cs | 2 +- .../Types.Tests/Types/InputObjectTypeTests.cs | 6 +- .../Types.Tests/Types/InterfaceTypeTests.cs | 2 +- .../test/Types.Tests/Types/ObjectTypeTests.cs | 2 +- .../Execution/Nodes/OperationCompiler.cs | 2 +- 86 files changed, 116 insertions(+), 659 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs index 0a301750db7..d67c0373e4d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationResolverMiddleware.cs @@ -1,6 +1,5 @@ using HotChocolate.Execution.Instrumentation; using HotChocolate.Execution.Processing; -using HotChocolate.Fusion.Rewriters; using static HotChocolate.Execution.ErrorHelper; namespace HotChocolate.Execution.Pipeline; @@ -40,14 +39,11 @@ public async ValueTask InvokeAsync(RequestContext context) { using (_diagnosticEvents.CompileOperation(context)) { - var operationName = context.Request.OperationName; - var operationDocument = documentInfo.Document; - var operationNode = operationDocument.GetOperation(operationName); - operation = _operationPlanner.Compile( operationId ?? Guid.NewGuid().ToString("N"), documentInfo.Hash.Value, - operationNode); + context.Request.OperationName, + documentInfo.Document); context.SetOperation(operation); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs index d1ba41b2545..e6dbd0f01c9 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs @@ -49,7 +49,6 @@ public void ReportError(string errorMessage) ErrorBuilder.New() .SetMessage(errorMessage) .SetPath(Path) - .AddLocations(_selection) .Build()); } @@ -75,8 +74,7 @@ public void ReportError(Exception exception, Action? configure = n { var errorBuilder = ErrorBuilder .FromException(exception) - .SetPath(Path) - .AddLocations(_selection); + .SetPath(Path); configure?.Invoke(errorBuilder); @@ -291,16 +289,3 @@ c is null s))); } } - -file static class Extensions -{ - public static ErrorBuilder AddLocations(this ErrorBuilder errorBuilder, Selection selection) - { - foreach (var (node, _) in selection.SyntaxNodes) - { - errorBuilder.AddLocation(node); - } - - return errorBuilder; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index e417997b6ae..5448655c3ae 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -36,14 +36,22 @@ internal OperationCompiler( public static Operation Compile( string id, - OperationDefinitionNode operationDefinition, + DocumentNode document, Schema schema) - => Compile(id, id, operationDefinition, schema); + => Compile(id, id, null, document, schema); + + public static Operation Compile( + string id, + string? operationName, + DocumentNode document, + Schema schema) + => Compile(id, id, operationName, document, schema); public static Operation Compile( string id, string hash, - OperationDefinitionNode operationDefinition, + string? operationName, + DocumentNode document, Schema schema) => new OperationCompiler( schema, @@ -51,20 +59,20 @@ public static Operation Compile( new DefaultObjectPool>>( new DefaultPooledObjectPolicy>>()), new OperationCompilerOptimizers()) - .Compile(id, hash, operationDefinition); + .Compile(id, hash, operationName, document); public Operation Compile( string id, string hash, - OperationDefinitionNode operationDefinition) + string? operationName, + DocumentNode document) { ArgumentException.ThrowIfNullOrWhiteSpace(id); - ArgumentNullException.ThrowIfNull(operationDefinition); + ArgumentNullException.ThrowIfNull(document); // Before we can plan an operation, we must de-fragmentize it and remove static include conditions. - var document = new DocumentNode([operationDefinition]); document = _documentRewriter.RewriteDocument(document); - operationDefinition = (OperationDefinitionNode)document.Definitions[0]; + var operationDefinition = document.GetOperation(operationName); var includeConditions = new IncludeConditionCollection(); IncludeConditionVisitor.Instance.Visit(operationDefinition, includeConditions); @@ -319,7 +327,7 @@ private SelectionSet BuildSelectionSet( compilationContext.Register(selection, selection.Id); selections[i++] = selection; - if (includeFlags.Count > 1) + if (includeFlags.Count > 0) { isConditional = true; } diff --git a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs index 9a886885497..2865bfed608 100644 --- a/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Extensions/ResolverContextExtensions.cs @@ -438,7 +438,7 @@ public bool IsSelected(string fieldName) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsIncluded(includeFlags) && selection.Field.Name.Equals(fieldName)) @@ -453,7 +453,7 @@ public bool IsSelected(string fieldName) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsIncluded(includeFlags) && selection.Field.Name.Equals(fieldName)) @@ -501,7 +501,7 @@ public bool IsSelected(string fieldName1, string fieldName2) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsSkipped(includeFlags)) { @@ -520,7 +520,7 @@ public bool IsSelected(string fieldName1, string fieldName2) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsSkipped(includeFlags)) { @@ -577,7 +577,7 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsSkipped(includeFlags)) { @@ -598,7 +598,7 @@ public bool IsSelected(string fieldName1, string fieldName2, string fieldName3) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsSkipped(includeFlags)) { @@ -647,7 +647,7 @@ public bool IsSelected(ISet fieldNames) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, possibleType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsIncluded(includeFlags) && fieldNames.Contains(selection.Field.Name)) @@ -662,7 +662,7 @@ public bool IsSelected(ISet fieldNames) var includeFlags = context.IncludeFlags; var selectionSet = context.Operation.GetSelectionSet(context.Selection, (ObjectType)namedType); - foreach(var selection in selectionSet.Selections) + foreach (var selection in selectionSet.Selections) { if (selection.IsIncluded(includeFlags) && fieldNames.Contains(selection.Field.Name)) diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Return_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Return_ApplicationError.json index b850c73db2b..6b78593e0be 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Return_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Return_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 6", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error6" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_ApplicationError.json index 7b000a4d97e..789fcde3231 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 4", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error4" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_UnexpectedError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_UnexpectedError.json index afbf6e89d41..4c878b126c4 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_UnexpectedError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_Await_Throw_UnexpectedError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error5" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Return_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Return_ApplicationError.json index fdefe0720fc..7bfbbfb8e89 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Return_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Return_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 3", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error3" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_ApplicationError.json index 4e2e87ae3a4..0d87efd2255 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 1", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error1" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_UnexpectedError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_UnexpectedError.json index d664a0c23c0..3fc814a785f 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_UnexpectedError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.AsyncMethod_NoAwait_Throw_UnexpectedError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error2" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_Filter_Adds_Details.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_Filter_Adds_Details.json index 1c8564fb675..a23da695a95 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_Filter_Adds_Details.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_Filter_Adds_Details.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error14" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_On_NonNull_Root_Field.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_On_NonNull_Root_Field.json index 0e2677a1dae..c556743fc23 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_On_NonNull_Root_Field.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Error_On_NonNull_Root_Field.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error15" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Return_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Return_ApplicationError.json index 1e0b49ac42f..96fe813df42 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Return_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Return_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 12", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error12" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_ApplicationError.json index 75de3a1df02..37bb2829107 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 10", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error10" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_UnexpectedError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_UnexpectedError.json index 97b6b55fea8..7d17b7ccf14 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_UnexpectedError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.Property_Throw_UnexpectedError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error11" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Return_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Return_ApplicationError.json index 19eb7bc4683..651f04b8fe5 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Return_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Return_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 9", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error9" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_ApplicationError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_ApplicationError.json index 33700a3ac45..976e35bf402 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_ApplicationError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_ApplicationError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "query error 7", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error7" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_UnexpectedError.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_UnexpectedError.json index c80eaa0aa71..c0c6aa99577 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_UnexpectedError.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorBehaviorTests.SyncMethod_Throw_UnexpectedError.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "error8" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter.json index ef697553c2f..4b69180ef2e 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingDI_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingDI_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json index 20e2cfaaf20..9a8d330d490 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingDI_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingDI_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingFactory_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingFactory_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json index 20e2cfaaf20..9a8d330d490 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingFactory_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterUsingFactory_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterWithFactory.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterWithFactory.json index ef697553c2f..4b69180ef2e 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterWithFactory.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilterWithFactory.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json index 20e2cfaaf20..9a8d330d490 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddClassErrorFilter_SchemaBuiltViaServiceExtensions_ErrorFilterWorks.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddFuncErrorFilter.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddFuncErrorFilter.json index ef697553c2f..4b69180ef2e 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddFuncErrorFilter.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.AddFuncErrorFilter.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.FilterOnlyNullRefExceptions.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.FilterOnlyNullRefExceptions.json index 8e67f4315f2..4cfef53f3ea 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.FilterOnlyNullRefExceptions.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.FilterOnlyNullRefExceptions.json @@ -2,24 +2,12 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ] }, { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 7 - } - ], "path": [ "bar" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.ReportAggregateError_In_Resolver.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.ReportAggregateError_In_Resolver.json index 8bce9986d95..07034838f59 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.ReportAggregateError_In_Resolver.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.ReportAggregateError_In_Resolver.json @@ -2,24 +2,12 @@ "errors": [ { "message": "abc", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ] }, { "message": "def", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.UseAggregateError_In_ErrorFilter.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.UseAggregateError_In_ErrorFilter.json index 550bc931dd5..a0f0b7e4f95 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.UseAggregateError_In_ErrorFilter.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/ErrorHandlerTests.UseAggregateError_In_ErrorFilter.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], @@ -17,12 +11,6 @@ }, { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nonnull_element.json index 40a93880bd1..d12e8f2d757 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nonnull_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nonnull_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 40 - } - ], "path": [ "foo", "nonnull_list_nonnull_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nullable_element.json index 31644d0b788..af36a82c07b 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nullable_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nonnull_list_nullable_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 41 - } - ], "path": [ "foo", "nonnull_list_nullable_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nonnull_element.json index 2329e540d0f..265459aee68 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nonnull_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nonnull_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 41 - } - ], "path": [ "foo", "nullable_list_nonnull_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nullable_element.json index 9575ba78887..3a8291a85f3 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nullable_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementHasError_nullable_list_nullable_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 42 - } - ], "path": [ "foo", "nullable_list_nullable_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nonnull_element.json index 431b16bef0c..353787c469a 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nonnull_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nonnull_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 40 - } - ], "path": [ "foo", "nonnull_list_nonnull_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nullable_element.json index 6befba572a7..c2a87772b88 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nullable_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nonnull_list_nullable_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 41 - } - ], "path": [ "foo", "nonnull_list_nullable_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nonnull_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nonnull_element.json index cb65fd9194d..12fd757bf13 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nonnull_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nonnull_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 41 - } - ], "path": [ "foo", "nullable_list_nonnull_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nullable_element.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nullable_element.json index 1cb53765ff2..82339e96531 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nullable_element.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.List_NonNullElementIsNull_nullable_list_nullable_element.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 42 - } - ], "path": [ "foo", "nullable_list_nullable_element", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nonnull_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nonnull_prop.json index 40d979abf24..2de6c622f64 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nonnull_prop.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nonnull_prop.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 24 - } - ], "path": [ "foo", "nonnull_prop", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nullable_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nullable_prop.json index ee6b4a00fa1..fca3c8ee191 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nullable_prop.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementHasError_nullable_prop.json @@ -2,12 +2,6 @@ "errors": [ { "message": "ERROR", - "locations": [ - { - "line": 1, - "column": 25 - } - ], "path": [ "foo", "nullable_prop", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nonnull_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nonnull_prop.json index add4b91ff56..1a5bb81281e 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nonnull_prop.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nonnull_prop.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 24 - } - ], "path": [ "foo", "nonnull_prop", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nullable_prop.json b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nullable_prop.json index 77c93273c7d..ec5ad8f3cb9 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nullable_prop.json +++ b/src/HotChocolate/Core/test/Execution.Tests/Errors/__snapshots__/NullErrorPropagationTests.Object_NonNullElementIsNull_nullable_prop.json @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 25 - } - ], "path": [ "foo", "nullable_prop", diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/__snapshots__/UseDataLoaderTests.UseDataLoader_Should_ThrowException_When_NotADataLoader.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/__snapshots__/UseDataLoaderTests.UseDataLoader_Should_ThrowException_When_NotADataLoader.snap index f8943c78f19..31655be4474 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/__snapshots__/UseDataLoaderTests.UseDataLoader_Should_ThrowException_When_NotADataLoader.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/__snapshots__/UseDataLoaderTests.UseDataLoader_Should_ThrowException_When_NotADataLoader.snap @@ -2,7 +2,7 @@ For more details look at the `Errors` property. 1. For more details look at the `Errors` property. -1. The provided type HotChocolate.Execution.Integration.DataLoader.UseDataLoaderTests+Foo is not a dataloader +1. The provided type HotChocolate.Execution.Integration.DataLoader.UseDataLoaderTests+Foo is not a DataLoader. (HotChocolate.Types.ObjectType) at HotChocolate.Types.DataLoaderObjectFieldExtensions.UseDataLoader(IObjectFieldDescriptor descriptor, Type dataLoaderType) in ObjectFieldDataLoaderExtensions.cs:line 28 diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap index 55c5694d490..de63f0ffdb4 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "Detected a non-null violation in argument `name`.", - "locations": [ - { - "line": 1, - "column": 12 - } - ], "path": [ "sayHello" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs index ff4017a85bf..431abffa852 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs @@ -110,24 +110,26 @@ await ExpectValid( public async Task GraphQLOrgFragmentExample() { await ExpectValid( - @"{ - leftComparison: hero(episode: EMPIRE) { - ...comparisonFields - } - rightComparison: hero(episode: JEDI) { - ...comparisonFields + """ + { + leftComparison: hero(episode: EMPIRE) { + ...comparisonFields + } + rightComparison: hero(episode: JEDI) { + ...comparisonFields + } } - } - fragment comparisonFields on Character { - name - appearsIn - friends { - nodes { - name + fragment comparisonFields on Character { + name + appearsIn + friends { + nodes { + name + } } } - }") + """) .MatchSnapshotAsync(); } @@ -191,23 +193,24 @@ query HeroNameAndFriends($episode: Episode = JEDI) { public async Task GraphQLOrgDirectiveIncludeExample1() { await ExpectValid( - @" - query Hero($episode: Episode, $withFriends: Boolean!) { - hero(episode: $episode) { - name - friends @include(if: $withFriends) { - nodes { - name - } + """ + query Hero($episode: Episode, $withFriends: Boolean!) { + hero(episode: $episode) { + name + friends @include(if: $withFriends) { + nodes { + name } } - }", - request: c => c.SetVariableValues( - new Dictionary - { - { "episode", new EnumValueNode("JEDI") }, - { "withFriends", new BooleanValueNode(false) } - })) + } + } + """, + request: c => c.SetVariableValues( + new Dictionary + { + { "episode", new EnumValueNode("JEDI") }, + { "withFriends", new BooleanValueNode(false) } + })) .MatchSnapshotAsync(); } @@ -263,7 +266,7 @@ friends @skip(if: $withFriends) { public async Task GraphQLOrgDirectiveSkipExample2() { await ExpectValid( - @" + """ query Hero($episode: Episode, $withFriends: Boolean!) { hero(episode: $episode) { name @@ -273,7 +276,8 @@ friends @skip(if: $withFriends) { } } } - }", + } + """, request: r => r.SetVariableValues( new Dictionary { diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs index 09311f012ba..103dee2fb3c 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs @@ -24,12 +24,10 @@ public void Prepare_One_Field() var document = Utf8GraphQLParser.Parse("{ foo }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -51,13 +49,10 @@ public void Prepare_Duplicate_Field() var document = Utf8GraphQLParser.Parse("{ foo foo }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -79,13 +74,10 @@ public void Prepare_Empty_Operation_SelectionSet() var document = Utf8GraphQLParser.Parse("{ }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -113,13 +105,10 @@ ... on Human { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -152,13 +141,10 @@ fragment def on Human { } "); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -218,13 +204,10 @@ fragment Human3 on Human { } """); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -247,12 +230,10 @@ public void Prepare_Duplicate_Field_With_Skip() var document = Utf8GraphQLParser.Parse( "{ foo @skip(if: true) foo @skip(if: false) }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -274,15 +255,12 @@ public void Field_Does_Not_Exist() var document = Utf8GraphQLParser.Parse("{ foo bar }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act void Action() { OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); } @@ -312,13 +290,10 @@ fragment abc on Droid { name }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -345,12 +320,10 @@ fragment abc on Droid { name }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -377,12 +350,10 @@ fragment abc on Droid { name }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -412,13 +383,10 @@ fragment abc on Droid { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -456,13 +424,10 @@ ... @include(if: $v) { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -525,12 +490,10 @@ fragment Human3 on Human { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -562,13 +525,10 @@ ... @include(if: $v) { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -590,12 +550,10 @@ name @include(if: $q) } }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -626,12 +584,10 @@ public void Field_Based_Optimizers() } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -656,13 +612,10 @@ ... @defer { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -689,13 +642,10 @@ fragment Foo on Droid { id }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -722,13 +672,10 @@ friends @include(if: $withFriends) { } }"); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -753,12 +700,10 @@ ... abc fragment abc on Droid { }"); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -783,12 +728,10 @@ ... on Droid { } } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -810,12 +753,10 @@ query foo($v: Boolean) { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -835,13 +776,10 @@ public async Task Large_Query_Test() var document = Utf8GraphQLParser.Parse( FileResource.Open("LargeQuery.graphql")); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -862,13 +800,10 @@ public async Task Crypto_Details_Test() var document = Utf8GraphQLParser.Parse( FileResource.Open("CryptoDetailQuery.graphql")); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -904,12 +839,10 @@ fragment PriceInfo on Asset { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -945,12 +878,10 @@ fragment PriceInfo on Asset { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -987,12 +918,10 @@ fragment PriceInfo on Asset { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -1013,13 +942,10 @@ public async Task Crypto_List_Test() var document = Utf8GraphQLParser.Parse( FileResource.Open("CryptoQuery.graphql")); - var operationDefinition = - document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -1098,12 +1024,10 @@ type OrganizationUnit2 implements OrganizationUnit { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -1182,12 +1106,10 @@ type OrganizationUnit2 implements OrganizationUnit { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert @@ -1225,12 +1147,10 @@ fragment TypeTwoParts on TypeTwo { } """); - var operationDefinition = document.Definitions.OfType().Single(); - // act var operation = OperationCompiler.Compile( "opid", - operationDefinition, + document, schema); // assert diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.AccessVariables_Fails_When_Variable_Not_Exists.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.AccessVariables_Fails_When_Variable_Not_Exists.snap index 9c1f3b954d6..c96c7071efb 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.AccessVariables_Fails_When_Variable_Not_Exists.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.AccessVariables_Fails_When_Variable_Not_Exists.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The variable with the name `abc` does not exist.", - "locations": [ - { - "line": 1, - "column": 26 - } - ], "path": [ "foo" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.ReplaceArguments_Delegate_ReplaceWithNull_ShouldFail.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.ReplaceArguments_Delegate_ReplaceWithNull_ShouldFail.snap index c04812ef5e3..081fea4c8ec 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.ReplaceArguments_Delegate_ReplaceWithNull_ShouldFail.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/MiddlewareContextTests.ReplaceArguments_Delegate_ReplaceWithNull_ShouldFail.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "abc" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/RequestExecutorTests.Ensure_Errors_Do_Not_Result_In_Timeouts.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/RequestExecutorTests.Ensure_Errors_Do_Not_Result_In_Timeouts.snap index 92153eb8136..f9b707d7a51 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/RequestExecutorTests.Ensure_Errors_Do_Not_Result_In_Timeouts.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/RequestExecutorTests.Ensure_Errors_Do_Not_Result_In_Timeouts.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 4, - "column": 25 - } - ], "path": [ "test" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeConverted.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeConverted.snap index 80077d78462..f4c607274eb 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeConverted.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeConverted.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "Name cannot serialize the given value.", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "stringToName" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeParsed.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeParsed.snap index 8291e303e9b..0f73e3da82c 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeParsed.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/ScalarExecutionErrorTests.OutputType_ClrValue_CannotBeParsed.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Foo cannot serialize the given value.", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "stringToFoo" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Returns_Null_Should_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Returns_Null_Should_Error_Item.snap index cef5849184d..e64c9d4a214 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Returns_Null_Should_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Returns_Null_Should_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectListItemReturningNull", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap index c136aaacabf..d578768ba80 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Another error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectListItemThrowingError", 1 @@ -15,12 +9,6 @@ }, { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectListItemThrowingError", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Returns_Null_Should_Error.snap index 5272b1193ac..cd74246f7cc 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectListReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Throwing_Should_Null_FAnd_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Throwing_Should_Null_FAnd_Error.snap index 584bc579f4d..1a8e1b1447f 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Throwing_Should_Null_FAnd_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_List_Throwing_Should_Null_FAnd_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectListThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Returns_Null_Should_Error.snap index fa19729099c..de90deed3b8 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Throwing_Should_Null_And_Error.snap index de64fcf0f25..57ccb939ca0 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Object_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "objectThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Returns_Null_Should_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Returns_Null_Should_Error_Item.snap index 6e3b5178b29..f4a6d5a8478 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Returns_Null_Should_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Returns_Null_Should_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarListItemReturningNull", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap index 87f194c0037..464d5cdb295 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Another error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarListItemThrowingError", 1 @@ -15,12 +9,6 @@ }, { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarListItemThrowingError", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Returns_Null_Should_Error.snap index 136f20e321e..7c3567e8c3f 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarListReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Throwing_Should_Null_And_Error.snap index fe169a3cc33..a406ecdc3d9 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_List_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarListThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Returns_Null_Should_Error.snap index d6f046b374e..d12cef73fdc 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Throwing_Should_Null_And_Error.snap index f992ef3496b..ced147f1349 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Async_Scalar_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "scalarThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Returns_Null_Should_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Returns_Null_Should_Error_Item.snap index 20741ef4898..702c8496c8a 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Returns_Null_Should_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Returns_Null_Should_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectListItemReturningNull", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap index 338ea110d60..561c8238624 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Item_Throwing_Should_Null_And_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Another error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectListItemThrowingError", 1 @@ -15,12 +9,6 @@ }, { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectListItemThrowingError", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Returns_Null_Should_Error.snap index dd9c523f560..2262faed20a 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectListReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Throwing_Should_Null_FAnd_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Throwing_Should_Null_FAnd_Error.snap index 89587618619..42516bd3c4b 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Throwing_Should_Null_FAnd_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_List_Throwing_Should_Null_FAnd_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectListThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Returns_Null_Should_Error.snap index 81b0b6ca595..c15611a44a1 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Throwing_Should_Null_And_Error.snap index 76230f78282..63eeb3487ae 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Object_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureObjectThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Middle_Item_Outer_And_Inner_Return_Null_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Middle_Item_Outer_And_Inner_Return_Null_Should_Null_And_Error.snap index 7c42ba3a2a3..7bf76b7e4c0 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Middle_Item_Outer_And_Inner_Return_Null_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Middle_Item_Outer_And_Inner_Return_Null_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "nestedScalarArrayNullableMiddleItem", 0, @@ -19,12 +13,6 @@ }, { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "nestedScalarArrayNullableMiddleItem", 2, diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Outer_And_Inner_Middle_Returns_Null_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Outer_And_Inner_Middle_Returns_Null_Should_Null_And_Error.snap index 5b68ea3fafb..bf9a690b5f8 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Outer_And_Inner_Middle_Returns_Null_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_ListOfList_Nullable_Outer_And_Inner_Middle_Returns_Null_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "nestedScalarArrayNullableOuterItems", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Returns_Null_Should_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Returns_Null_Should_Error_Item.snap index f3a0b0bb1ca..ed0a4dd9a70 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Returns_Null_Should_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Returns_Null_Should_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarListItemReturningNull", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap index e5ecb022752..cdb53b6f7ff 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Item_Throwing_Should_Null_And_Error_Item.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Another error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarListItemThrowingError", 1 @@ -15,12 +9,6 @@ }, { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarListItemThrowingError", 1 diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Returns_Null_Should_Error.snap index e6c89302539..465984d2f34 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarListReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Throwing_Should_Null_And_Error.snap index 87eb04d1690..44c06c8d747 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_List_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarListThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Returns_Null_Should_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Returns_Null_Should_Error.snap index 4ddf157a011..d2e3122ede9 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Returns_Null_Should_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Returns_Null_Should_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Cannot return null for semantic non-null field.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarReturningNull" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Throwing_Should_Null_And_Error.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Throwing_Should_Null_And_Error.snap index a1980169f92..1cbac92d059 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Throwing_Should_Null_And_Error.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Pure_Scalar_Throwing_Should_Null_And_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "pureScalarThrowingError" ] diff --git a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Query_With_Connection.snap b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Query_With_Connection.snap index af087216eda..e0e253ee4af 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Query_With_Connection.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/__snapshots__/SemanticNonNullTests.Query_With_Connection.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 4, - "column": 7 - } - ], "path": [ "scalarConnection", "edges", diff --git a/src/HotChocolate/Core/test/Types.Tests/Extensions/SchemaBuilderExtensions.Resolvers.Tests.cs b/src/HotChocolate/Core/test/Types.Tests/Extensions/SchemaBuilderExtensions.Resolvers.Tests.cs index 3763da8f045..cc4c61b9e7f 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Extensions/SchemaBuilderExtensions.Resolvers.Tests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Extensions/SchemaBuilderExtensions.Resolvers.Tests.cs @@ -21,7 +21,7 @@ public void AddResolverContextObject_BuilderIsNull_ArgNullExcept() new Func(c => new object())); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -78,7 +78,7 @@ public void AddResolverContextTaskObject_BuilderIsNull_ArgNullExcept() c => Task.FromResult(new object()))); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -137,7 +137,7 @@ public void AddResolverContextTResult_BuilderIsNull_ArgNullExcept() c => "abc")); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -197,7 +197,7 @@ public void AddResolverContextTaskTResult_BuilderIsNull_ArgNullExcept() c => Task.FromResult("abc"))); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -256,7 +256,7 @@ public void AddResolverObject_BuilderIsNull_ArgNullExcept() new Func(() => "abc")); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs index ad52c19a3b4..7ad560d1e7f 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ArgumentDescriptorTests.cs @@ -254,6 +254,6 @@ public void Type_Syntax_Type_Null() public void Type_Syntax_Descriptor_Null() { void Error() => default(ArgumentDescriptor)!.Type("foo"); - Assert.Throws(Error); + Assert.Throws(Error); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/DirectiveArgumentDescriptorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/DirectiveArgumentDescriptorTests.cs index 0d2960e0a16..5a0c82a5207 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/DirectiveArgumentDescriptorTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/DirectiveArgumentDescriptorTests.cs @@ -16,7 +16,7 @@ public void Type_Syntax_Type_Null() public void Type_Syntax_Descriptor_Null() { void Error() => default(DirectiveArgumentDescriptor)!.Type("foo"); - Assert.Throws(Error); + Assert.Throws(Error); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs index 4f3a202a4c5..a8ae1bfe3a0 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InputFieldDescriptorTests.cs @@ -275,6 +275,6 @@ public void Type_Syntax_Type_Null() public void Type_Syntax_Descriptor_Null() { void Error() => default(InputFieldDescriptor)!.Type("foo"); - Assert.Throws(Error); + Assert.Throws(Error); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InterfaceFieldDescriptorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InterfaceFieldDescriptorTests.cs index 32fe4edbef0..15fdd5ba3b9 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InterfaceFieldDescriptorTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/InterfaceFieldDescriptorTests.cs @@ -15,6 +15,6 @@ public void Type_Syntax_Type_Null() public void Type_Syntax_Descriptor_Null() { void Error() => default(InterfaceFieldDescriptor)!.Type("foo"); - Assert.Throws(Error); + Assert.Throws(Error); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ObjectFieldDescriptorTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ObjectFieldDescriptorTests.cs index 60012d8f644..9bfdc1e5b6e 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ObjectFieldDescriptorTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Descriptors/ObjectFieldDescriptorTests.cs @@ -200,7 +200,7 @@ public void Type_Syntax_Type_Null() public void Type_Syntax_Descriptor_Null() { void Error() => default(IObjectFieldDescriptor)!.Type("foo"); - Assert.Throws(Error); + Assert.Throws(Error); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/DirectiveTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/DirectiveTypeTests.cs index 29302077107..10d61b736cc 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/DirectiveTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/DirectiveTypeTests.cs @@ -224,7 +224,7 @@ public void Ignore_DescriptorIsNull_ArgumentNullException() .Ignore(null!, t => t.Argument2); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/InputObjectTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/InputObjectTypeTests.cs index d5c75930696..9950a885fc9 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/InputObjectTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/InputObjectTypeTests.cs @@ -370,7 +370,7 @@ void Action() => InputObjectTypeDescriptorExtensions.Ignore(null!, t => t.Id); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -723,7 +723,7 @@ public void OneOf_descriptor_is_null() { void Fail() => InputObjectTypeDescriptorExtensions.OneOf(null!); - Assert.Throws(Fail); + Assert.Throws(Fail); } [Fact] @@ -731,7 +731,7 @@ public void OneOf_generic_descriptor_is_null() { void Fail() => InputObjectTypeDescriptorExtensions.OneOf(null!); - Assert.Throws(Fail); + Assert.Throws(Fail); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/InterfaceTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/InterfaceTypeTests.cs index 5ce75ba4a04..d4b1590cfa3 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/InterfaceTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/InterfaceTypeTests.cs @@ -439,7 +439,7 @@ public void Ignore_DescriptorIsNull_ArgumentNullException() void Action() => InterfaceTypeDescriptorExtensions.Ignore(null!, t => t.Bar); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs index f8ef72e86dc..4d625b68366 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/ObjectTypeTests.cs @@ -1236,7 +1236,7 @@ public void IgnoreField_DescriptorIsNull_ArgumentNullException() void Action() => ObjectTypeDescriptorExtensions.Ignore(null!, t => t.Description); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationCompiler.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationCompiler.cs index bfabcec6ed3..f61b6edcba4 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationCompiler.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Nodes/OperationCompiler.cs @@ -254,7 +254,7 @@ private SelectionSet BuildSelectionSet( compilationContext.Register(selection, selection.Id); selections[i++] = selection; - if (includeFlags.Count > 1) + if (includeFlags.Count > 0) { isConditional = true; } From e4180e61d0349d0d91d38b78081b632dd7cb0207 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 9 Dec 2025 12:06:02 +0100 Subject: [PATCH 28/42] Updated Snapshots --- .../Execution/Processing/OperationCompiler.cs | 4 +- .../Processing/SelectionFeatureCollection.cs | 2 +- .../Processing/Tasks/ResolverTaskFactory.cs | 1 + ..._To_NonNullArgument_With_DefaultValue.snap | 6 +++ .../StarWarsCodeFirstTests.cs | 16 ++++---- .../QueryableCursorPagingProviderTests.cs | 5 +-- .../IntegrationTests.First_Value_Not_Set.snap | 6 --- ...ationTests.Invalid_After_Index_Cursor.snap | 6 --- ...tionTests.Invalid_Before_Index_Cursor.snap | 6 --- ...nvalid_EmptyString_After_Index_Cursor.snap | 6 --- ...valid_EmptyString_Before_Index_Cursor.snap | 6 --- ...grationTests.MaxPageSizeReached_First.snap | 6 --- ...egrationTests.MaxPageSizeReached_Last.snap | 6 --- ...grationTests.MinPageSizeReached_First.snap | 6 --- ...egrationTests.MinPageSizeReached_Last.snap | 6 --- .../IntegrationTests.No_Boundaries_Set.snap | 6 --- ...s.Mutation_Aggregate_Error_Not_Mapped.snap | 6 --- .../IntegrationTests.MaxPageSizeReached.snap | 8 +--- ...IntegrationTests.No_Paging_Boundaries.snap | 8 +--- ...esult_And_Exceptions_Unexpected_Error.snap | 6 --- ...esult_And_Exceptions_Unexpected_Error.snap | 6 --- .../Resolvers/ResolverCompilerTests.cs | 10 +---- ...ptorTests.Input_Should_EmptySelection.snap | 8 +--- ...ceptorTests.Input_Should_UnknownValue.snap | 8 +--- ...ttributeTests.Id_On_Objects_InvalidId.snap | 4 +- ...ributeTests.Id_On_Objects_InvalidType.snap | 4 +- ...g_Throws_On_InvalidInputs_InvalidArgs.snap | 24 ------------ ....Node_Resolve_Implicit_Custom_IdField.snap | 6 --- .../NodeFieldSupportTests.Tow_Many_Nodes.snap | 6 --- ...houldReturnNonNullError_When_IdIsNull.snap | 8 +--- ..._Against_Interface_Without_Impl_Field.snap | 6 --- .../Rewriters/DocumentRewriter.cs | 2 +- .../InlineFragmentOperationRewriter.cs | 22 ++++++----- ...ault_ErrorHandlingMode_Can_Be_Changed.yaml | 6 --- ...Http_Request_In_Node_Is_Still_Ongoing.yaml | 6 --- ...d_While_Subscription_Is_Still_Ongoing.yaml | 6 --- ..._Source_Schema_Are_Properly_Forwarded.yaml | 6 --- ..._On_Lookup_Field_In_List_OnError_Halt.yaml | 18 --------- ..._On_Lookup_Field_In_List_OnError_Null.yaml | 18 --------- ...ookup_Field_In_List_OnError_Propagate.yaml | 18 --------- ...ts.Error_On_Lookup_Field_OnError_Halt.yaml | 6 --- ...ts.Error_On_Lookup_Field_OnError_Null.yaml | 6 --- ...ror_On_Lookup_Field_OnError_Propagate.yaml | 6 --- ...kup_Leaf_In_List_NonNull_OnError_Halt.yaml | 18 --------- ...kup_Leaf_In_List_NonNull_OnError_Null.yaml | 18 --------- ...eaf_In_List_NonNull_OnError_Propagate.yaml | 18 --------- ...r_On_Lookup_Leaf_In_List_OnError_Halt.yaml | 18 --------- ...r_On_Lookup_Leaf_In_List_OnError_Null.yaml | 18 --------- ...Lookup_Leaf_In_List_OnError_Propagate.yaml | 18 --------- ...r_On_Lookup_Leaf_NonNull_OnError_Halt.yaml | 6 --- ...r_On_Lookup_Leaf_NonNull_OnError_Null.yaml | 6 --- ...Lookup_Leaf_NonNull_OnError_Propagate.yaml | 6 --- ...sts.Error_On_Lookup_Leaf_OnError_Halt.yaml | 6 --- ...sts.Error_On_Lookup_Leaf_OnError_Null.yaml | 6 --- ...rror_On_Lookup_Leaf_OnError_Propagate.yaml | 6 --- ...ests.Error_On_Root_Field_OnError_Halt.yaml | 6 --- ...ests.Error_On_Root_Field_OnError_Null.yaml | 6 --- ...Error_On_Root_Field_OnError_Propagate.yaml | 6 --- ...Tests.Error_On_Root_Leaf_OnError_Halt.yaml | 6 --- ...Tests.Error_On_Root_Leaf_OnError_Null.yaml | 6 --- ....Error_On_Root_Leaf_OnError_Propagate.yaml | 6 --- ...For_Lookup_Field_NonNull_OnError_Halt.yaml | 6 --- ...For_Lookup_Field_NonNull_OnError_Null.yaml | 6 --- ...ookup_Field_NonNull_OnError_Propagate.yaml | 6 --- ..._For_Lookup_Leaf_NonNull_OnError_Halt.yaml | 6 --- ..._For_Lookup_Leaf_NonNull_OnError_Null.yaml | 6 --- ...Lookup_Leaf_NonNull_OnError_Propagate.yaml | 6 --- ...h_For_Root_Field_NonNull_OnError_Halt.yaml | 6 --- ...h_For_Root_Field_NonNull_OnError_Null.yaml | 6 --- ..._Root_Field_NonNull_OnError_Propagate.yaml | 6 --- ...NonNull_One_Service_Errors_EntryField.yaml | 6 --- ...ullable_One_Service_Errors_EntryField.yaml | 6 --- ...d_NonNull_One_Service_Errors_SubField.yaml | 6 --- ..._Nullable_One_Service_Errors_SubField.yaml | 6 --- ..._Nullable_One_Service_Errors_SubField.yaml | 6 --- ...NonNull_One_Service_Errors_EntryField.yaml | 6 --- ...t_NonNull_One_Service_Errors_SubField.yaml | 6 --- ...ullable_One_Service_Errors_EntryField.yaml | 6 --- ..._Nullable_One_Service_Errors_SubField.yaml | 6 --- ...ullable_One_Service_Errors_EntryField.yaml | 6 --- ..._Nullable_One_Service_Errors_SubField.yaml | 6 --- .../InlineFragmentOperationRewriterTests.cs | 37 +++++++++++++++++++ 82 files changed, 80 insertions(+), 589 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs index 5448655c3ae..b9d6de55af4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.cs @@ -14,7 +14,7 @@ public sealed partial class OperationCompiler private readonly Schema _schema; private readonly ObjectPool>> _fieldsPool; private readonly OperationCompilerOptimizers _optimizers; - private readonly DocumentRewriter _documentRewriter; + private readonly InlineFragmentOperationRewriter _documentRewriter; private readonly InputParser _inputValueParser; private static readonly ArrayPool s_objectArrayPool = ArrayPool.Shared; @@ -30,7 +30,7 @@ internal OperationCompiler( _schema = schema; _inputValueParser = inputValueParser; _fieldsPool = fieldsPool; - _documentRewriter = new DocumentRewriter(schema, removeStaticallyExcludedSelections: true); + _documentRewriter = new InlineFragmentOperationRewriter(schema, removeStaticallyExcludedSelections: true); _optimizers = optimizers; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs index f14458099ba..ce8d18f2e11 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SelectionFeatureCollection.cs @@ -101,7 +101,7 @@ public bool TryGet([NotNullWhen(true)] out TFeature? feature) /// The existing or newly created feature instance. /// This method is thread-safe. public TFeature GetOrSetSafe() where TFeature : new() - => GetOrSetSafe(static () => new TFeature()); + => GetOrSetSafe(static () => new TFeature()); internal TFeature GetOrSetSafe(Func factory) => _parent.GetOrSetSafe(_selectionId, factory); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index c54b36a56f5..d48b6592620 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -76,6 +76,7 @@ public static ObjectResult EnqueueResolverTasks( } } + // TODO : remove ? public static ResolverTask EnqueueElementTasks( OperationContext operationContext, Selection selection, diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap index de63f0ffdb4..5644d15eb0b 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/Spec/__snapshots__/ArgumentCoercionTests.Pass_In_Null_To_NonNullArgument_With_DefaultValue.snap @@ -2,6 +2,12 @@ "errors": [ { "message": "Detected a non-null violation in argument `name`.", + "locations": [ + { + "line": 1, + "column": 12 + } + ], "path": [ "sayHello" ], diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs index 431abffa852..610a421e5ba 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs @@ -1101,15 +1101,15 @@ name @include(if: {{ifValue}}) public async Task Include_With_Variable(bool ifValue) { await ExpectValid( - """ - query ($if: Boolean!) { - human(id: "1000") { - name @include(if: $if) - height - } + """ + query ($if: Boolean!) { + human(id: "1000") { + name @include(if: $if) + height } - """, - request: r => r.SetVariableValues(new Dictionary { { "if", ifValue } })) + } + """, + request: r => r.SetVariableValues(new Dictionary { { "if", ifValue } })) .MatchSnapshotAsync(postFix: ifValue); } diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs index 7555d0f1906..8b4a846d4c4 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/QueryableCursorPagingProviderTests.cs @@ -519,10 +519,7 @@ public static async Task CreateContextAsync(CursorPagingArgume } """); - var operation = OperationCompiler.Compile( - "abc", - document.Definitions.OfType().First(), - schema); + var operation = OperationCompiler.Compile("abc", document, schema); return new MockContext(arguments, operation, operation.RootSelectionSet.Selections[0]); } diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.First_Value_Not_Set.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.First_Value_Not_Set.snap index d7a9894ef12..a1203609ca9 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.First_Value_Not_Set.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.First_Value_Not_Set.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "You must provide a `first` value to properly paginate the `LettersConnection`.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_After_Index_Cursor.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_After_Index_Cursor.snap index 826e7a0cb9b..7aa38b4514b 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_After_Index_Cursor.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_After_Index_Cursor.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The cursor specified in `after` has an invalid format.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_Before_Index_Cursor.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_Before_Index_Cursor.snap index cd2cb54e714..dd21d96ff6d 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_Before_Index_Cursor.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_Before_Index_Cursor.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The cursor specified in `before` has an invalid format.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_After_Index_Cursor.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_After_Index_Cursor.snap index c15f8a3745b..deeb2a245cc 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_After_Index_Cursor.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_After_Index_Cursor.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The cursor specified in `after` has an invalid format.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_Before_Index_Cursor.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_Before_Index_Cursor.snap index f130bc24d0f..d10fd0432e0 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_Before_Index_Cursor.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.Invalid_EmptyString_Before_Index_Cursor.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The cursor specified in `before` has an invalid format.", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_First.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_First.snap index aff5a792fec..b48fc9361dd 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_First.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_First.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The maximum allowed items per page were exceeded.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_Last.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_Last.snap index aff5a792fec..b48fc9361dd 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_Last.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached_Last.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The maximum allowed items per page were exceeded.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_First.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_First.snap index 2f4bd3fe3d0..e3b36abf61b 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_First.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_First.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The requested number of values per page must be at least 0.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_Last.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_Last.snap index 2f4bd3fe3d0..e3b36abf61b 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_Last.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.MinPageSizeReached_Last.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The requested number of values per page must be at least 0.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.No_Boundaries_Set.snap b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.No_Boundaries_Set.snap index 9ff705486c9..5c3f2ffa91f 100644 --- a/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.No_Boundaries_Set.snap +++ b/src/HotChocolate/Core/test/Types.CursorPagination.Tests/__snapshots__/IntegrationTests.No_Boundaries_Set.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "You must provide a `first` or `last` value to properly paginate the `LettersConnection`.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.Mutations.Tests/__snapshots__/AnnotationBasedMutations.Mutation_Aggregate_Error_Not_Mapped.snap b/src/HotChocolate/Core/test/Types.Mutations.Tests/__snapshots__/AnnotationBasedMutations.Mutation_Aggregate_Error_Not_Mapped.snap index 76b40b4a801..6a0504ad745 100644 --- a/src/HotChocolate/Core/test/Types.Mutations.Tests/__snapshots__/AnnotationBasedMutations.Mutation_Aggregate_Error_Not_Mapped.snap +++ b/src/HotChocolate/Core/test/Types.Mutations.Tests/__snapshots__/AnnotationBasedMutations.Mutation_Aggregate_Error_Not_Mapped.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 5 - } - ], "path": [ "doSomething2" ] diff --git a/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached.snap b/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached.snap index 4201ec8fb7f..2dad32b0401 100644 --- a/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached.snap +++ b/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.MaxPageSizeReached.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "The maximum allowed items per page were exceeded.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.No_Paging_Boundaries.snap b/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.No_Paging_Boundaries.snap index 3320ff188f4..d516032374a 100644 --- a/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.No_Paging_Boundaries.snap +++ b/src/HotChocolate/Core/test/Types.OffsetPagination.Tests/__snapshots__/IntegrationTests.No_Paging_Boundaries.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "You must provide take to properly paginate the `LettersCollectionSegment`.", - "locations": [ - { - "line": 3, - "column": 21 - } - ], "path": [ "letters" ], diff --git a/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/AnnotationBasedSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap b/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/AnnotationBasedSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap index 13609ca9403..884083d29d0 100644 --- a/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/AnnotationBasedSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap +++ b/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/AnnotationBasedSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "userById" ] diff --git a/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/CodeFirstSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap b/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/CodeFirstSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap index 13609ca9403..884083d29d0 100644 --- a/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/CodeFirstSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap +++ b/src/HotChocolate/Core/test/Types.Queries.Tests/__snapshots__/CodeFirstSchemaTests.Execute_Query_With_FieldResult_And_Exceptions_Unexpected_Error.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "userById" ] diff --git a/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs b/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs index 1ae88b29256..329c2ae5357 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Resolvers/ResolverCompilerTests.cs @@ -630,10 +630,7 @@ public async Task Compile_Arguments_Operation() .Create(); var document = Utf8GraphQLParser.Parse("{ abc }"); - var operation = OperationCompiler.Compile( - "abc", - document.Definitions.OfType().First(), - schema); + var operation = OperationCompiler.Compile("abc", document, schema); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); @@ -747,10 +744,7 @@ public async Task Compile_Arguments_Document() .Create(); var document = Utf8GraphQLParser.Parse("{ abc }"); - var operation = OperationCompiler.Compile( - "abc", - document.Definitions.OfType().First(), - schema); + var operation = OperationCompiler.Compile("abc", document, schema); var context = new Mock(); context.Setup(t => t.Parent()).Returns(new Resolvers()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_EmptySelection.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_EmptySelection.snap index dbfb030642e..a5a60149dd2 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_EmptySelection.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_EmptySelection.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "Flags need to have at least one selection. Type: FlagsEnumFlagsInput", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "test" ] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_UnknownValue.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_UnknownValue.snap index 163f6e8b341..e4b071e30f2 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_UnknownValue.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Interceptors/__snapshots__/FlagEnumInterceptorTests.Input_Should_UnknownValue.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "The value isAsd is not known for type FlagsEnumFlagsInput", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "test" ] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidId.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidId.snap index 3e0559c0364..e4427c22fe6 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidId.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidId.snap @@ -1,4 +1,4 @@ -{ - "result": "{\n \"errors\": [\n {\n \"message\": \"The node ID string has an invalid format.\",\n \"locations\": [\n {\n \"line\": 2,\n \"column\": 5\n }\n ],\n \"path\": [\n \"foo\"\n ],\n \"extensions\": {\n \"originalValue\": \"abc\"\n }\n }\n ],\n \"data\": null\n}", +{ + "result": "{\n \"errors\": [\n {\n \"message\": \"The node ID string has an invalid format.\",\n \"path\": [\n \"foo\"\n ],\n \"extensions\": {\n \"originalValue\": \"abc\"\n }\n }\n ],\n \"data\": null\n}", "someId": "abc" } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidType.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidType.snap index b1a75519cee..2377ccf1b7d 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidType.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdAttributeTests.Id_On_Objects_InvalidType.snap @@ -1,4 +1,4 @@ -{ - "result": "{\n \"errors\": [\n {\n \"message\": \"The node id type name `Query` does not match the expected type name `Some`.\",\n \"locations\": [\n {\n \"line\": 2,\n \"column\": 5\n }\n ],\n \"path\": [\n \"foo\"\n ]\n }\n ],\n \"data\": null\n}", +{ + "result": "{\n \"errors\": [\n {\n \"message\": \"The node id type name `Query` does not match the expected type name `Some`.\",\n \"path\": [\n \"foo\"\n ]\n }\n ],\n \"data\": null\n}", "someId": "UXVlcnk6AAAAAAAAAAAAAAAAAAAAAA==" } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdDescriptorTests.Id_Honors_CustomTypeNaming_Throws_On_InvalidInputs_InvalidArgs.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdDescriptorTests.Id_Honors_CustomTypeNaming_Throws_On_InvalidInputs_InvalidArgs.snap index dd746ccc21a..696c3baa90b 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdDescriptorTests.Id_Honors_CustomTypeNaming_Throws_On_InvalidInputs_InvalidArgs.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/IdDescriptorTests.Id_Honors_CustomTypeNaming_Throws_On_InvalidInputs_InvalidArgs.snap @@ -2,48 +2,24 @@ "errors": [ { "message": "The node id type name `FooFoo` does not match the expected type name `RenamedUser`.", - "locations": [ - { - "line": 2, - "column": 5 - } - ], "path": [ "validUserIdInput" ] }, { "message": "The node id type name `FooFooFluent` does not match the expected type name `FooFoo`.", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "validFooIdInput" ] }, { "message": "The node id type name `FooFooFluentSingle` does not match the expected type name `FooFooFluent`.", - "locations": [ - { - "line": 4, - "column": 5 - } - ], "path": [ "validFluentFooIdInput" ] }, { "message": "The node id type name `RenamedUser` does not match the expected type name `FooFooFluentSingle`.", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "validSingleTypeFluentFooIdInput" ] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Node_Resolve_Implicit_Custom_IdField.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Node_Resolve_Implicit_Custom_IdField.snap index f375a3abe1c..1473ba45ce5 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Node_Resolve_Implicit_Custom_IdField.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Node_Resolve_Implicit_Custom_IdField.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Could not resolve the actual object type from `HotChocolate.Types.Relay.NodeFieldSupportTests+Bar2` for the abstract type `node`.", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "node" ] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Tow_Many_Nodes.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Tow_Many_Nodes.snap index 06301c15d06..c5202261061 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Tow_Many_Nodes.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/NodeFieldSupportTests.Tow_Many_Nodes.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "The maximum number of nodes that can be fetched at once is 1. This selection tried to fetch 2 nodes that exceeded the maximum allowed amount.", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "nodes" ], diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/RelaySchemaTests.Relay_ShouldReturnNonNullError_When_IdIsNull.snap b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/RelaySchemaTests.Relay_ShouldReturnNonNullError_When_IdIsNull.snap index fa2eb7d3585..a4d5f0b6cfa 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/RelaySchemaTests.Relay_ShouldReturnNonNullError_When_IdIsNull.snap +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Relay/__snapshots__/RelaySchemaTests.Relay_ShouldReturnNonNullError_When_IdIsNull.snap @@ -1,13 +1,7 @@ -{ +{ "errors": [ { "message": "Cannot return null for non-nullable field.", - "locations": [ - { - "line": 1, - "column": 16 - } - ], "path": [ "user", "id" diff --git a/src/HotChocolate/Core/test/Types.Tests/__snapshots__/SchemaBuilderTests.Execute_Against_Interface_Without_Impl_Field.snap b/src/HotChocolate/Core/test/Types.Tests/__snapshots__/SchemaBuilderTests.Execute_Against_Interface_Without_Impl_Field.snap index 981d9a23dc4..1e5d92424a3 100644 --- a/src/HotChocolate/Core/test/Types.Tests/__snapshots__/SchemaBuilderTests.Execute_Against_Interface_Without_Impl_Field.snap +++ b/src/HotChocolate/Core/test/Types.Tests/__snapshots__/SchemaBuilderTests.Execute_Against_Interface_Without_Impl_Field.snap @@ -2,12 +2,6 @@ "errors": [ { "message": "Could not resolve the actual object type from `System.String` for the abstract type `foo`.", - "locations": [ - { - "line": 1, - "column": 3 - } - ], "path": [ "foo" ] diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/DocumentRewriter.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/DocumentRewriter.cs index 689620e30dc..d4aea762a95 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/DocumentRewriter.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/DocumentRewriter.cs @@ -828,7 +828,7 @@ private sealed class Context( /// /// Provides a fast way to get all FieldNodes for the same response name. - /// The key is the respones name. + /// The key is the response name. /// public Dictionary>? Fields { get; private set; } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/InlineFragmentOperationRewriter.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/InlineFragmentOperationRewriter.cs index 7ea0e766b4f..07b5f8a91de 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/InlineFragmentOperationRewriter.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Utilities/Rewriters/InlineFragmentOperationRewriter.cs @@ -568,19 +568,21 @@ private static IReadOnlyList RemoveStaticIncludeConditions( static bool IsStaticIncludeCondition(DirectiveNode directive, ref bool skipChecked, ref bool includeChecked) { - if (directive.Name.Value.Equals(DirectiveNames.Skip.Name, StringComparison.Ordinal) - && directive.Arguments.Count == 1 - && directive.Arguments[0].Value is BooleanValueNode skipConstant - && !skipConstant.Value) + if(directive.Name.Value.Equals(DirectiveNames.Skip.Name, StringComparison.Ordinal)) { - return true; + skipChecked = true; + if (directive.Arguments is [{ Value: BooleanValueNode }]) + { + return true; + } } - else if (directive.Name.Value.Equals(DirectiveNames.Include.Name, StringComparison.Ordinal) - && (directive.Arguments.Count != 1 - || directive.Arguments[0].Value is not BooleanValueNode includeConstant - || includeConstant.Value)) + else if(directive.Name.Value.Equals(DirectiveNames.Include.Name, StringComparison.Ordinal)) { - return true; + includeChecked = true; + if (directive.Arguments is [{ Value: BooleanValueNode }]) + { + return true; + } } return false; diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml index 74b61133c8e..a16305dda21 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Default_ErrorHandlingMode_Can_Be_Changed.yaml @@ -47,12 +47,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve reviews", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "reviews" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml index 142c5dedb94..d43e5fef38d 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Http_Request_In_Node_Is_Still_Ongoing.yaml @@ -72,12 +72,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve reviews", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "reviews" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml index c56a349960c..39cb784934f 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/CancellationTests.Execution_Is_Halted_While_Subscription_Is_Still_Ongoing.yaml @@ -68,12 +68,6 @@ sourceSchemas: "errors": [ { "message": "Could not produce review", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "onReviewCreated" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_Extensions_From_Source_Schema_Are_Properly_Forwarded.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_Extensions_From_Source_Schema_Are_Properly_Forwarded.yaml index ffd7c58bb2c..3936766b644 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_Extensions_From_Source_Schema_Are_Properly_Forwarded.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_Extensions_From_Source_Schema_Are_Properly_Forwarded.yaml @@ -46,12 +46,6 @@ sourceSchemas: "errors": [ { "message": "Something went wrong", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "someField" ], diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml index ad5d46a25f4..86f6bbda802 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Halt.yaml @@ -113,12 +113,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -133,12 +127,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -153,12 +141,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Null.yaml index 71e8d18bf91..3fc85073acc 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Null.yaml @@ -145,12 +145,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -165,12 +159,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -185,12 +173,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Propagate.yaml index e68f2836769..1a913d705ee 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_In_List_OnError_Propagate.yaml @@ -144,12 +144,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -164,12 +158,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -184,12 +172,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml index 1101ad8bd1a..94720026ab0 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Halt.yaml @@ -94,12 +94,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Null.yaml index a2fd147935b..d0e7c4a9957 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Null.yaml @@ -100,12 +100,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Propagate.yaml index ba31c74d2db..7850f33c18e 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Field_OnError_Propagate.yaml @@ -99,12 +99,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml index 012eaad7478..cb5f798e19d 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Halt.yaml @@ -113,12 +113,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -133,12 +127,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -153,12 +141,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Null.yaml index 588e98daca9..ba8a5029d94 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Null.yaml @@ -145,12 +145,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -165,12 +159,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -185,12 +173,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Propagate.yaml index ead712a5f2f..18552f06227 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_NonNull_OnError_Propagate.yaml @@ -112,12 +112,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -132,12 +126,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] @@ -152,12 +140,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml index 25b8242856b..dec776c96b4 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Halt.yaml @@ -113,12 +113,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -136,12 +130,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -159,12 +147,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Null.yaml index 159f5a363f4..467ce3b9060 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Null.yaml @@ -145,12 +145,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -168,12 +162,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -191,12 +179,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Propagate.yaml index 5e1e3ea6e5c..f2e9911e655 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_In_List_OnError_Propagate.yaml @@ -144,12 +144,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -167,12 +161,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" @@ -190,12 +178,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml index 25ebf37958f..157973a0108 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Halt.yaml @@ -94,12 +94,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Null.yaml index 82e0e776c41..a66d94e7cdf 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Null.yaml @@ -100,12 +100,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Propagate.yaml index e6b5913d04c..7a4186d81ec 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_NonNull_OnError_Propagate.yaml @@ -93,12 +93,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml index 2b35f43081d..2b40e33950a 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Halt.yaml @@ -94,12 +94,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Null.yaml index cdfb5bfee91..41e32d1c801 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Null.yaml @@ -100,12 +100,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Propagate.yaml index 37913ca0554..852d595015b 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Lookup_Leaf_OnError_Propagate.yaml @@ -99,12 +99,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml index 2e63fcd8853..1c5a760f448 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Halt.yaml @@ -49,12 +49,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Null.yaml index 28f1bb1aa06..2025c497028 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Null.yaml @@ -52,12 +52,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Propagate.yaml index 4ab469854c4..cb08cd00a61 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Field_OnError_Propagate.yaml @@ -51,12 +51,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml index ace8a030e95..65b5c9895d3 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Halt.yaml @@ -50,12 +50,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Null.yaml index f26ed11ca88..c445fb8baaf 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Null.yaml @@ -55,12 +55,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Propagate.yaml index dfed1bc3ec2..fd07ff284ef 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.Error_On_Root_Leaf_OnError_Propagate.yaml @@ -54,12 +54,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml index 80d61079dd3..de2886aecd4 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Halt.yaml @@ -94,12 +94,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Null.yaml index b5808323917..b798d10242b 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Null.yaml @@ -100,12 +100,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Propagate.yaml index 5a6ef6d3431..0ce71a9e555 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Field_NonNull_OnError_Propagate.yaml @@ -93,12 +93,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml index ee505e22443..889bd2c60a6 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Halt.yaml @@ -94,12 +94,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Null.yaml index 65e4bfa011b..34802735c60 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Null.yaml @@ -100,12 +100,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Propagate.yaml index 965f0f72366..870450722b8 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Lookup_Leaf_NonNull_OnError_Propagate.yaml @@ -93,12 +93,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product.name", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "productById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml index e78b20a3a68..2f39e67321a 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Halt.yaml @@ -49,12 +49,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Null.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Null.yaml index ebd23e3d03e..fcf5004f6a9 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Null.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Null.yaml @@ -52,12 +52,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Propagate.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Propagate.yaml index 7969aba8bc1..0ad108fc55f 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Propagate.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/__snapshots__/SourceSchemaErrorTests.No_Data_And_Error_With_Path_For_Root_Field_NonNull_OnError_Propagate.yaml @@ -48,12 +48,6 @@ sourceSchemas: "errors": [ { "message": "Could not resolve Product", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "productById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_NonNull_One_Service_Errors_EntryField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_NonNull_One_Service_Errors_EntryField.yaml index b63f5d8c073..b64c80f82a4 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_NonNull_One_Service_Errors_EntryField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_NonNull_One_Service_Errors_EntryField.yaml @@ -72,12 +72,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "other" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_Nullable_One_Service_Errors_EntryField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_Nullable_One_Service_Errors_EntryField.yaml index a1741c8cd93..e1d8b1e02fc 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_Nullable_One_Service_Errors_EntryField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_EntryField_Nullable_One_Service_Errors_EntryField.yaml @@ -87,12 +87,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 2, - "column": 3 - } - ], "path": [ "other" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_NonNull_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_NonNull_One_Service_Errors_SubField.yaml index 0fa953035e8..a98f1e81628 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_NonNull_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_NonNull_One_Service_Errors_SubField.yaml @@ -72,12 +72,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "other", "userId" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_Nullable_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_Nullable_One_Service_Errors_SubField.yaml index 24d0820925f..eff02802c8c 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_Nullable_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_NonNull_EntryField_Nullable_One_Service_Errors_SubField.yaml @@ -87,12 +87,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "other", "userId" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_Nullable_EntryField_Nullable_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_Nullable_EntryField_Nullable_One_Service_Errors_SubField.yaml index df4dff0c19b..85438db1290 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_Nullable_EntryField_Nullable_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Parallel_SubField_Nullable_EntryField_Nullable_One_Service_Errors_SubField.yaml @@ -90,12 +90,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 3, - "column": 5 - } - ], "path": [ "other", "userId" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_EntryField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_EntryField.yaml index 60d3fb6a170..1b3d0f292f6 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_EntryField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_EntryField.yaml @@ -105,12 +105,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "brandById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_SubField.yaml index 25eac97730e..a595dc063b5 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_NonNull_One_Service_Errors_SubField.yaml @@ -105,12 +105,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "brandById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_EntryField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_EntryField.yaml index 767440f9dce..7d0ef901476 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_EntryField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_EntryField.yaml @@ -108,12 +108,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "brandById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_SubField.yaml index 82f7987e4c1..8730cfc995b 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_NonNull_Parent_Nullable_One_Service_Errors_SubField.yaml @@ -108,12 +108,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "brandById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_EntryField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_EntryField.yaml index f0a77593a12..e0d03c5fccb 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_EntryField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_EntryField.yaml @@ -111,12 +111,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 4, - "column": 3 - } - ], "path": [ "brandById" ] diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_SubField.yaml b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_SubField.yaml index f7a3aa98214..63be5799b16 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_SubField.yaml +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/v15/__snapshots__/SubgraphErrorTests.Resolve_Sequence_SubField_Nullable_Parent_Nullable_One_Service_Errors_SubField.yaml @@ -111,12 +111,6 @@ sourceSchemas: "errors": [ { "message": "Unexpected Execution Error", - "locations": [ - { - "line": 5, - "column": 5 - } - ], "path": [ "brandById", "name" diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/Rewriters/InlineFragmentOperationRewriterTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/Rewriters/InlineFragmentOperationRewriterTests.cs index 8c66269a3ed..4a03c817556 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/Rewriters/InlineFragmentOperationRewriterTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/Rewriters/InlineFragmentOperationRewriterTests.cs @@ -699,4 +699,41 @@ ... UnknownFragment "A fragment with the name 'UnknownFragment' does not exist.", Assert.Throws(Action).Message); } + + [Fact] + public void Single_Include_With_Variable() + { + // arrange + var sourceText = FileResource.Open("schema1.graphql"); + var schemaDefinition = SchemaParser.Parse(sourceText); + + var doc = Utf8GraphQLParser.Parse( + """ + query($skip: Boolean!) { + productById(id: 1) { + name @include(if: $skip) + id + } + } + """); + + // act + var rewriter = new InlineFragmentOperationRewriter( + schemaDefinition, + removeStaticallyExcludedSelections: true); + var rewritten = rewriter.RewriteDocument(doc); + + // assert + rewritten.MatchInlineSnapshot( + """ + query( + $skip: Boolean! + ) { + productById(id: 1) { + name @include(if: $skip) + id + } + } + """); + } } From 183bce543a7b745e34bcc0a5a824ddfac0a7db9a Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 9 Dec 2025 12:17:47 +0100 Subject: [PATCH 29/42] fixed tests --- .../Types/Execution/Processing/OperationCompilerOptimizers.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs index e60919fe435..855c089dfd4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompilerOptimizers.cs @@ -7,8 +7,8 @@ namespace HotChocolate.Execution.Processing; // TODO : We might remove this internal sealed class OperationCompilerOptimizers { - private ImmutableArray _operationOptimizers; - private ImmutableArray _selectionSetOptimizers; + private ImmutableArray _operationOptimizers = []; + private ImmutableArray _selectionSetOptimizers = []; private PropertyInitFlags _initFlags; public ImmutableArray OperationOptimizers From 11075e61ff83f2546392271bc94392e94ef0a8db Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 12 Dec 2025 09:50:52 +0100 Subject: [PATCH 30/42] wip --- .../Processing/OperationCompilerTests.cs | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs index 103dee2fb3c..a5d11e907b5 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/OperationCompilerTests.cs @@ -544,11 +544,13 @@ public void Object_Field_Visibility_Is_Correctly_Inherited_3() .Create(); var document = Utf8GraphQLParser.Parse( - @"query foo($v: Boolean!, $q: Boolean!) { - hero(episode: EMPIRE) @include(if: $v) { - name @include(if: $q) - } - }"); + """ + query foo($v: Boolean!, $q: Boolean!) { + hero(episode: EMPIRE) @include(if: $v) { + name @include(if: $q) + } + } + """); // act var operation = OperationCompiler.Compile( @@ -603,14 +605,16 @@ public void Defer_Inline_Fragment() .Create(); var document = Utf8GraphQLParser.Parse( - @"{ - hero(episode: EMPIRE) { - name - ... @defer { - id - } + """ + { + hero(episode: EMPIRE) { + name + ... @defer { + id } - }"); + } + } + """); // act var operation = OperationCompiler.Compile( @@ -631,16 +635,18 @@ public void Defer_Fragment_Spread() .Create(); var document = Utf8GraphQLParser.Parse( - @"{ - hero(episode: EMPIRE) { - name - ... Foo @defer - } + """ + { + hero(episode: EMPIRE) { + name + ... Foo @defer + } } fragment Foo on Droid { - id - }"); + id + } + """); // act var operation = OperationCompiler.Compile( @@ -691,14 +697,16 @@ public void FragmentSpread_SelectionsSet_Empty() .Create(); var document = Utf8GraphQLParser.Parse( - @"query foo($v: Boolean){ - hero(episode: EMPIRE) { - name @include(if: $v) - ... abc - } + """ + query foo($v: Boolean){ + hero(episode: EMPIRE) { + name @include(if: $v) + ... abc + } } - fragment abc on Droid { }"); + fragment abc on Droid { } + """); // act var operation = OperationCompiler.Compile( From f8e619c907a1c05f7d4bdc8c298299f3e515de04 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 15 Dec 2025 08:27:10 +0100 Subject: [PATCH 31/42] wip --- .../Internal/MiddlewareContextMarshal.cs | 2 +- .../Processing/MiddlewareContext.Global.cs | 2 +- .../Processing/MiddlewareContext.Pooling.cs | 13 +- .../Processing/MiddlewareContext.Selection.cs | 2 - .../Processing/MiddlewareContext.State.cs | 5 +- .../Processing/OperationContext.Execution.cs | 15 +- .../Types/Execution/Processing/PathHelper.cs | 146 -------- .../Execution/Processing/QueryExecutor.cs | 20 +- .../Execution/Processing/Result/ListResult.cs | 192 ---------- .../Processing/Result/ListResultPool.cs | 40 --- .../Processing/Result/ObjectFieldResult.cs | 44 --- .../Processing/Result/ObjectResult.cs | 301 ---------------- .../Result/ObjectResultExtensions.cs | 11 - .../Processing/Result/ObjectResultPool.cs | 40 --- .../Processing/Result/ResultBucket.cs | 81 ----- .../Result/ResultBuilder.NonNullHandling.cs | 45 --- .../Result/ResultBuilder.ObjectResult.cs | 46 --- .../Result/ResultBuilder.Pooling.cs | 58 --- .../Processing/Result/ResultBuilder.cs | 339 ------------------ .../Execution/Processing/Result/ResultData.cs | 72 ---- .../Processing/Result/ResultMemoryOwner.cs | 28 -- .../Execution/Processing/Result/ResultPool.cs | 37 -- .../Processing/Result/ResultPoolDefaults.cs | 8 - .../Tasks/ResolverTask.CompleteValue.cs | 15 +- .../Processing/Tasks/ResolverTask.Execute.cs | 6 +- .../Processing/Tasks/ResolverTask.Pooling.cs | 12 +- .../Processing/Tasks/ResolverTask.cs | 5 - .../Processing/Tasks/ResolverTaskFactory.cs | 25 +- .../Processing/ValueCompletion.Leaf.cs | 29 +- .../Processing/ValueCompletion.List.cs | 42 +-- .../Processing/ValueCompletion.Object.cs | 1 - .../Execution/Processing/ValueCompletion.cs | 52 +-- .../Core/src/Types/HotChocolate.Types.csproj | 4 + .../src/Types/Text/Json/ResultDocument.cs | 4 +- .../src/Types/Types/Contracts/ILeafType.cs | 61 ++++ 35 files changed, 162 insertions(+), 1641 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs diff --git a/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs index 01f583a780f..1d32ba7964d 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs @@ -25,7 +25,7 @@ public static class MiddlewareContextMarshal ArgumentNullException.ThrowIfNull(context); return context is MiddlewareContext middlewareContext - ? middlewareContext.ParentResult + ? middlewareContext.ResultValue : null; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs index e6dbd0f01c9..4b495a813d5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs @@ -226,7 +226,7 @@ public IMiddlewareContext Clone() _operationContext.CreateResolverTask( Selection, _parent, - ParentResult, + ResultValue, ResponseIndex, ScopedContextData); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs index 73d88af6347..314510bea0c 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Text.Json; namespace HotChocolate.Execution.Processing; @@ -17,11 +18,10 @@ public MiddlewareContext() } public void Initialize( - OperationContext operationContext, - Selection selection, - ObjectResult parentResult, - int responseIndex, object? parent, + Selection selection, + ResultElement resultValue, + OperationContext operationContext, IImmutableDictionary scopedContextData, Path? path) { @@ -30,8 +30,7 @@ public void Initialize( _services = operationContext.Services; _selection = selection; _path = path; - ParentResult = parentResult; - ResponseIndex = responseIndex; + ResultValue = resultValue; _parent = parent; _parser = operationContext.InputParser; ScopedContextData = scopedContextData; @@ -60,7 +59,7 @@ public void Clean() IsResultModified = false; ValueType = null; ResponseIndex = 0; - ParentResult = null!; + ResultValue = default; HasErrors = false; Arguments = null!; RequestAborted = CancellationToken.None; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 88ac8f0e8d5..549e9eca418 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -17,8 +17,6 @@ internal partial class MiddlewareContext public string ResponseName => _selection.ResponseName; - public int ResponseIndex { get; private set; } - public FieldDelegate? ResolverPipeline => _selection.ResolverPipeline; public PureFieldDelegate? PureResolver => _selection.PureResolver; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs index 2fb48366a1a..5af573e6aee 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Text.Json; using HotChocolate.Types; using HotChocolate.Utilities; @@ -10,7 +11,7 @@ internal partial class MiddlewareContext private object? _parent; private Path? _path; - public Path Path => _path ??= PathHelper.CreatePathFromContext(Selection, ParentResult, -1); + public Path Path => _path ??= ResultValue.Path.Append(Selection.ResponseName); public IImmutableDictionary ScopedContextData { get; set; } = null!; @@ -18,7 +19,7 @@ internal partial class MiddlewareContext public IType? ValueType { get; set; } - public ObjectResult ParentResult { get; private set; } = null!; + public ResultElement ResultValue { get; private set; } public bool HasErrors { get; private set; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs index 3fca2464889..f5fc05827e6 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs @@ -1,5 +1,6 @@ using System.Collections.Immutable; using HotChocolate.Execution.Processing.Tasks; +using HotChocolate.Text.Json; namespace HotChocolate.Execution.Processing; @@ -33,6 +34,8 @@ public ResultBuilder Result } } + public ResultDocument ResultDocument => throw new NotImplementedException(); + public RequestContext RequestContext { get @@ -43,10 +46,9 @@ public RequestContext RequestContext } public ResolverTask CreateResolverTask( - Selection selection, object? parent, - ObjectResult parentResult, - int responseIndex, + Selection selection, + ResultElement resultValue, IImmutableDictionary scopedContextData, Path? path = null) { @@ -55,11 +57,10 @@ public ResolverTask CreateResolverTask( var resolverTask = _resolverTaskFactory.Create(); resolverTask.Initialize( - this, - selection, - parentResult, - responseIndex, parent, + selection, + resultValue, + this, scopedContextData, path); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs deleted file mode 100644 index 1ecbecaf37e..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/PathHelper.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System.Buffers; -using System.Text.Json; - -namespace HotChocolate.Execution.Processing; - -internal static class PathHelper -{ - private const int InitialPathLength = 64; - - public static Path CreatePathFromContext(ObjectResult parent) - { - if (parent.Parent is null) - { - if (parent.PatchPath is null) - { - return Path.Root; - } - - return parent.PatchPath; - } - - return CreatePath(parent); - } - - public static Path CreatePathFromContext(ISelection selection, ResultData parent, int index) - => parent switch - { - ObjectResult => CreatePath(parent, selection.ResponseName), - ListResult => CreatePath(parent, index), - _ => throw new NotSupportedException($"{parent.GetType().FullName} is not a supported parent type.") - }; - - public static Path CombinePath(Path path, JsonElement errorSubPath, int skipSubElements) - { - for (var i = skipSubElements; i < errorSubPath.GetArrayLength(); i++) - { - path = errorSubPath[i] switch - { - { ValueKind: JsonValueKind.String } nameElement => path.Append(nameElement.GetString()!), - { ValueKind: JsonValueKind.Number } indexElement => path.Append(indexElement.GetInt32()), - _ => throw new InvalidOperationException("The error path contains an unsupported element.") - }; - } - - return path; - } - - public static Path CreatePathFromSelection(IReadOnlyList selections, int depth) - { - var path = Path.Root; - for (var j = 0; j < depth; j++) - { - path = path.Append(selections[j].ResponseName); - } - - return path; - } - - private static Path CreatePath(ResultData parent, object segmentValue) - { - var segments = ArrayPool.Shared.Rent(InitialPathLength); - segments[0] = segmentValue; - var current = parent; - var length = Build(segments, ref current); - var path = CreatePath(current.PatchPath, segments, length); - ArrayPool.Shared.Return(segments); - return path; - } - - private static Path CreatePath(ResultData parent) - { - var segments = ArrayPool.Shared.Rent(InitialPathLength); - var current = parent; - var length = Build(segments, ref current, 0); - var path = CreatePath(current.PatchPath, segments, length); - ArrayPool.Shared.Return(segments); - return path; - } - - private static Path CreatePath(Path? patchPath, object[] segments, int length) - { - var root = patchPath ?? Path.Root; - var path = root.Append((string)segments[length - 1]); - - if (length > 1) - { - for (var i = length - 2; i >= 0; i--) - { - path = segments[i] switch - { - string s => path.Append(s), - int n => path.Append(n), - _ => path - }; - } - } - - return path; - } - - private static int Build(object[] segments, ref ResultData parent, int start = 1) - { - var segment = start; - var current = parent; - - while (current.Parent is not null) - { - if (segments.Length <= segment) - { - var temp = ArrayPool.Shared.Rent(segments.Length * 2); - segments.AsSpan().CopyTo(temp); - ArrayPool.Shared.Return(segments); - segments = temp; - } - - var i = current.ParentIndex; - var p = current.Parent; - - switch (p) - { - case ObjectResult o: - var field = o[i]; - - if (!field.IsInitialized) - { - throw new InvalidOperationException("Cannot build path from an uninitialized field."); - } - - segments[segment++] = field.Name; - current = o; - break; - - case ListResult l: - segments[segment++] = i; - current = l; - break; - - default: - throw new NotSupportedException($"{p.GetType().FullName} is not a supported parent type."); - } - } - - parent = current; - return segment; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs index 0953a0a3c5e..cec7f1fa841 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs @@ -23,16 +23,16 @@ private static async Task ExecuteInternalAsync( OperationContext operationContext, IImmutableDictionary scopedContext) { - var resultMap = EnqueueResolverTasks( + EnqueueResolverTasks( operationContext, - operationContext.Operation.RootSelectionSet, operationContext.RootValue, - Path.Root, - scopedContext); + operationContext.ResultDocument.Data, + scopedContext, + Path.Root); await operationContext.Scheduler.ExecuteAsync().ConfigureAwait(false); - return operationContext.SetData(resultMap).BuildResult(); + return operationContext.BuildResult(); } public async Task ExecuteBatchAsync( @@ -62,14 +62,12 @@ private static void FillSchedulerWithWork( var context = contextOwner.OperationContext; context.Scheduler = scheduler; - var resultMap = EnqueueResolverTasks( + EnqueueResolverTasks( context, - context.Operation.RootSelectionSet, context.RootValue, - Path.Root, - scopedContext); - - context.SetData(resultMap); + context.ResultDocument.Data, + scopedContext, + Path.Root); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs deleted file mode 100644 index 4278df600a1..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResult.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System.Collections; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text.Json; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents an optimized list result that is used by the execution engine -/// to store completed elements. -/// -public sealed class ListResult : ResultData, IReadOnlyList -{ - private object?[] _buffer = []; - private int _capacity; - private int _count; - - /// - /// Gets the number of elements this list can hold. - /// - public int Capacity => _capacity; - - /// - /// Gets the number of elements in this list. - /// - public int Count => _count; - - /// - public object? this[int index] => _buffer[index]; - - /// - /// Defines if the elements of this list are nullable. - /// - internal bool IsNullable { get; set; } - - internal int AddUnsafe(object? item) - { - var index = _count++; - _buffer[index] = item; - return index; - } - - internal int AddUnsafe(ResultData? item) - { - var index = _count++; - item?.SetParent(this, index); - _buffer[index] = item; - return index; - } - - internal void SetUnsafe(int index, object? item) - { - _buffer[index] = item; - } - - internal void SetUnsafe(int index, ResultData? item) - { - item?.SetParent(this, index); - _buffer[index] = item; - } - - internal bool TrySetNull(int index) - { - if (_count > index) - { - _buffer[index] = null; - return IsNullable; - } - - return false; - } - - /// - /// Ensures that the result object has enough capacity on the buffer - /// to store the expected fields. - /// - /// - /// The capacity needed. - /// - internal void EnsureCapacity(int requiredCapacity) - { - // If this list has a capacity specified we will reset it. - // The capacity is only set when the list is rented out, - // Once the item is returned the capacity is reset to zero. - if (_capacity > 0) - { - Reset(); - } - - if (_buffer.Length < requiredCapacity) - { - Array.Resize(ref _buffer, requiredCapacity); - } - - _capacity = requiredCapacity; - } - - /// - /// Grows the internal capacity. - /// - internal void Grow() - { - if (_capacity == 0) - { - EnsureCapacity(4); - return; - } - - var newCapacity = _capacity * 2; - Array.Resize(ref _buffer, newCapacity); - _capacity = newCapacity; - } - - public override void WriteTo( - Utf8JsonWriter writer, - JsonSerializerOptions? options = null, - JsonNullIgnoreCondition nullIgnoreCondition = JsonNullIgnoreCondition.None) - { -#if NET9_0_OR_GREATER - options ??= JsonSerializerOptions.Web; -#else - options ??= JsonSerializerOptions.Default; -#endif - - writer.WriteStartArray(); - - ref var item = ref GetReference(); - ref var end = ref Unsafe.Add(ref item, _count); - - while (Unsafe.IsAddressLessThan(ref item, ref end)) - { - if (item is null) - { - if ((nullIgnoreCondition & JsonNullIgnoreCondition.Lists) != JsonNullIgnoreCondition.Lists) - { - writer.WriteNullValue(); - } - } - else - { - if (item is ResultData resultData) - { - resultData.WriteTo(writer, options, nullIgnoreCondition); - } - else - { - JsonValueFormatter.WriteValue(writer, item, options, nullIgnoreCondition); - } - } - - item = ref Unsafe.Add(ref item, 1)!; - } - - writer.WriteEndArray(); - } - - /// - /// Resets the result object. - /// - internal void Reset() - { - if (_capacity > 0) - { - _buffer.AsSpan()[.._capacity].Clear(); - _capacity = 0; - _count = 0; - } - - IsInvalidated = false; - ParentIndex = 0; - Parent = null; - PatchId = 0; - PatchPath = null; - } - - private ref object? GetReference() - => ref MemoryMarshal.GetReference(_buffer.AsSpan()); - - /// - public IEnumerator GetEnumerator() - { - for (var i = 0; i < _count; i++) - { - yield return _buffer[i]; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs deleted file mode 100644 index f2ff62fee19..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ListResultPool.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Extensions.ObjectPool; - -namespace HotChocolate.Execution.Processing; - -internal sealed class ListResultPool(int maximumRetained, int maxAllowedCapacity, int bucketSize) - : DefaultObjectPool>(new BufferPolicy(maxAllowedCapacity, bucketSize), maximumRetained) -{ - private sealed class BufferPolicy(int maxAllowedCapacity, int bucketSize) - : PooledObjectPolicy> - { - private readonly ObjectPolicy _objectPolicy = new(maxAllowedCapacity); - - public override ResultBucket Create() - => new(bucketSize, _objectPolicy); - - public override bool Return(ResultBucket obj) - { - obj.Reset(); - return true; - } - } - - private sealed class ObjectPolicy(int maxAllowedCapacity) - : PooledObjectPolicy - { - public override ListResult Create() => new(); - - public override bool Return(ListResult obj) - { - if (obj.Count > maxAllowedCapacity) - { - obj.Reset(); - return false; - } - - obj.Reset(); - return true; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs deleted file mode 100644 index 09fbb050557..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectFieldResult.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -public sealed class ObjectFieldResult -{ - private Flags _flags = Flags.Nullable; - private string _name = null!; - private object? _value; - - public string Name => _name; - - public object? Value => _value; - - internal bool IsNullable => (_flags & Flags.Nullable) == Flags.Nullable; - - internal bool IsInitialized => (_flags & Flags.Initialized) == Flags.Initialized; - - internal void Set(string name, object? value, bool isNullable) - { - _name = name; - _value = value; - _flags = isNullable ? Flags.InitializedAndNullable : Flags.Initialized; - } - - internal bool TrySetNull() - { - _value = null; - return (_flags & Flags.InitializedAndNullable) == Flags.InitializedAndNullable; - } - - internal void Reset() - { - _name = null!; - _value = null; - _flags = Flags.Nullable; - } - - [Flags] - private enum Flags : byte - { - Initialized = 1, - Nullable = 2, - InitializedAndNullable = Initialized | Nullable - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs deleted file mode 100644 index cd6fb31319b..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResult.cs +++ /dev/null @@ -1,301 +0,0 @@ -using System.Collections; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text.Json; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents an optimized object result that is used by the execution engine -/// to store completed values. -/// -public sealed class ObjectResult - : ResultData - , IReadOnlyDictionary - , IEnumerable -{ - private ObjectFieldResult[] _buffer = []; - private int _capacity; - - /// - /// Gets the capacity of this object result. - /// It essentially specifies how many field results can be stored. - /// - internal int Capacity => _capacity; - - /// - /// This indexer allows direct access to the underlying buffer - /// to access a . - /// - internal ObjectFieldResult this[int index] => _buffer[index]; - - /// - /// Gets a reference to the first in the buffer. - /// - private ref ObjectFieldResult GetReference() - => ref MemoryMarshal.GetReference(_buffer.AsSpan()); - - /// - /// Sets a field value in the buffer. - /// Note: Set will not validate if the buffer has enough space. - /// - /// - /// The index in the buffer on which the value shall be stored. - /// - /// - /// The name of the field. - /// - /// - /// The field value. - /// - /// - /// Specifies if the value is allowed to be null. - /// - internal void SetValueUnsafe(int index, string name, object? value, bool isNullable = true) - => _buffer[index].Set(name, value, isNullable); - - /// - /// Sets a field value in the buffer. - /// Note: Set will not validate if the buffer has enough space. - /// - /// - /// The index in the buffer on which the value shall be stored. - /// - /// - /// The name of the field. - /// - /// - /// The field value. - /// - /// - /// Specifies if the value is allowed to be null. - /// - internal void SetValueUnsafe(int index, string name, ResultData? value, bool isNullable = true) - { - value?.SetParent(this, index); - _buffer[index].Set(name, value, isNullable); - } - - /// - /// Removes a field value from the buffer. - /// Note: Remove will not validate if the buffer has enough space. - /// - /// - /// The index in the buffer on which the value shall be removed. - /// - internal void RemoveValueUnsafe(int index) - { - _buffer[index].Reset(); - } - - /// - /// Searches within the capacity of the buffer to find a field value that matches - /// the specified . - /// - /// - /// The name of the field to search for. - /// - /// - /// The index on the buffer where the field value is located. - /// - /// - /// Returns the field value or null. - /// - internal ObjectFieldResult? TryGetValue(string name, out int index) - { - ref var searchSpace = ref GetReference(); - - for (var i = 0; i < _capacity; i++) - { - var item = Unsafe.Add(ref searchSpace, i); - if (name.Equals(item.Name, StringComparison.Ordinal)) - { - index = i; - return item; - } - } - - index = -1; - return null; - } - - /// - /// Ensures that the result object has enough capacity on the buffer - /// to store the expected fields. - /// - /// - /// The capacity needed. - /// - internal void EnsureCapacity(int capacity) - { - if (_capacity > 0) - { - Reset(); - } - - if (_buffer.Length < capacity) - { - var oldCapacity = _buffer.Length; - Array.Resize(ref _buffer, capacity); - - for (var i = oldCapacity; i < _buffer.Length; i++) - { - _buffer[i] = new ObjectFieldResult(); - } - } - - _capacity = capacity; - } - - public override void WriteTo( - Utf8JsonWriter writer, - JsonSerializerOptions? options = null, - JsonNullIgnoreCondition nullIgnoreCondition = JsonNullIgnoreCondition.None) - { -#if NET9_0_OR_GREATER - options ??= JsonSerializerOptions.Web; -#else - options ??= JsonSerializerOptions.Default; -#endif - - writer.WriteStartObject(); - - ref var field = ref GetReference(); - ref var end = ref Unsafe.Add(ref field, _capacity); - - while (Unsafe.IsAddressLessThan(ref field, ref end)) - { - if (field.IsInitialized) - { - switch (field.Value) - { - case null: - if ((nullIgnoreCondition & JsonNullIgnoreCondition.Fields) == JsonNullIgnoreCondition.Fields) - { - break; - } - - writer.WriteNull(field.Name); - break; - - case ResultData resultData: - writer.WritePropertyName(field.Name); - resultData.WriteTo(writer, options, nullIgnoreCondition); - break; - - default: - writer.WritePropertyName(field.Name); - JsonValueFormatter.WriteValue(writer, field.Value, options, nullIgnoreCondition); - break; - } - } - - field = ref Unsafe.Add(ref field, 1)!; - } - - writer.WriteEndObject(); - } - - /// - /// Resets the result object. - /// - internal void Reset() - { - ref var searchSpace = ref GetReference(); - - for (var i = 0; i < _capacity; i++) - { - Unsafe.Add(ref searchSpace, i).Reset(); - } - - _capacity = 0; - IsInvalidated = false; - ParentIndex = 0; - Parent = null; - PatchId = 0; - PatchPath = null; - } - - object? IReadOnlyDictionary.this[string key] - => TryGetValue(key, out _)?.Value; - - IEnumerable IReadOnlyDictionary.Keys - { - get - { - for (var i = 0; i < _capacity; i++) - { - var fieldResult = _buffer[i]; - - if (fieldResult.IsInitialized) - { - yield return fieldResult.Name; - } - } - } - } - - IEnumerable IReadOnlyDictionary.Values - { - get - { - for (var i = 0; i < _capacity; i++) - { - var fieldResult = _buffer[i]; - - if (fieldResult.IsInitialized) - { - yield return fieldResult.Value; - } - } - } - } - - int IReadOnlyCollection>.Count => _capacity; - - bool IReadOnlyDictionary.ContainsKey(string key) - => TryGetValue(key, out _)?.Name is not null; - - bool IReadOnlyDictionary.TryGetValue(string key, out object? value) - { - var field = TryGetValue(key, out _); - - if (field?.Name is not null) - { - value = field.Value; - return true; - } - - value = null; - return false; - } - - public IEnumerator GetEnumerator() - { - for (var i = 0; i < _capacity; i++) - { - var field = _buffer[i]; - - if (field.IsInitialized) - { - yield return field; - } - } - } - - IEnumerator> - IEnumerable>.GetEnumerator() - { - for (var i = 0; i < _capacity; i++) - { - var field = _buffer[i]; - - if (field.IsInitialized) - { - yield return new KeyValuePair(field.Name, field.Value); - } - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs deleted file mode 100644 index 4e2c4fad373..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Runtime.CompilerServices; -using HotChocolate.Types; - -namespace HotChocolate.Execution.Processing; - -internal static class ObjectResultExtensions -{ - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InitValueUnsafe(this ObjectResult result, int index, ISelection selection) - => result.SetValueUnsafe(index, selection.ResponseName, null, selection.Type.Kind is not TypeKind.NonNull); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs deleted file mode 100644 index 9134c068f54..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ObjectResultPool.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Extensions.ObjectPool; - -namespace HotChocolate.Execution.Processing; - -internal sealed class ObjectResultPool(int maximumRetained, int maxAllowedCapacity, int bucketSize) - : DefaultObjectPool>(new BufferPolicy(maxAllowedCapacity, bucketSize), maximumRetained) -{ - private sealed class BufferPolicy(int maxAllowedCapacity, int bucketSize) - : PooledObjectPolicy> - { - private readonly ObjectPolicy _objectPolicy = new(maxAllowedCapacity); - - public override ResultBucket Create() - => new(bucketSize, _objectPolicy); - - public override bool Return(ResultBucket obj) - { - obj.Reset(); - return true; - } - } - - private sealed class ObjectPolicy(int maxAllowedCapacity) - : PooledObjectPolicy - { - public override ObjectResult Create() => new(); - - public override bool Return(ObjectResult obj) - { - if (obj.Capacity > maxAllowedCapacity) - { - obj.Reset(); - return false; - } - - obj.Reset(); - return true; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs deleted file mode 100644 index aa4260e50f6..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBucket.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Microsoft.Extensions.ObjectPool; - -namespace HotChocolate.Execution.Processing; - -internal sealed class ResultBucket where T : class -{ - private readonly int _capacity; - private readonly IPooledObjectPolicy _policy; - private readonly T?[] _buffer; - private int _index; - - public ResultBucket(int capacity, IPooledObjectPolicy policy) - { - _capacity = capacity; - _policy = policy; - _buffer = new T[capacity]; - } - - public T Pop() - { - if (TryPop(out var obj)) - { - return obj; - } - - throw new InvalidOperationException("Buffer is used up."); - } - - public bool TryPop([NotNullWhen(true)] out T? obj) - { - var nextIndex = Interlocked.Increment(ref _index); - if (nextIndex < _capacity) - { - var buffered = _buffer[nextIndex]; - - if (buffered is not null) - { - obj = buffered; - return true; - } - - obj = _policy.Create(); - _buffer[nextIndex] = obj; - return true; - } - - obj = null; - return false; - } - - public void Reset() - { - if (_index == 0) - { - return; - } - - if (_index >= _capacity) - { - _index = _capacity; - } - - ref var mem = ref MemoryMarshal.GetReference(_buffer.AsSpan()); - ref var end = ref Unsafe.Add(ref mem, _index); - - while (Unsafe.IsAddressLessThan(ref mem, ref end)) - { - if (mem is not null && !_policy.Return(mem)) - { - mem = null; - } - - mem = ref Unsafe.Add(ref mem, 1); - } - - _index = 0; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs deleted file mode 100644 index 2eda9295e82..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.NonNullHandling.cs +++ /dev/null @@ -1,45 +0,0 @@ -using HotChocolate.Language; -using static HotChocolate.Execution.ErrorHelper; - -namespace HotChocolate.Execution.Processing; - -internal sealed partial class ResultBuilder -{ - private void ApplyNonNullViolations( - List errors, - List violations, - HashSet fieldErrors) - { - if (violations.Count == 0) - { - return; - } - - var errorHandler = _context.Schema.Services.GetRequiredService(); - - while (violations.TryPop(out var violation)) - { - if (fieldErrors.Contains(violation.Selection)) - { - continue; - } - - if (_errorPaths.Contains(violation.Path)) - { - continue; - } - - var error = NonNullOutputFieldViolation(violation.Path, violation.Selection.GetSyntaxNodes().First()); - error = errorHandler.Handle(error); - _diagnosticEvents.ResolverError(_context, violation.Selection, error); - errors.Add(error); - } - } - - private sealed class NonNullViolation(ISelection selection, Path path) - { - public ISelection Selection { get; } = selection; - - public Path Path { get; } = path; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs deleted file mode 100644 index 73a5ced5248..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.ObjectResult.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -internal sealed partial class ResultBuilder -{ - private readonly ResultPool _resultPool; - private readonly object _objectSync = new(); - private ResultBucket _objectBucket = null!; - private readonly object _listSync = new(); - private ResultBucket _listBucket = null!; - - public ObjectResult RentObject(int capacity) - { - while (true) - { - if (_objectBucket.TryPop(out var obj)) - { - obj.EnsureCapacity(capacity); - return obj; - } - - lock (_objectSync) - { - _objectBucket = _resultPool.GetObjectBucket(); - _resultOwner.ObjectBuckets.Add(_objectBucket); - } - } - } - - public ListResult RentList(int capacity) - { - while (true) - { - if (_listBucket.TryPop(out var obj)) - { - obj.EnsureCapacity(capacity); - return obj; - } - - lock (_listSync) - { - _listBucket = _resultPool.GetListBucket(); - _resultOwner.ListBuckets.Add(_listBucket); - } - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs deleted file mode 100644 index c0a131faae2..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.Pooling.cs +++ /dev/null @@ -1,58 +0,0 @@ -using HotChocolate.Execution.Instrumentation; - -namespace HotChocolate.Execution.Processing; - -internal sealed partial class ResultBuilder -{ - private RequestContext _context = null!; - private IExecutionDiagnosticEvents _diagnosticEvents = null!; - - public ResultBuilder(ResultPool resultPool) - { - _resultPool = resultPool; - InitializeResult(); - } - - public void Initialize( - RequestContext context, - IExecutionDiagnosticEvents diagnosticEvents) - { - _context = context; - _diagnosticEvents = diagnosticEvents; - } - - public void Clear() - { - _errors.Clear(); - _errorPaths.Clear(); - _fieldErrors.Clear(); - _nonNullViolations.Clear(); - _extensions.Clear(); - _contextData.Clear(); - _cleanupTasks.Clear(); - _removedResults.Clear(); - _patchIds.Clear(); - - InitializeResult(); - - _context = null!; - _diagnosticEvents = null!; - _data = null; - _items = null; - _path = null; - _label = null; - _hasNext = null; - _requestIndex = null; - _variableIndex = null; - _singleErrorPerPath = false; - } - - private void InitializeResult() - { - _resultOwner = new ResultMemoryOwner(_resultPool); - _objectBucket = _resultPool.GetObjectBucket(); - _resultOwner.ObjectBuckets.Add(_objectBucket); - _listBucket = _resultPool.GetListBucket(); - _resultOwner.ListBuckets.Add(_listBucket); - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs deleted file mode 100644 index 653ea7c7d95..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultBuilder.cs +++ /dev/null @@ -1,339 +0,0 @@ -using System.Buffers; -using System.Runtime.CompilerServices; -using HotChocolate.Properties; -using HotChocolate.Resolvers; - -namespace HotChocolate.Execution.Processing; - -internal sealed partial class ResultBuilder -{ - private readonly List _errors = []; - private readonly HashSet _errorPaths = []; - private readonly HashSet _fieldErrors = []; - private readonly List _nonNullViolations = []; - private readonly HashSet _removedResults = []; - private readonly HashSet _patchIds = []; - - private readonly Dictionary _extensions = []; - private readonly Dictionary _contextData = []; - private readonly List> _cleanupTasks = []; - - private ResultMemoryOwner _resultOwner = null!; - private ObjectResult? _data; - private IReadOnlyList? _items; - private Path? _path; - private string? _label; - private bool? _hasNext; - private int? _requestIndex; - private int? _variableIndex; - private bool _singleErrorPerPath; - - public IReadOnlyList Errors => _errors; - - public void SetData(ObjectResult? data) - { - if (_items is not null) - { - throw new InvalidOperationException( - Resources.ResultBuilder_DataAndItemsNotAllowed); - } - - _data = data; - } - - public void SetItems(IReadOnlyList items) - { - if (_data is not null) - { - throw new InvalidOperationException( - Resources.ResultBuilder_DataAndItemsNotAllowed); - } - - _items = items; - } - - public void SetExtension(string key, object? value) - { - lock (_extensions) - { - _extensions[key] = value; - } - } - - public void SetExtension(string key, UpdateState value) - { - lock (_extensions) - { - if (_extensions.TryGetValue(key, out var current) && current is T casted) - { - _extensions[key] = value(key, casted); - } - else - { - _extensions[key] = value(key, default!); - } - } - } - - public void SetExtension(string key, TState state, UpdateState value) - { - lock (_extensions) - { - if (_extensions.TryGetValue(key, out var current) && current is T casted) - { - _extensions[key] = value(key, casted, state); - } - else - { - _extensions[key] = value(key, default!, state); - } - } - } - - public void SetContextData(string key, object? value) - { - lock (_contextData) - { - _contextData[key] = value; - } - } - - public void SetContextData(string key, UpdateState value) - { - lock (_contextData) - { - _contextData.TryGetValue(key, out var current); - _contextData[key] = value(key, current); - } - } - - public void SetContextData(string key, TState state, UpdateState value) - { - lock (_contextData) - { - _contextData.TryGetValue(key, out var current); - _contextData[key] = value(key, current, state); - } - } - - /// - /// Register cleanup tasks that will be executed after resolver execution is finished. - /// - /// - /// Cleanup action. - /// - public void RegisterForCleanup(Func action) - { - lock (_cleanupTasks) - { - _cleanupTasks.Add(action); - } - } - - public void RegisterForCleanup(T state, Func action) - { - lock (_cleanupTasks) - { - _cleanupTasks.Add(() => action(state)); - } - } - - public void RegisterForCleanup(T state) where T : IDisposable - { - lock (_cleanupTasks) - { - _cleanupTasks.Add( - () => - { - state.Dispose(); - return default!; - }); - } - } - - public void SetPath(Path? path) - => _path = path; - - public void SetLabel(string? label) - => _label = label; - - public void SetHasNext(bool value) - => _hasNext = value; - - public void SetSingleErrorPerPath(bool value = true) - { - _singleErrorPerPath = value; - } - - public void AddError(IError error, ISelection? selection = null) - { - lock (_errors) - { - if (!_singleErrorPerPath || error.Path is null || _errorPaths.Add(error.Path)) - { - _errors.Add(error); - } - - if (selection is not null) - { - _fieldErrors.Add(selection); - } - } - } - - public void AddNonNullViolation(ISelection selection, Path path) - { - var violation = new NonNullViolation(selection, path); - - lock (_errors) - { - _nonNullViolations.Add(violation); - } - } - - public void AddRemovedResult(ResultData result) - { - if (result.PatchId <= 0) - { - return; - } - - lock (_errors) - { - _removedResults.Add(result.PatchId); - } - } - - public void AddPatchId(uint patchId) - { - lock (_patchIds) - { - _patchIds.Add(patchId); - } - } - - public void SetRequestIndex(int requestIndex) - => _requestIndex = requestIndex; - - public void SetVariableIndex(int variableIndex) - => _variableIndex = variableIndex; - - // ReSharper disable InconsistentlySynchronizedField - public IOperationResult BuildResult() - { - ApplyNonNullViolations(_errors, _nonNullViolations, _fieldErrors); - - if (_data?.IsInvalidated == true) - { - // The non-null violation cased the whole result being deleted. - _data = null; - _resultOwner.Dispose(); - } - - if (_data is null && _items is null && _errors.Count == 0 && _hasNext is not false) - { - throw new InvalidOperationException(Resources.ResultHelper_BuildResult_InvalidResult); - } - - if (_errors.Count > 1) - { - _errors.Sort(ErrorComparer.Default); - } - - _removedResults.Remove(0); - - if (_removedResults.Count > 0) - { - _contextData.Add(WellKnownContextData.RemovedResults, _removedResults.ToArray()); - } - - _patchIds.Remove(0); - - if (_patchIds.Count > 0) - { - _contextData.Add(WellKnownContextData.ExpectedPatches, _patchIds.ToArray()); - } - - Func[] cleanupTasks = []; - var cleanupTasksLength = _cleanupTasks.Count; - if (cleanupTasksLength > 0) - { - cleanupTasks = ArrayPool>.Shared.Rent(cleanupTasksLength); - for (var i = 0; i < cleanupTasksLength; i++) - { - cleanupTasks[i] = _cleanupTasks[i]; - } - } - - var result = new OperationResult( - _data, - _errors.Count == 0 ? null : _errors.ToArray(), - CreateExtensionData(_extensions), - CreateExtensionData(_contextData), - items: _items, - incremental: null, - label: _label, - path: _path, - hasNext: _hasNext, - cleanupTasks: (cleanupTasks, cleanupTasksLength), - isDataSet: true, - requestIndex: _requestIndex, - variableIndex: _variableIndex); - - if (_data is not null) - { - result.RegisterForCleanup(_resultOwner); - } - - return result; - } - - // ReSharper restore InconsistentlySynchronizedField - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Dictionary? CreateExtensionData(Dictionary data) - => data.Count == 0 ? null : new Dictionary(data); - - public void DiscardResult() - => _resultOwner.Dispose(); - - private sealed class ErrorComparer : IComparer - { - public int Compare(IError? x, IError? y) - { - if (ReferenceEquals(x, y)) - { - return 0; - } - - if (ReferenceEquals(null, y)) - { - return 1; - } - - if (ReferenceEquals(null, x)) - { - return -1; - } - - if (y.Locations?.Count > 0) - { - if (x.Locations?.Count > 0) - { - return x.Locations[0].CompareTo(y.Locations[0]); - } - - return 1; - } - - if (x.Locations?.Count > 0) - { - return -1; - } - - return 0; - } - - public static readonly ErrorComparer Default = new(); - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs deleted file mode 100644 index 3d8d79da9ef..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultData.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Text.Json; - -namespace HotChocolate.Execution.Processing; - -/// -/// Represents a result data object like an object or list. -/// -public abstract class ResultData : IResultDataJsonFormatter -{ - /// - /// Gets the parent result data object. - /// - protected internal ResultData? Parent { get; protected set; } - - /// - /// Gets the index under which this data is stored in the parent result. - /// - protected internal int ParentIndex { get; protected set; } - - /// - /// Defines that this result was invalidated by one task and can be discarded. - /// - protected internal bool IsInvalidated { get; set; } - - /// - /// Gets an internal ID that tracks result objects. - /// In most cases, this id is 0. But if this result object has - /// significance for deferred work, it will get assigned a proper id which - /// allows us to efficiently track if this result was deleted due to - /// non-null propagation. - /// - public uint PatchId { get; set; } - - /// - /// Gets an internal patch path that specifies from where this result was branched of. - /// - protected internal Path? PatchPath { get; set; } - - /// - /// Connects this result to the parent result. - /// - /// - /// The parent result. - /// - /// - /// The index under which this result is stored in the parent result. - /// - public void SetParent(ResultData parent, int index) - { - ArgumentOutOfRangeException.ThrowIfNegative(index); - - Parent = parent ?? throw new ArgumentNullException(nameof(parent)); - ParentIndex = index; - } - - /// - /// Writes the result data to the given . - /// - /// - /// The writer to write the result data to. - /// - /// - /// The serializer options to use. - /// - /// - /// The null ignore condition. - /// - public abstract void WriteTo( - Utf8JsonWriter writer, - JsonSerializerOptions? options = null, - JsonNullIgnoreCondition nullIgnoreCondition = JsonNullIgnoreCondition.None); -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs deleted file mode 100644 index 3a23e261eaf..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultMemoryOwner.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -internal sealed class ResultMemoryOwner : IDisposable -{ - private readonly ResultPool _resultPool; - private bool _disposed; - - public ResultMemoryOwner(ResultPool resultPool) - { - _resultPool = resultPool; - } - - public ObjectResult? Data { get; set; } - - public List> ObjectBuckets { get; } = []; - - public List> ListBuckets { get; } = []; - - public void Dispose() - { - if (!_disposed) - { - _resultPool.Return(ObjectBuckets); - _resultPool.Return(ListBuckets); - _disposed = true; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs deleted file mode 100644 index 729e0424dbf..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPool.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -internal sealed class ResultPool -{ - private readonly ObjectResultPool _objectResultPool; - private readonly ListResultPool _listResultPool; - - public ResultPool( - ObjectResultPool objectResultPool, - ListResultPool listResultPool) - { - _objectResultPool = objectResultPool; - _listResultPool = listResultPool; - } - - public ResultBucket GetObjectBucket() - => _objectResultPool.Get(); - - public ResultBucket GetListBucket() - => _listResultPool.Get(); - - public void Return(IList> buffers) - { - for (var i = 0; i < buffers.Count; i++) - { - _objectResultPool.Return(buffers[i]); - } - } - - public void Return(IList> buffers) - { - for (var i = 0; i < buffers.Count; i++) - { - _listResultPool.Return(buffers[i]); - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs deleted file mode 100644 index 4356e12589f..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Result/ResultPoolDefaults.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -internal static class ResultPoolDefaults -{ - public const int MaximumRetained = 512; - public const int BucketSize = 64; - public const int MaximumAllowedCapacity = 512; -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs index 66ec8dc8bfc..7b5f944f2da 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs @@ -12,11 +12,9 @@ internal sealed partial class ResolverTask /// The execution cancellation token. private void CompleteValue(bool success, CancellationToken cancellationToken) { - var responseIndex = _context.ResponseIndex; var responseName = _context.ResponseName; - var parentResult = _context.ParentResult; + var resultValue = _context.ResultValue; var result = _context.Result; - object? completedResult = null; try { @@ -24,7 +22,7 @@ private void CompleteValue(bool success, CancellationToken cancellationToken) if (success) { var completionContext = new ValueCompletionContext(_operationContext, _context, _taskBuffer); - completedResult = Complete(completionContext, _selection, parentResult, responseIndex, result); + Complete(completionContext, _selection, resultValue, result); } } catch (OperationCanceledException) @@ -42,16 +40,13 @@ private void CompleteValue(bool success, CancellationToken cancellationToken) if (!cancellationToken.IsCancellationRequested) { _context.ReportError(ex); - completedResult = null; + resultValue.SetNullValue(); } } - var isNonNullType = _selection.Type.Kind is TypeKind.NonNull; - _context.ParentResult.SetValueUnsafe(responseIndex, responseName, completedResult, !isNonNullType); - - if (completedResult is null && isNonNullType) + if (resultValue is { IsNullable: false, IsNullOrInvalidated: true }) { - PropagateNullValues(parentResult); + PropagateNullValues(resultValue); _completionStatus = ExecutionTaskStatus.Faulted; _operationContext.Result.AddNonNullViolation(_selection, _context.Path); _taskBuffer.Clear(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs index 0ffe890c8a2..f536c07f65c 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Execute.cs @@ -6,16 +6,12 @@ namespace HotChocolate.Execution.Processing.Tasks; internal sealed partial class ResolverTask { - private async Task ExecuteAsync(CancellationToken cancellationToken) + private async ValueTask ExecuteAsync(CancellationToken cancellationToken) { try { using (DiagnosticEvents.ResolveFieldValue(_context)) { - // we initialize the field, so we are able to propagate non-null violations - // through the result tree. - _context.ParentResult.InitValueUnsafe(_context.ResponseIndex, _context.Selection); - var success = await TryExecuteAsync(cancellationToken).ConfigureAwait(false); CompleteValue(success, cancellationToken); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs index a5d30fe42a4..50e086e5c8c 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.Pooling.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Text.Json; namespace HotChocolate.Execution.Processing.Tasks; @@ -8,18 +9,16 @@ internal sealed partial class ResolverTask /// Initializes this task after it is retrieved from its pool. /// public void Initialize( - OperationContext operationContext, - Selection selection, - ObjectResult parentResult, - int responseIndex, object? parent, + Selection selection, + ResultElement resultValue, + OperationContext operationContext, IImmutableDictionary scopedContextData, Path? path) { _operationContext = operationContext; _selection = selection; - _context.Initialize(operationContext, selection, parentResult, responseIndex, parent, scopedContextData, path); - ParentResult = parentResult; + _context.Initialize(parent, selection, resultValue, operationContext, scopedContextData, path); IsSerial = selection.Strategy is SelectionExecutionStrategy.Serial; } @@ -33,7 +32,6 @@ internal bool Reset() _operationContext = null!; _selection = null!; _context.Clean(); - ParentResult = null!; Status = ExecutionTaskStatus.WaitingToRun; IsSerial = false; IsRegistered = false; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs index 277a00bd565..07244b911ab 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.cs @@ -53,11 +53,6 @@ public ExecutionTaskKind Kind /// public IExecutionTask? Previous { get; set; } - /// - /// Gets access to the internal result map into which the task will write the result. - /// - public ObjectResult ParentResult { get; private set; } = null!; - /// public object? State { get; set; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index d48b6592620..6db66a53bb4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -1,8 +1,8 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Runtime.InteropServices; +using HotChocolate.Text.Json; using HotChocolate.Types; -using static HotChocolate.Execution.Processing.PathHelper; using static HotChocolate.Execution.Processing.ValueCompletion; namespace HotChocolate.Execution.Processing.Tasks; @@ -13,18 +13,16 @@ internal static class ResolverTaskFactory static ResolverTaskFactory() { } - public static ObjectResult EnqueueResolverTasks( + public static void EnqueueResolverTasks( OperationContext operationContext, - SelectionSet selectionSet, object? parent, - Path path, + ResultElement parentResult, IImmutableDictionary scopedContext, - ObjectResult? parentResult = null) + Path path) { + var selectionSet = parentResult.AssertSelectionSet(); var selections = selectionSet.Selections; - var selectionsCount = selections.Length; - var responseIndex = selectionsCount; - parentResult ??= operationContext.Result.RentObject(selectionsCount); + var scheduler = operationContext.Scheduler; var includeFlags = operationContext.IncludeFlags; var final = !selectionSet.IsConditional; @@ -40,7 +38,7 @@ public static ObjectResult EnqueueResolverTasks( // the scheduler tries to schedule new work first. // coincidentally we can use that to schedule a mutation so that we honor the spec // guarantees while executing efficient. - for (var i = selectionsCount - 1; i >= 0; i--) + for (var i = selections.Length - 1; i >= 0; i--) { var selection = selections[i]; @@ -48,10 +46,9 @@ public static ObjectResult EnqueueResolverTasks( { bufferedTasks.Add( operationContext.CreateResolverTask( - selection, parent, + selection, parentResult, - --responseIndex, scopedContext)); } } @@ -59,15 +56,13 @@ public static ObjectResult EnqueueResolverTasks( if (bufferedTasks.Count == 0) { // in the case all root fields are skipped we execute a dummy task in order - // to not have to many extra API for this special case. + // to not have extra logic for this case. scheduler.Register(new NoOpExecutionTask(operationContext)); } else { scheduler.Register(CollectionsMarshal.AsSpan(bufferedTasks)); } - - return parentResult; } finally { @@ -77,6 +72,7 @@ public static ObjectResult EnqueueResolverTasks( } // TODO : remove ? + /* public static ResolverTask EnqueueElementTasks( OperationContext operationContext, Selection selection, @@ -125,6 +121,7 @@ public static ResolverTask EnqueueElementTasks( return resolverTask; } + */ public static ObjectResult? EnqueueOrInlineResolverTasks( ValueCompletionContext context, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs index a2866256f59..7fdaf7aa7d2 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs @@ -1,49 +1,48 @@ +using HotChocolate.Text.Json; using HotChocolate.Types; using HotChocolate.Utilities; using static HotChocolate.Execution.ErrorHelper; -using static HotChocolate.Execution.Processing.PathHelper; namespace HotChocolate.Execution.Processing; internal static partial class ValueCompletion { - private static object? CompleteLeafValue( + private static void CompleteLeafValue( ValueCompletionContext context, Selection selection, - IType type, - ResultData parent, - int index, - object? result) + ILeafType2 type, + ResultElement resultValue, + object? runtimeValue) { var operationContext = context.OperationContext; var resolverContext = context.ResolverContext; try { - var leafType = (ILeafType)type; - var runtimeType = leafType.ToRuntimeType(); + var runtimeType = type.ToRuntimeType(); - if (!runtimeType.IsInstanceOfType(result) - && operationContext.Converter.TryConvert(runtimeType, result, out var c)) + if (!runtimeType.IsInstanceOfType(runtimeValue) + && operationContext.Converter.TryConvert(runtimeType, runtimeValue, out var c)) { - result = c; + runtimeValue = c; } - return leafType.Serialize(result); + type.Serialize(runtimeValue, resultValue); + return; } catch (SerializationException ex) { - var errorPath = CreatePathFromContext(selection, parent, index); + var errorPath = resultValue.Path; var error = InvalidLeafValue(ex, selection, errorPath); operationContext.ReportError(error, resolverContext, selection); } catch (Exception ex) { - var errorPath = CreatePathFromContext(selection, parent, index); + var errorPath = resultValue.Path; var error = UnexpectedLeafValueSerializationError(ex, selection, errorPath); operationContext.ReportError(error, resolverContext, selection); } - return null; + resultValue.SetNullValue(); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs index cfa0ba15099..892bf5176ed 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs @@ -1,8 +1,8 @@ using System.Collections; using System.Text.Json; +using HotChocolate.Text.Json; using HotChocolate.Types; using static HotChocolate.Execution.ErrorHelper; -using static HotChocolate.Execution.Processing.PathHelper; namespace HotChocolate.Execution.Processing; @@ -156,46 +156,14 @@ private static bool TryCompleteElement( return list.IsNullable; } - internal static void PropagateNullValues(ResultData result) + internal static void PropagateNullValues(ResultElement result) { - if (result.IsInvalidated) - { - return; - } - - result.IsInvalidated = true; + result.Invalidate(); - while (result.Parent is not null) + while (result.IsInvalidated || result.IsInvalidated) { - var index = result.ParentIndex; - var parent = result.Parent; - - if (parent.IsInvalidated) - { - return; - } - - switch (parent) - { - case ObjectResult objectResult: - var field = objectResult[index]; - if (field.TrySetNull()) - { - return; - } - objectResult.IsInvalidated = true; - break; - - case ListResult listResult: - if (listResult.TrySetNull(index)) - { - return; - } - listResult.IsInvalidated = true; - break; - } + result = result.Parent; - result = parent; } } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs index 522a3698743..dc459f2c4ca 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs @@ -2,7 +2,6 @@ using HotChocolate.Types; using HotChocolate.Utilities; using static HotChocolate.Execution.ErrorHelper; -using static HotChocolate.Execution.Processing.PathHelper; using static HotChocolate.Execution.Processing.Tasks.ResolverTaskFactory; namespace HotChocolate.Execution.Processing; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs index 3eb8a859f72..c0605295da6 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs @@ -1,25 +1,23 @@ +using HotChocolate.Text.Json; using HotChocolate.Types; using static HotChocolate.Execution.ErrorHelper; -using static HotChocolate.Execution.Processing.PathHelper; namespace HotChocolate.Execution.Processing; internal static partial class ValueCompletion { - public static object? Complete( + public static void Complete( ValueCompletionContext context, Selection selection, - ResultData parent, - int index, + ResultElement resultValue, object? result) - => Complete(context, selection, selection.Type, parent, index, result); + => Complete(context, selection, selection.Type, resultValue, index, result); - public static object? Complete( + public static void Complete( ValueCompletionContext context, Selection selection, IType type, - ResultData parent, - int index, + ResultElement parent, object? result) { var typeKind = type.Kind; @@ -32,27 +30,29 @@ internal static partial class ValueCompletion if (result is null) { - return null; + parent.SetNullValue(); + return; } - if (typeKind is TypeKind.Scalar or TypeKind.Enum) + switch (typeKind) { - return CompleteLeafValue(context, selection, type, parent, index, result); + case TypeKind.Scalar or TypeKind.Enum: + CompleteLeafValue(context, selection, type, parent, index, result); + break; + + case TypeKind.List: + return CompleteListValue(context, selection, type, parent, index, result); + + case TypeKind.Object or TypeKind.Interface or TypeKind.Union: + return CompleteCompositeValue(context, selection, type, parent, index, result); + + default: + { + var errorPath = CreatePathFromContext(selection, parent, index); + var error = UnexpectedValueCompletionError(selection, errorPath); + context.OperationContext.ReportError(error, context.ResolverContext, selection); + return null; + } } - - if (typeKind is TypeKind.List) - { - return CompleteListValue(context, selection, type, parent, index, result); - } - - if (typeKind is TypeKind.Object or TypeKind.Interface or TypeKind.Union) - { - return CompleteCompositeValue(context, selection, type, parent, index, result); - } - - var errorPath = CreatePathFromContext(selection, parent, index); - var error = UnexpectedValueCompletionError(selection, errorPath); - context.OperationContext.ReportError(error, context.ResolverContext, selection); - return null; } } diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 17b5240fe90..26d565a8354 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -239,6 +239,10 @@ True FetchingResources.resx + + + SubscriptionExecutor.cs + diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index d4fae9588fc..8bc813ba527 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -178,8 +178,8 @@ internal Path CreatePath(Cursor current) if (parentTokenType is ElementTokenType.StartArray) { // arrayIndex = abs(child) - (abs(parent) + 1) - var absChild = c.Chunk * Cursor.RowsPerChunk + c.Row; - var absParent = parentCursor.Chunk * Cursor.RowsPerChunk + parentCursor.Row; + var absChild = (c.Chunk * Cursor.RowsPerChunk) + c.Row; + var absParent = (parentCursor.Chunk * Cursor.RowsPerChunk) + parentCursor.Row; var arrayIndex = absChild - (absParent + 1); path = path.Append(arrayIndex); } diff --git a/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs b/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs index e0b4e7fe862..1703bffc19d 100644 --- a/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs @@ -1,4 +1,5 @@ using HotChocolate.Language; +using HotChocolate.Text.Json; // ReSharper disable once CheckNamespace namespace HotChocolate.Types; @@ -110,3 +111,63 @@ public interface ILeafType : IInputTypeDefinition, IOutputTypeDefinition /// bool TryDeserialize(object? resultValue, out object? runtimeValue); } + +/// +/// Represents a GraphQL leaf-type e.g., scalar or enum. +/// +public interface ILeafType2 : IInputTypeDefinition, IOutputTypeDefinition +{ + /// + /// Defines if the given is possibly of this type. + /// + /// + /// The runtime value which shall be validated. + /// + /// + /// true if the given is possibly of this type. + /// + bool IsInstanceOfType(object? runtimeValue); + + /// + /// Parses the GraphQL value syntax of this type into a runtime value representation. + /// + /// + /// A GraphQL value syntax representation of this type. + /// + /// + /// Returns a runtime value representation of this type. + /// + object? ParseLiteral(IValueNode valueSyntax); + + /// + /// Parses a runtime value of this type into a GraphQL value syntax representation. + /// + /// + /// A result value representation of this type. + /// + /// + /// Returns a GraphQL value syntax representation of the . + /// + /// + /// Unable to parse the given + /// into a GraphQL value syntax representation of this type. + /// + IValueNode ParseValue(object? runtimeValue); + + /// + /// Serializes a runtime value of this type to the result value format. + /// + /// + /// A runtime value representation of this type. + /// + /// + /// + /// + /// + /// Returns a result value representation of this type. + /// + /// + /// Unable to serialize the given . + /// + void Serialize(object? runtimeValue, ResultElement resultValue); +} From a25b01059250da320fb2193d718950865ce50856 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 15 Dec 2025 09:13:51 +0100 Subject: [PATCH 32/42] wip --- .../Factories/OperationContextFactory.cs | 2 - .../Internal/MiddlewareContextMarshal.cs | 75 ---------- .../Processing/MiddlewareContext.Pooling.cs | 1 - .../Processing/MiddlewareContext.Pure.cs | 21 +-- .../Processing/MiddlewareContext.Selection.cs | 7 +- .../Processing/MiddlewareContext.State.cs | 1 + .../Processing/OperationContext.Execution.cs | 14 +- .../OperationContext.IExecutionTaskContext.cs | 5 +- .../Processing/OperationContext.Pooling.cs | 39 ++--- .../Execution/Processing/QueryExecutor.cs | 4 +- .../Tasks/ResolverTask.CompleteValue.cs | 1 - .../Processing/Tasks/ResolverTaskFactory.cs | 134 ++++-------------- .../Processing/ValueCompletion.Object.cs | 35 +++-- .../src/Types/Text/Json/ResultDocument.cs | 4 + 14 files changed, 87 insertions(+), 256 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs index 6f86b46fd29..f0e36070029 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/Factories/OperationContextFactory.cs @@ -19,7 +19,6 @@ namespace Microsoft.Extensions.DependencyInjection; /// internal sealed class OperationContextFactory( IFactory resolverTaskFactory, - ResultPool resultPool, ITypeConverter typeConverter, AggregateServiceScopeInitializer serviceScopeInitializer) : IFactory @@ -27,7 +26,6 @@ internal sealed class OperationContextFactory( public OperationContext Create() => new OperationContext( resolverTaskFactory, - new ResultBuilder(resultPool), typeConverter, serviceScopeInitializer); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs b/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs deleted file mode 100644 index 1d32ba7964d..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Internal/MiddlewareContextMarshal.cs +++ /dev/null @@ -1,75 +0,0 @@ -using HotChocolate.Execution.Processing; -using HotChocolate.Resolvers; - -namespace HotChocolate.Execution.Internal; - -/// -/// An unsafe class that provides a set of methods to access the -/// underlying data representations of the middleware context. -/// -public static class MiddlewareContextMarshal -{ - /// - /// Gets access to the result data of an object in the GraphQL execution. - /// ResultData is pooled and writing to it can corrupt the result. - /// Multiple threads might be writing into the result object. - /// - /// - /// The resolver context. - /// - /// - /// Returns the result data of the current resolver context. - /// - public static ObjectResult? GetParentResultUnsafe(IResolverContext context) - { - ArgumentNullException.ThrowIfNull(context); - - return context is MiddlewareContext middlewareContext - ? middlewareContext.ResultValue - : null; - } - - /// - /// Gets the parent result data of the current . - /// - /// - /// The result data for which to get the parent. - /// - /// - /// The type of the result data. - /// - /// - /// Returns the parent result data of the current . - /// - /// - /// Throws if is null. - /// - public static ResultData? GetParent(T resultData) where T : ResultData - { - ArgumentNullException.ThrowIfNull(resultData); - - return resultData.Parent; - } - - /// - /// Gets the index under which the is stored in the parent result. - /// - /// - /// The result data for which to get the parent index. - /// - /// - /// The type of the result data. - /// - /// - /// Returns the index under which the is stored in the parent result. - /// - /// - /// Throws if is null. - /// - public static int GetParentIndex(T resultData) where T : ResultData - { - ArgumentNullException.ThrowIfNull(resultData); - - return resultData.ParentIndex; - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs index 314510bea0c..49bcf648d8f 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pooling.cs @@ -58,7 +58,6 @@ public void Clean() LocalContextData = null!; IsResultModified = false; ValueType = null; - ResponseIndex = 0; ResultValue = default; HasErrors = false; Arguments = null!; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs index 896dd713716..a87acc09772 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Pure.cs @@ -3,6 +3,7 @@ using HotChocolate.Features; using HotChocolate.Language; using HotChocolate.Resolvers; +using HotChocolate.Text.Json; using HotChocolate.Types; using HotChocolate.Utilities; using static HotChocolate.Execution.ThrowHelper; @@ -16,19 +17,19 @@ private sealed class PureResolverContext(MiddlewareContext parentContext) : IRes private ITypeConverter? _typeConverter; private IReadOnlyDictionary _argumentValues = null!; private Selection _selection = null!; - private ObjectType _parentType = null!; - private ObjectResult _parentResult = null!; + private ObjectType _selectionSetType = null!; + private ResultElement _resultValue; private object? _parent; public bool Initialize( Selection selection, - ObjectType parentType, - ObjectResult parentResult, + ObjectType selectionSetType, + ResultElement resultValue, object? parent) { _selection = selection; - _parentType = parentType; - _parentResult = parentResult; + _selectionSetType = selectionSetType; + _resultValue = resultValue; _parent = parent; _argumentValues = selection.Arguments; @@ -49,21 +50,21 @@ public bool Initialize( public void Clear() { _selection = null!; - _parentType = null!; - _parentResult = null!; + _selectionSetType = null!; + _resultValue = default; _parent = null; _argumentValues = null!; } public Schema Schema => parentContext.Schema; - public ObjectType ObjectType => _parentType; + public ObjectType ObjectType => _selectionSetType; public Operation Operation => parentContext.Operation; public Selection Selection => _selection; - public Path Path => PathHelper.CreatePathFromContext(_selection, _parentResult, -1); + public Path Path => _resultValue.Path; public ulong IncludeFlags => parentContext.IncludeFlags; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs index 549e9eca418..22ee26c41ce 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Selection.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using HotChocolate.Resolvers; +using HotChocolate.Text.Json; using HotChocolate.Types; namespace HotChocolate.Execution.Processing; @@ -23,12 +24,12 @@ internal partial class MiddlewareContext public bool TryCreatePureContext( Selection selection, - ObjectType parentType, - ObjectResult parentResult, + ObjectType selectionSetType, + ResultElement resultValue, object? parent, [NotNullWhen(true)] out IResolverContext? context) { - if (_childContext.Initialize(selection, parentType, parentResult, parent)) + if (_childContext.Initialize(selection, selectionSetType, resultValue, parent)) { context = _childContext; return true; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs index 5af573e6aee..b3cf76ae8d9 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs @@ -17,6 +17,7 @@ internal partial class MiddlewareContext public IImmutableDictionary LocalContextData { get; set; } = null!; + // TODO : Remove? public IType? ValueType { get; set; } public ResultElement ResultValue { get; private set; } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs index f5fc05827e6..2c8130038a0 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs @@ -22,19 +22,7 @@ internal set } } - /// - /// The result helper which provides utilities to build up the result. - /// - public ResultBuilder Result - { - get - { - AssertInitialized(); - return _resultBuilder; - } - } - - public ResultDocument ResultDocument => throw new NotImplementedException(); + public ResultDocument Result => _resultDocument; public RequestContext RequestContext { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs index 511ede6b1cc..45508919dfc 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs @@ -33,18 +33,19 @@ private void ReportError(IExecutionTask task, IError error) void ReportSingle(IError singleError) { var handled = ErrorHandler.Handle(singleError); + Result.Errors ??= []; if (handled is AggregateError ar) { foreach (var ie in ar.Errors) { - Result.AddError(ie); + Result.Errors.Add(ie); _diagnosticEvents.TaskError(task, ie); } } else { - Result.AddError(handled); + Result.Errors.Add(handled); _diagnosticEvents.TaskError(task, handled); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs index c396301d366..bcc1e64f9e3 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs @@ -4,6 +4,7 @@ using HotChocolate.Execution.Processing.Tasks; using HotChocolate.Fetching; using HotChocolate.Resolvers; +using HotChocolate.Text.Json; using HotChocolate.Types; using HotChocolate.Utilities; using static HotChocolate.Execution.ThrowHelper; @@ -15,8 +16,8 @@ internal sealed partial class OperationContext private readonly IFactory _resolverTaskFactory; private readonly WorkScheduler _workScheduler; private WorkScheduler _currentWorkScheduler; - private readonly ResultBuilder _resultBuilder; private readonly AggregateServiceScopeInitializer _serviceScopeInitializer; + private ResultDocument _resultDocument = null!; private RequestContext _requestContext = null!; private Schema _schema = null!; private IErrorHandler _errorHandler = null!; @@ -36,14 +37,12 @@ internal sealed partial class OperationContext public OperationContext( IFactory resolverTaskFactory, - ResultBuilder resultBuilder, ITypeConverter typeConverter, AggregateServiceScopeInitializer serviceScopeInitializer) { _resolverTaskFactory = resolverTaskFactory; _workScheduler = new WorkScheduler(this); _currentWorkScheduler = _workScheduler; - _resultBuilder = resultBuilder; _serviceScopeInitializer = serviceScopeInitializer; Converter = typeConverter; } @@ -80,19 +79,13 @@ public void Initialize( _isInitialized = true; IncludeFlags = operation.CreateIncludeFlags(variables); - _workScheduler.Initialize(batchDispatcher); - _resultBuilder.Initialize(_requestContext, _diagnosticEvents); - - if (requestContext.RequestIndex != -1) + _resultDocument = new ResultDocument(operation, IncludeFlags) { - _resultBuilder.SetRequestIndex(requestContext.RequestIndex); - } - - if (variableIndex != -1) - { - _resultBuilder.SetVariableIndex(variableIndex); - } + RequestIndex = _requestContext.RequestIndex, + VariableIndex = variableIndex + }; + _workScheduler.Initialize(batchDispatcher); _currentWorkScheduler = _workScheduler; } @@ -115,19 +108,13 @@ public void InitializeFrom(OperationContext context) _isInitialized = true; IncludeFlags = _operation.CreateIncludeFlags(_variables); - _workScheduler.Initialize(_batchDispatcher); - _resultBuilder.Initialize(_requestContext, _diagnosticEvents); - - if (context._requestContext.RequestIndex != -1) + _resultDocument = new ResultDocument(_operation, IncludeFlags) { - _resultBuilder.SetRequestIndex(context._requestContext.RequestIndex); - } - - if (context._variableIndex != -1) - { - _resultBuilder.SetVariableIndex(context._variableIndex); - } + RequestIndex = _requestContext.RequestIndex, + VariableIndex = context._variableIndex + }; + _workScheduler.Initialize(_batchDispatcher); _currentWorkScheduler = _workScheduler; } @@ -137,7 +124,7 @@ public void Clean() { _currentWorkScheduler = _workScheduler; _workScheduler.Clear(); - _resultBuilder.Clear(); + _resultDocument = null!; _requestContext = null!; _schema = null!; _errorHandler = null!; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs index cec7f1fa841..50d8ece2ad3 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs @@ -26,7 +26,7 @@ private static async Task ExecuteInternalAsync( EnqueueResolverTasks( operationContext, operationContext.RootValue, - operationContext.ResultDocument.Data, + operationContext.Result.Data, scopedContext, Path.Root); @@ -65,7 +65,7 @@ private static void FillSchedulerWithWork( EnqueueResolverTasks( context, context.RootValue, - context.ResultDocument.Data, + context.Result.Data, scopedContext, Path.Root); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs index 7b5f944f2da..52e84d7fa20 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs @@ -12,7 +12,6 @@ internal sealed partial class ResolverTask /// The execution cancellation token. private void CompleteValue(bool success, CancellationToken cancellationToken) { - var responseName = _context.ResponseName; var resultValue = _context.ResultValue; var result = _context.Result; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index 6db66a53bb4..a1303e38f38 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -123,83 +123,67 @@ public static ResolverTask EnqueueElementTasks( } */ - public static ObjectResult? EnqueueOrInlineResolverTasks( + public static void EnqueueOrInlineResolverTasks( ValueCompletionContext context, - ObjectType parentType, - ResultData parentResult, - int parentIndex, - object parent, - SelectionSet selectionSet) + SelectionSet selectionSet, + ObjectType selectionSetType, + ResultElement resultValue, + object parent) { - var responseIndex = 0; - var selections = selectionSet.Selections; - var selectionsCount = selections.Length; + Debug.Assert(selectionSet.Type == selectionSetType); + Debug.Assert(resultValue.Type == selectionSetType); + var operationContext = context.OperationContext; - var result = operationContext.Result.RentObject(selectionsCount); - var includeFlags = operationContext.IncludeFlags; - var final = !selectionSet.IsConditional; - result.SetParent(parentResult, parentIndex); + resultValue.SetObjectValue(selectionSet); - foreach (var selection in selections) + foreach (var field in resultValue.EnumerateObject()) { - if (result.IsInvalidated) - { - return null; - } - - if (!final && !selection.IsIncluded(includeFlags)) - { - continue; - } + var selection = field.AssertSelection(); if (selection.Strategy is SelectionExecutionStrategy.Pure) { ResolveAndCompleteInline( context, selection, - responseIndex++, - parentType, - parent, - result); + selectionSetType, + field.Value, + parent); } else { context.Tasks.Add( operationContext.CreateResolverTask( - selection, parent, - result, - responseIndex++, + selection, + resultValue, context.ResolverContext.ScopedContextData)); } } - - return result.IsInvalidated ? null : result; } private static void ResolveAndCompleteInline( ValueCompletionContext context, Selection selection, - int responseIndex, - ObjectType parentType, - object parent, - ObjectResult parentResult) + ObjectType selectionSetType, + ResultElement fieldValue, + object parent) { var operationContext = context.OperationContext; var resolverContext = context.ResolverContext; var executedSuccessfully = false; object? resolverResult = null; - parentResult.InitValueUnsafe(responseIndex, selection); - try { // we first try to create a context for our pure resolver. // this should actually only fail if we are unable to coerce // the field arguments. if (resolverContext.TryCreatePureContext( - selection, parentType, parentResult, parent, + selection, + selectionSetType, + fieldValue, + parent, out var childContext)) { // if we have a pure context we can execute out pure resolver. @@ -215,53 +199,17 @@ private static void ResolveAndCompleteInline( } catch (Exception ex) { - var path = CreatePathFromContext(selection, parentResult, responseIndex); - operationContext.ReportError(ex, resolverContext, selection, path); + operationContext.ReportError(ex, resolverContext, selection, fieldValue.Path); } - if (executedSuccessfully) + if (!executedSuccessfully) { - // if we were able to execute the resolver we will try to complete the - // resolver result inline and commit the value to the result. - CompleteInline( - operationContext, - resolverContext, - selection, - selection.Type, - responseIndex, - parentResult, - resolverResult, - context.Tasks); + fieldValue.SetNullValue(); } - else - { - // if we were not able to execute the resolver we will commit the null value - // of the resolver to the object result which could trigger a non-null propagation. - CommitValue( - operationContext, - selection, - responseIndex, - parentResult, - resolverResult); - } - } - - private static void CompleteInline( - OperationContext operationContext, - MiddlewareContext resolverContext, - Selection selection, - IType type, - int responseIndex, - ObjectResult parentResult, - object? value, - List bufferedTasks) - { - object? completedValue = null; try { - var completionContext = new ValueCompletionContext(operationContext, resolverContext, bufferedTasks); - completedValue = Complete(completionContext, selection, type, parentResult, responseIndex, value); + Complete(context, selection, fieldValue, resolverResult); } catch (OperationCanceledException) { @@ -271,33 +219,13 @@ private static void CompleteInline( } catch (Exception ex) { - var errorPath = CreatePathFromContext(selection, parentResult, responseIndex); - operationContext.ReportError(ex, resolverContext, selection, errorPath); + operationContext.ReportError(ex, resolverContext, selection, fieldValue.Path); } - CommitValue(operationContext, selection, responseIndex, parentResult, completedValue); - } - - private static void CommitValue( - OperationContext operationContext, - ISelection selection, - int responseIndex, - ObjectResult parentResult, - object? completedValue) - { - var isNonNullType = selection.Type.Kind is TypeKind.NonNull; - - parentResult.SetValueUnsafe( - responseIndex, - selection.ResponseName, - completedValue, - !isNonNullType); - - if (completedValue is null && isNonNullType) + if (fieldValue is { IsNullable: false, IsNullOrInvalidated: true }) { - PropagateNullValues(parentResult); - var errorPath = CreatePathFromContext(selection, parentResult, responseIndex); - operationContext.Result.AddNonNullViolation(selection, errorPath); + PropagateNullValues(fieldValue); + operationContext.Result.AddNonNullViolation(_selection, _context.Path); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs index dc459f2c4ca..30bb5f92356 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using HotChocolate.Text.Json; using HotChocolate.Types; using HotChocolate.Utilities; using static HotChocolate.Execution.ErrorHelper; @@ -8,32 +9,31 @@ namespace HotChocolate.Execution.Processing; internal static partial class ValueCompletion { - private static ObjectResult? CompleteCompositeValue( + private static void CompleteCompositeValue( ValueCompletionContext context, Selection selection, IType type, - ResultData parent, - int index, - object result) + ResultElement resultValue, + object runtimeValue) { var operationContext = context.OperationContext; - if (TryResolveObjectType(context, selection, type, parent, index, result, out var objectType)) + if (TryResolveObjectType(context, selection, type, resultValue, runtimeValue, out var objectType)) { - var selectionSet = operationContext.CollectFields(selection, objectType); + var selectionSet = selection.DeclaringOperation.GetSelectionSet(selection, objectType); var runtimeType = objectType.RuntimeType; - if (!runtimeType.IsInstanceOfType(result) - && operationContext.Converter.TryConvert(runtimeType, result, out var converted)) + if (!runtimeType.IsInstanceOfType(runtimeValue) + && operationContext.Converter.TryConvert(runtimeType, runtimeValue, out var converted)) { - result = converted; + runtimeValue = converted; } - return EnqueueOrInlineResolverTasks(context, objectType, parent, index, result, selectionSet); + return EnqueueOrInlineResolverTasks(context, objectType, parent, index, runtimeValue, selectionSet); } var errorPath = CreatePathFromContext(selection, parent, index); - var error = ValueCompletion_CouldNotResolveAbstractType(selection, errorPath, result); + var error = ValueCompletion_CouldNotResolveAbstractType(selection, errorPath, runtimeValue); operationContext.ReportError(error, context.ResolverContext, selection); return null; } @@ -42,9 +42,8 @@ private static bool TryResolveObjectType( ValueCompletionContext context, Selection selection, IType fieldType, - ResultData parent, - int index, - object result, + ResultElement resultValue, + object runtimeValue, [NotNullWhen(true)] out ObjectType? objectType) { try @@ -64,19 +63,19 @@ private static bool TryResolveObjectType( case TypeKind.Interface: objectType = ((InterfaceType)fieldType) - .ResolveConcreteType(context.ResolverContext, result); + .ResolveConcreteType(context.ResolverContext, runtimeValue); return objectType is not null; case TypeKind.Union: objectType = ((UnionType)fieldType) - .ResolveConcreteType(context.ResolverContext, result); + .ResolveConcreteType(context.ResolverContext, runtimeValue); return objectType is not null; } var error = UnableToResolveTheAbstractType( fieldType.Print(), selection, - CreatePathFromContext(selection, parent, index)); + resultValue.Path); context.OperationContext.ReportError(error, context.ResolverContext, selection); } catch (Exception ex) @@ -85,7 +84,7 @@ private static bool TryResolveObjectType( ex, fieldType.Print(), selection, - CreatePathFromContext(selection, parent, index)); + resultValue.Path); context.OperationContext.ReportError(error, context.ResolverContext, selection); } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index 8bc813ba527..4d931fed0de 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -40,6 +40,10 @@ public List? Errors internal set => _errors = value; } + public int RequestIndex { get; init; } + + public int VariableIndex { get; init; } + public Dictionary? Extensions { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 9a79137b84585cefcd0dffed0118388302e4f64d Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Mon, 15 Dec 2025 23:09:02 +0100 Subject: [PATCH 33/42] wip --- .../OpenApiResultFormatter.cs | 6 +- .../Execution/CompletedResult.cs | 24 ++ .../Execution/ExecutionResult.cs | 20 +- .../CoreExecutionResultExtensions.cs | 4 +- .../Execution/IExecutionResult.cs | 7 +- .../Execution/IIncrementalListResult.cs | 12 + .../Execution/IIncrementalObjectResult.cs | 19 ++ .../Execution/IIncrementalResult.cs | 18 ++ .../Execution/IOperationResult.cs | 51 ++-- .../Execution/OperationResult.cs | 183 ------------- .../Execution/OperationResultBatch.cs | 45 +--- .../Execution/OperationResultBuilder.cs | 250 ------------------ .../OperationResultBuilderExtensions.cs | 64 ----- .../Execution/PendingResult.cs | 31 +++ .../Execution/ResponseStream.cs | 48 +--- .../Execution/WarmupExecutionResult.cs | 2 - .../InternalServiceCollectionExtensions.cs | 34 --- .../RequestExecutorBuilderExtensions.cs | 26 -- ...uestExecutorServiceCollectionExtensions.cs | 1 - .../Extensions/OperationContextExtensions.cs | 53 +--- .../Execution/Options/ResultBufferOptions.cs | 82 ------ .../Processing/ValueCompletion.List.cs | 182 ++++++------- .../Processing/ValueCompletion.Object.cs | 12 +- .../Execution/Processing/ValueCompletion.cs | 21 +- .../Processing/WorkScheduler.Pooling.cs | 3 - .../Types/Text/Json/ResultDocument.WriteTo.cs | 4 +- .../src/Types/Text/Json/ResultDocument.cs | 84 +++--- 27 files changed, 306 insertions(+), 980 deletions(-) create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/CompletedResult.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalListResult.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalObjectResult.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalResult.cs delete mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs delete mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilder.cs delete mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilderExtensions.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/PendingResult.cs delete mode 100644 src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs diff --git a/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs b/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs index a0c93ad8c4d..1f05da24626 100644 --- a/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs +++ b/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs @@ -8,10 +8,10 @@ namespace HotChocolate.Adapters.OpenApi; internal sealed class OpenApiResultFormatter : IOpenApiResultFormatter { private static readonly JsonWriterOptions s_jsonWriterOptions = - new JsonWriterOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + new() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; private static readonly JsonSerializerOptions s_jsonSerializerOptions = - new JsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + new() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; public async Task FormatResultAsync( IOperationResult operationResult, @@ -19,7 +19,7 @@ public async Task FormatResultAsync( OpenApiEndpointDescriptor endpoint, CancellationToken cancellationToken) { - // If the root field is null and we don't have any errors, + // If the root field is null, and we don't have any errors, // we return HTTP 404 for queries and HTTP 500 otherwise. if (operationResult.Data?.TryGetValue(endpoint.ResponseNameToExtract, out var responseData) != true || responseData is null) diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/CompletedResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/CompletedResult.cs new file mode 100644 index 00000000000..a036a399afc --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/CompletedResult.cs @@ -0,0 +1,24 @@ +namespace HotChocolate.Execution; + +/// +/// Represents the completion of a pending incremental delivery operation in a GraphQL response. +/// Indicates that all data associated with the corresponding pending result has been delivered. +/// +/// The request unique pending data identifier that matches a prior pending result. +/// +/// Field errors that caused the incremental delivery to fail due to error bubbling above the incremental result's path. +/// When present, indicates the delivery has failed. +/// +public sealed record CompletedResult(uint Id, IReadOnlyList? Errors = null) +{ + /// + /// Gets the request unique pending data identifier that matches a prior pending result. + /// + public uint Id { get; init; } = Id; + + /// + /// Gets field errors that caused the incremental delivery to fail due to error bubbling + /// above the incremental result's path. When present, indicates the delivery has failed. + /// + public IReadOnlyList? Errors { get; init; } = Errors; +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs index 904a1d47621..88b7c2035a7 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs @@ -1,4 +1,5 @@ using System.Buffers; +using System.Collections.Immutable; using HotChocolate.Features; namespace HotChocolate.Execution; @@ -15,26 +16,27 @@ public abstract class ExecutionResult : IExecutionResult protected ExecutionResult() { + Features = new FeatureCollection(); } - protected ExecutionResult((Func[] Tasks, int Length) cleanupTasks) + protected ExecutionResult((Func[] Tasks, int Length)? cleanupTasks, IFeatureCollection? features) { - if (cleanupTasks.Tasks is null) - { - throw new ArgumentNullException(nameof(cleanupTasks)); - } - - (_cleanUpTasks, _cleanupTasksLength) = cleanupTasks; + Features = features ?? new FeatureCollection(); + (_cleanUpTasks, _cleanupTasksLength) = cleanupTasks ?? ([], 0); } /// public abstract ExecutionResultKind Kind { get; } /// - public abstract IReadOnlyDictionary? ContextData { get; } + public ImmutableDictionary ContextData + { + get => Features.Get>() ?? ImmutableDictionary.Empty; + set => Features.Set(value); + } /// - public IFeatureCollection Features { get; } = new FeatureCollection(); + public IFeatureCollection Features { get; } /// /// This helper allows someone else to take over the responsibility over the cleanup tasks. diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs index f18b6e30e81..6e7a1985f1d 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs @@ -78,9 +78,9 @@ public static bool IsStreamResult(this IExecutionResult result) /// /// Expects a single GraphQL operation result. /// - public static OperationResult ExpectOperationResult(this IExecutionResult result) + public static IOperationResult ExpectOperationResult(this IExecutionResult result) { - if (result is OperationResult qr) + if (result is IOperationResult qr) { return qr; } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IExecutionResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IExecutionResult.cs index d46dad49d59..1b16e2a40d3 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IExecutionResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IExecutionResult.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Features; namespace HotChocolate.Execution; @@ -21,7 +22,11 @@ public interface IExecutionResult : IFeatureProvider, IAsyncDisposable /// Gets the result context data which represent additional /// properties that are NOT written to the transport. /// - IReadOnlyDictionary? ContextData { get; } + ImmutableDictionary ContextData + { + get => Features.Get>() ?? ImmutableDictionary.Empty; + set => Features.Set(value); + } /// /// Registers a cleanup task for execution resources bound to this execution result. diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalListResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalListResult.cs new file mode 100644 index 00000000000..148ec3d3e03 --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalListResult.cs @@ -0,0 +1,12 @@ +namespace HotChocolate.Execution; + +/// +/// Represents an incremental result that delivers additional list items for a @stream directive. +/// +public interface IIncrementalListResult : IIncrementalResult +{ + /// + /// Gets the additional list items to append to the streamed list field. + /// + IReadOnlyList Items { get; } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalObjectResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalObjectResult.cs new file mode 100644 index 00000000000..8e04e2dc878 --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalObjectResult.cs @@ -0,0 +1,19 @@ +namespace HotChocolate.Execution; + +/// +/// Represents an incremental result that delivers additional fields for a @defer directive. +/// +public interface IIncrementalObjectResult : IIncrementalResult +{ + /// + /// Gets the sub-path that is concatenated with the pending result's path to determine + /// the final path for this incremental data. When null, the path is the same + /// as the pending result's path. + /// + Path? SubPath { get; } + + /// + /// Gets the additional response fields to merge into the deferred fragment location. + /// + object? Data { get; } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalResult.cs new file mode 100644 index 00000000000..52861205a19 --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IIncrementalResult.cs @@ -0,0 +1,18 @@ +namespace HotChocolate.Execution; + +/// +/// Represents an incremental result that delivers data for a @defer or @stream directive. +/// +public interface IIncrementalResult +{ + /// + /// Gets the request unique pending data identifier that matches a prior pending result. + /// + uint Id { get; } + + /// + /// Gets field errors that occurred during execution of this incremental result. + /// Only includes errors that did not bubble above the incremental result's path. + /// + IReadOnlyList? Errors { get; } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs index f05abd205a7..5404286d00a 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs @@ -1,9 +1,9 @@ namespace HotChocolate.Execution; /// -/// Represents a query result object. +/// Represents a GraphQL operation result payload. /// -public interface IOperationResult : IExecutionResult +public interface IOperationResult : IExecutionResult, IResultDataJsonFormatter { /// /// Gets the index of the request that corresponds to this result. @@ -15,34 +15,22 @@ public interface IOperationResult : IExecutionResult /// int? VariableIndex { get; } - /// - /// A string that was passed to the label argument of the @defer or @stream - /// directive that corresponds to this result. - /// - /// - string? Label { get; } - /// /// A path to the insertion point that informs the client how to patch a /// subsequent delta payload into the original payload. /// - /// Path? Path { get; } /// /// The data that is being delivered. /// - /// - IReadOnlyDictionary? Data { get; } + object? Data { get; } /// - /// The `items` entry in a stream payload is a list of results from the execution of - /// the associated @stream directive. This output will be a list of the same type as - /// the field with the associated `@stream` directive. If `items` is set to `null`, - /// it indicates that an error has caused a `null` to bubble up to a field higher - /// than the list field with the associated `@stream` directive. + /// Specifies if data was explicitly set. + /// If false the data was not set (including null). /// - IReadOnlyList? Items { get; } + bool IsDataSet { get; } /// /// Gets the GraphQL errors of the result. @@ -56,22 +44,27 @@ public interface IOperationResult : IExecutionResult IReadOnlyDictionary? Extensions { get; } /// - /// Gets the incremental patches provided with this result. + /// Gets the list of pending incremental delivery operations. + /// Each pending result announces data that will be delivered incrementally in subsequent payloads. /// - IReadOnlyList? Incremental { get; } + IReadOnlyList? Pending { get; } /// - /// A boolean that is present and true when there are more payloads - /// that will be sent for this operation. The last payload in a multi payload response - /// should return HasNext: false. - /// HasNext is null for single-payload responses to preserve backwards compatibility. + /// Gets the list of incremental results containing data from @defer or @stream directives. + /// Contains the actual data for previously announced pending operations. /// - /// - bool? HasNext { get; } + IReadOnlyList? Incremental { get; } /// - /// Specifies if data was explicitly set. - /// If false the data was not set (including null). + /// Gets the list of completed incremental delivery operations. + /// Each completed result indicates that all data for a pending operation has been delivered. /// - bool IsDataSet { get; } + IReadOnlyList? Completed { get; } + + /// + /// Indicates whether more payloads will follow in the response stream. + /// When true, clients should expect additional incremental data. + /// When false, this is the final payload. + /// + bool HasNext { get; } } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs deleted file mode 100644 index 6aa84238825..00000000000 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs +++ /dev/null @@ -1,183 +0,0 @@ -namespace HotChocolate.Execution; - -/// -/// Represents an operation result object. -/// -public sealed class OperationResult : ExecutionResult, IOperationResult -{ - internal OperationResult( - IReadOnlyDictionary? data, - IReadOnlyList? errors, - IReadOnlyDictionary? extensions, - IReadOnlyDictionary? contextData, - IReadOnlyList? items, - IReadOnlyList? incremental, - string? label, - Path? path, - bool? hasNext, - (Func[] Tasks, int Length) cleanupTasks, - bool isDataSet, - int? requestIndex, - int? variableIndex, - bool skipValidation = false) - : base(cleanupTasks) - { - if (!skipValidation - && data is null - && items is null - && errors is null - && incremental is null - && hasNext is not false) - { - throw new ArgumentException( - ExecutionAbstractionsResources.QueryResult_DataAndResultAreNull, - nameof(data)); - } - - Data = data; - Items = items; - Errors = errors; - Extensions = extensions; - ContextData = contextData; - Incremental = incremental; - Label = label; - Path = path; - HasNext = hasNext; - IsDataSet = isDataSet; - RequestIndex = requestIndex; - VariableIndex = variableIndex; - } - - /// - /// Initializes a new . - /// - public OperationResult( - IReadOnlyDictionary? data, - IReadOnlyList? errors = null, - IReadOnlyDictionary? extensions = null, - IReadOnlyDictionary? contextData = null, - IReadOnlyList? items = null, - IReadOnlyList? incremental = null, - string? label = null, - Path? path = null, - bool? hasNext = null, - int? requestIndex = null, - int? variableIndex = null) - { - if (data is null - && items is null - && errors is null - && incremental is null - && hasNext is not false) - { - throw new ArgumentException( - ExecutionAbstractionsResources.QueryResult_DataAndResultAreNull, - nameof(data)); - } - - Data = data; - Items = items; - Errors = errors; - Extensions = extensions; - ContextData = contextData; - Incremental = incremental; - Label = label; - Path = path; - HasNext = hasNext; - RequestIndex = requestIndex; - VariableIndex = variableIndex; - } - - /// - public override ExecutionResultKind Kind => ExecutionResultKind.SingleResult; - - /// - public int? RequestIndex { get; } - - /// - public int? VariableIndex { get; } - - /// - public string? Label { get; } - - /// - public Path? Path { get; } - - /// - public IReadOnlyDictionary? Data { get; } - - /// - public IReadOnlyList? Items { get; } - - /// - public IReadOnlyList? Errors { get; } - - /// - public IReadOnlyDictionary? Extensions { get; } - - /// - public IReadOnlyList? Incremental { get; } - - /// - public override IReadOnlyDictionary? ContextData { get; } - - /// - public bool? HasNext { get; } - - /// - public bool IsDataSet { get; } - - /// - /// Creates a new with the specified extension data. - /// - /// - /// The extension data that shall be added to the result. - /// - /// - /// Returns a new that represents the result. - /// - public OperationResult WithExtensions( - IReadOnlyDictionary? extensions) - { - return new OperationResult( - data: Data, - errors: Errors, - extensions: extensions, - contextData: ContextData, - items: Items, - incremental: Incremental, - label: Label, - path: Path, - hasNext: HasNext, - cleanupTasks: TakeCleanUpTasks(), - isDataSet: IsDataSet, - requestIndex: RequestIndex, - variableIndex: VariableIndex); - } - - /// - /// Creates a new with the specified context data. - /// - /// - /// The context data that shall be added to the result. - /// - /// - /// Returns a new that represents the result. - /// - public OperationResult WithContextData( - IReadOnlyDictionary? contextData) - => new OperationResult( - data: Data, - errors: Errors, - extensions: Extensions, - contextData: contextData, - items: Items, - incremental: Incremental, - label: Label, - path: Path, - hasNext: HasNext, - cleanupTasks: TakeCleanUpTasks(), - isDataSet: IsDataSet, - requestIndex: RequestIndex, - variableIndex: VariableIndex); -} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs index fc932b5262d..a2d59c69a96 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs @@ -11,24 +11,19 @@ public sealed class OperationResultBatch : ExecutionResult /// /// The results of this batch. /// - /// - /// The result context data which represent additional properties that are NOT written to the transport. - /// /// /// The result must be either an operation result or a response stream. /// /// /// is null. /// - public OperationResultBatch( - IReadOnlyList results, - IReadOnlyDictionary? contextData = null) + public OperationResultBatch(IReadOnlyList results) { ArgumentNullException.ThrowIfNull(results); foreach (var result in results) { - if (result is not IResponseStream and not OperationResult) + if (result is not IResponseStream and not IOperationResult) { throw new ArgumentException( ExecutionAbstractionsResources.OperationResultBatch_ResponseStreamOrOperationResult, @@ -37,8 +32,6 @@ public OperationResultBatch( } Results = results ?? throw new ArgumentNullException(nameof(results)); - ContextData = contextData; - RegisterForCleanup(() => RunCleanUp(results)); } @@ -52,40 +45,6 @@ public OperationResultBatch( /// public IReadOnlyList Results { get; } - /// - /// Gets the result context data which represent additional - /// properties that are NOT written to the transport. - /// - public override IReadOnlyDictionary? ContextData { get; } - - /// - /// Creates a new with the specified results. - /// - /// - /// The results of this batch. - /// - /// - /// Returns a new with the specified results. - /// - public OperationResultBatch WithResults(IReadOnlyList results) - { - var newBatch = new OperationResultBatch(results, ContextData); - var (tasks, length) = TakeCleanUpTasks(); - - if (length > 0) - { - foreach (var cleanupTask in tasks) - { - newBatch.RegisterForCleanup(cleanupTask); - } - - tasks.AsSpan(0, length).Clear(); - CleanUpTaskPool.Return(tasks); - } - - return newBatch; - } - private static async ValueTask RunCleanUp(IReadOnlyList results) { foreach (var result in results) diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilder.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilder.cs deleted file mode 100644 index 3e4e2850a29..00000000000 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilder.cs +++ /dev/null @@ -1,250 +0,0 @@ -using System.Buffers; - -namespace HotChocolate.Execution; - -public sealed class OperationResultBuilder -{ - private static readonly ArrayPool> s_arrayPool = ArrayPool>.Shared; - private IReadOnlyDictionary? _data; - private IReadOnlyList? _items; - private List? _errors; - private OrderedDictionary? _extensionData; - private Dictionary? _contextData; - private List? _incremental; - private string? _label; - private Path? _path; - private bool? _hasNext; - private bool? _isDataSet; - private int? _requestIndex; - private int? _variableIndex; - private Func[] _cleanupTasks = []; - private int _cleanupTasksLength; - - public OperationResultBuilder SetData(IReadOnlyDictionary? data) - { - _data = data; - _items = null; - _isDataSet = true; - return this; - } - - public OperationResultBuilder SetItems(IReadOnlyList? items) - { - _items = items; - - if (items is not null) - { - _data = null; - } - - return this; - } - - public OperationResultBuilder AddError(IError error) - { - ArgumentNullException.ThrowIfNull(error); - - _errors ??= []; - _errors.Add(error); - return this; - } - - public OperationResultBuilder AddErrors(IEnumerable errors) - { - ArgumentNullException.ThrowIfNull(errors); - - _errors ??= []; - _errors.AddRange(errors); - return this; - } - - public OperationResultBuilder AddExtension(string key, object? data) - { - _extensionData ??= []; - _extensionData.Add(key, data); - return this; - } - - public OperationResultBuilder SetExtension(string key, object? data) - { - _extensionData ??= []; - _extensionData[key] = data; - return this; - } - - public OperationResultBuilder SetExtensions(IReadOnlyDictionary? extensions) - { - if (extensions is OrderedDictionary extensionData) - { - _extensionData = extensionData; - } - else if (extensions is not null) - { -#if NET9_0_OR_GREATER - _extensionData = new OrderedDictionary(extensions); -#else - _extensionData = []; -#endif - } - else - { - _extensionData = null; - } - - return this; - } - - public OperationResultBuilder AddContextData(string key, object? data) - { - _contextData ??= []; - _contextData.Add(key, data); - return this; - } - - public OperationResultBuilder SetContextData(string key, object? data) - { - _contextData ??= []; - _contextData[key] = data; - return this; - } - - public OperationResultBuilder SetContextData(IReadOnlyDictionary? contextData) - { - if (contextData is Dictionary extensionData) - { - _contextData = extensionData; - } - else if (contextData is not null) - { - _contextData = new Dictionary(contextData); - } - else - { - _contextData = null; - } - - return this; - } - - public OperationResultBuilder AddPatch(IOperationResult patch) - { - ArgumentNullException.ThrowIfNull(patch); - - _incremental ??= []; - _incremental.Add(patch); - return this; - } - - public OperationResultBuilder SetLabel(string? label) - { - _label = label; - return this; - } - - public OperationResultBuilder SetPath(Path? path) - { - _path = path; - return this; - } - - public OperationResultBuilder SetHasNext(bool? hasNext) - { - _hasNext = hasNext; - return this; - } - - public OperationResultBuilder RegisterForCleanup(Func clean) - { - ArgumentNullException.ThrowIfNull(clean); - - if (_cleanupTasks.Length == 0) - { - _cleanupTasks = s_arrayPool.Rent(9); - } - else if (_cleanupTasksLength >= _cleanupTasks.Length) - { - var buffer = s_arrayPool.Rent(_cleanupTasks.Length * 2); - - var oldBuffer = _cleanupTasks.AsSpan(); - oldBuffer.CopyTo(buffer); - oldBuffer.Clear(); - s_arrayPool.Return(buffer); - - _cleanupTasks = buffer; - } - - _cleanupTasks[_cleanupTasksLength++] = clean; - return this; - } - - public IOperationResult Build() - => new OperationResult( - _data, - _errors?.Count > 0 ? _errors : null, - _extensionData?.Count > 0 ? _extensionData : null, - _contextData?.Count > 0 ? _contextData : null, - _items, - _incremental, - _label, - _path, - _hasNext, - (_cleanupTasks, _cleanupTasksLength), - _isDataSet ?? false, - _requestIndex, - _variableIndex); - - public static OperationResultBuilder New() => new(); - - public static OperationResultBuilder FromResult(IOperationResult result) - { - var builder = new OperationResultBuilder { _data = result.Data }; - - if (result.Errors is not null) - { - builder._errors = [.. result.Errors]; - } - - if (result.Extensions is OrderedDictionary ext) - { - builder._extensionData = ext; - } - else if (result.Extensions is not null) - { -#if NET9_0_OR_GREATER - builder._extensionData = new OrderedDictionary(result.Extensions); -#else - builder._extensionData = []; -#endif - } - - if (result.ContextData is Dictionary cd) - { - builder._contextData = cd; - } - else if (result.ContextData is not null) - { - builder._contextData = new Dictionary(result.ContextData); - } - - builder._label = result.Label; - builder._path = result.Path; - builder._hasNext = result.HasNext; - builder._isDataSet = result.IsDataSet; - builder._requestIndex = result.RequestIndex; - builder._variableIndex = result.VariableIndex; - - return builder; - } - - public static IOperationResult CreateError( - IError error, - IReadOnlyDictionary? contextData = null) - => error is AggregateError aggregateError - ? CreateError(aggregateError.Errors, contextData) - : new OperationResult(null, new List { error }, contextData: contextData); - - public static IOperationResult CreateError( - IReadOnlyList errors, - IReadOnlyDictionary? contextData = null) - => new OperationResult(null, errors, contextData: contextData); -} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilderExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilderExtensions.cs deleted file mode 100644 index 1d7bac150c0..00000000000 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBuilderExtensions.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace HotChocolate.Execution; - -/// -/// Extensions methods for . -/// -public static class OperationResultBuilderExtensions -{ - /// - /// Registers a cleanup task for execution resources with the . - /// - /// - /// The . - /// - /// - /// A cleanup task that will be executed when this result is disposed. - /// - public static void RegisterForCleanup(this OperationResultBuilder builder, Action clean) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(clean); - - builder.RegisterForCleanup(() => - { - clean(); - return default; - }); - } - - /// - /// Registers a cleanup task for execution resources with the . - /// - /// - /// The . - /// - /// - /// The resource that needs to be disposed. - /// - public static void RegisterForCleanup(this OperationResultBuilder builder, IDisposable disposable) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(disposable); - - builder.RegisterForCleanup(disposable.Dispose); - } - - /// - /// Registers a cleanup task for execution resources with the . - /// - /// - /// The . - /// - /// - /// The resource that needs to be disposed. - /// - public static void RegisterForCleanup( - this OperationResultBuilder builder, - IAsyncDisposable disposable) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(disposable); - - builder.RegisterForCleanup(disposable.DisposeAsync); - } -} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/PendingResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/PendingResult.cs new file mode 100644 index 00000000000..38c0fab5469 --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/PendingResult.cs @@ -0,0 +1,31 @@ +namespace HotChocolate.Execution; + +/// +/// Represents a pending incremental delivery operation in a GraphQL response. +/// +/// The request unique pending data identifier. +/// +/// The path in the response where the incremental data will be delivered. +/// For @stream: indicates the list field that is not complete. +/// For @defer: indicates where the deferred fragment fields will be added. +/// +/// The label from the @defer or @stream directive's label argument, if present. +public sealed record PendingResult(uint Id, Path Path, string? Label = null) +{ + /// + /// Gets the request unique pending data identifier. + /// + public uint Id { get; init; } = Id; + + /// + /// Gets the path in the response where the incremental data will be delivered. + /// For @stream: indicates the list field that is not complete. + /// For @defer: indicates where the deferred fragment fields will be added. + /// + public Path Path { get; init; } = Path; + + /// + /// Gets the label from the @defer or @stream directive's label argument, if present. + /// + public string? Label { get; init; } = Label; +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs index 90ffb231465..48a406bbe35 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs @@ -11,9 +11,7 @@ public sealed class ResponseStream : ExecutionResult, IResponseStream public ResponseStream( Func>? resultStreamFactory, - ExecutionResultKind kind = SubscriptionResult, - IReadOnlyDictionary? contextData = null, - IReadOnlyList>? onFirstResult = null) + ExecutionResultKind kind = SubscriptionResult) { _resultStreamFactory = resultStreamFactory ?? throw new ArgumentNullException(nameof(resultStreamFactory)); @@ -24,15 +22,15 @@ public ResponseStream( } Kind = kind; - ContextData = contextData; - OnFirstResult = onFirstResult ?? ImmutableArray>.Empty; } public override ExecutionResultKind Kind { get; } - public override IReadOnlyDictionary? ContextData { get; } - - public IReadOnlyList> OnFirstResult { get; } + public ImmutableList> OnFirstResult + { + get => Features.Get>>() ?? []; + set => Features.Set(value); + } public IAsyncEnumerable ReadResultsAsync() { @@ -52,40 +50,6 @@ public IAsyncEnumerable ReadResultsAsync() return new OperationResultStream(_resultStreamFactory, ExecuteOnFirstResult); } - /// - /// Creates a new response stream with a list of mutators that are applied to the first result of this stream. - /// - /// - /// The mutators that are applied to the first result of this stream. - /// - /// - /// Returns a new response stream with the specified mutators. - /// - public ResponseStream WithOnFirstResult( - IReadOnlyList> onFirstResult) - { - var newStream = new ResponseStream( - _resultStreamFactory, - Kind, - ContextData, - onFirstResult); - - var (tasks, length) = TakeCleanUpTasks(); - - if (length > 0) - { - for (var i = 0; i < length; i++) - { - newStream.RegisterForCleanup(tasks[i]); - } - - tasks.AsSpan(0, length).Clear(); - CleanUpTaskPool.Return(tasks); - } - - return newStream; - } - private class OperationResultStream( Func> resultStreamFactory, Func onFirstResult) diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/WarmupExecutionResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/WarmupExecutionResult.cs index d4b864c9fc8..89de5f61b3b 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/WarmupExecutionResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/WarmupExecutionResult.cs @@ -3,6 +3,4 @@ namespace HotChocolate.Execution; public sealed class WarmupExecutionResult : ExecutionResult { public override ExecutionResultKind Kind => ExecutionResultKind.WarmupResult; - - public override IReadOnlyDictionary? ContextData => null; } diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs index be71c7446e7..0d8c703d88b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/InternalServiceCollectionExtensions.cs @@ -2,7 +2,6 @@ using GreenDonut.DependencyInjection; using HotChocolate.Execution; using HotChocolate.Execution.DependencyInjection; -using HotChocolate.Execution.Options; using HotChocolate.Execution.Processing; using HotChocolate.Execution.Processing.Tasks; using HotChocolate.Fetching; @@ -24,39 +23,6 @@ internal static IServiceCollection TryAddVariableCoercion( return services; } - internal static IServiceCollection TryAddResultPool( - this IServiceCollection services) - { - services.TryAddSingleton(sp => - { - var options = new ResultBufferOptions(); - var modifiers = sp.GetServices>(); - - foreach (var modifier in modifiers) - { - modifier.Invoke(options); - } - - return options; - }); - - services.TryAddSingleton(sp => - { - var options = sp.GetRequiredService(); - return new ObjectResultPool(options.MaximumRetained, options.MaximumAllowedCapacity, options.BucketSize); - }); - - services.TryAddSingleton(sp => - { - var options = sp.GetRequiredService(); - return new ListResultPool(options.MaximumRetained, options.MaximumAllowedCapacity, options.BucketSize); - }); - - services.TryAddSingleton(); - - return services; - } - internal static IServiceCollection TryAddResolverTaskPool( this IServiceCollection services, int maximumRetained = 128) diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs index 92324f6a32c..3cc7a1a354b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorBuilderExtensions.cs @@ -290,32 +290,6 @@ public static IRequestExecutorBuilder ModifyParserOptions( return builder; } - /// - /// Configures the result buffer options. - /// - /// - /// The request executor builder. - /// - /// - /// The configuration action. - /// - /// - /// Returns the request executor builder. - /// - /// - /// is null. - /// - public static IRequestExecutorBuilder ModifyResultBuffersOptions( - this IRequestExecutorBuilder builder, - Action configure) - { - ArgumentNullException.ThrowIfNull(builder); - ArgumentNullException.ThrowIfNull(configure); - - builder.Services.AddSingleton(configure); - return builder; - } - public static IRequestExecutorBuilder ConfigureSchemaServices( this IRequestExecutorBuilder builder, Action configureServices) diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs index 1c77312e894..3e8fd18f4e5 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceCollectionExtensions.cs @@ -52,7 +52,6 @@ public static IServiceCollection AddGraphQLCore(this IServiceCollection services // pools services - .TryAddResultPool() .TryAddResolverTaskPool() .TryAddOperationContextPool() .TryAddSingleton>(new DocumentValidatorContextPool()); diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs index d721a1e8f24..867091cd66e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs @@ -7,7 +7,8 @@ internal static class OperationContextExtensions { extension(OperationContext context) { - public OperationContext ReportError(Exception exception, + public OperationContext ReportError( + Exception exception, MiddlewareContext resolverContext, ISelection? selection = null, Path? path = null) @@ -21,7 +22,7 @@ public OperationContext ReportError(Exception exception, { foreach (var error in ex.Errors) { - ReportError(context, error, resolverContext, selection); + ReportError(context, error, resolverContext); } } else @@ -32,15 +33,15 @@ public OperationContext ReportError(Exception exception, .AddLocations(selection.GetSyntaxNodes()) .Build(); - ReportError(context, error, resolverContext, selection); + ReportError(context, error, resolverContext); } return context; } - public OperationContext ReportError(IError error, - MiddlewareContext resolverContext, - ISelection? selection = null) + public OperationContext ReportError( + IError error, + MiddlewareContext resolverContext) { var errors = new List(); @@ -49,53 +50,17 @@ public OperationContext ReportError(IError error, error, errors); - selection ??= resolverContext.Selection; + context.Result.Errors ??= []; foreach (var handled in errors) { - context.Result.AddError(handled, selection); + context.Result.Errors.Add(handled); context.DiagnosticEvents.ResolverError(resolverContext, handled); } return context; } - public OperationContext SetLabel(string? label) - { - context.Result.SetLabel(label); - return context; - } - - public OperationContext SetPath(Path? path) - { - context.Result.SetPath(path); - return context; - } - - public OperationContext SetData(ObjectResult objectResult) - { - context.Result.SetData(objectResult); - return context; - } - - public OperationContext SetItems(IReadOnlyList items) - { - context.Result.SetItems(items); - return context; - } - - public OperationContext SetPatchId(uint patchId) - { - context.Result.SetContextData(WellKnownContextData.PatchId, patchId); - return context; - } - - public OperationContext ClearResult() - { - context.Result.Clear(); - return context; - } - public IOperationResult BuildResult() => context.Result.BuildResult(); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs b/src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs deleted file mode 100644 index 09121d622d5..00000000000 --- a/src/HotChocolate/Core/src/Types/Execution/Options/ResultBufferOptions.cs +++ /dev/null @@ -1,82 +0,0 @@ -using HotChocolate.Execution.Processing; - -namespace HotChocolate.Execution.Options; - -/// -/// Defines the options for the result buffers. -/// -public sealed class ResultBufferOptions -{ - private int _maximumAllowedCapacity = ResultPoolDefaults.MaximumAllowedCapacity; - private int _bucketSize = ResultPoolDefaults.BucketSize; - private int _maximumRetained = ResultPoolDefaults.MaximumRetained; - - /// - /// Defines the maximum number of pooled result objects that are retained in a bucket. - /// - /// - /// The maximum retained must be greater than or equal to 16. - /// - public int MaximumRetained - { - get => _maximumRetained; - set - { - if (value <= 16) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The maximum retained must be greater than or equal to 16."); - } - - _maximumRetained = value; - } - } - - /// - /// Defines the bucket size for pooled result objects. - /// - /// - /// The bucket size must be greater than or equal to 8. - /// - public int BucketSize - { - get - { - return _bucketSize; - } - set - { - if (value <= 8) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The bucket size must be greater than or equal to 8."); - } - - _bucketSize = value; - } - } - - /// - /// Defines the maximum allowed fields or list entries of a pooled object. - /// - /// - /// The maximum allowed capacity must be greater than or equal to 16. - /// - public int MaximumAllowedCapacity - { - get => _maximumAllowedCapacity; - set - { - if (value <= 16) - { - throw new ArgumentOutOfRangeException( - nameof(value), - "The maximum allowed capacity must be greater than or equal to 16."); - } - - _maximumAllowedCapacity = value; - } - } -} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs index 892bf5176ed..ce2a7f9fe9b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs @@ -8,162 +8,136 @@ namespace HotChocolate.Execution.Processing; internal static partial class ValueCompletion { - private static object? CompleteListValue( + private static void CompleteListValue( ValueCompletionContext context, Selection selection, IType type, - ResultData parent, - int index, - object? result) + ResultElement resultValue, + object runtimeValue) { - if (result is null) - { - return null; - } - var elementType = type.InnerType(); - var isLeafType = elementType.IsLeafType(); - var operationContext = context.OperationContext; - var resolverContext = context.ResolverContext; - if (result is Array array) + if (runtimeValue is Array array) { - var resultList = operationContext.Result.RentList(array.Length); - resultList.IsNullable = elementType.Kind is not TypeKind.NonNull; - resultList.SetParent(parent, index); + var i = 0; - for (var i = 0; i < array.Length; i++) - { - var elementResult = array.GetValue(i); + resultValue.SetArrayValue(array.Length); - if (!TryCompleteElement(context, selection, elementType, isLeafType, resultList, i, elementResult)) + foreach (var element in resultValue.EnumerateArray()) + { + Complete( + context, + selection, + elementType, + element, + array.GetValue(i++)); + + // if we ran into an error that invalidated the result we abort. + if (element.IsInvalidated) { - operationContext.Result.AddRemovedResult(resultList); - return null; + return; } } - - return resultList; } - if (result is IList list) + if (runtimeValue is IList list) { - var resultList = operationContext.Result.RentList(list.Count); - resultList.IsNullable = elementType.Kind is not TypeKind.NonNull; - resultList.SetParent(parent, index); + var i = 0; + + resultValue.SetArrayValue(list.Count); - for (var i = 0; i < list.Count; i++) + foreach (var element in resultValue.EnumerateArray()) { - if (!TryCompleteElement(context, selection, elementType, isLeafType, resultList, i, list[i])) + Complete( + context, + selection, + elementType, + element, + list[i++]); + + // if we ran into an error that invalidated the result we abort. + if (element.IsInvalidated) { - operationContext.Result.AddRemovedResult(resultList); - return null; + return; } } - - return resultList; } - if (result is IEnumerable enumerable) + if (runtimeValue is JsonElement { ValueKind: JsonValueKind.Array } node) { - var resultList = operationContext.Result.RentList(4); - resultList.IsNullable = elementType.Kind is not TypeKind.NonNull; - resultList.SetParent(parent, index); + resultValue.SetArrayValue(node.GetArrayLength()); - var i = 0; + using var runtimeEnumerator = node.EnumerateArray().GetEnumerator(); - foreach (var element in enumerable) + foreach (var element in resultValue.EnumerateArray()) { - if (resultList.Count == resultList.Capacity) - { - resultList.Grow(); - } + runtimeEnumerator.MoveNext(); - if (!TryCompleteElement(context, selection, elementType, isLeafType, resultList, i++, element)) + Complete( + context, + selection, + elementType, + element, + runtimeEnumerator.Current); + + // if we ran into an error that invalidated the result we abort. + if (element.IsInvalidated) { - operationContext.Result.AddRemovedResult(resultList); - return null; + return; } } - - return resultList; } - if (result is JsonElement { ValueKind: JsonValueKind.Array } node) + if (runtimeValue is IEnumerable enumerable) { - var resultList = operationContext.Result.RentList(4); - resultList.IsNullable = elementType.Kind is not TypeKind.NonNull; - resultList.SetParent(parent, index); - var i = 0; - foreach (var element in node.EnumerateArray()) - { - if (resultList.Count == resultList.Capacity) - { - resultList.Grow(); - } + var temp = new List(); - if (!TryCompleteElement(context, selection, elementType, isLeafType, resultList, i++, element)) - { - operationContext.Result.AddRemovedResult(resultList); - return null; - } + foreach (var value in enumerable) + { + temp.Add(value); } - return resultList; - } - - var errorPath = CreatePathFromContext(selection, parent, index); - var error = ListValueIsNotSupported(result.GetType(), selection, errorPath); - operationContext.ReportError(error, resolverContext, selection); - - return null; - } + resultValue.SetArrayValue(temp.Count); - private static bool TryCompleteElement( - ValueCompletionContext context, - Selection selection, - IType elementType, - bool isLeafType, - ListResult list, - int parentIndex, - object? elementResult) - { - // We first add a null entry so that the null-propagation has an element to traverse. - var index = list.AddUnsafe(null); - var completedElement = Complete(context, selection, elementType, list, parentIndex, elementResult); - - if (completedElement is not null) - { - if (isLeafType) + foreach (var element in resultValue.EnumerateArray()) { - list.SetUnsafe(index, completedElement); - } - else - { - var resultData = (ResultData)completedElement; - - if (resultData.IsInvalidated) + Complete( + context, + selection, + elementType, + element, + temp[i++]); + + // if we ran into an error that invalidated the result we abort. + if (element.IsInvalidated) { - return list.IsNullable; + return; } - - list.SetUnsafe(index, resultData); } - return true; } - return list.IsNullable; + var operationContext = context.OperationContext; + var resolverContext = context.ResolverContext; + var error = ListValueIsNotSupported(runtimeValue.GetType(), selection, resultValue.Path); + operationContext.ReportError(error, resolverContext, selection); } internal static void PropagateNullValues(ResultElement result) { result.Invalidate(); - while (result.IsInvalidated || result.IsInvalidated) + do { result = result.Parent; - } + if (result.IsNullable) + { + result.SetNullValue(); + return; + } + + result.Invalidate(); + } while (result is { IsInvalidated: false }); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs index 30bb5f92356..080e9a75d99 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs @@ -29,13 +29,17 @@ private static void CompleteCompositeValue( runtimeValue = converted; } - return EnqueueOrInlineResolverTasks(context, objectType, parent, index, runtimeValue, selectionSet); + EnqueueOrInlineResolverTasks( + context, + selectionSet, + objectType, + resultValue, + runtimeValue); + return; } - var errorPath = CreatePathFromContext(selection, parent, index); - var error = ValueCompletion_CouldNotResolveAbstractType(selection, errorPath, runtimeValue); + var error = ValueCompletion_CouldNotResolveAbstractType(selection, resultValue.Path, runtimeValue); operationContext.ReportError(error, context.ResolverContext, selection); - return null; } private static bool TryResolveObjectType( diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs index c0605295da6..6c849e2d813 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs @@ -11,13 +11,13 @@ public static void Complete( Selection selection, ResultElement resultValue, object? result) - => Complete(context, selection, selection.Type, resultValue, index, result); + => Complete(context, selection, selection.Type, resultValue, result); public static void Complete( ValueCompletionContext context, Selection selection, IType type, - ResultElement parent, + ResultElement resultValue, object? result) { var typeKind = type.Kind; @@ -30,29 +30,28 @@ public static void Complete( if (result is null) { - parent.SetNullValue(); + resultValue.SetNullValue(); return; } switch (typeKind) { case TypeKind.Scalar or TypeKind.Enum: - CompleteLeafValue(context, selection, type, parent, index, result); + CompleteLeafValue(context, selection, (ILeafType2)type, resultValue, result); break; case TypeKind.List: - return CompleteListValue(context, selection, type, parent, index, result); + CompleteListValue(context, selection, type, resultValue, result); + break; case TypeKind.Object or TypeKind.Interface or TypeKind.Union: - return CompleteCompositeValue(context, selection, type, parent, index, result); + CompleteCompositeValue(context, selection, type, resultValue, result); + break; default: - { - var errorPath = CreatePathFromContext(selection, parent, index); - var error = UnexpectedValueCompletionError(selection, errorPath); + var error = UnexpectedValueCompletionError(selection, resultValue.Path); context.OperationContext.ReportError(error, context.ResolverContext, selection); - return null; - } + break; } } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs index f769423b490..e0f6c02a344 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs @@ -17,7 +17,6 @@ internal sealed partial class WorkScheduler(OperationContext operationContext) private IBatchDispatcher _batchDispatcher = null!; private IDisposable _batchDispatcherSession = null!; private IErrorHandler _errorHandler = null!; - private ResultBuilder _result = null!; private IExecutionDiagnosticEvents _diagnosticEvents = null!; private readonly ConcurrentDictionary _completed = new(); private uint _nextId = 1; @@ -33,7 +32,6 @@ public void Initialize(IBatchDispatcher batchDispatcher) _batchDispatcherSession = _batchDispatcher.Subscribe(this); _errorHandler = operationContext.ErrorHandler; - _result = operationContext.Result; _diagnosticEvents = operationContext.DiagnosticEvents; _ct = operationContext.RequestAborted; @@ -63,7 +61,6 @@ public void Clear() _nextId = 1; _requestContext = null!; _errorHandler = null!; - _result = null!; _diagnosticEvents = null!; _ct = CancellationToken.None; diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs index 9246b7aca06..41b9d050cd4 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -28,7 +28,7 @@ public void Write() _indentation++; } - if (document._errors?.Count > 0) + if (document.Errors?.Count > 0) { if (indented) { @@ -49,7 +49,7 @@ public void Write() using var jsonWriter = new Utf8JsonWriter(writer, options); JsonValueFormatter.WriteErrors( jsonWriter, - document._errors, + document.Errors, new JsonSerializerOptions(JsonSerializerDefaults.Web), default); jsonWriter.Flush(); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index 4d931fed0de..5fafdee1c60 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -1,10 +1,13 @@ using System.Buffers; +using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; using HotChocolate.Buffers; using HotChocolate.Execution; using HotChocolate.Execution.Processing; +using HotChocolate.Features; using HotChocolate.Types; namespace HotChocolate.Text.Json; @@ -18,8 +21,11 @@ public sealed partial class ResultDocument : IDisposable private int _nextDataIndex; private int _rentedDataSize; private readonly List _data = []; +#if NET10_0_OR_GREATER + private readonly Lock _dataChunkLock = new(); +#else private readonly object _dataChunkLock = new(); - private List? _errors; +#endif private bool _disposed; internal ResultDocument(Operation operation, ulong includeFlags) @@ -33,19 +39,6 @@ internal ResultDocument(Operation operation, ulong includeFlags) public ResultElement Data { get; } - // we need extra methods to add stuff - public List? Errors - { - get => _errors; - internal set => _errors = value; - } - - public int RequestIndex { get; init; } - - public int VariableIndex { get; init; } - - public Dictionary? Extensions { get; set; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ElementTokenType GetElementTokenType(Cursor cursor) => _metaDb.GetElementTokenType(cursor); @@ -216,8 +209,8 @@ internal ResultElement GetParent(Cursor current) // if we have not yet reached the root and the element type of the parent is an object or an array // then we need to get still the parent of this row as we want to get the logical parent // which is the value level of the property or the element in an array. - if (parent != Cursor.Zero - && _metaDb.GetElementTokenType(parent) is ElementTokenType.StartObject or ElementTokenType.StartArray) + if (parent != Cursor.Zero && + _metaDb.GetElementTokenType(parent) is ElementTokenType.StartObject or ElementTokenType.StartArray) { parent = _metaDb.GetParentCursor(parent); @@ -449,52 +442,61 @@ private ReadOnlySpan ReadLocalData(int location, int size) // Data spans chunk boundaries - this should be rare for typical JSON values throw new NotSupportedException( - "Reading data that spans chunk boundaries as a span is not supported. " - + "Use WriteLocalDataTo for writing to an IBufferWriter instead."); + "Reading data that spans chunk boundaries as a span is not supported. " + + "Use WriteLocalDataTo for writing to an IBufferWriter instead."); } internal ResultElement CreateObject(Cursor parent, SelectionSet selectionSet) { - var startObjectCursor = WriteStartObject(parent, selectionSet.Id); - - var selectionCount = 0; - foreach (var selection in selectionSet.Selections) + lock (_dataChunkLock) { - WriteEmptyProperty(startObjectCursor, selection); - selectionCount++; - } + var startObjectCursor = WriteStartObject(parent, selectionSet.Id); - WriteEndObject(startObjectCursor, selectionCount); + var selectionCount = 0; + foreach (var selection in selectionSet.Selections) + { + WriteEmptyProperty(startObjectCursor, selection); + selectionCount++; + } - return new ResultElement(this, startObjectCursor); + WriteEndObject(startObjectCursor, selectionCount); + + return new ResultElement(this, startObjectCursor); + } } internal ResultElement CreateObject(Cursor parent, int propertyCount) { - var startObjectCursor = WriteStartObject(parent, isSelectionSet: false); - - for (var i = 0; i < propertyCount; i++) + lock (_dataChunkLock) { - WriteEmptyProperty(startObjectCursor); - } + var startObjectCursor = WriteStartObject(parent, isSelectionSet: false); - WriteEndObject(startObjectCursor, propertyCount); + for (var i = 0; i < propertyCount; i++) + { + WriteEmptyProperty(startObjectCursor); + } - return new ResultElement(this, startObjectCursor); + WriteEndObject(startObjectCursor, propertyCount); + + return new ResultElement(this, startObjectCursor); + } } internal ResultElement CreateArray(Cursor parent, int length) { - var cursor = WriteStartArray(parent, length); - - for (var i = 0; i < length; i++) + lock (_dataChunkLock) { - WriteEmptyValue(cursor); - } + var cursor = WriteStartArray(parent, length); + + for (var i = 0; i < length; i++) + { + WriteEmptyValue(cursor); + } - WriteEndArray(); + WriteEndArray(); - return new ResultElement(this, cursor); + return new ResultElement(this, cursor); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 8da86fd931663da6d5989f5ae3eb7d55a581efbd Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 10:55:25 +0100 Subject: [PATCH 34/42] wip --- .../DefaultHttpResponseFormatter.cs | 22 +- .../DefaultWebSocketPayloadFormatter.cs | 2 +- .../Formatters/IWebSocketPayloadFormatter.cs | 2 +- .../HttpMultipartMiddleware.cs | 2 +- .../HttpPostMiddlewareBase.cs | 16 +- .../AggregateServerDiagnosticEventListener.cs | 2 +- .../IServerDiagnosticEvents.cs | 2 +- .../NoopServerDiagnosticEventListener.cs | 2 +- .../Interceptors/ISocketSessionInterceptor.cs | 6 +- .../Utilities/ErrorHelper.cs | 22 +- .../Utilities/MiddlewareHelper.cs | 10 +- .../EventStreamResultFormatter.cs | 8 +- .../JsonLinesResultFormatter.cs | 8 +- .../JsonResultFormatter.cs | 82 +---- .../MultiPartResultFormatter.cs | 8 +- .../src/Transport.Http/GraphQLHttpResponse.cs | 33 +- .../GraphQLOverHttpSpecTests.cs | 1 + .../Execution/OperationResultHelper.cs | 83 ----- .../Abstractions/SingleValueExtensionData.cs | 91 ----- .../Execution/ExecutionResult.cs | 38 +-- .../CoreExecutionResultExtensions.cs | 164 +++++---- .../Features/IncrementalDataFeature.cs | 16 + .../Execution/IOperationResult.cs | 70 ---- .../Execution/IOperationResultFormatter.cs | 6 +- .../Execution/IRawJsonFormatter.cs | 5 +- .../Execution/IRequestExecutor.cs | 6 +- .../Execution/IResponseStream.cs | 4 +- .../Execution/OperationResult.cs | 314 ++++++++++++++++++ .../Execution/OperationResultBatch.cs | 10 +- .../Execution/OperationResultData.cs | 58 ++++ .../Execution/RequestExecutorProxy.cs | 6 +- .../Execution/ResponseStream.cs | 20 +- .../DocumentParserMiddleware.cs | 2 +- .../DocumentValidationMiddleware.cs | 13 +- .../src/Execution.Pipeline/ErrorHelper.cs | 4 +- .../Execution.Pipeline/ExceptionMiddleware.cs | 6 +- .../src/Validation/DocumentValidatorResult.cs | 4 +- .../FusionTestBase.MatchSnapshot.cs | 8 +- ...ticPersistedOperationNotFoundMiddleware.cs | 29 +- ...nlyPersistedOperationsAllowedMiddleware.cs | 9 +- .../PersistedOperationNotFoundMiddleware.cs | 6 +- .../WritePersistedOperationMiddleware.cs | 11 +- 42 files changed, 643 insertions(+), 568 deletions(-) delete mode 100644 src/HotChocolate/Core/src/Abstractions/Execution/OperationResultHelper.cs delete mode 100644 src/HotChocolate/Core/src/Abstractions/SingleValueExtensionData.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/Features/IncrementalDataFeature.cs delete mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs create mode 100644 src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultData.cs diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultHttpResponseFormatter.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultHttpResponseFormatter.cs index d16564200d0..fbd0f33c145 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultHttpResponseFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultHttpResponseFormatter.cs @@ -201,22 +201,20 @@ private async ValueTask FormatInternalAsync( { switch (result) { - case IOperationResult operationResult: + case OperationResult operationResult: { var statusCode = (int)OnDetermineStatusCode(operationResult, format, proposedStatusCode); response.ContentType = format.ContentType; response.StatusCode = statusCode; - if (result.ContextData is not null - && result.ContextData.TryGetValue(ExecutionContextData.CacheControlHeaderValue, out var value) + if (result.ContextData.TryGetValue(ExecutionContextData.CacheControlHeaderValue, out var value) && value is CacheControlHeaderValue cacheControlHeaderValue) { response.GetTypedHeaders().CacheControl = cacheControlHeaderValue; } - if (result.ContextData is not null - && result.ContextData.TryGetValue(ExecutionContextData.VaryHeaderValue, out var varyValue) + if (result.ContextData.TryGetValue(ExecutionContextData.VaryHeaderValue, out var varyValue) && varyValue is string varyHeaderValue) { response.Headers.Vary = varyHeaderValue; @@ -301,7 +299,7 @@ CachedSchemaOutput Update(string _) /// Determines which status code shall be returned for this result. /// /// - /// The . + /// The . /// /// /// Provides information about the transport format that is applied. @@ -313,7 +311,7 @@ CachedSchemaOutput Update(string _) /// Returns the that the formatter must use. /// protected virtual HttpStatusCode OnDetermineStatusCode( - IOperationResult result, + OperationResult result, FormatInfo format, HttpStatusCode? proposedStatusCode) { @@ -346,10 +344,8 @@ protected virtual HttpStatusCode OnDetermineStatusCode( // if the GraphQL result has context data, we will check if some middleware provided // a status code or indicated an error that should be interpreted as a status code. - if (result.ContextData is not null) + if (result.ContextData is { Count: > 0 } contextData) { - var contextData = result.ContextData; - // First, we check if there is an explicit HTTP status code override by the user. if (contextData.TryGetValue(ExecutionContextData.HttpStatusCode, out var value)) { @@ -371,7 +367,7 @@ protected virtual HttpStatusCode OnDetermineStatusCode( return HttpStatusCode.BadRequest; } - if (result.ContextData.ContainsKey(ExecutionContextData.OperationNotAllowed)) + if (contextData.ContainsKey(ExecutionContextData.OperationNotAllowed)) { return HttpStatusCode.MethodNotAllowed; } @@ -405,7 +401,7 @@ protected virtual HttpStatusCode OnDetermineStatusCode( /// the formatter starts writing the response body. /// /// - /// The . + /// The . /// /// /// Provides information about the transport format that is applied. @@ -414,7 +410,7 @@ protected virtual HttpStatusCode OnDetermineStatusCode( /// The header dictionary. /// protected virtual void OnWriteResponseHeaders( - IOperationResult result, + OperationResult result, FormatInfo format, IHeaderDictionary headers) { diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultWebSocketPayloadFormatter.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultWebSocketPayloadFormatter.cs index f7eda176d65..0516575b22c 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultWebSocketPayloadFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/DefaultWebSocketPayloadFormatter.cs @@ -12,7 +12,7 @@ public class DefaultWebSocketPayloadFormatter(WebSocketPayloadFormatterOptions o private readonly JsonResultFormatter _jsonFormatter = new(options.Json); /// - public void Format(IOperationResult result, Utf8JsonWriter jsonWriter) + public void Format(OperationResult result, Utf8JsonWriter jsonWriter) { _jsonFormatter.Format(result, jsonWriter); } diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/IWebSocketPayloadFormatter.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/IWebSocketPayloadFormatter.cs index 6833e680501..367939e0f69 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/IWebSocketPayloadFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Formatters/IWebSocketPayloadFormatter.cs @@ -16,7 +16,7 @@ public interface IWebSocketPayloadFormatter /// /// The JSON writer that is used to write the payload. /// - void Format(IOperationResult result, Utf8JsonWriter jsonWriter); + void Format(OperationResult result, Utf8JsonWriter jsonWriter); /// /// Formats the into a WebSocket payload. diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpMultipartMiddleware.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpMultipartMiddleware.cs index 7f96517c911..a2f1df11c1a 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpMultipartMiddleware.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpMultipartMiddleware.cs @@ -20,7 +20,7 @@ public sealed class HttpMultipartMiddleware : HttpPostMiddlewareBase private const string Operations = "operations"; private const string Map = "map"; private readonly FormOptions _formOptions; - private readonly IOperationResult _multipartRequestError = MultiPartRequestPreflightRequired(); + private readonly OperationResult _multipartRequestError = MultiPartRequestPreflightRequired(); public HttpMultipartMiddleware( HttpRequestDelegate next, diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs index 739fa6f5263..655d7fe06be 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs @@ -79,7 +79,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses statusCode = HttpStatusCode.NotAcceptable; var error = ErrorHelper.NoSupportedAcceptMediaType(); - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); goto HANDLE_RESULT; } @@ -100,7 +100,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses // GraphQL error result. statusCode = HttpStatusCode.BadRequest; var errors = session.Handle(ex.Errors); - result = OperationResultBuilder.CreateError(errors); + result = OperationResult.FromError([..errors]); session.DiagnosticEvents.ParserErrors(context, errors); goto HANDLE_RESULT; } @@ -108,7 +108,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { statusCode = HttpStatusCode.InternalServerError; var error = ErrorBuilder.FromException(ex).Build(); - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); goto HANDLE_RESULT; } @@ -125,7 +125,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { statusCode = HttpStatusCode.BadRequest; var error = session.Handle(ErrorHelper.RequestHasNoElements()); - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); break; } @@ -151,7 +151,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { var error = session.Handle(ErrorHelper.InvalidRequest()); statusCode = HttpStatusCode.BadRequest; - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); } @@ -180,7 +180,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { var error = session.Handle(ErrorHelper.InvalidRequest()); statusCode = HttpStatusCode.BadRequest; - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); } break; @@ -190,7 +190,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { // This allows extensions to throw GraphQL exceptions in the GraphQL interceptor. statusCode = null; // we let the serializer determine the status code. - result = OperationResultBuilder.CreateError(ex.Errors); + result = OperationResult.FromError([..ex.Errors]); foreach (var error in ex.Errors) { @@ -201,7 +201,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses { statusCode = HttpStatusCode.InternalServerError; var error = ErrorBuilder.FromException(ex).Build(); - result = OperationResultBuilder.CreateError(error); + result = OperationResult.FromError(error); session.DiagnosticEvents.HttpRequestError(context, error); } diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/AggregateServerDiagnosticEventListener.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/AggregateServerDiagnosticEventListener.cs index 5f0dbf09438..3fd66e60177 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/AggregateServerDiagnosticEventListener.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/AggregateServerDiagnosticEventListener.cs @@ -87,7 +87,7 @@ public void ParserErrors(HttpContext context, IReadOnlyList errors) } } - public IDisposable FormatHttpResponse(HttpContext context, IOperationResult result) + public IDisposable FormatHttpResponse(HttpContext context, OperationResult result) { var scopes = new IDisposable[_listeners.Length]; diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/IServerDiagnosticEvents.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/IServerDiagnosticEvents.cs index 925a546f5c1..781460bcdb1 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/IServerDiagnosticEvents.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/IServerDiagnosticEvents.cs @@ -124,7 +124,7 @@ void StartOperationBatchRequest( /// /// A scope that will be disposed when GraphQL query result is written to the response stream. /// - IDisposable FormatHttpResponse(HttpContext context, IOperationResult result); + IDisposable FormatHttpResponse(HttpContext context, OperationResult result); /// /// Called when starting to establish a GraphQL WebSocket session. diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/NoopServerDiagnosticEventListener.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/NoopServerDiagnosticEventListener.cs index 2387107c8e0..2270cb61880 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/NoopServerDiagnosticEventListener.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/NoopServerDiagnosticEventListener.cs @@ -37,7 +37,7 @@ public void ParserErrors(HttpContext context, IReadOnlyList errors) { } - public IDisposable FormatHttpResponse(HttpContext context, IOperationResult result) => EmptyScope; + public IDisposable FormatHttpResponse(HttpContext context, OperationResult result) => EmptyScope; public IDisposable WebSocketSession(HttpContext context) => EmptyScope; diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs index 6945d03bca1..4333b22b3ca 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs @@ -67,12 +67,12 @@ ValueTask OnRequestAsync( /// The cancellation token. /// /// - /// Returns the result that shall be send to the client. + /// Returns the result that shall be sent to the client. /// - ValueTask OnResultAsync( + ValueTask OnResultAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken = default); /// diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/ErrorHelper.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/ErrorHelper.cs index 2f250d25e4e..4497118695b 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/ErrorHelper.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/ErrorHelper.cs @@ -26,8 +26,8 @@ public static IError NoSupportedAcceptMediaType() .SetCode(ErrorCodes.Server.NoSupportedAcceptMediaType) .Build(); - public static IOperationResult TypeNameIsEmpty() - => OperationResultBuilder.CreateError( + public static OperationResult TypeNameIsEmpty() + => OperationResult.FromError( new Error { Message = ErrorHelper_TypeNameIsEmpty, @@ -35,8 +35,8 @@ public static IOperationResult TypeNameIsEmpty() .Add("code", ErrorCodes.Server.TypeParameterIsEmpty) }); - public static IOperationResult InvalidTypeName(string typeName) - => OperationResultBuilder.CreateError( + public static OperationResult InvalidTypeName(string typeName) + => OperationResult.FromError( new Error { Message = ErrorHelper_InvalidTypeName, @@ -45,8 +45,8 @@ public static IOperationResult InvalidTypeName(string typeName) .Add(nameof(typeName), typeName) }); - public static IOperationResult TypeNotFound(string typeName) - => OperationResultBuilder.CreateError( + public static OperationResult TypeNotFound(string typeName) + => OperationResult.FromError( new Error { Message = string.Format(ErrorHelper_TypeNotFound, typeName), @@ -55,8 +55,8 @@ public static IOperationResult TypeNotFound(string typeName) .Add(nameof(typeName), typeName) }); - public static IOperationResult InvalidAcceptMediaType(string headerValue) - => OperationResultBuilder.CreateError( + public static OperationResult InvalidAcceptMediaType(string headerValue) + => OperationResult.FromError( new Error { Message = string.Format(ErrorHelper_InvalidAcceptMediaType, headerValue), @@ -65,8 +65,8 @@ public static IOperationResult InvalidAcceptMediaType(string headerValue) .Add(nameof(headerValue), headerValue) }); - public static IOperationResult MultiPartRequestPreflightRequired() - => OperationResultBuilder.CreateError( + public static OperationResult MultiPartRequestPreflightRequired() + => OperationResult.FromError( new Error { Message = ErrorHelper_MultiPartRequestPreflightRequired, @@ -81,7 +81,7 @@ public static GraphQLRequestException InvalidOperationIdFormat() .Build()); public static IExecutionResult OperationNameRequired() - => OperationResultBuilder.CreateError( + => OperationResult.FromError( ErrorBuilder.New() .SetMessage("The operation name is required.") .Build()); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs index 9c9e3ac6ff7..d894b5a34fd 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs @@ -227,14 +227,14 @@ await executorSession.OnCreateAsync( } return new ExecuteRequestResult( - OperationResultBuilder.CreateError(ex.Errors)); + OperationResult.FromError([..ex.Errors])); } catch (Exception ex) { var error = ErrorBuilder.FromException(ex).Build(); executorSession.DiagnosticEvents.HttpRequestError(context, error); return new ExecuteRequestResult( - OperationResultBuilder.CreateError(error), + OperationResult.FromError(error), HttpStatusCode.InternalServerError); } } @@ -313,7 +313,7 @@ public ValidateAcceptContentTypeResult( AcceptMediaType[] acceptMediaTypes) { IsValid = false; - Error = OperationResultBuilder.CreateError(error); + Error = OperationResult.FromError(error); StatusCode = statusCode; RequestFlags = RequestFlags.None; AcceptMediaTypes = acceptMediaTypes; @@ -345,7 +345,7 @@ public ParseRequestResult(GraphQLRequest request) public ParseRequestResult(IReadOnlyList errors, HttpStatusCode statusCode) { IsValid = false; - Error = OperationResultBuilder.CreateError(errors); + Error = OperationResult.FromError([..errors]); StatusCode = statusCode; Request = null; } @@ -353,7 +353,7 @@ public ParseRequestResult(IReadOnlyList errors, HttpStatusCode statusCod public ParseRequestResult(IError error, HttpStatusCode statusCode) { IsValid = false; - Error = OperationResultBuilder.CreateError(error); + Error = OperationResult.FromError(error); StatusCode = statusCode; Request = null; } diff --git a/src/HotChocolate/AspNetCore/src/Transport.Formatters/EventStreamResultFormatter.cs b/src/HotChocolate/AspNetCore/src/Transport.Formatters/EventStreamResultFormatter.cs index a939da7cf81..e5905bd7649 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Formatters/EventStreamResultFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Formatters/EventStreamResultFormatter.cs @@ -34,7 +34,7 @@ public ValueTask FormatAsync( return result switch { - IOperationResult operationResult + OperationResult operationResult => FormatOperationResultAsync(operationResult, writer, cancellationToken), OperationResultBatch resultBatch => FormatResultBatchAsync(resultBatch, writer, cancellationToken), @@ -45,7 +45,7 @@ IResponseStream responseStream } private async ValueTask FormatOperationResultAsync( - IOperationResult operationResult, + OperationResult operationResult, PipeWriter writer, CancellationToken ct) { @@ -83,7 +83,7 @@ private async ValueTask FormatResultBatchAsync( { switch (result) { - case IOperationResult operationResult: + case OperationResult operationResult: { using var scope = Log.FormatOperationResultStart(); await semaphore.WaitAsync(ct).ConfigureAwait(false); @@ -364,7 +364,7 @@ private static class MessageHelper public static void FormatNextMessage( JsonResultFormatter payloadFormatter, - IOperationResult result, + OperationResult result, IBufferWriter writer) { // write the SSE event field diff --git a/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonLinesResultFormatter.cs b/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonLinesResultFormatter.cs index 9b0804e7d8b..382ffaf74db 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonLinesResultFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonLinesResultFormatter.cs @@ -23,7 +23,7 @@ public ValueTask FormatAsync( return result switch { - IOperationResult operationResult + OperationResult operationResult => FormatOperationResultAsync(operationResult, writer, cancellationToken), OperationResultBatch resultBatch => FormatResultBatchAsync(resultBatch, writer, cancellationToken), @@ -37,7 +37,7 @@ IResponseStream responseStream /// Writes a single GraphQL response and then completes. /// private async ValueTask FormatOperationResultAsync( - IOperationResult operationResult, + OperationResult operationResult, PipeWriter writer, CancellationToken ct) { @@ -78,7 +78,7 @@ private async ValueTask FormatResultBatchAsync( { switch (result) { - case IOperationResult operationResult: + case OperationResult operationResult: { using var scope = Log.FormatOperationResultStart(); await semaphore.WaitAsync(ct).ConfigureAwait(false); @@ -316,7 +316,7 @@ private static class MessageHelper public static void FormatNextMessage( JsonResultFormatter payloadFormatter, - IOperationResult result, + OperationResult result, IBufferWriter writer) { // write the result data diff --git a/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonResultFormatter.cs b/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonResultFormatter.cs index 5589fcde80d..788b2877a89 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonResultFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Formatters/JsonResultFormatter.cs @@ -8,7 +8,7 @@ namespace HotChocolate.Transport.Formatters; /// -/// The default JSON formatter for . +/// The default JSON formatter for . /// public sealed class JsonResultFormatter : IOperationResultFormatter, IExecutionResultFormatter { @@ -42,12 +42,12 @@ public JsonResultFormatter(JsonResultFormatterOptions options) } /// - /// The default JSON formatter for with indentations. + /// The default JSON formatter for with indentations. /// public static JsonResultFormatter Indented { get; } = new(true); /// - /// The default JSON formatter for without indentations. + /// The default JSON formatter for without indentations. /// public static JsonResultFormatter Default { get; } = new(); @@ -62,7 +62,7 @@ public ValueTask FormatAsync( return result switch { - IOperationResult singleResult => FormatInternalAsync(singleResult, writer, cancellationToken), + OperationResult singleResult => FormatInternalAsync(singleResult, writer, cancellationToken), OperationResultBatch resultBatch => FormatInternalAsync(resultBatch, writer, cancellationToken), IResponseStream responseStream => FormatInternalAsync(responseStream, writer, cancellationToken), _ => throw new NotSupportedException($"The result type '{result.GetType().FullName}' is not supported.") @@ -82,7 +82,7 @@ public ValueTask FormatAsync( /// is null. /// is null. /// - public void Format(IOperationResult result, Utf8JsonWriter writer) + public void Format(OperationResult result, Utf8JsonWriter writer) { ArgumentNullException.ThrowIfNull(result); ArgumentNullException.ThrowIfNull(writer); @@ -147,7 +147,7 @@ public void FormatDictionary(IReadOnlyDictionary dictionary, Ut WriteDictionary(writer, dictionary, _serializerOptions, _nullIgnoreCondition); } - public void Format(IOperationResult result, IBufferWriter writer) + public void Format(OperationResult result, IBufferWriter writer) { ArgumentNullException.ThrowIfNull(result); ArgumentNullException.ThrowIfNull(writer); @@ -155,11 +155,11 @@ public void Format(IOperationResult result, IBufferWriter writer) FormatInternal(result, writer); } - private void FormatInternal(IOperationResult result, IBufferWriter writer) + private void FormatInternal(OperationResult result, IBufferWriter writer) { - if (result is IRawJsonFormatter formatter) + if (result.JsonFormatter is { } formatter) { - formatter.WriteTo(writer, _options.Indented); + formatter.WriteTo(result, writer, _options.Indented); return; } @@ -169,7 +169,7 @@ private void FormatInternal(IOperationResult result, IBufferWriter writer) } public ValueTask FormatAsync( - IOperationResult result, + OperationResult result, PipeWriter writer, CancellationToken cancellationToken = default) { @@ -180,7 +180,7 @@ public ValueTask FormatAsync( } private async ValueTask FormatInternalAsync( - IOperationResult result, + OperationResult result, PipeWriter writer, CancellationToken cancellationToken) { @@ -197,7 +197,7 @@ private async ValueTask FormatInternalAsync( { switch (result) { - case IOperationResult singleResult: + case OperationResult singleResult: FormatInternal(singleResult, writer); break; @@ -244,7 +244,7 @@ private async ValueTask FormatInternalAsync( } } - private void WriteResult(Utf8JsonWriter writer, IOperationResult result) + private void WriteResult(Utf8JsonWriter writer, OperationResult result) { writer.WriteStartObject(); @@ -260,33 +260,15 @@ private void WriteResult(Utf8JsonWriter writer, IOperationResult result) WriteErrors(writer, result.Errors); WriteData(writer, result); - WriteItems(writer, result.Items); - WriteIncremental(writer, result.Incremental); WriteExtensions(writer, result.Extensions, _serializerOptions, _nullIgnoreCondition); - WritePatchInfo(writer, result); WriteHasNext(writer, result); writer.WriteEndObject(); } - private static void WritePatchInfo( - Utf8JsonWriter writer, - IOperationResult result) - { - if (result.Label is not null) - { - writer.WriteString("label", result.Label); - } - - if (result.Path is not null) - { - WritePath(writer, result.Path); - } - } - private static void WriteHasNext( Utf8JsonWriter writer, - IOperationResult result) + OperationResult result) { if (result.HasNext.HasValue) { @@ -296,7 +278,7 @@ private static void WriteHasNext( private void WriteData( Utf8JsonWriter writer, - IOperationResult result) + OperationResult result) { if (!result.IsDataSet) { @@ -314,23 +296,6 @@ private void WriteData( WriteValue(writer, result.Data, _serializerOptions, _nullIgnoreCondition); } - private void WriteItems(Utf8JsonWriter writer, IReadOnlyList? items) - { - if (items is { Count: > 0 }) - { - writer.WritePropertyName(Items); - - writer.WriteStartArray(); - - for (var i = 0; i < items.Count; i++) - { - WriteValue(writer, items[i], _serializerOptions, _nullIgnoreCondition); - } - - writer.WriteEndArray(); - } - } - private void WriteErrors(Utf8JsonWriter writer, IReadOnlyList? errors) { if (errors is { Count: > 0 }) @@ -348,23 +313,6 @@ private void WriteErrors(Utf8JsonWriter writer, IReadOnlyList? errors) } } - private void WriteIncremental(Utf8JsonWriter writer, IReadOnlyList? patches) - { - if (patches is { Count: > 0 }) - { - writer.WritePropertyName(Incremental); - - writer.WriteStartArray(); - - for (var i = 0; i < patches.Count; i++) - { - WriteResult(writer, patches[i]); - } - - writer.WriteEndArray(); - } - } - private Utf8JsonWriter CreateWriter(IBufferWriter buffer) { if (_writer.Value is not { } writer) diff --git a/src/HotChocolate/AspNetCore/src/Transport.Formatters/MultiPartResultFormatter.cs b/src/HotChocolate/AspNetCore/src/Transport.Formatters/MultiPartResultFormatter.cs index acbd3a4b2f5..06d8160d54e 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Formatters/MultiPartResultFormatter.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Formatters/MultiPartResultFormatter.cs @@ -59,7 +59,7 @@ public ValueTask FormatAsync( return result switch { - IOperationResult operationResult + OperationResult operationResult => FormatOperationResultAsync(operationResult, writer, cancellationToken), OperationResultBatch resultBatch => FormatResultBatchAsync(resultBatch, writer, cancellationToken), @@ -70,7 +70,7 @@ IResponseStream responseStream } private async ValueTask FormatOperationResultAsync( - IOperationResult result, + OperationResult result, PipeWriter writer, CancellationToken ct = default) { @@ -98,7 +98,7 @@ private async ValueTask FormatResultBatchAsync( { switch (result) { - case IOperationResult operationResult: + case OperationResult operationResult: buffer ??= new PooledArrayWriter(); MessageHelper.WriteNext(buffer); MessageHelper.WriteResultHeader(buffer); @@ -186,7 +186,7 @@ public static void WriteEnd(IBufferWriter writer) public static void WritePayload( IBufferWriter writer, - IOperationResult result, + OperationResult result, IOperationResultFormatter payloadFormatter) => payloadFormatter.Format(result, writer); diff --git a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs index 2281101d5b2..5bcefd216d2 100644 --- a/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs +++ b/src/HotChocolate/AspNetCore/src/Transport.Http/GraphQLHttpResponse.cs @@ -1,5 +1,3 @@ - -using HotChocolate.Buffers; #if FUSION using System.Buffers; using System.Net; @@ -12,6 +10,7 @@ using System.Net.Http.Headers; using System.Text.Json; #endif +using HotChocolate.Buffers; #if FUSION namespace HotChocolate.Fusion.Transport.Http; @@ -105,19 +104,29 @@ public GraphQLHttpResponse(HttpResponseMessage message) /// public HttpResponseHeaders TrailingHeaders => _message.TrailingHeaders; +#if FUSION /// - /// Reads the GraphQL response as a . + /// Reads the GraphQL response as a . /// /// /// A cancellation token that can be used to cancel the HTTP request. /// /// /// A that represents the asynchronous read operation - /// to read the from the underlying . + /// to read the from the underlying . /// -#if FUSION public ValueTask ReadAsResultAsync(CancellationToken cancellationToken = default) #else + /// + /// Reads the GraphQL response as a . + /// + /// + /// A cancellation token that can be used to cancel the HTTP request. + /// + /// + /// A that represents the asynchronous read operation + /// to read the from the underlying . + /// public ValueTask ReadAsResultAsync(CancellationToken cancellationToken = default) #endif { @@ -302,6 +311,17 @@ private async ValueTask ReadAsResultInternalAsync(string? charS #endif } +#if FUSION + /// + /// Reads the GraphQL response as a of . + /// + /// + /// A of that represents the asynchronous + /// read operation to read the stream of s from the underlying + /// . + /// + public IAsyncEnumerable ReadAsResultStreamAsync() +#else /// /// Reads the GraphQL response as a of . /// @@ -310,9 +330,6 @@ private async ValueTask ReadAsResultInternalAsync(string? charS /// read operation to read the stream of s from the underlying /// . /// -#if FUSION - public IAsyncEnumerable ReadAsResultStreamAsync() -#else public IAsyncEnumerable ReadAsResultStreamAsync() #endif { diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs index 799e4afb4cc..c0bfcc614dd 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs @@ -10,6 +10,7 @@ using static System.Net.HttpStatusCode; using static HotChocolate.AspNetCore.HttpTransportVersion; using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue; +using OperationResult = HotChocolate.Execution.OperationResult; namespace HotChocolate.AspNetCore; diff --git a/src/HotChocolate/Core/src/Abstractions/Execution/OperationResultHelper.cs b/src/HotChocolate/Core/src/Abstractions/Execution/OperationResultHelper.cs deleted file mode 100644 index b8e26e910cc..00000000000 --- a/src/HotChocolate/Core/src/Abstractions/Execution/OperationResultHelper.cs +++ /dev/null @@ -1,83 +0,0 @@ -namespace HotChocolate.Execution; - -internal static class OperationResultHelper -{ - private const string Data = "data"; - private const string Errors = "errors"; - private const string Extensions = "extensions"; - private const string Message = "message"; - private const string Locations = "locations"; - private const string Path = "path"; - private const string Line = "line"; - private const string Column = "column"; - - public static IReadOnlyDictionary ToDictionary(IOperationResult result) - { - var formatted = new OrderedDictionary(); - - if (result.Errors is { Count: > 0 }) - { - formatted[Errors] = SerializeErrors(result.Errors); - } - - if (result.Data is { Count: > 0 }) - { - formatted[Data] = result.Data; - } - - if (result.Extensions is { Count: > 0 }) - { - formatted[Extensions] = result.Extensions; - } - - return formatted; - } - - private static ICollection SerializeErrors( - IReadOnlyCollection errors) - { - var formattedErrors = new List(); - - foreach (var error in errors) - { - var formattedError = new OrderedDictionary { [Message] = error.Message }; - - if (error.Locations is { Count: > 0 }) - { - formattedError[Locations] = SerializeLocations(error.Locations); - } - - if (error.Path is { }) - { - formattedError[Path] = error.Path.ToList(); - } - - if (error.Extensions is { Count: > 0 }) - { - formattedError[Extensions] = error.Extensions; - } - - formattedErrors.Add(formattedError); - } - - return formattedErrors; - } - - private static IReadOnlyList> SerializeLocations( - IReadOnlyList locations) - { - var serializedLocations = new IReadOnlyDictionary[locations.Count]; - - for (var i = 0; i < locations.Count; i++) - { - var location = locations[i]; - serializedLocations[i] = new OrderedDictionary - { - { Line, location.Line }, - { Column, location.Column } - }; - } - - return serializedLocations; - } -} diff --git a/src/HotChocolate/Core/src/Abstractions/SingleValueExtensionData.cs b/src/HotChocolate/Core/src/Abstractions/SingleValueExtensionData.cs deleted file mode 100644 index 67fc7f375c3..00000000000 --- a/src/HotChocolate/Core/src/Abstractions/SingleValueExtensionData.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System.Collections; -using HotChocolate.Execution; -using static HotChocolate.Properties.AbstractionResources; - -namespace HotChocolate; - -/// -/// An optimized extension data dictionary for or -/// when only one value is needed. -/// -public sealed class SingleValueExtensionData : IReadOnlyDictionary -{ - private readonly string _key; - private readonly object? _value; - - /// - /// Creates a new instance of . - /// - /// The key. - /// The value. - public SingleValueExtensionData(string key, object? value) - { - ArgumentException.ThrowIfNullOrEmpty(key); - - _key = key; - _value = value; - } - - /// - public int Count => 1; - - /// - public bool ContainsKey(string key) => string.Equals(_key, key, StringComparison.Ordinal); - - /// - public bool TryGetValue(string key, out object? value) - { - if (ContainsKey(key)) - { - value = _value; - return true; - } - - value = null; - return false; - } - - /// - public object? this[string key] - { - get - { - if (TryGetValue(key, out var value)) - { - return value; - } - - throw new KeyNotFoundException(string.Format( - SingleValueExtensionData_KeyNotFound, - key)); - } - } - - /// - public IEnumerable Keys - { - get - { - yield return _key; - } - } - - /// - public IEnumerable Values - { - get - { - yield return _value; - } - } - - /// - public IEnumerator> GetEnumerator() - { - yield return new KeyValuePair(_key, _value); - } - - /// - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); -} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs index 88b7c2035a7..a3d5f869992 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ExecutionResult.cs @@ -9,22 +9,11 @@ namespace HotChocolate.Execution; /// public abstract class ExecutionResult : IExecutionResult { - protected static readonly ArrayPool> CleanUpTaskPool = ArrayPool>.Shared; + private static readonly ArrayPool> s_cleanUpTaskPool = ArrayPool>.Shared; private Func[] _cleanUpTasks = []; private int _cleanupTasksLength; private bool _disposed; - protected ExecutionResult() - { - Features = new FeatureCollection(); - } - - protected ExecutionResult((Func[] Tasks, int Length)? cleanupTasks, IFeatureCollection? features) - { - Features = features ?? new FeatureCollection(); - (_cleanUpTasks, _cleanupTasksLength) = cleanupTasks ?? ([], 0); - } - /// public abstract ExecutionResultKind Kind { get; } @@ -36,22 +25,7 @@ protected ExecutionResult((Func[] Tasks, int Length)? cleanupTasks, I } /// - public IFeatureCollection Features { get; } - - /// - /// This helper allows someone else to take over the responsibility over the cleanup tasks. - /// This object no longer will track them after they were taken over. - /// - private protected (Func[] Tasks, int Length) TakeCleanUpTasks() - { - var tasks = _cleanUpTasks; - var taskLength = _cleanupTasksLength; - - _cleanUpTasks = []; - _cleanupTasksLength = 0; - - return (tasks, taskLength); - } + public IFeatureCollection Features { get; } = new FeatureCollection(); /// public void RegisterForCleanup(Func clean) @@ -60,17 +34,17 @@ public void RegisterForCleanup(Func clean) if (_cleanUpTasks.Length == 0) { - _cleanUpTasks = CleanUpTaskPool.Rent(8); + _cleanUpTasks = s_cleanUpTaskPool.Rent(8); _cleanupTasksLength = 0; } else if (_cleanupTasksLength >= _cleanUpTasks.Length) { - var buffer = CleanUpTaskPool.Rent(_cleanupTasksLength * 2); + var buffer = s_cleanUpTaskPool.Rent(_cleanupTasksLength * 2); var currentBuffer = _cleanUpTasks.AsSpan(); currentBuffer.CopyTo(buffer); currentBuffer.Clear(); - CleanUpTaskPool.Return(_cleanUpTasks); + s_cleanUpTaskPool.Return(_cleanUpTasks); _cleanUpTasks = buffer; } @@ -98,7 +72,7 @@ public async ValueTask DisposeAsync() } tasks.AsSpan(0, _cleanupTasksLength).Clear(); - CleanUpTaskPool.Return(tasks); + s_cleanUpTaskPool.Return(tasks); } _disposed = true; diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs index 6e7a1985f1d..c704855ca06 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs @@ -8,109 +8,97 @@ namespace HotChocolate.Execution; /// public static class CoreExecutionResultExtensions { - /// - /// Registers a cleanup task for execution resources bound to this execution result. - /// - /// - /// The . - /// - /// - /// A cleanup task that will be executed when this result is disposed. - /// - public static void RegisterForCleanup(this IExecutionResult result, Action clean) + extension(IExecutionResult result) { - ArgumentNullException.ThrowIfNull(result); - ArgumentNullException.ThrowIfNull(clean); - - result.RegisterForCleanup(() => + /// + /// Registers a cleanup task for execution resources bound to this execution result. + /// + /// + /// A cleanup task that will be executed when this result is disposed. + /// + public void RegisterForCleanup(Action clean) { - clean(); - return default; - }); - } - - /// - /// Registers a resource that needs to be disposed when the result is being disposed. - /// - /// - /// The . - /// - /// - /// The resource that needs to be disposed. - /// - public static void RegisterForCleanup(this IExecutionResult result, IDisposable disposable) - { - ArgumentNullException.ThrowIfNull(result); - ArgumentNullException.ThrowIfNull(disposable) -; - result.RegisterForCleanup(disposable.Dispose); - } + ArgumentNullException.ThrowIfNull(clean); - /// - /// Registers a resource that needs to be disposed when the result is being disposed. - /// - /// - /// The . - /// - /// - /// The resource that needs to be disposed. - /// - public static void RegisterForCleanup(this IExecutionResult result, IAsyncDisposable disposable) - { - ArgumentNullException.ThrowIfNull(result); - ArgumentNullException.ThrowIfNull(disposable); + result.RegisterForCleanup(() => + { + clean(); + return default; + }); + } - result.RegisterForCleanup(disposable.DisposeAsync); - } + /// + /// Registers a resource that needs to be disposed when the result is being disposed. + /// + /// + /// The resource that needs to be disposed. + /// + public void RegisterForCleanup(IDisposable disposable) + { + ArgumentNullException.ThrowIfNull(disposable); - /// - /// Defines if the specified is a response stream. - /// - /// - /// The . - /// - /// - /// A boolean that specifies if the is a response stream. - /// - public static bool IsStreamResult(this IExecutionResult result) - => result.Kind is BatchResult or DeferredResult or SubscriptionResult; + result.RegisterForCleanup(disposable.Dispose); + } - /// - /// Expects a single GraphQL operation result. - /// - public static IOperationResult ExpectOperationResult(this IExecutionResult result) - { - if (result is IOperationResult qr) + /// + /// Registers a resource that needs to be disposed when the result is being disposed. + /// + /// + /// The resource that needs to be disposed. + /// + public void RegisterForCleanup(IAsyncDisposable disposable) { - return qr; + ArgumentNullException.ThrowIfNull(disposable); + + result.RegisterForCleanup(disposable.DisposeAsync); } - throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResult_NotOperationResult); - } + /// + /// Defines if the specified is a response stream. + /// + /// + /// A boolean that specifies if the is a response stream. + /// + public bool IsStreamResult() + => result.Kind is BatchResult or DeferredResult or SubscriptionResult; - /// - /// Expects a batch of operation results. - /// - public static OperationResultBatch ExpectOperationResultBatch(this IExecutionResult result) - { - if (result is OperationResultBatch qr) + /// + /// Expects a single GraphQL operation result. + /// + public OperationResult ExpectOperationResult() { - return qr; - } + if (result is OperationResult qr) + { + return qr; + } - throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResultBatch_NotOperationResultBatch); - } + throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResult_NotOperationResult); + } - /// - /// Expect a stream result. - /// - public static ResponseStream ExpectResponseStream(this IExecutionResult result) - { - if (result is ResponseStream rs) + /// + /// Expects a batch of operation results. + /// + public OperationResultBatch ExpectOperationResultBatch() { - return rs; + if (result is OperationResultBatch qr) + { + return qr; + } + + throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResultBatch_NotOperationResultBatch); } - throw new ArgumentException(ExecutionResultExtensions_ExpectResponseStream_NotResponseStream); + /// + /// Expect a stream result. + /// + public ResponseStream ExpectResponseStream() + { + if (result is ResponseStream rs) + { + return rs; + } + + throw new ArgumentException(ExecutionResultExtensions_ExpectResponseStream_NotResponseStream); + } } } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Features/IncrementalDataFeature.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Features/IncrementalDataFeature.cs new file mode 100644 index 00000000000..9910ad658ee --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Features/IncrementalDataFeature.cs @@ -0,0 +1,16 @@ +using System.Collections.Immutable; + +namespace HotChocolate.Execution; + +internal sealed class IncrementalDataFeature +{ + public Path? Path { get; set; } + + public ImmutableList? Pending { get; set; } + + public ImmutableList? Incremental { get; set; } + + public ImmutableList? Completed { get; set; } + + public bool? HasNext { get; set; } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs deleted file mode 100644 index 5404286d00a..00000000000 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResult.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace HotChocolate.Execution; - -/// -/// Represents a GraphQL operation result payload. -/// -public interface IOperationResult : IExecutionResult, IResultDataJsonFormatter -{ - /// - /// Gets the index of the request that corresponds to this result. - /// - int? RequestIndex { get; } - - /// - /// Gets the index of the variable set that corresponds to this result. - /// - int? VariableIndex { get; } - - /// - /// A path to the insertion point that informs the client how to patch a - /// subsequent delta payload into the original payload. - /// - Path? Path { get; } - - /// - /// The data that is being delivered. - /// - object? Data { get; } - - /// - /// Specifies if data was explicitly set. - /// If false the data was not set (including null). - /// - bool IsDataSet { get; } - - /// - /// Gets the GraphQL errors of the result. - /// - IReadOnlyList? Errors { get; } - - /// - /// Gets the additional information that is passed along - /// with the result and will be serialized for transport. - /// - IReadOnlyDictionary? Extensions { get; } - - /// - /// Gets the list of pending incremental delivery operations. - /// Each pending result announces data that will be delivered incrementally in subsequent payloads. - /// - IReadOnlyList? Pending { get; } - - /// - /// Gets the list of incremental results containing data from @defer or @stream directives. - /// Contains the actual data for previously announced pending operations. - /// - IReadOnlyList? Incremental { get; } - - /// - /// Gets the list of completed incremental delivery operations. - /// Each completed result indicates that all data for a pending operation has been delivered. - /// - IReadOnlyList? Completed { get; } - - /// - /// Indicates whether more payloads will follow in the response stream. - /// When true, clients should expect additional incremental data. - /// When false, this is the final payload. - /// - bool HasNext { get; } -} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResultFormatter.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResultFormatter.cs index cdf3eab0661..b0c43f1e5cb 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResultFormatter.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IOperationResultFormatter.cs @@ -4,7 +4,7 @@ namespace HotChocolate.Execution; /// -/// Represents a formatter for s. +/// Represents a formatter for s. /// public interface IOperationResultFormatter { @@ -26,7 +26,7 @@ public interface IOperationResultFormatter /// is null. /// ValueTask FormatAsync( - IOperationResult result, + OperationResult result, PipeWriter writer, CancellationToken cancellationToken = default); @@ -45,6 +45,6 @@ ValueTask FormatAsync( /// is null. /// void Format( - IOperationResult result, + OperationResult result, IBufferWriter writer); } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRawJsonFormatter.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRawJsonFormatter.cs index 313cdac91ab..d6ea127ba1e 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRawJsonFormatter.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRawJsonFormatter.cs @@ -12,11 +12,14 @@ public interface IRawJsonFormatter /// /// Writes the JSON data into the . /// + /// + /// The result that shall be serialized. + /// /// /// The pipe writer of the transport layer. /// /// /// Specifies if the JSON shall be indented. /// - void WriteTo(IBufferWriter writer, bool indented = false); + void WriteTo(OperationResult result, IBufferWriter writer, bool indented = false); } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRequestExecutor.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRequestExecutor.cs index 0ecbd56e3da..581b36a48c7 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRequestExecutor.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IRequestExecutor.cs @@ -32,16 +32,16 @@ public interface IRequestExecutor : IFeatureProvider /// Returns the execution result of the given GraphQL . /// /// If the request operation is a simple query or mutation the result is a - /// . + /// . /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result - /// that the yields is a . + /// that the yields is a . /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . /// Task ExecuteAsync( IOperationRequest request, diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IResponseStream.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IResponseStream.cs index b1977f8dcd2..b40bffdcfc0 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IResponseStream.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/IResponseStream.cs @@ -1,7 +1,7 @@ namespace HotChocolate.Execution; /// -/// The response stream represents a stream of that are produced +/// The response stream represents a stream of that are produced /// by the execution engine. /// public interface IResponseStream : IExecutionResult @@ -9,5 +9,5 @@ public interface IResponseStream : IExecutionResult /// /// Reads the result stream. /// - IAsyncEnumerable ReadResultsAsync(); + IAsyncEnumerable ReadResultsAsync(); } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs new file mode 100644 index 00000000000..2d6904a02be --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs @@ -0,0 +1,314 @@ +using System.Collections.Immutable; + +namespace HotChocolate.Execution; + +/// +/// Represents a GraphQL operation result containing data, errors, extensions, and incremental delivery information. +/// +public sealed class OperationResult : ExecutionResult +{ + private readonly DataFlags _dataFlags; + + /// + /// Initializes a new instance of with structured data and an optional formatter. + /// + /// + /// The operation result data with its formatter and memory management. + /// + /// + /// The GraphQL errors that occurred during execution. + /// + /// + /// Additional information passed along with the result. + /// + /// + /// Thrown when the data structure is invalid or when neither data, errors, nor extensions are provided. + /// + public OperationResult( + OperationResultData data, + ImmutableList? errors = null, + ImmutableDictionary? extensions = null) + { + if (data.Value is not null && data.Formatter is not null) + { + throw new ArgumentException("The result data structure is not supported."); + } + + if (data.IsValueNull && errors is null or { Count: 0 } && extensions is null or { Count: 0 }) + { + throw new ArgumentException("Either data or errors must be provided or extensions must be provided."); + } + + _dataFlags = data.IsValueNull + ? DataFlags.DataIsSet | DataFlags.DataIsNull + : DataFlags.DataIsSet; + Data = data.Value; + Errors = errors; + Extensions = extensions; + + Features.Set(data.Formatter); + + if (data.MemoryHolder is { } memoryHolder) + { + RegisterForCleanup(() => + { + memoryHolder.Dispose(); + return ValueTask.CompletedTask; + }); + } + } + + /// + /// Initializes a new instance of with dictionary-based data. + /// + /// + /// The data dictionary representing the GraphQL response data. + /// + /// + /// The GraphQL errors that occurred during execution. + /// + /// + /// Additional information passed along with the result. + /// + /// + /// Thrown when neither data, errors, nor extensions are provided. + /// + public OperationResult( + IReadOnlyDictionary? data, + ImmutableList? errors = null, + ImmutableDictionary? extensions = null) + { + if (data is null && errors is null or { Count: 0 } && extensions is null or { Count: 0 }) + { + throw new ArgumentException("Either data or errors must be provided or extensions must be provided."); + } + + _dataFlags = data is null + ? DataFlags.DataIsSet | DataFlags.DataIsNull + : DataFlags.DataIsSet; + + Data = data; + Errors = errors; + Extensions = extensions; + } + + /// + /// Initializes a new instance of with only errors. + /// + /// + /// The GraphQL errors that occurred during execution. + /// + /// + /// Additional information passed along with the result. + /// + /// + /// Thrown when is null. + /// + /// + /// Thrown when the errors list is empty. + /// + public OperationResult(ImmutableList errors, ImmutableDictionary? extensions = null) + { + ArgumentNullException.ThrowIfNull(errors); + + if (errors.Count == 0) + { + throw new ArgumentException("At least one error must be provided."); + } + + _dataFlags = DataFlags.DataIsNull; + Errors = errors; + Extensions = extensions; + } + + /// + /// Initializes a new instance of with only extensions. + /// + /// + /// Additional information passed along with the result. + /// + /// + /// Thrown when is null. + /// + /// + /// Thrown when the extensions dictionary is empty. + /// + public OperationResult(ImmutableDictionary extensions) + { + ArgumentNullException.ThrowIfNull(extensions); + + if (extensions.Count == 0) + { + throw new ArgumentException("At least one extension must be provided."); + } + + _dataFlags = DataFlags.DataIsNull; + Extensions = extensions; + } + + /// + /// Gets the kind of execution result. + /// + public override ExecutionResultKind Kind => ExecutionResultKind.SingleResult; + + /// + /// Gets or initializes the index of the request that corresponds to this result. + /// Used in batched operations to correlate results with requests. + /// + public int? RequestIndex { get; init; } + + /// + /// Gets or initializes the index of the variable set that corresponds to this result. + /// Used when executing operations with multiple variable sets. + /// + public int? VariableIndex { get; init; } + + /// + /// Gets or sets the path to the insertion point for incremental delivery. + /// Informs clients how to patch subsequent delta payloads into the original payload. + /// + public Path? Path + { + get => Features.Get()?.Path; + set + { + var feature = Features.Get() ?? new IncrementalDataFeature(); + feature.Path = value; + Features.Set(feature); + } + } + + /// + /// Gets the data that is being delivered in this operation result. + /// + public object? Data { get; } + + /// + /// Gets a value indicating whether data was explicitly set. + /// If false, the data was not set (including null). + /// + public bool IsDataSet => (_dataFlags & DataFlags.DataIsSet) == DataFlags.DataIsSet; + + /// + /// Gets a value indicating whether is null or not set. + /// If true, the data is null or not set. + /// + public bool IsDataNull => (_dataFlags & DataFlags.DataIsNull) == DataFlags.DataIsNull; + + /// + /// Gets the GraphQL errors that occurred during execution. + /// + public ImmutableList? Errors { get; } + + /// + /// Gets or sets additional information passed along with the result. + /// + /// + /// Thrown when setting to null or empty when data and errors are also null or empty. + /// + public ImmutableDictionary? Extensions + { + get; + set + { + if (IsDataNull && Errors is null or { Count: 0 } && Extensions is null or { Count: 0 }) + { + throw new ArgumentException("Either data, errors or extensions must be provided."); + } + + field = value; + } + } + + /// + /// Gets or sets the list of pending incremental delivery operations. + /// Each pending result announces data that will be delivered incrementally in subsequent payloads. + /// + public ImmutableList? Pending + { + get => Features.Get()?.Pending; + set + { + var feature = Features.Get() ?? new IncrementalDataFeature(); + feature.Pending = value; + Features.Set(feature); + } + } + + /// + /// Gets or sets the list of incremental results containing data from @defer or @stream directives. + /// Contains the actual data for previously announced pending operations. + /// + public ImmutableList? Incremental + { + get => Features.Get()?.Incremental; + set + { + var feature = Features.Get() ?? new IncrementalDataFeature(); + feature.Incremental = value; + Features.Set(feature); + } + } + + /// + /// Gets or sets the list of completed incremental delivery operations. + /// Each completed result indicates that all data for a pending operation has been delivered. + /// + public ImmutableList? Completed + { + get => Features.Get()?.Completed; + set + { + var feature = Features.Get() ?? new IncrementalDataFeature(); + feature.Completed = value; + Features.Set(feature); + } + } + + /// + /// Gets or sets a value indicating whether more payloads will follow in the response stream. + /// When true, clients should expect additional incremental data. + /// When false, this is the final payload. + /// + public bool? HasNext + { + get => Features.Get()?.HasNext; + set + { + var feature = Features.Get() ?? new IncrementalDataFeature(); + feature.HasNext = value; + Features.Set(feature); + } + } + + /// + /// Gets the JSON formatter that can serialize this operation result. + /// Used for high-performance custom serialization. + /// + public IRawJsonFormatter? JsonFormatter => Features.Get(); + + /// + /// Creates an operation result containing a single error. + /// + /// The error to include in the result. + /// An operation result containing the specified error. + public static OperationResult FromError(IError error) + => new([error]); + + /// + /// Creates an operation result containing multiple errors. + /// + /// The errors to include in the result. + /// An operation result containing the specified errors. + public static OperationResult FromError(params ImmutableList errors) + => new(errors); + + [Flags] + private enum DataFlags + { + // ReSharper disable once UnusedMember.Local + None = 0, + DataIsNull = 1, + DataIsSet = 2 + } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs index a2d59c69a96..c823b372817 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultBatch.cs @@ -1,3 +1,5 @@ +using System.Collections.Immutable; + namespace HotChocolate.Execution; /// @@ -17,13 +19,13 @@ public sealed class OperationResultBatch : ExecutionResult /// /// is null. /// - public OperationResultBatch(IReadOnlyList results) + public OperationResultBatch(ImmutableList results) { ArgumentNullException.ThrowIfNull(results); foreach (var result in results) { - if (result is not IResponseStream and not IOperationResult) + if (result is not IResponseStream and not OperationResult) { throw new ArgumentException( ExecutionAbstractionsResources.OperationResultBatch_ResponseStreamOrOperationResult, @@ -32,7 +34,7 @@ public OperationResultBatch(IReadOnlyList results) } Results = results ?? throw new ArgumentNullException(nameof(results)); - RegisterForCleanup(() => RunCleanUp(results)); + RegisterForCleanup(() => RunCleanUp(Results)); } /// @@ -43,7 +45,7 @@ public OperationResultBatch(IReadOnlyList results) /// /// Gets the results of this batch. /// - public IReadOnlyList Results { get; } + public ImmutableList Results { get; } private static async ValueTask RunCleanUp(IReadOnlyList results) { diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultData.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultData.cs new file mode 100644 index 00000000000..b6a5555512e --- /dev/null +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResultData.cs @@ -0,0 +1,58 @@ +namespace HotChocolate.Execution; + +/// +/// Represents the data portion of a GraphQL operation result with its associated formatter and memory management. +/// +public readonly ref struct OperationResultData +{ + /// + /// Initializes a new instance of . + /// + /// + /// The object representing the data property of the GraphQL response. + /// + /// + /// true if the value object represents a null value; otherwise, false. + /// This allows distinguishing between a null data payload and an object that serializes to null. + /// + /// + /// The formatter that can serialize the operation result and its data to JSON. + /// + /// + /// The memory holder that needs to be disposed after the operation result was handled. + /// + /// + /// Thrown when or is null. + /// + public OperationResultData(object value, bool isValueNull, IRawJsonFormatter formatter, IDisposable? memoryHolder) + { + ArgumentNullException.ThrowIfNull(value); + ArgumentNullException.ThrowIfNull(formatter); + + Value = value; + IsValueNull = isValueNull; + Formatter = formatter; + MemoryHolder = memoryHolder; + } + + /// + /// Gets the object representing the `Data` property of the GraphQL response. + /// + public object Value { get; } + + /// + /// Gets a value indicating whether the value object represents a null value. + /// This allows distinguishing between a null data payload and an object that serializes to null. + /// + public bool IsValueNull { get; } + + /// + /// Gets the formatter that can serialize the operation result and its data. + /// + public IRawJsonFormatter Formatter { get; } + + /// + /// Gets the memory holder that needs to be disposed after the operation result was handled. + /// + public IDisposable? MemoryHolder { get; } +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/RequestExecutorProxy.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/RequestExecutorProxy.cs index 924a028c859..5d6a12b9c09 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/RequestExecutorProxy.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/RequestExecutorProxy.cs @@ -93,16 +93,16 @@ IFeatureCollection IFeatureProvider.Features /// Returns the execution result of the given GraphQL . /// /// If the request operation is a simple query or mutation the result is a - /// . + /// . /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result - /// that the yields is a . + /// that the yields is a . /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . /// public async Task ExecuteAsync( IOperationRequest request, diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs index 48a406bbe35..2af98f1b67f 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/ResponseStream.cs @@ -6,11 +6,11 @@ namespace HotChocolate.Execution; public sealed class ResponseStream : ExecutionResult, IResponseStream { - private readonly Func>? _resultStreamFactory; + private readonly Func>? _resultStreamFactory; private bool _isRead; public ResponseStream( - Func>? resultStreamFactory, + Func>? resultStreamFactory, ExecutionResultKind kind = SubscriptionResult) { _resultStreamFactory = resultStreamFactory ?? @@ -26,13 +26,13 @@ public ResponseStream( public override ExecutionResultKind Kind { get; } - public ImmutableList> OnFirstResult + public ImmutableList> OnFirstResult { - get => Features.Get>>() ?? []; + get => Features.Get>>() ?? []; set => Features.Set(value); } - public IAsyncEnumerable ReadResultsAsync() + public IAsyncEnumerable ReadResultsAsync() { if (_resultStreamFactory is null) { @@ -51,11 +51,11 @@ public IAsyncEnumerable ReadResultsAsync() } private class OperationResultStream( - Func> resultStreamFactory, - Func onFirstResult) - : IAsyncEnumerable + Func> resultStreamFactory, + Func onFirstResult) + : IAsyncEnumerable { - public async IAsyncEnumerator GetAsyncEnumerator( + public async IAsyncEnumerator GetAsyncEnumerator( CancellationToken cancellationToken) { var first = true; @@ -74,7 +74,7 @@ public async IAsyncEnumerator GetAsyncEnumerator( } } - private IOperationResult ExecuteOnFirstResult(IOperationResult firstResult) + private OperationResult ExecuteOnFirstResult(OperationResult firstResult) { foreach (var mutator in OnFirstResult) { diff --git a/src/HotChocolate/Core/src/Execution.Pipeline/DocumentParserMiddleware.cs b/src/HotChocolate/Core/src/Execution.Pipeline/DocumentParserMiddleware.cs index eee6268bbaf..6696c954451 100644 --- a/src/HotChocolate/Core/src/Execution.Pipeline/DocumentParserMiddleware.cs +++ b/src/HotChocolate/Core/src/Execution.Pipeline/DocumentParserMiddleware.cs @@ -80,7 +80,7 @@ public async ValueTask InvokeAsync(RequestContext context) .AddLocation(new Location(ex.Line, ex.Column)) .Build()); - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); _diagnosticEvents.RequestError(context, ex); } } diff --git a/src/HotChocolate/Core/src/Execution.Pipeline/DocumentValidationMiddleware.cs b/src/HotChocolate/Core/src/Execution.Pipeline/DocumentValidationMiddleware.cs index a497edb86c1..736e8277d0b 100644 --- a/src/HotChocolate/Core/src/Execution.Pipeline/DocumentValidationMiddleware.cs +++ b/src/HotChocolate/Core/src/Execution.Pipeline/DocumentValidationMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution.Instrumentation; using HotChocolate.Validation; using Microsoft.Extensions.DependencyInjection; @@ -50,10 +51,8 @@ public async ValueTask InvokeAsync(RequestContext context) if (result.HasErrors) { // create result context data that indicate that validation has failed. - var resultContextData = new Dictionary - { - { ExecutionContextData.ValidationErrors, true } - }; + var resultContextData = ImmutableDictionary.CreateBuilder(); + resultContextData.Add(ExecutionContextData.ValidationErrors, true); // if one of the validation rules proposed a status code, we will add // it as a proposed status code to the result context data. @@ -64,7 +63,11 @@ public async ValueTask InvokeAsync(RequestContext context) resultContextData.Add(ExecutionContextData.HttpStatusCode, value); } - context.Result = OperationResultBuilder.CreateError(result.Errors, resultContextData); + context.Result = new OperationResult(result.Errors) + { + ContextData = resultContextData.ToImmutable() + }; + _diagnosticEvents.ValidationErrors(context, result.Errors); return; } diff --git a/src/HotChocolate/Core/src/Execution.Pipeline/ErrorHelper.cs b/src/HotChocolate/Core/src/Execution.Pipeline/ErrorHelper.cs index b4188ba9a33..c986e9fa362 100644 --- a/src/HotChocolate/Core/src/Execution.Pipeline/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Execution.Pipeline/ErrorHelper.cs @@ -16,8 +16,8 @@ public static IError OperationCanceled(Exception ex) public static NotSupportedException QueryTypeNotSupported() => new(ExecutionPipelineResources.ThrowHelper_QueryTypeNotSupported_Message); - public static IOperationResult StateInvalidForDocumentValidation() - => OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForDocumentValidation() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage(ExecutionPipelineResources.ErrorHelper_StateInvalidForDocumentValidation_Message) .SetCode(ErrorCodes.Execution.OperationDocumentNotFound) diff --git a/src/HotChocolate/Core/src/Execution.Pipeline/ExceptionMiddleware.cs b/src/HotChocolate/Core/src/Execution.Pipeline/ExceptionMiddleware.cs index 6c116f92fd5..93ca9418ca0 100644 --- a/src/HotChocolate/Core/src/Execution.Pipeline/ExceptionMiddleware.cs +++ b/src/HotChocolate/Core/src/Execution.Pipeline/ExceptionMiddleware.cs @@ -32,19 +32,19 @@ public async ValueTask InvokeAsync(RequestContext context) catch (OperationCanceledException ex) { var error = _errorHandler.Handle(ErrorHelper.OperationCanceled(ex)); - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); _diagnosticEvents.RequestError(context, ex); } catch (GraphQLException ex) { var errors = _errorHandler.Handle(ex.Errors); - context.Result = OperationResultBuilder.CreateError(errors); + context.Result = OperationResult.FromError([..errors]); _diagnosticEvents.RequestError(context, ex); } catch (Exception ex) { var error = _errorHandler.Handle(ErrorBuilder.FromException(ex).Build()); - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); _diagnosticEvents.RequestError(context, ex); } } diff --git a/src/HotChocolate/Core/src/Validation/DocumentValidatorResult.cs b/src/HotChocolate/Core/src/Validation/DocumentValidatorResult.cs index 5f1ce368ce8..b70b98b89e7 100644 --- a/src/HotChocolate/Core/src/Validation/DocumentValidatorResult.cs +++ b/src/HotChocolate/Core/src/Validation/DocumentValidatorResult.cs @@ -1,3 +1,5 @@ +using System.Collections.Immutable; + namespace HotChocolate.Validation; public class DocumentValidatorResult @@ -18,7 +20,7 @@ public DocumentValidatorResult(IEnumerable errors) public bool HasErrors { get; } - public IReadOnlyList Errors { get; } + public ImmutableList Errors { get; } public static DocumentValidatorResult OK { get; } = new(); } diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs index 7ef9ea1992e..c4ac83b5bc7 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs @@ -27,7 +27,7 @@ protected async Task MatchSnapshotAsync( { var snapshot = new Snapshot(postFix, ".yaml"); - var results = new List(); + var results = new List(); // We first wait and capture all possible gateway responses. await foreach (var result in response.ReadAsResultStreamAsync()) @@ -78,7 +78,7 @@ protected async Task MatchSnapshotAsync( private static async Task TryWriteOperationPlanAsync( CodeWriter writer, Gateway gateway, - List results) + List results) { foreach (var result in results) { @@ -121,7 +121,7 @@ private static async Task TryWriteOperationPlanAsync( } } - private void WriteResults(CodeWriter writer, List results) + private void WriteResults(CodeWriter writer, List results) { if (results is [{ } singleResult]) { @@ -154,7 +154,7 @@ private void WriteResults(CodeWriter writer, List results) } } - private static void WriteResult(CodeWriter writer, OperationResult result) + private static void WriteResult(CodeWriter writer, HotChocolate.Execution.OperationResult result) { var memoryStream = new MemoryStream(); using var jsonWriter = new Utf8JsonWriter(memoryStream, new JsonWriterOptions { Indented = true }); diff --git a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/AutomaticPersistedOperationNotFoundMiddleware.cs b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/AutomaticPersistedOperationNotFoundMiddleware.cs index b8451fa312f..d28c4038871 100644 --- a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/AutomaticPersistedOperationNotFoundMiddleware.cs +++ b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/AutomaticPersistedOperationNotFoundMiddleware.cs @@ -1,31 +1,23 @@ -using HotChocolate.Execution.Instrumentation; -using Microsoft.Extensions.DependencyInjection; +using System.Collections.Immutable; namespace HotChocolate.Execution.Pipeline; internal sealed class AutomaticPersistedOperationNotFoundMiddleware { - private static readonly IOperationResult s_errorResult = - OperationResultBuilder.CreateError( - PersistedOperationNotFound(), - contextData: new Dictionary - { - { ExecutionContextData.HttpStatusCode, 400 } - }); + private static readonly OperationResult s_errorResult = + new([PersistedOperationNotFound()]) + { + ContextData = ImmutableDictionary.Empty.Add(ExecutionContextData.HttpStatusCode, 400) + }; + private readonly RequestDelegate _next; -#pragma warning disable IDE0052 // WIP - private readonly ICoreExecutionDiagnosticEvents _diagnosticEvents; -#pragma warning restore IDE0052 private AutomaticPersistedOperationNotFoundMiddleware( - RequestDelegate next, - ICoreExecutionDiagnosticEvents diagnosticEvents) + RequestDelegate next) { ArgumentNullException.ThrowIfNull(next); - ArgumentNullException.ThrowIfNull(diagnosticEvents); _next = next; - _diagnosticEvents = diagnosticEvents; } public ValueTask InvokeAsync(RequestContext context) @@ -50,10 +42,9 @@ public static IError PersistedOperationNotFound() public static RequestMiddlewareConfiguration Create() => new RequestMiddlewareConfiguration( - static (factoryContext, next) => + static (_, next) => { - var diagnosticEvents = factoryContext.SchemaServices.GetRequiredService(); - var middleware = new AutomaticPersistedOperationNotFoundMiddleware(next, diagnosticEvents); + var middleware = new AutomaticPersistedOperationNotFoundMiddleware(next); return context => middleware.InvokeAsync(context); }, WellKnownRequestMiddleware.AutomaticPersistedOperationNotFoundMiddleware); diff --git a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/OnlyPersistedOperationsAllowedMiddleware.cs b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/OnlyPersistedOperationsAllowedMiddleware.cs index 195c54186a3..65dcb3c53de 100644 --- a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/OnlyPersistedOperationsAllowedMiddleware.cs +++ b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/OnlyPersistedOperationsAllowedMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution.Instrumentation; using HotChocolate.PersistedOperations; using Microsoft.Extensions.DependencyInjection; @@ -9,8 +10,7 @@ internal sealed class OnlyPersistedOperationsAllowedMiddleware private readonly RequestDelegate _next; private readonly ICoreExecutionDiagnosticEvents _diagnosticEvents; private readonly PersistedOperationOptions _options; - private readonly IOperationResult _errorResult; - private readonly Dictionary _statusCode = new() { { ExecutionContextData.HttpStatusCode, 400 } }; + private readonly OperationResult _errorResult; private OnlyPersistedOperationsAllowedMiddleware( RequestDelegate next, @@ -26,7 +26,10 @@ private OnlyPersistedOperationsAllowedMiddleware( // prepare options. _options = options; - _errorResult = OperationResultBuilder.CreateError(options.OperationNotAllowedError, _statusCode); + _errorResult = new OperationResult([options.OperationNotAllowedError]) + { + ContextData = ImmutableDictionary.Empty.Add(ExecutionContextData.HttpStatusCode, 400) + }; } public ValueTask InvokeAsync(RequestContext context) diff --git a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/PersistedOperationNotFoundMiddleware.cs b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/PersistedOperationNotFoundMiddleware.cs index 3a5c22418bd..e43fd2d9c2f 100644 --- a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/PersistedOperationNotFoundMiddleware.cs +++ b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/PersistedOperationNotFoundMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution.Instrumentation; using HotChocolate.Language; using Microsoft.Extensions.DependencyInjection; @@ -6,9 +7,10 @@ namespace HotChocolate.Execution.Pipeline; internal sealed class PersistedOperationNotFoundMiddleware { + private static readonly ImmutableDictionary s_statusCode = + ImmutableDictionary.Empty.Add(ExecutionContextData.HttpStatusCode, 400); private readonly RequestDelegate _next; private readonly ICoreExecutionDiagnosticEvents _diagnosticEvents; - private readonly Dictionary _statusCode = new() { { ExecutionContextData.HttpStatusCode, 400 } }; private PersistedOperationNotFoundMiddleware( RequestDelegate next, @@ -41,7 +43,7 @@ context.OperationDocumentInfo.Document is not null // must be present, otherwise the request would not have been routed to this middleware. _diagnosticEvents.DocumentNotFoundInStorage(context, context.Request.DocumentId); var error = PersistedOperationNotFound(context.Request.DocumentId); - context.Result = OperationResultBuilder.CreateError(error, _statusCode); + context.Result = new OperationResult([error]) { ContextData = s_statusCode }; return default; } diff --git a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs index 2e279d0f78c..0188ef4d7a8 100644 --- a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs +++ b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using HotChocolate.Language; using HotChocolate.PersistedOperations; @@ -40,13 +41,13 @@ public async ValueTask InvokeAsync(RequestContext context) && documentInfo.IsValidated && documentInfo.Document is not null && !documentInfo.Id.IsEmpty - && context.Result is IOperationResult result + && context.Result is OperationResult result && context.Request.Document is { } document && context.Request.Extensions is not null && context.Request.Extensions.TryGetValue(PersistedQuery, out var s) && s is IReadOnlyDictionary settings) { - var resultBuilder = OperationResultBuilder.FromResult(result); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; // hash is found and matches the query key -> store the query if (DoHashesMatch(settings, documentInfo.Id, _hashProvider.Name, out var userHash)) @@ -55,7 +56,7 @@ public async ValueTask InvokeAsync(RequestContext context) await _operationDocumentStorage.SaveAsync(documentInfo.Id, document).ConfigureAwait(false); // add persistence receipt to the result - resultBuilder.SetExtension( + extensions = extensions.SetItem( PersistedQuery, new Dictionary { @@ -67,7 +68,7 @@ public async ValueTask InvokeAsync(RequestContext context) } else { - resultBuilder.SetExtension( + extensions = extensions.SetItem( PersistedQuery, new Dictionary { @@ -79,7 +80,7 @@ public async ValueTask InvokeAsync(RequestContext context) }); } - context.Result = resultBuilder.Build(); + result.Extensions = extensions; } } From 36ac559e6ceb4d57d378506b79f515f76b5a9cf1 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 14:46:54 +0100 Subject: [PATCH 35/42] wip --- .../Extensions/CommonTestExtensions.cs | 6 +- .../Handlers/CallToolHandler.cs | 2 +- .../Execution/DynamicEndpointMiddleware.cs | 18 +- .../Execution/IOpenApiResultFormatter.cs | 2 +- .../FusionOpenApiResultFormatter.cs | 7 +- .../HttpPostMiddlewareBase.cs | 2 +- .../ServerDiagnosticEventListener.cs | 2 +- .../DefaultSocketSessionInterceptor.cs | 4 +- .../Interceptors/ISocketSessionInterceptor.cs | 2 +- .../Subscriptions/OperationSession.cs | 4 +- .../ApolloSubscriptionProtocolHandler.cs | 2 +- .../GraphQLOverWebSocketProtocolHandler.cs | 2 +- .../Protocols/IProtocolHandler.cs | 2 +- .../Utilities/HeaderUtilities.cs | 2 +- .../Utilities/MiddlewareHelper.cs | 8 +- .../src/Caching/QueryCacheMiddleware.cs | 13 +- .../Pipeline/AuthorizeRequestMiddleware.cs | 11 +- .../Types/Execution/DefaultRequestExecutor.cs | 15 +- ...equestExecutorServiceProviderExtensions.cs | 36 ++-- .../Core/src/Types/Execution/ErrorHelper.cs | 67 +++---- .../Extensions/ExecutionResultExtensions.cs | 4 +- .../Extensions/OperationContextExtensions.cs | 52 ++++-- .../src/Types/Execution/NeedsFormatting.cs | 3 + .../Pipeline/OperationExecutionMiddleware.cs | 19 +- .../Processing/MiddlewareContext.Global.cs | 28 +-- .../Processing/MiddlewareContext.State.cs | 2 +- .../Processing/OperationContext.Execution.cs | 2 +- .../OperationContext.IExecutionTaskContext.cs | 5 +- .../Processing/OperationContext.Pooling.cs | 19 +- .../Processing/OperationContextOwner.cs | 2 + .../Processing/OperationResultBuilder.cs | 170 ++++++++++++++++++ .../Execution/Processing/QueryExecutor.cs | 14 +- .../SubscriptionExecutor.Subscription.cs | 40 ++--- .../Processing/SubscriptionExecutor.cs | 14 +- .../Tasks/ResolverTask.CompleteValue.cs | 2 +- .../Processing/Tasks/ResolverTaskFactory.cs | 2 +- .../Processing/ValueCompletion.Leaf.cs | 4 +- .../Processing/ValueCompletion.List.cs | 2 +- .../Processing/ValueCompletion.Object.cs | 6 +- .../Execution/Processing/ValueCompletion.cs | 2 +- .../Processing/WorkScheduler.Pooling.cs | 3 + .../Core/src/Types/HotChocolate.Types.csproj | 104 +++++++++++ .../Types/Text/Json/ResultDocument.DbRow.cs | 3 +- .../Types/Text/Json/ResultDocument.WriteTo.cs | 18 +- .../src/Types/Text/Json/ResultDocument.cs | 11 +- .../Core/src/Types/Text/Json/ResultElement.cs | 16 +- .../Fusion.Execution/Execution/ErrorHelper.cs | 12 +- .../Execution/FusionRequestExecutor.cs | 14 +- .../Execution/OperationPlanContext.cs | 11 +- .../Execution/OperationPlanExecutor.cs | 4 +- .../Pipeline/OperationExecutionMiddleware.cs | 5 +- .../OperationVariableCoercionMiddleware.cs | 4 +- .../Execution/Results/RawOperationResult.cs | 60 ------- .../Json/CompositeResultDocument.WriteTo.cs | 2 +- .../Text/Json/CompositeResultElement.cs | 2 +- 55 files changed, 545 insertions(+), 323 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs delete mode 100644 src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/RawOperationResult.cs diff --git a/src/CookieCrumble/src/CookieCrumble.HotChocolate/Extensions/CommonTestExtensions.cs b/src/CookieCrumble/src/CookieCrumble.HotChocolate/Extensions/CommonTestExtensions.cs index b5686f4c0c5..26fb999cda1 100644 --- a/src/CookieCrumble/src/CookieCrumble.HotChocolate/Extensions/CommonTestExtensions.cs +++ b/src/CookieCrumble/src/CookieCrumble.HotChocolate/Extensions/CommonTestExtensions.cs @@ -15,11 +15,7 @@ public static ValueTask CreateExceptionExecutor( await next(context); if (context.ContextData.TryGetValue("ex", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("ex", queryString) - .Build(); + context.Result!.ContextData = context.Result.ContextData.SetItem("ex", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Handlers/CallToolHandler.cs b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Handlers/CallToolHandler.cs index f9df5cfab4c..2b61924e662 100644 --- a/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Handlers/CallToolHandler.cs +++ b/src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Handlers/CallToolHandler.cs @@ -59,7 +59,7 @@ public static async ValueTask HandleAsync( .SetVariableValues(variableValues) .Build(); var result = await requestExecutor.ExecuteAsync(request, cancellationToken).ConfigureAwait(false); - var operationResult = (IOperationResult)result; + var operationResult = result.ExpectOperationResult(); using var writer = new PooledArrayWriter(); diff --git a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs index 3d9a11ba6b5..226e8265a9d 100644 --- a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs +++ b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/DynamicEndpointMiddleware.cs @@ -1,12 +1,12 @@ using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; using HotChocolate.AspNetCore; using HotChocolate.Buffers; using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Types; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; namespace HotChocolate.Adapters.OpenApi; @@ -62,22 +62,22 @@ await Results.Problem( requestBuilder.Build(), cancellationToken).ConfigureAwait(false); - // If the request was cancelled, we do not attempt to write a response. + // If the request was canceled, we do not attempt to write a response. if (cancellationToken.IsCancellationRequested) { return; } - // If we do not have an operation result, something went wrong and we return HTTP 500. - if (executionResult is not IOperationResult operationResult) + // If we do not have an operation result, something went wrong, and we return HTTP 500. + if (executionResult is not OperationResult operationResult) { await Results.InternalServerError().ExecuteAsync(context); return; } // If the request had validation errors or execution didn't start, we return HTTP 400. - if (operationResult.ContextData?.ContainsKey(ExecutionContextData.ValidationErrors) == true - || operationResult is OperationResult { IsDataSet: false }) + if (operationResult.ContextData.ContainsKey(ExecutionContextData.ValidationErrors) + || operationResult is { IsDataSet: false }) { var firstErrorMessage = operationResult.Errors?.FirstOrDefault()?.Message; @@ -279,7 +279,7 @@ private static bool TryGetValueForParameter( IQueryCollection query, [NotNullWhen(true)] out IValueNode? parameterValue) { - parameterValue = default; + parameterValue = null; if (leaf.ParameterType is OpenApiEndpointParameterType.Route) { diff --git a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/IOpenApiResultFormatter.cs b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/IOpenApiResultFormatter.cs index 2d3ab506c34..b96ceb58ea3 100644 --- a/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/IOpenApiResultFormatter.cs +++ b/src/HotChocolate/Adapters/src/Adapters.OpenApi.Core/Execution/IOpenApiResultFormatter.cs @@ -6,7 +6,7 @@ namespace HotChocolate.Adapters.OpenApi; internal interface IOpenApiResultFormatter { Task FormatResultAsync( - IOperationResult operationResult, + OperationResult operationResult, HttpContext httpContext, OpenApiEndpointDescriptor endpoint, CancellationToken cancellationToken); diff --git a/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs b/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs index 154e4516082..49613679281 100644 --- a/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs +++ b/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs @@ -1,5 +1,6 @@ using HotChocolate.Execution; using HotChocolate.Fusion.Execution.Results; +using HotChocolate.Fusion.Text.Json; using Microsoft.AspNetCore.Http; namespace HotChocolate.Adapters.OpenApi; @@ -7,18 +8,18 @@ namespace HotChocolate.Adapters.OpenApi; internal sealed class FusionOpenApiResultFormatter : IOpenApiResultFormatter { public async Task FormatResultAsync( - IOperationResult operationResult, + OperationResult operationResult, HttpContext httpContext, OpenApiEndpointDescriptor endpoint, CancellationToken cancellationToken) { - if (operationResult is not RawOperationResult rawOperationResult) + if (operationResult.Data is not CompositeResultDocument resultDocument) { await Results.InternalServerError().ExecuteAsync(httpContext); return; } - if (!rawOperationResult.Result.Data.TryGetProperty(endpoint.ResponseNameToExtract, out var rootProperty)) + if (!resultDocument.Data.TryGetProperty(endpoint.ResponseNameToExtract, out var rootProperty)) { await Results.InternalServerError().ExecuteAsync(httpContext); return; diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs index 655d7fe06be..da3e85f30e3 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/HttpPostMiddlewareBase.cs @@ -221,7 +221,7 @@ protected async Task HandleRequestAsync(HttpContext context, ExecutorSession ses // to the HTTP response stream. Debug.Assert(result is not null, "No GraphQL result was created."); - if (result is IOperationResult operationResult) + if (result is OperationResult operationResult) { formatScope = session.DiagnosticEvents.FormatHttpResponse(context, operationResult); } diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/ServerDiagnosticEventListener.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/ServerDiagnosticEventListener.cs index c4b43872714..ee6e9db0de0 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/ServerDiagnosticEventListener.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Instrumentation/ServerDiagnosticEventListener.cs @@ -57,7 +57,7 @@ public virtual void ParserErrors(HttpContext context, IReadOnlyList erro } /// - public virtual IDisposable FormatHttpResponse(HttpContext context, IOperationResult result) + public virtual IDisposable FormatHttpResponse(HttpContext context, OperationResult result) => EmptyScope; /// diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/DefaultSocketSessionInterceptor.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/DefaultSocketSessionInterceptor.cs index af437c15c50..d1119ba8d37 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/DefaultSocketSessionInterceptor.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/DefaultSocketSessionInterceptor.cs @@ -43,10 +43,10 @@ public virtual ValueTask OnRequestAsync( return default; } - public virtual ValueTask OnResultAsync( + public virtual ValueTask OnResultAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken = default) => new(result); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs index 4333b22b3ca..7b38b5479c6 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Interceptors/ISocketSessionInterceptor.cs @@ -80,7 +80,7 @@ ValueTask OnResultAsync( /// This interception method is guaranteed to be invoked even if the operation /// fails or the connection is closed. /// - /// The cancellation token might be cancelled if the connection is closed. + /// The cancellation token might be canceled if the connection is closed. /// /// /// The socket session. diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/OperationSession.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/OperationSession.cs index 89db615bdbb..68959a8cdae 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/OperationSession.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/OperationSession.cs @@ -47,7 +47,7 @@ private async Task SendResultsAsync(GraphQLRequest request, CancellationToken ca switch (result) { - case IOperationResult queryResult: + case OperationResult queryResult: if (queryResult.Data is null && queryResult.Errors is { Count: > 0 }) { await _session.Protocol.SendErrorMessageAsync( @@ -163,7 +163,7 @@ private static OperationRequestBuilder CreateRequestBuilder(GraphQLRequest reque return requestBuilder; } - private async Task SendResultMessageAsync(IOperationResult result, CancellationToken ct) + private async Task SendResultMessageAsync(OperationResult result, CancellationToken ct) { result = await _interceptor.OnResultAsync(_session, Id, result, ct); await _session.Protocol.SendResultMessageAsync(_session, Id, result, ct); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/Apollo/ApolloSubscriptionProtocolHandler.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/Apollo/ApolloSubscriptionProtocolHandler.cs index 724d89d0529..0bc372971bf 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/Apollo/ApolloSubscriptionProtocolHandler.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/Apollo/ApolloSubscriptionProtocolHandler.cs @@ -236,7 +236,7 @@ public ValueTask SendKeepAliveMessageAsync( public async ValueTask SendResultMessageAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken) { using var arrayWriter = new PooledArrayWriter(); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/GraphQLOverWebSocket/GraphQLOverWebSocketProtocolHandler.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/GraphQLOverWebSocket/GraphQLOverWebSocketProtocolHandler.cs index 17e9c3dc178..7d6b537ccf6 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/GraphQLOverWebSocket/GraphQLOverWebSocketProtocolHandler.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/GraphQLOverWebSocket/GraphQLOverWebSocketProtocolHandler.cs @@ -209,7 +209,7 @@ public ValueTask SendKeepAliveMessageAsync( public async ValueTask SendResultMessageAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken) { using var arrayWriter = new PooledArrayWriter(); diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/IProtocolHandler.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/IProtocolHandler.cs index d9548e9b490..9c5b77435f8 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/IProtocolHandler.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Subscriptions/Protocols/IProtocolHandler.cs @@ -62,7 +62,7 @@ ValueTask SendKeepAliveMessageAsync( ValueTask SendResultMessageAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken = default); /// diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/HeaderUtilities.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/HeaderUtilities.cs index b49666beb19..9725273c505 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/HeaderUtilities.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/HeaderUtilities.cs @@ -165,7 +165,7 @@ public AcceptHeaderResult(string headerValue) public AcceptMediaType[] AcceptMediaTypes { get; } - public IOperationResult? ErrorResult { get; } + public OperationResult? ErrorResult { get; } [MemberNotNullWhen(true, nameof(ErrorResult))] public bool HasError { get; } diff --git a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs index d894b5a34fd..6d432782c7a 100644 --- a/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs +++ b/src/HotChocolate/AspNetCore/src/AspNetCore.Pipeline/Utilities/MiddlewareHelper.cs @@ -264,7 +264,7 @@ public static async Task WriteResultAsync( // to the HTTP response stream. Debug.Assert(result is not null, "No GraphQL result was created."); - if (result is IOperationResult queryResult) + if (result is OperationResult queryResult) { formatScope = executorSession.DiagnosticEvents.FormatHttpResponse(context, queryResult); } @@ -297,7 +297,7 @@ public ValidateAcceptContentTypeResult( } public ValidateAcceptContentTypeResult( - IOperationResult errorResult, + OperationResult errorResult, HttpStatusCode statusCode) { IsValid = false; @@ -323,7 +323,7 @@ public ValidateAcceptContentTypeResult( [MemberNotNullWhen(false, nameof(StatusCode))] public bool IsValid { get; } - public IOperationResult? Error { get; } + public OperationResult? Error { get; } public HttpStatusCode? StatusCode { get; } @@ -365,7 +365,7 @@ public ParseRequestResult(IError error, HttpStatusCode statusCode) public GraphQLRequest? Request { get; } - public IOperationResult? Error { get; } + public OperationResult? Error { get; } public HttpStatusCode? StatusCode { get; } } diff --git a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs index 889d3476e28..2953f9e26f1 100644 --- a/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs +++ b/src/HotChocolate/Caching/src/Caching/QueryCacheMiddleware.cs @@ -39,21 +39,16 @@ public async ValueTask InvokeAsync(RequestContext context) // only single operation results can be cached. var operationResult = context.Result?.ExpectOperationResult(); - if (operationResult is { Errors: null }) + if (operationResult is { Errors: null, ContextData: { } contextData }) { - var contextData = - operationResult.ContextData is not null - ? new ExtensionData(operationResult.ContextData) - : []; - - contextData.Add(ExecutionContextData.CacheControlHeaderValue, headerValue); + contextData = contextData.Add(ExecutionContextData.CacheControlHeaderValue, headerValue); if (constraints.Vary.Length > 0) { - contextData.Add(ExecutionContextData.VaryHeaderValue, constraints.Vary); + contextData =contextData.Add(ExecutionContextData.VaryHeaderValue, constraints.Vary); } - context.Result = operationResult.WithContextData(contextData); + operationResult.ContextData = contextData; } } diff --git a/src/HotChocolate/Core/src/Authorization/Pipeline/AuthorizeRequestMiddleware.cs b/src/HotChocolate/Core/src/Authorization/Pipeline/AuthorizeRequestMiddleware.cs index 78b0ef09fe5..c17c494a8c3 100644 --- a/src/HotChocolate/Core/src/Authorization/Pipeline/AuthorizeRequestMiddleware.cs +++ b/src/HotChocolate/Core/src/Authorization/Pipeline/AuthorizeRequestMiddleware.cs @@ -45,11 +45,12 @@ public async ValueTask InvokeAsync(RequestContext context) await next(context); } - private static IOperationResult CreateErrorResult(AuthorizeResult result) - => OperationResultBuilder.New() - .AddError(CreateError(result)) - .SetContextData(ExecutionContextData.HttpStatusCode, 401) - .Build(); + private static OperationResult CreateErrorResult(AuthorizeResult authorizeResult) + { + var result = OperationResult.FromError(CreateError(authorizeResult)); + result.ContextData = result.ContextData.Add(ExecutionContextData.HttpStatusCode, 401); + return result; + } private static IError CreateError(AuthorizeResult result) { diff --git a/src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs index b786d8a9579..25757de7d35 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DefaultRequestExecutor.cs @@ -1,7 +1,6 @@ using System.Runtime.CompilerServices; using HotChocolate.Features; using HotChocolate.Fetching; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.ObjectPool; namespace HotChocolate.Execution; @@ -183,7 +182,7 @@ private async Task ExecuteAsync( /// /// Executes a batch of GraphQL operation requests and returns an /// that yields each individual - /// as it becomes available. + /// as it becomes available. /// /// /// The batch of operation requests. @@ -203,7 +202,7 @@ public Task ExecuteBatchAsync( ExecutionResultKind.BatchResult)); } - private async IAsyncEnumerable CreateResponseStream( + private async IAsyncEnumerable CreateResponseStream( OperationRequestBatch requestBatch, [EnumeratorCancellation] CancellationToken ct = default) { @@ -241,7 +240,7 @@ private async IAsyncEnumerable CreateResponseStream( } } - private async IAsyncEnumerable ExecuteBatchStream( + private async IAsyncEnumerable ExecuteBatchStream( OperationRequestBatch requestBatch, IServiceProvider services, [EnumeratorCancellation] CancellationToken ct = default) @@ -250,14 +249,14 @@ private async IAsyncEnumerable ExecuteBatchStream( var requestCount = requests.Count; var tasks = Interlocked.Exchange(ref _taskList, null) ?? new List(requestCount); - var completed = new List(); + var completed = new List(); for (var i = 0; i < requestCount; i++) { tasks.Add(ExecuteBatchItemAsync(WithServices(requests[i], services), i, completed, ct)); } - var buffer = new IOperationResult[Math.Min(16, requestCount)]; + var buffer = new OperationResult[Math.Min(16, requestCount)]; while (tasks.Count > 0 || completed.Count > 0) { @@ -314,7 +313,7 @@ private static IOperationRequest WithServices( private async Task ExecuteBatchItemAsync( IOperationRequest request, int requestIndex, - List completed, + List completed, CancellationToken cancellationToken) { var result = await ExecuteAsync(request, false, requestIndex, cancellationToken).ConfigureAwait(false); @@ -323,7 +322,7 @@ private async Task ExecuteBatchItemAsync( private static async Task UnwrapBatchItemResultAsync( IExecutionResult result, - List completed, + List completed, CancellationToken cancellationToken) { switch (result) diff --git a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs index 686acf72861..6501a64d3be 100644 --- a/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/DependencyInjection/RequestExecutorServiceProviderExtensions.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using HotChocolate.Execution.Configuration; -using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace namespace HotChocolate.Execution; @@ -132,19 +131,24 @@ public static ValueTask BuildRequestExecutorAsync( /// The cancellation token. /// /// + /// /// Returns the execution result of the given GraphQL . - /// + /// + /// /// If the request operation is a simple query or mutation the result is a - /// . - /// + /// . + /// + /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result - /// that the yields is a . - /// + /// that the yields is a . + /// + /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . + /// /// public static async Task ExecuteRequestAsync( this IServiceProvider services, @@ -180,16 +184,16 @@ await GetRequestExecutorAsync(services, schemaName, cancellationToken) /// Returns the execution result of the given GraphQL . /// /// If the request operation is a simple query or mutation the result is a - /// . + /// . /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result - /// that the yields is a . + /// that the yields is a . /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . /// public static async Task ExecuteRequestAsync( this IRequestExecutorBuilder builder, @@ -225,17 +229,17 @@ await BuildRequestExecutorAsync(builder, schemaName, cancellationToken) /// Returns the execution result of the given GraphQL . /// /// If the request operation is a simple query or mutation the result is a - /// . + /// . /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result /// that the yields is a - /// . + /// . /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . /// public static async Task ExecuteRequestAsync( this IServiceProvider services, @@ -271,19 +275,19 @@ await GetRequestExecutorAsync(services, schemaName, cancellationToken) /// Returns the execution result of the given GraphQL . /// /// If the request operation is a simple query or mutation the result is a - /// . + /// . /// /// /// If the request operation is a query or mutation where data is deferred, streamed or /// includes live data the result is a where each result /// that the yields is a - /// . + /// . /// /// /// If the request operation is a subscription the result is a /// where each result that the /// yields is a - /// . + /// . /// /// public static async Task ExecuteRequestAsync( diff --git a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs index 2507ff251a6..03ffb49c778 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ErrorHelper.cs @@ -108,30 +108,30 @@ public static IError UnexpectedValueCompletionError( .Build(); } - public static IOperationResult RootTypeNotFound(OperationType operationType) => - OperationResultBuilder.CreateError( + public static OperationResult RootTypeNotFound(OperationType operationType) + { + var result = OperationResult.FromError( ErrorBuilder.New() .SetMessage(ErrorHelper_RootTypeNotFound_Message, operationType) - .Build(), - new Dictionary - { - { ExecutionContextData.HttpStatusCode, HttpStatusCode.BadRequest } - }); + .Build()); + result.ContextData = result.ContextData.Add(ExecutionContextData.HttpStatusCode, HttpStatusCode.BadRequest); + return result; + } - public static IOperationResult StateInvalidForOperationResolver() => - OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForOperationResolver() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage(ErrorHelper_StateInvalidForOperationResolver_Message) .Build()); - public static IOperationResult StateInvalidForOperationVariableCoercion() => - OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForOperationVariableCoercion() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage(ErrorHelper_StateInvalidForOperationVariableCoercion_Message) .Build()); - public static IOperationResult StateInvalidForOperationExecution() => - OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForOperationExecution() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage(ErrorHelper_StateInvalidForOperationExecution_Message) .Build()); @@ -139,8 +139,8 @@ public static IOperationResult StateInvalidForOperationExecution() => public static IError ValueCompletion_CouldNotResolveAbstractType( Selection selection, Path path, - object result) => - ErrorBuilder.New() + object result) + => ErrorBuilder.New() .SetMessage( ErrorHelper_ValueCompletion_CouldNotResolveAbstractType_Message, result.GetType().FullName ?? result.GetType().Name, @@ -149,34 +149,39 @@ public static IError ValueCompletion_CouldNotResolveAbstractType( .AddLocations(selection) .Build(); - public static IOperationResult OperationKindNotAllowed() => - OperationResultBuilder.CreateError( + public static OperationResult OperationKindNotAllowed() + { + var result = OperationResult.FromError( ErrorBuilder.New() .SetMessage("The specified operation kind is not allowed.") - .Build(), - new Dictionary - { - { ExecutionContextData.OperationNotAllowed, null } - }); + .Build()); - public static IOperationResult RequestTypeNotAllowed() => - OperationResultBuilder.CreateError( + result.ContextData = result.ContextData.Add(ExecutionContextData.OperationNotAllowed, null); + + return result; + } + + public static OperationResult RequestTypeNotAllowed() + { + var result = OperationResult.FromError( ErrorBuilder.New() .SetMessage("Variable batch requests are only allowed for mutations and subscriptions.") - .Build(), - new Dictionary - { - { ExecutionContextData.ValidationErrors, null } - }); + .Build()); + + result.ContextData = result.ContextData.Add(ExecutionContextData.ValidationErrors, null); + + return result; + } - public static IOperationResult RequestTimeout(TimeSpan timeout) => - OperationResultBuilder.CreateError( + public static OperationResult RequestTimeout(TimeSpan timeout) + => OperationResult.FromError( new Error { Message = string.Format(ErrorHelper_RequestTimeout, timeout), Extensions = ImmutableDictionary.Empty.Add("code", ErrorCodes.Execution.Timeout) }); + // TODO : Remove? public static IError NonNullOutputFieldViolation(Path? path, FieldNode selection) => ErrorBuilder.New() .SetMessage("Cannot return null for non-nullable field.") diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs index 08931bcac27..5086de1e7d2 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionResultExtensions.cs @@ -14,7 +14,7 @@ public static class ExecutionResultExtensions private static readonly JsonResultFormatter s_formatterIndented = JsonResultFormatter.Indented; public static void WriteTo( - this IOperationResult result, + this OperationResult result, IBufferWriter writer, bool withIndentations = true) { @@ -53,7 +53,7 @@ public static string ToJson( { ArgumentNullException.ThrowIfNull(result); - if (result is IOperationResult operationResult) + if (result is OperationResult operationResult) { using var writer = new PooledArrayWriter(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs index 867091cd66e..229eeb2d74e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs @@ -45,27 +45,61 @@ public OperationContext ReportError( { var errors = new List(); - ReportSingleError( + UnwrapError( context.ErrorHandler, error, errors); - context.Result.Errors ??= []; + context.Result.AddErrorRange(errors); foreach (var handled in errors) { - context.Result.Errors.Add(handled); context.DiagnosticEvents.ResolverError(resolverContext, handled); } return context; } - public IOperationResult BuildResult() - => context.Result.BuildResult(); + public OperationResult BuildResult() + { + var resultBuilder = context.Result; + + var result = new OperationResult( + new OperationResultData( + resultBuilder.Data, + resultBuilder.Data.Data.IsNullOrInvalidated, + resultBuilder.Data, + resultBuilder.Data), + resultBuilder.Errors is { Count: > 0 } errors ? errors : null, + resultBuilder.Extensions is { Count: > 0 } extensions ? extensions : null) + { + RequestIndex = resultBuilder.RequestIndex > -1 ? resultBuilder.RequestIndex : 0, + VariableIndex = resultBuilder.VariableIndex > -1 ? resultBuilder.VariableIndex : 0, + ContextData = resultBuilder.ContextData + }; + + if (resultBuilder.Path is not null + || resultBuilder.HasNext.HasValue + || resultBuilder.Pending is not null + || resultBuilder.Incremental is not null + || resultBuilder.Completed is not null) + { + result.Features.Set( + new IncrementalDataFeature + { + Path = resultBuilder.Path, + HasNext = resultBuilder.HasNext, + Pending = resultBuilder.Pending, + Incremental = resultBuilder.Incremental, + Completed = resultBuilder.Completed + }); + } + + return result; + } } - private static void ReportSingleError( + private static void UnwrapError( IErrorHandler errorHandler, IError error, List errors, @@ -84,11 +118,7 @@ private static void ReportSingleError( { foreach (var innerError in aggregateError.Errors) { - ReportSingleError( - errorHandler, - innerError, - errors, - depth++); + UnwrapError(errorHandler, innerError, errors, depth++); } } else diff --git a/src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs b/src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs index 126086ceef0..057c777ae01 100644 --- a/src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs +++ b/src/HotChocolate/Core/src/Types/Execution/NeedsFormatting.cs @@ -41,6 +41,9 @@ void IResultDataJsonFormatter.WriteTo( #else => FormatValue(writer, options ?? JsonSerializerOptions.Default, nullIgnoreCondition); #endif + + public static NeedsFormatting Create(TValue value) + => new(value); } /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs index 6355bf99f58..8124581c387 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Pipeline/OperationExecutionMiddleware.cs @@ -122,7 +122,7 @@ private async Task ExecuteVariableBatchRequestAsync( } var variableSet = context.VariableValues; - var tasks = new Task[variableSet.Length]; + var tasks = new Task[variableSet.Length]; for (var i = 0; i < variableSet.Length; i++) { @@ -130,7 +130,7 @@ private async Task ExecuteVariableBatchRequestAsync( } var results = await Task.WhenAll(tasks).ConfigureAwait(false); - context.Result = new OperationResultBatch(results); + context.Result = new OperationResultBatch([..results]); } private async Task ExecuteVariableBatchRequestOptimizedAsync( @@ -141,7 +141,7 @@ private async Task ExecuteVariableBatchRequestOptimizedAsync( var variableSets = context.VariableValues; var query = GetQueryRootValue(context); var operationContextBuffer = ArrayPool.Shared.Rent(variableSets.Length); - var resultBuffer = ArrayPool.Shared.Rent(variableSets.Length); + var resultBuffer = ArrayPool.Shared.Rent(variableSets.Length); for (var variableIndex = 0; variableIndex < variableSets.Length; variableIndex++) { @@ -162,7 +162,7 @@ await _queryExecutor.ExecuteBatchAsync( operationContextBuffer.AsMemory(0, variableSets.Length), resultBuffer.AsMemory(0, variableSets.Length)); - context.Result = new OperationResultBatch(CreateResults(resultBuffer.AsSpan(0, variableSets.Length))); + context.Result = new OperationResultBatch([..resultBuffer.AsSpan(0, variableSets.Length)]); } catch (OperationCanceledException) { @@ -204,9 +204,6 @@ static void Initialize( operationContexts[variableIndex] = operationContextOwner; } - static IOperationResult[] CreateResults(ReadOnlySpan results) - => results.ToArray(); - static void AbandonContexts(ref OperationContextOwner[]? operationContextBuffer, int length) { if (operationContextBuffer is not null) @@ -220,12 +217,12 @@ static void AbandonContexts(ref OperationContextOwner[]? operationContextBuffer, static void ReleaseResources( ref OperationContextOwner[]? operationContextBuffer, - IOperationResult[] resultBuffer, + IExecutionResult[] resultBuffer, int length) { var results = resultBuffer.AsSpan(0, length); results.Clear(); - ArrayPool.Shared.Return(resultBuffer); + ArrayPool.Shared.Return(resultBuffer); if (operationContextBuffer is null) { @@ -293,7 +290,7 @@ await ExecuteQueryOrMutationAsync( } } - private async Task ExecuteQueryOrMutationNoStreamAsync( + private async Task ExecuteQueryOrMutationNoStreamAsync( RequestContext context, IBatchDispatcher batchDispatcher, Operation operation, @@ -329,7 +326,7 @@ private async Task ExecuteQueryOrMutationNoStreamAsync( } } - private async Task ExecuteQueryOrMutationAsync( + private async Task ExecuteQueryOrMutationAsync( RequestContext context, IBatchDispatcher batchDispatcher, Operation operation, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs index 4b495a813d5..85151fa4dad 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Global.cs @@ -108,14 +108,14 @@ void ReportSingle(IError singleError) foreach (var ie in ar.Errors) { var errorWithPath = EnsurePathAndLocation(ie, _selection.SyntaxNodes[0].Node, Path); - _operationContext.Result.AddError(errorWithPath, _selection); + _operationContext.Result.AddError(errorWithPath); diagnosticEvents.ResolverError(this, errorWithPath); } } else { var errorWithPath = EnsurePathAndLocation(handled, _selection.SyntaxNodes[0].Node, Path); - _operationContext.Result.AddError(errorWithPath, _selection); + _operationContext.Result.AddError(errorWithPath); diagnosticEvents.ResolverError(this, errorWithPath); } @@ -224,10 +224,9 @@ public IMiddlewareContext Clone() // this context. var resolverTask = _operationContext.CreateResolverTask( - Selection, _parent, + Selection, ResultValue, - ResponseIndex, ScopedContextData); // We need to manually copy the local state. @@ -249,16 +248,16 @@ private sealed class OperationResultBuilderFacade : IOperationResultBuilder public OperationContext Context { get; set; } = null!; public void SetResultState(string key, object? value) - => Context.Result.SetContextData(key, value); + => Context.Result.SetResultState(key, value); public void SetResultState(string key, UpdateState value) - => Context.Result.SetContextData(key, value); + => Context.Result.SetResultState(key, value); public void SetResultState( string key, TState state, UpdateState value) - => Context.Result.SetContextData(key, state, value); + => Context.Result.SetResultState(key, state, value); public void SetExtension(string key, TValue value) => Context.Result.SetExtension(key, new NeedsFormatting(value)); @@ -266,12 +265,7 @@ public void SetExtension(string key, TValue value) public void SetExtension(string key, UpdateState value) => Context.Result.SetExtension?>( key, - (k, c) => new NeedsFormatting( - value( - k, - c is null - ? default! - : c.Value))); + (k, c) => NeedsFormatting.Create(value(k, c is null ? default! : c.Value))); public void SetExtension( string key, @@ -280,12 +274,6 @@ public void SetExtension( => Context.Result.SetExtension?, TState>( key, state, - (k, c, s) => new NeedsFormatting( - value( - k, - c is null - ? default! - : c.Value, - s))); + (k, c, s) => NeedsFormatting.Create(value(k, c is null ? default! : c.Value, s))); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs index b3cf76ae8d9..cf50c859c87 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.State.cs @@ -11,7 +11,7 @@ internal partial class MiddlewareContext private object? _parent; private Path? _path; - public Path Path => _path ??= ResultValue.Path.Append(Selection.ResponseName); + public Path Path => _path ??= ResultValue.Path; public IImmutableDictionary ScopedContextData { get; set; } = null!; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs index 2c8130038a0..87c7c41ec72 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Execution.cs @@ -22,7 +22,7 @@ internal set } } - public ResultDocument Result => _resultDocument; + public OperationResultBuilder Result { get; } = new(); public RequestContext RequestContext { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs index 45508919dfc..511ede6b1cc 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.IExecutionTaskContext.cs @@ -33,19 +33,18 @@ private void ReportError(IExecutionTask task, IError error) void ReportSingle(IError singleError) { var handled = ErrorHandler.Handle(singleError); - Result.Errors ??= []; if (handled is AggregateError ar) { foreach (var ie in ar.Errors) { - Result.Errors.Add(ie); + Result.AddError(ie); _diagnosticEvents.TaskError(task, ie); } } else { - Result.Errors.Add(handled); + Result.AddError(handled); _diagnosticEvents.TaskError(task, handled); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs index bcc1e64f9e3..4c2d9605d8a 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContext.Pooling.cs @@ -17,7 +17,6 @@ internal sealed partial class OperationContext private readonly WorkScheduler _workScheduler; private WorkScheduler _currentWorkScheduler; private readonly AggregateServiceScopeInitializer _serviceScopeInitializer; - private ResultDocument _resultDocument = null!; private RequestContext _requestContext = null!; private Schema _schema = null!; private IErrorHandler _errorHandler = null!; @@ -79,11 +78,9 @@ public void Initialize( _isInitialized = true; IncludeFlags = operation.CreateIncludeFlags(variables); - _resultDocument = new ResultDocument(operation, IncludeFlags) - { - RequestIndex = _requestContext.RequestIndex, - VariableIndex = variableIndex - }; + Result.Data = new ResultDocument(operation, IncludeFlags); + Result.RequestIndex = _requestContext.RequestIndex; + Result.VariableIndex = variableIndex; _workScheduler.Initialize(batchDispatcher); _currentWorkScheduler = _workScheduler; @@ -108,11 +105,9 @@ public void InitializeFrom(OperationContext context) _isInitialized = true; IncludeFlags = _operation.CreateIncludeFlags(_variables); - _resultDocument = new ResultDocument(_operation, IncludeFlags) - { - RequestIndex = _requestContext.RequestIndex, - VariableIndex = context._variableIndex - }; + Result.Data = new ResultDocument(_operation, IncludeFlags); + Result.RequestIndex = _requestContext.RequestIndex; + Result.VariableIndex = context._variableIndex; _workScheduler.Initialize(_batchDispatcher); _currentWorkScheduler = _workScheduler; @@ -124,7 +119,6 @@ public void Clean() { _currentWorkScheduler = _workScheduler; _workScheduler.Clear(); - _resultDocument = null!; _requestContext = null!; _schema = null!; _errorHandler = null!; @@ -138,6 +132,7 @@ public void Clean() _resolveQueryRootValue = null!; _batchDispatcher = null!; _isInitialized = false; + Result.Reset(); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs index c0aa82e3049..3bb712d0666 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationContextOwner.cs @@ -22,6 +22,8 @@ internal sealed class OperationContextOwner : IDisposable public OperationContextOwner(ObjectPool operationContextPool) { + ArgumentNullException.ThrowIfNull(operationContextPool); + _pool = operationContextPool; _context = operationContextPool.Get(); } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs new file mode 100644 index 00000000000..f5b8376561d --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs @@ -0,0 +1,170 @@ +using System.Collections.Immutable; +using HotChocolate.Resolvers; +using HotChocolate.Text.Json; + +namespace HotChocolate.Execution; + +internal sealed class OperationResultBuilder : IOperationResultBuilder +{ + private readonly object _sync = new(); + + public int RequestIndex { get; set; } = -1; + + public int VariableIndex { get; set; } = -1; + + public Path? Path { get; set; } + + public ResultDocument Data { get; set; } = null!; + + public ImmutableList Errors { get; set; } = ImmutableList.Empty; + + public ImmutableDictionary Extensions { get; set; } = ImmutableDictionary.Empty; + + public ImmutableDictionary ContextData { get; set; } = ImmutableDictionary.Empty; + + public ImmutableList? Pending { get; set; } + + public ImmutableList? Incremental { get; set; } + + public ImmutableList? Completed { get; set; } + + public ImmutableList> CleanupTasks { get; set; } = ImmutableList>.Empty; + + // TODO : Is this still needed? + public ImmutableHashSet NonNullViolations { get; set; } = ImmutableHashSet.Empty; + + public bool? HasNext { get; set; } + + public void AddError(IError error) + { + lock (_sync) + { + Errors = Errors.Add(error); + } + } + + public void AddErrorRange(IReadOnlyList errors) + { + lock (_sync) + { + Errors = Errors.AddRange(errors); + } + } + + public void AddNonNullViolation(Path path) + { + lock (_sync) + { + NonNullViolations = NonNullViolations.Add(path); + } + } + + public void SetExtension(string key, TValue value) + { + lock (_sync) + { + Extensions = Extensions.SetItem(key, value); + } + } + + public void SetExtension(string key, UpdateState value) + { + lock (_sync) + { + if (Extensions.TryGetValue(key, out var currentValue)) + { + var newValue = value(key, (TValue)currentValue!); + Extensions = Extensions.SetItem(key, newValue); + } + else + { + var initialValue = value(key, default!); + Extensions = Extensions.Add(key, initialValue); + } + } + } + + public void SetExtension(string key, TState state, UpdateState value) + { + lock (_sync) + { + if (Extensions.TryGetValue(key, out var currentValue)) + { + var newValue = value(key, (TValue)currentValue!, state); + Extensions = Extensions.SetItem(key, newValue); + } + else + { + var initialValue = value(key, default!, state); + Extensions = Extensions.Add(key, initialValue); + } + } + } + + public void SetResultState(string key, object? value) + { + lock (_sync) + { + ContextData = ContextData.SetItem(key, value); + } + } + + public void SetResultState(string key, UpdateState value) + { + lock (_sync) + { + if (Extensions.TryGetValue(key, out var currentValue)) + { + var newValue = value(key, currentValue); + Extensions = Extensions.SetItem(key, newValue); + } + else + { + var initialValue = value(key, null); + Extensions = Extensions.Add(key, initialValue); + } + } + } + + public void SetResultState(string key, TState state, UpdateState value) + { + lock (_sync) + { + if (Extensions.TryGetValue(key, out var currentValue)) + { + var newValue = value(key, currentValue, state); + Extensions = Extensions.SetItem(key, newValue); + } + else + { + var initialValue = value(key, null, state); + Extensions = Extensions.Add(key, initialValue); + } + } + } + + public void RegisterForCleanup(Func action) + { + lock (_sync) + { + CleanupTasks = CleanupTasks.Add(action); + } + } + + public void Reset() + { + RequestIndex = -1; + VariableIndex = -1; + Path = null; + Data = null!; + Errors = ImmutableList.Empty; + Pending = ImmutableList.Empty; + Extensions = ImmutableDictionary.Empty; + CleanupTasks = ImmutableList>.Empty; + NonNullViolations = ImmutableHashSet.Empty; + Pending = null; + Incremental = null; + Completed = null; + HasNext = null; + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs index 50d8ece2ad3..6fce5589c74 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs @@ -5,11 +5,11 @@ namespace HotChocolate.Execution.Processing; internal sealed class QueryExecutor { - public Task ExecuteAsync( + public Task ExecuteAsync( OperationContext operationContext) => ExecuteAsync(operationContext, ImmutableDictionary.Empty); - public Task ExecuteAsync( + public Task ExecuteAsync( OperationContext operationContext, IImmutableDictionary scopedContext) { @@ -19,14 +19,14 @@ public Task ExecuteAsync( return ExecuteInternalAsync(operationContext, scopedContext); } - private static async Task ExecuteInternalAsync( + private static async Task ExecuteInternalAsync( OperationContext operationContext, IImmutableDictionary scopedContext) { EnqueueResolverTasks( operationContext, operationContext.RootValue, - operationContext.Result.Data, + operationContext.Result.Data.Data, scopedContext, Path.Root); @@ -37,7 +37,7 @@ private static async Task ExecuteInternalAsync( public async Task ExecuteBatchAsync( ReadOnlyMemory operationContexts, - Memory results) + Memory results) { var scopedContext = ImmutableDictionary.Empty; @@ -65,7 +65,7 @@ private static void FillSchedulerWithWork( EnqueueResolverTasks( context, context.RootValue, - context.Result.Data, + context.Result.Data.Data, scopedContext, Path.Root); } @@ -73,7 +73,7 @@ private static void FillSchedulerWithWork( private static void BuildResults( ReadOnlySpan operationContexts, - Span results) + Span results) { for (var i = 0; i < operationContexts.Length; ++i) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs index ef15af5a215..1eda1d3c4a4 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.Subscription.cs @@ -103,7 +103,7 @@ public static async ValueTask SubscribeAsync( return subscription; } - public IAsyncEnumerable ExecuteAsync() + public IAsyncEnumerable ExecuteAsync() => new SubscriptionEnumerable( _requestContext, Id, @@ -147,7 +147,7 @@ public async ValueTask DisposeAsync() /// /// Returns a query result which will be enqueued to the response stream. /// - private async Task OnEvent(object payload) + private async Task OnEvent(object payload) { using var es = _diagnosticEvents.OnSubscriptionEvent(_requestContext, _id); using var serviceScope = _requestContext.RequestServices.CreateScope(); @@ -183,9 +183,7 @@ private async Task OnEvent(object payload) rootValue, _resolveQueryRootValue); - operationContext.Result.SetContextData( - WellKnownContextData.EventMessage, - payload); + operationContext.Result.SetResultState(WellKnownContextData.EventMessage, payload); var result = await _queryExecutor .ExecuteAsync(operationContext, scopedContextData) @@ -247,18 +245,17 @@ private async ValueTask SubscribeAsync() // next we need a result map so that we can store the subscribe temporarily // while executing the subscribe pipeline. - var resultMap = operationContext.Result.RentObject(1); + var resultMap = operationContext.Result.Data.Data; var rootSelection = _rootSelections.Selections[0]; // we create a temporary middleware context so that we can use the standard // resolver pipeline. var middlewareContext = new MiddlewareContext(); middlewareContext.Initialize( - operationContext, + rootValue, rootSelection, resultMap, - 1, - rootValue, + operationContext, _scopedContextData, null); @@ -314,18 +311,19 @@ await rootSelection.Field.SubscribeResolver! } finally { - operationContext.Result.DiscardResult(); + operationContext.Result.Data.Dispose(); + operationContext.Result.Reset(); _operationContextPool.Return(operationContext); } } } - private sealed class SubscriptionEnumerable : IAsyncEnumerable + private sealed class SubscriptionEnumerable : IAsyncEnumerable { private readonly RequestContext _requestContext; private readonly ulong _subscriptionId; private readonly ISourceStream _sourceStream; - private readonly Func> _onEvent; + private readonly Func> _onEvent; private readonly IExecutionDiagnosticEvents _diagnosticEvents; private readonly IErrorHandler _errorHandler; @@ -333,7 +331,7 @@ public SubscriptionEnumerable( RequestContext requestContext, ulong subscriptionId, ISourceStream sourceStream, - Func> onEvent, + Func> onEvent, IExecutionDiagnosticEvents diagnosticEvents, IErrorHandler errorHandler) { @@ -345,7 +343,7 @@ public SubscriptionEnumerable( _errorHandler = errorHandler; } - public IAsyncEnumerator GetAsyncEnumerator( + public IAsyncEnumerator GetAsyncEnumerator( CancellationToken cancellationToken = default) { try @@ -371,12 +369,12 @@ public IAsyncEnumerator GetAsyncEnumerator( } } - private sealed class SubscriptionEnumerator : IAsyncEnumerator + private sealed class SubscriptionEnumerator : IAsyncEnumerator { private readonly RequestContext _requestContext; private readonly ulong _subscriptionId; private readonly IAsyncEnumerator _eventEnumerator; - private readonly Func> _onEvent; + private readonly Func> _onEvent; private readonly IExecutionDiagnosticEvents _diagnosticEvents; private readonly IErrorHandler _errorHandler; private readonly CancellationToken _requestAborted; @@ -387,7 +385,7 @@ public SubscriptionEnumerator( RequestContext requestContext, ulong subscriptionId, IAsyncEnumerator eventEnumerator, - Func> onEvent, + Func> onEvent, IExecutionDiagnosticEvents diagnosticEvents, IErrorHandler errorHandler, CancellationToken requestAborted) @@ -401,7 +399,7 @@ public SubscriptionEnumerator( _requestAborted = requestAborted; } - public IOperationResult Current { get; private set; } = null!; + public OperationResult Current { get; private set; } = null!; public async ValueTask MoveNextAsync() { @@ -429,7 +427,7 @@ public async ValueTask MoveNextAsync() _diagnosticEvents.SubscriptionEventError(_requestContext, _subscriptionId, ex); _completed = true; - Current = OperationResultBuilder.CreateError(error); + Current = OperationResult.FromError(error); return true; } @@ -446,9 +444,9 @@ public async ValueTask DisposeAsync() } } - private sealed class ErrorSubscriptionEnumerator : IAsyncEnumerator + private sealed class ErrorSubscriptionEnumerator : IAsyncEnumerator { - public IOperationResult Current => null!; + public OperationResult Current => null!; public ValueTask MoveNextAsync() => new(false); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs index e10abc1e2a5..ee00cb1b8aa 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/SubscriptionExecutor.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution.Instrumentation; using Microsoft.Extensions.ObjectPool; using static HotChocolate.Execution.ThrowHelper; @@ -60,11 +61,8 @@ public async Task ExecuteAsync( _diagnosticEvents) .ConfigureAwait(false); - var response = new ResponseStream( - () => subscription.ExecuteAsync(), - contextData: new SingleValueExtensionData( - WellKnownContextData.Subscription, - subscription)); + var response = new ResponseStream(() => subscription.ExecuteAsync()); + response.ContextData = response.ContextData.SetItem(WellKnownContextData.Subscription, subscription); response.RegisterForCleanup(subscription); return response; } @@ -75,7 +73,7 @@ public async Task ExecuteAsync( await subscription.DisposeAsync().ConfigureAwait(false); } - return new OperationResult(null, ex.Errors); + return new OperationResult([..ex.Errors]); } catch (Exception ex) { @@ -89,11 +87,11 @@ public async Task ExecuteAsync( return new OperationResult(null, Unwrap(error)); } - static IReadOnlyList Unwrap(IError error) + static ImmutableList Unwrap(IError error) { if (error is AggregateError aggregateError) { - return aggregateError.Errors; + return [..aggregateError.Errors]; } return [error]; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs index 52e84d7fa20..22e050998a8 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTask.CompleteValue.cs @@ -47,7 +47,7 @@ private void CompleteValue(bool success, CancellationToken cancellationToken) { PropagateNullValues(resultValue); _completionStatus = ExecutionTaskStatus.Faulted; - _operationContext.Result.AddNonNullViolation(_selection, _context.Path); + _operationContext.Result.AddNonNullViolation(_context.Path); _taskBuffer.Clear(); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs index a1303e38f38..e20aa151edf 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs @@ -225,7 +225,7 @@ private static void ResolveAndCompleteInline( if (fieldValue is { IsNullable: false, IsNullOrInvalidated: true }) { PropagateNullValues(fieldValue); - operationContext.Result.AddNonNullViolation(_selection, _context.Path); + operationContext.Result.AddNonNullViolation(fieldValue.Path); } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs index 7fdaf7aa7d2..297eb489584 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs @@ -34,13 +34,13 @@ private static void CompleteLeafValue( { var errorPath = resultValue.Path; var error = InvalidLeafValue(ex, selection, errorPath); - operationContext.ReportError(error, resolverContext, selection); + operationContext.ReportError(error, resolverContext); } catch (Exception ex) { var errorPath = resultValue.Path; var error = UnexpectedLeafValueSerializationError(ex, selection, errorPath); - operationContext.ReportError(error, resolverContext, selection); + operationContext.ReportError(error, resolverContext); } resultValue.SetNullValue(); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs index ce2a7f9fe9b..3665f80bb3e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.List.cs @@ -120,7 +120,7 @@ private static void CompleteListValue( var operationContext = context.OperationContext; var resolverContext = context.ResolverContext; var error = ListValueIsNotSupported(runtimeValue.GetType(), selection, resultValue.Path); - operationContext.ReportError(error, resolverContext, selection); + operationContext.ReportError(error, resolverContext); } internal static void PropagateNullValues(ResultElement result) diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs index 080e9a75d99..9d59648c26e 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Object.cs @@ -39,7 +39,7 @@ private static void CompleteCompositeValue( } var error = ValueCompletion_CouldNotResolveAbstractType(selection, resultValue.Path, runtimeValue); - operationContext.ReportError(error, context.ResolverContext, selection); + operationContext.ReportError(error, context.ResolverContext); } private static bool TryResolveObjectType( @@ -80,7 +80,7 @@ private static bool TryResolveObjectType( fieldType.Print(), selection, resultValue.Path); - context.OperationContext.ReportError(error, context.ResolverContext, selection); + context.OperationContext.ReportError(error, context.ResolverContext); } catch (Exception ex) { @@ -89,7 +89,7 @@ private static bool TryResolveObjectType( fieldType.Print(), selection, resultValue.Path); - context.OperationContext.ReportError(error, context.ResolverContext, selection); + context.OperationContext.ReportError(error, context.ResolverContext); } objectType = null; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs index 6c849e2d813..87b48c2572b 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs @@ -50,7 +50,7 @@ public static void Complete( default: var error = UnexpectedValueCompletionError(selection, resultValue.Path); - context.OperationContext.ReportError(error, context.ResolverContext, selection); + context.OperationContext.ReportError(error, context.ResolverContext); break; } } diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs index e0f6c02a344..8304359ae77 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Pooling.cs @@ -16,6 +16,7 @@ internal sealed partial class WorkScheduler(OperationContext operationContext) private RequestContext _requestContext = null!; private IBatchDispatcher _batchDispatcher = null!; private IDisposable _batchDispatcherSession = null!; + private OperationResultBuilder _result = null!; private IErrorHandler _errorHandler = null!; private IExecutionDiagnosticEvents _diagnosticEvents = null!; private readonly ConcurrentDictionary _completed = new(); @@ -31,6 +32,7 @@ public void Initialize(IBatchDispatcher batchDispatcher) _batchDispatcher = batchDispatcher; _batchDispatcherSession = _batchDispatcher.Subscribe(this); + _result = operationContext.Result; _errorHandler = operationContext.ErrorHandler; _diagnosticEvents = operationContext.DiagnosticEvents; _ct = operationContext.RequestAborted; @@ -54,6 +56,7 @@ public void Clear() _completed.Clear(); _signal.Reset(); + _result = null!; _batchDispatcherSession.Dispose(); _batchDispatcherSession = null!; _batchDispatcher = null!; diff --git a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj index 26d565a8354..b974b656938 100644 --- a/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj +++ b/src/HotChocolate/Core/src/Types/HotChocolate.Types.csproj @@ -243,6 +243,110 @@ SubscriptionExecutor.cs + + + WorkScheduler.cs + + + + WorkScheduler.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + RequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + + + + SchemaRequestExecutorBuilderExtensions.cs + diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs index 5e613d3f224..8228e23195a 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.DbRow.cs @@ -39,11 +39,10 @@ public DbRow( { Debug.Assert((byte)tokenType < 16); Debug.Assert(location is >= 0 and <= 0x07FFFFFF); // 27 bits - Debug.Assert(sizeOrLength == UnknownSize || sizeOrLength is >= 0 and <= 0x07FFFFFF); // 27 bits + Debug.Assert(sizeOrLength is UnknownSize or >= 0 and <= 0x07FFFFFF); // 27 bits Debug.Assert(parentRow is >= 0 and <= 0x07FFFFFF); // 27 bits Debug.Assert(operationReferenceId is >= 0 and <= 0x7FFF); // 15 bits Debug.Assert(numberOfRows is >= 0 and <= 0x07FFFFFF); // 27 bits - Debug.Assert((byte)flags <= 255); // 8 bits (0xFF) Debug.Assert((byte)operationReferenceType <= 3); // 2 bits Debug.Assert(Unsafe.SizeOf() == Size); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs index 41b9d050cd4..709bcecbea8 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -8,13 +8,17 @@ namespace HotChocolate.Text.Json; public sealed partial class ResultDocument : IRawJsonFormatter { - public void WriteTo(IBufferWriter writer, bool indented = false) + public void WriteTo(OperationResult result, IBufferWriter writer, bool indented = false) { - var formatter = new RawJsonFormatter(this, writer, indented); + var formatter = new RawJsonFormatter(result, this, writer, indented); formatter.Write(); } - internal ref struct RawJsonFormatter(ResultDocument document, IBufferWriter writer, bool indented) + internal ref struct RawJsonFormatter( + OperationResult result, + ResultDocument document, + IBufferWriter writer, + bool indented) { private int _indentation = 0; @@ -28,7 +32,7 @@ public void Write() _indentation++; } - if (document.Errors?.Count > 0) + if (result.Errors?.Count > 0) { if (indented) { @@ -49,7 +53,7 @@ public void Write() using var jsonWriter = new Utf8JsonWriter(writer, options); JsonValueFormatter.WriteErrors( jsonWriter, - document.Errors, + result.Errors, new JsonSerializerOptions(JsonSerializerDefaults.Web), default); jsonWriter.Flush(); @@ -86,7 +90,7 @@ public void Write() WriteObject(root, row); } - if (document.Extensions?.Count > 0) + if (result.Extensions?.Count > 0) { WriteByte(JsonConstants.Comma); @@ -109,7 +113,7 @@ public void Write() using var jsonWriter = new Utf8JsonWriter(writer, options); JsonValueFormatter.WriteDictionary( jsonWriter, - document.Extensions, + result.Extensions, new JsonSerializerOptions(JsonSerializerDefaults.Web), default); jsonWriter.Flush(); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs index 5fafdee1c60..857764161b6 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.cs @@ -1,13 +1,10 @@ using System.Buffers; -using System.Collections.Immutable; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Text; using HotChocolate.Buffers; using HotChocolate.Execution; using HotChocolate.Execution.Processing; -using HotChocolate.Features; using HotChocolate.Types; namespace HotChocolate.Text.Json; @@ -209,8 +206,8 @@ internal ResultElement GetParent(Cursor current) // if we have not yet reached the root and the element type of the parent is an object or an array // then we need to get still the parent of this row as we want to get the logical parent // which is the value level of the property or the element in an array. - if (parent != Cursor.Zero && - _metaDb.GetElementTokenType(parent) is ElementTokenType.StartObject or ElementTokenType.StartArray) + if (parent != Cursor.Zero + && _metaDb.GetElementTokenType(parent) is ElementTokenType.StartObject or ElementTokenType.StartArray) { parent = _metaDb.GetParentCursor(parent); @@ -442,8 +439,8 @@ private ReadOnlySpan ReadLocalData(int location, int size) // Data spans chunk boundaries - this should be rare for typical JSON values throw new NotSupportedException( - "Reading data that spans chunk boundaries as a span is not supported. " + - "Use WriteLocalDataTo for writing to an IBufferWriter instead."); + "Reading data that spans chunk boundaries as a span is not supported. " + + "Use WriteLocalDataTo for writing to an IBufferWriter instead."); } internal ResultElement CreateObject(Cursor parent, SelectionSet selectionSet) diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs index de454de6cd1..452973d3dab 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -12,7 +12,7 @@ namespace HotChocolate.Text.Json; -public readonly partial struct ResultElement : IRawJsonFormatter +public readonly partial struct ResultElement { private readonly ResultDocument _parent; private readonly ResultDocument.Cursor _cursor; @@ -26,20 +26,6 @@ internal ResultElement(ResultDocument parent, ResultDocument.Cursor cursor) _cursor = cursor; } - /// - /// Writes this element as JSON to the specified buffer writer. - /// - /// The buffer writer to write to. - /// - /// true to write indented JSON; otherwise, false. - /// - public void WriteTo(IBufferWriter writer, bool indented = false) - { - var formatter = new ResultDocument.RawJsonFormatter(_parent, writer, indented); - var row = _parent._metaDb.Get(_cursor); - formatter.WriteValue(_cursor, row); - } - /// /// Gets the internal meta-db cursor. /// diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/ErrorHelper.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/ErrorHelper.cs index 5ec44b36aa3..1926ddd14aa 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/ErrorHelper.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/ErrorHelper.cs @@ -5,23 +5,23 @@ namespace HotChocolate.Fusion.Execution; internal static class ErrorHelper { - public static IOperationResult RequestTimeout(TimeSpan timeout) => - OperationResultBuilder.CreateError( + public static OperationResult RequestTimeout(TimeSpan timeout) => + OperationResult.FromError( new Error { Message = string.Format("The request exceeded the configured timeout of `{0}`.", timeout), Extensions = ImmutableOrderedDictionary.Empty.Add("code", ErrorCodes.Execution.Timeout) }); - public static IOperationResult StateInvalidForOperationPlanCache() - => OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForOperationPlanCache() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage("The operation plan cache requires a operation document hash.") .SetCode(ErrorCodes.Execution.OperationDocumentNotFound) .Build()); - public static IOperationResult StateInvalidForVariableCoercion() - => OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForVariableCoercion() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage("The variable coercion requires an operation execution plan.") .Build()); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutor.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutor.cs index d6ac169bde9..a1c2dd9fcdf 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutor.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/FusionRequestExecutor.cs @@ -152,7 +152,7 @@ private async Task ExecuteAsync( /// /// Executes a batch of GraphQL operation requests and returns an /// that yields each individual - /// as it becomes available. + /// as it becomes available. /// /// /// The batch of operation requests. @@ -172,7 +172,7 @@ public Task ExecuteBatchAsync( ExecutionResultKind.BatchResult)); } - private async IAsyncEnumerable CreateResponseStream( + private async IAsyncEnumerable CreateResponseStream( OperationRequestBatch requestBatch, [EnumeratorCancellation] CancellationToken ct = default) { @@ -207,7 +207,7 @@ private async IAsyncEnumerable CreateResponseStream( } } - private async IAsyncEnumerable ExecuteBatchStream( + private async IAsyncEnumerable ExecuteBatchStream( OperationRequestBatch requestBatch, IServiceProvider services, [EnumeratorCancellation] CancellationToken ct = default) @@ -216,14 +216,14 @@ private async IAsyncEnumerable ExecuteBatchStream( var requestCount = requests.Count; var tasks = Interlocked.Exchange(ref _taskList, null) ?? new List(requestCount); - var completed = new List(); + var completed = new List(); for (var i = 0; i < requestCount; i++) { tasks.Add(ExecuteBatchItemAsync(WithServices(requests[i], services), i, completed, ct)); } - var buffer = new IOperationResult[Math.Min(16, requestCount)]; + var buffer = new OperationResult[Math.Min(16, requestCount)]; while (tasks.Count > 0 || completed.Count > 0) { @@ -280,7 +280,7 @@ private static IOperationRequest WithServices( private async Task ExecuteBatchItemAsync( IOperationRequest request, int requestIndex, - List completed, + List completed, CancellationToken cancellationToken) { var result = await ExecuteAsync(request, requestIndex, cancellationToken).ConfigureAwait(false); @@ -289,7 +289,7 @@ private async Task ExecuteBatchItemAsync( private static async Task UnwrapBatchItemResultAsync( IExecutionResult result, - List completed, + List completed, CancellationToken cancellationToken) { switch (result) diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs index ea53da84b23..eeb6ddfb7ad 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs @@ -261,7 +261,7 @@ internal void Begin(long? start = null, string? traceId = null) } } - internal IOperationResult Complete(bool reusable = false) + internal OperationResult Complete(bool reusable = false) { var environment = Schema.TryGetEnvironment(); @@ -277,7 +277,14 @@ internal IOperationResult Complete(bool reusable = false) : null; var result = _resultStore.Result; - var operationResult = new RawOperationResult(result, contextData: null); + var operationResult = new OperationResult( + new OperationResultData( + result, + result.Data.IsNullOrInvalidated, + result, + result), + result.Errors?.ToImmutableList(), + result.Extensions?.ToImmutableDictionary()); // we take over the memory owners from the result context // and store them on the response so that the server can diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanExecutor.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanExecutor.cs index e4217d6296a..abe4de8c703 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanExecutor.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanExecutor.cs @@ -197,7 +197,7 @@ private static async Task ExecuteMutationAsync( } } - private static async IAsyncEnumerable CreateSubscriptionEnumerable( + private static async IAsyncEnumerable CreateSubscriptionEnumerable( OperationPlanContext context, OperationExecutionNode subscriptionNode, SubscriptionResult subscriptionResult, @@ -217,7 +217,7 @@ private static async IAsyncEnumerable CreateSubscriptionEnumer subscriptionNode.SchemaName ?? context.GetDynamicSchemaName(subscriptionNode), subscriptionResult.Id); - IOperationResult result; + OperationResult result; try { diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationExecutionMiddleware.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationExecutionMiddleware.cs index 57cfba647d7..a6595cb8a26 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationExecutionMiddleware.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationExecutionMiddleware.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using System.Runtime.InteropServices; using HotChocolate.Execution; using HotChocolate.Fusion.Diagnostics; @@ -41,7 +42,7 @@ public async ValueTask InvokeAsync( _diagnosticEvents.RequestError(context, error); - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); return; } @@ -63,7 +64,7 @@ public async ValueTask InvokeAsync( cancellationToken); } - var results = await Task.WhenAll(tasks); + var results = ImmutableList.CreateRange(await Task.WhenAll(tasks)); context.Result = new OperationResultBatch(results); } else diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationVariableCoercionMiddleware.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationVariableCoercionMiddleware.cs index 9d7611b703a..53397ab4db8 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationVariableCoercionMiddleware.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Pipeline/OperationVariableCoercionMiddleware.cs @@ -70,7 +70,7 @@ private static bool TryCoerceVariables( return true; } - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); return false; } } @@ -96,7 +96,7 @@ private static bool TryCoerceVariables( } else { - context.Result = OperationResultBuilder.CreateError(error); + context.Result = OperationResult.FromError(error); return false; } } diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/RawOperationResult.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/RawOperationResult.cs deleted file mode 100644 index 820a87794b4..00000000000 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/Results/RawOperationResult.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Buffers; -using System.Text.Json; -using HotChocolate.Execution; -using HotChocolate.Fusion.Text.Json; - -namespace HotChocolate.Fusion.Execution.Results; - -public sealed class RawOperationResult : ExecutionResult, IRawJsonFormatter, IOperationResult -{ - private readonly CompositeResultDocument _result; - private readonly IReadOnlyDictionary? _contextData; - - internal RawOperationResult( - CompositeResultDocument result, - IReadOnlyDictionary? contextData) - { - _result = result; - _contextData = contextData; - } - - public override ExecutionResultKind Kind => ExecutionResultKind.SingleResult; - - public CompositeResultDocument Result => _result; - - public IReadOnlyList? Errors => _result.Errors; - - public IReadOnlyDictionary? Extensions => _result.Extensions; - - public override IReadOnlyDictionary? ContextData => _contextData; - - public void WriteTo(IBufferWriter writer, bool indented = false) - { - ArgumentNullException.ThrowIfNull(writer); - _result.WriteTo(writer); - } - - #region NotSupported - - int? IOperationResult.RequestIndex => throw new NotSupportedException(); - - int? IOperationResult.VariableIndex => throw new NotSupportedException(); - - string? IOperationResult.Label => throw new NotSupportedException(); - - Path? IOperationResult.Path => throw new NotSupportedException(); - - IReadOnlyDictionary? IOperationResult.Data => throw new NotSupportedException(); - - IReadOnlyList? IOperationResult.Items => throw new NotSupportedException(); - - IReadOnlyDictionary? IOperationResult.Extensions => throw new NotSupportedException(); - - IReadOnlyList? IOperationResult.Incremental => throw new NotSupportedException(); - - bool? IOperationResult.HasNext => throw new NotSupportedException(); - - bool IOperationResult.IsDataSet => _result.Data.ValueKind is JsonValueKind.Object; - - #endregion -} diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.WriteTo.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.WriteTo.cs index 0a80ae01435..cd60ae23faa 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.WriteTo.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.WriteTo.cs @@ -8,7 +8,7 @@ namespace HotChocolate.Fusion.Text.Json; public sealed partial class CompositeResultDocument : IRawJsonFormatter { - public void WriteTo(IBufferWriter writer, bool indented = false) + public void WriteTo(OperationResult result, IBufferWriter writer, bool indented = false) { var formatter = new RawJsonFormatter(this, writer, indented); formatter.Write(); diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs index a72d6ac3b94..7aef388f1c2 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultElement.cs @@ -10,7 +10,7 @@ namespace HotChocolate.Fusion.Text.Json; -public readonly partial struct CompositeResultElement : IRawJsonFormatter +public readonly partial struct CompositeResultElement { private readonly CompositeResultDocument _parent; private readonly CompositeResultDocument.Cursor _cursor; From 91d3d60d67375f043ff5b8beb8e27bb42689e0aa Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 20:05:35 +0100 Subject: [PATCH 36/42] wip --- .../OpenApiResultFormatter.cs | 25 ++-- .../FusionOpenApiResultFormatter.cs | 1 - .../src/Caching/ICacheControlConstraints.cs | 2 +- .../CoreExecutionResultExtensions.cs | 81 ++++++------ .../Types/Text/Json/ResultDocument.WriteTo.cs | 7 +- .../Core/src/Types/Text/Json/ResultElement.cs | 14 +++ .../Execution/OperationResultBuilderTests.cs | 71 ----------- .../Execution/OperationResultBuilderTests.cs | 71 ----------- .../CostAnalysis/Utilities/ResultHelper.cs | 117 ++++++------------ .../SortVisitorTestBase.cs | 7 +- .../src/Diagnostics/ActivityEnricher.cs | 2 +- .../ActivityServerDiagnosticListener.cs | 6 +- .../Scopes/ExecuteOperationScope.cs | 2 +- .../Diagnostics/Scopes/ExecuteRequestScope.cs | 2 +- .../ProjectionVisitorTestBase.cs | 11 +- .../SortVisitorTestBase.cs | 7 +- .../IntegrationTests.cs | 7 +- .../IntegrationTests.cs | 21 +--- .../FilterVisitorTestBase.cs | 9 +- .../Transport.InMemory/InMemoryConnection.cs | 29 ++--- 20 files changed, 151 insertions(+), 341 deletions(-) delete mode 100644 src/HotChocolate/Core/test/Abstractions.Tests/Execution/OperationResultBuilderTests.cs delete mode 100644 src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationResultBuilderTests.cs diff --git a/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs b/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs index 1f05da24626..bf6e56be174 100644 --- a/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs +++ b/src/HotChocolate/Adapters/src/Adapters.OpenApi/OpenApiResultFormatter.cs @@ -1,6 +1,7 @@ using System.Text.Encodings.Web; using System.Text.Json; using HotChocolate.Execution; +using HotChocolate.Text.Json; using Microsoft.AspNetCore.Http; namespace HotChocolate.Adapters.OpenApi; @@ -14,15 +15,26 @@ internal sealed class OpenApiResultFormatter : IOpenApiResultFormatter new() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; public async Task FormatResultAsync( - IOperationResult operationResult, + OperationResult operationResult, HttpContext httpContext, OpenApiEndpointDescriptor endpoint, CancellationToken cancellationToken) { + if (operationResult.Data is not ResultDocument resultDocument) + { + await Results.InternalServerError().ExecuteAsync(httpContext); + return; + } + + if (!resultDocument.Data.TryGetProperty(endpoint.ResponseNameToExtract, out var rootProperty)) + { + await Results.InternalServerError().ExecuteAsync(httpContext); + return; + } + // If the root field is null, and we don't have any errors, // we return HTTP 404 for queries and HTTP 500 otherwise. - if (operationResult.Data?.TryGetValue(endpoint.ResponseNameToExtract, out var responseData) != true - || responseData is null) + if (rootProperty.IsNullOrInvalidated) { var result = endpoint.HttpMethod == HttpMethods.Get ? Results.NotFound() @@ -35,11 +47,10 @@ public async Task FormatResultAsync( httpContext.Response.StatusCode = StatusCodes.Status200OK; httpContext.Response.ContentType = "application/json"; - var jsonWriter = new Utf8JsonWriter(httpContext.Response.BodyWriter, s_jsonWriterOptions); + var bodyWriter = httpContext.Response.BodyWriter; - JsonValueFormatter.WriteValue(jsonWriter, responseData, s_jsonSerializerOptions, - JsonNullIgnoreCondition.None); + rootProperty.WriteTo(bodyWriter); - await jsonWriter.FlushAsync(cancellationToken); + await bodyWriter.FlushAsync(cancellationToken); } } diff --git a/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs b/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs index 49613679281..362b3d01bba 100644 --- a/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs +++ b/src/HotChocolate/Adapters/src/Fusion.Adapters.OpenApi/FusionOpenApiResultFormatter.cs @@ -1,5 +1,4 @@ using HotChocolate.Execution; -using HotChocolate.Fusion.Execution.Results; using HotChocolate.Fusion.Text.Json; using Microsoft.AspNetCore.Http; diff --git a/src/HotChocolate/Caching/src/Caching/ICacheControlConstraints.cs b/src/HotChocolate/Caching/src/Caching/ICacheControlConstraints.cs index 8fd3dc23966..2b33b511552 100644 --- a/src/HotChocolate/Caching/src/Caching/ICacheControlConstraints.cs +++ b/src/HotChocolate/Caching/src/Caching/ICacheControlConstraints.cs @@ -21,7 +21,7 @@ public interface ICacheConstraints int? SharedMaxAge { get; } /// - /// The scope of the that shall be cached. + /// The scope of the that shall be cached. /// CacheControlScope Scope { get; } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs index c704855ca06..dd6aa672b08 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/Extensions/CoreExecutionResultExtensions.cs @@ -8,6 +8,48 @@ namespace HotChocolate.Execution; /// public static class CoreExecutionResultExtensions { + extension(IExecutionResult? result) + { + /// + /// Expects a single GraphQL operation result. + /// + public OperationResult ExpectOperationResult() + { + if (result is OperationResult qr) + { + return qr; + } + + throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResult_NotOperationResult); + } + + /// + /// Expects a batch of operation results. + /// + public OperationResultBatch ExpectOperationResultBatch() + { + if (result is OperationResultBatch qr) + { + return qr; + } + + throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResultBatch_NotOperationResultBatch); + } + + /// + /// Expect a stream result. + /// + public ResponseStream ExpectResponseStream() + { + if (result is ResponseStream rs) + { + return rs; + } + + throw new ArgumentException(ExecutionResultExtensions_ExpectResponseStream_NotResponseStream); + } + } + extension(IExecutionResult result) { /// @@ -61,44 +103,5 @@ public void RegisterForCleanup(IAsyncDisposable disposable) /// public bool IsStreamResult() => result.Kind is BatchResult or DeferredResult or SubscriptionResult; - - /// - /// Expects a single GraphQL operation result. - /// - public OperationResult ExpectOperationResult() - { - if (result is OperationResult qr) - { - return qr; - } - - throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResult_NotOperationResult); - } - - /// - /// Expects a batch of operation results. - /// - public OperationResultBatch ExpectOperationResultBatch() - { - if (result is OperationResultBatch qr) - { - return qr; - } - - throw new ArgumentException(ExecutionResultExtensions_ExpectOperationResultBatch_NotOperationResultBatch); - } - - /// - /// Expect a stream result. - /// - public ResponseStream ExpectResponseStream() - { - if (result is ResponseStream rs) - { - return rs; - } - - throw new ArgumentException(ExecutionResultExtensions_ExpectResponseStream_NotResponseStream); - } } } diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs index 709bcecbea8..ea50b4df715 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultDocument.WriteTo.cs @@ -10,19 +10,18 @@ public sealed partial class ResultDocument : IRawJsonFormatter { public void WriteTo(OperationResult result, IBufferWriter writer, bool indented = false) { - var formatter = new RawJsonFormatter(result, this, writer, indented); - formatter.Write(); + var formatter = new RawJsonFormatter(this, writer, indented); + formatter.Write(result); } internal ref struct RawJsonFormatter( - OperationResult result, ResultDocument document, IBufferWriter writer, bool indented) { private int _indentation = 0; - public void Write() + public void Write(OperationResult result) { WriteByte(JsonConstants.OpenBrace); diff --git a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs index 452973d3dab..9f6d6f12291 100644 --- a/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs +++ b/src/HotChocolate/Core/src/Types/Text/Json/ResultElement.cs @@ -1140,6 +1140,20 @@ public void SetNumberValue(decimal value) _parent.AssignNumberValue(this, buffer[..bytesWritten]); } + /// + /// Writes this element as JSON to the specified buffer writer. + /// + /// The buffer writer to write to. + /// + /// true to write indented JSON; otherwise, false. + /// + public void WriteTo(IBufferWriter writer, bool indented = false) + { + var formatter = new ResultDocument.RawJsonFormatter(_parent, writer, indented); + var row = _parent._metaDb.Get(_cursor); + formatter.WriteValue(_cursor, row); + } + /// public override string ToString() { diff --git a/src/HotChocolate/Core/test/Abstractions.Tests/Execution/OperationResultBuilderTests.cs b/src/HotChocolate/Core/test/Abstractions.Tests/Execution/OperationResultBuilderTests.cs deleted file mode 100644 index dfac59c39f5..00000000000 --- a/src/HotChocolate/Core/test/Abstractions.Tests/Execution/OperationResultBuilderTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace HotChocolate.Execution; - -public class OperationResultBuilderTests -{ - [Fact] - public void Create_Result_Without_Data_And_Errors() - { - // arrange - // act - Action result = () => OperationResultBuilder.New().Build(); - - // assert - Assert.Throws(result); - } - - [Fact] - public void Create_Result_Set_Data() - { - // arrange - var builder = new OperationResultBuilder(); - - // act - builder.SetData(new Dictionary { { "a", "b" } }); - - // assert - builder.Build().MatchSnapshot(); - } - - [Fact] - public void Create_Result_Set_Items() - { - // arrange - var builder = new OperationResultBuilder(); - - // act - builder.SetItems(new List { 1 }); - - // assert - builder.Build().MatchSnapshot(); - } - - [Fact] - public void ExpectOperationResult() - { - // arrange - IExecutionResult result = OperationResultBuilder.New() - .SetData(new Dictionary { { "a", "b" } }) - .Build(); - - // act - var queryResult = result.ExpectOperationResult(); - - // assert - Assert.NotNull(queryResult); - } - - [Fact] - public void ExpectResponseStream() - { - // arrange - IExecutionResult result = OperationResultBuilder.New() - .SetData(new Dictionary { { "a", "b" } }) - .Build(); - - // act - void Fail() => result.ExpectResponseStream(); - - // assert - Assert.Throws(Fail); - } -} diff --git a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationResultBuilderTests.cs b/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationResultBuilderTests.cs deleted file mode 100644 index dfac59c39f5..00000000000 --- a/src/HotChocolate/Core/test/Execution.Abstractions.Tests/Execution/OperationResultBuilderTests.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace HotChocolate.Execution; - -public class OperationResultBuilderTests -{ - [Fact] - public void Create_Result_Without_Data_And_Errors() - { - // arrange - // act - Action result = () => OperationResultBuilder.New().Build(); - - // assert - Assert.Throws(result); - } - - [Fact] - public void Create_Result_Set_Data() - { - // arrange - var builder = new OperationResultBuilder(); - - // act - builder.SetData(new Dictionary { { "a", "b" } }); - - // assert - builder.Build().MatchSnapshot(); - } - - [Fact] - public void Create_Result_Set_Items() - { - // arrange - var builder = new OperationResultBuilder(); - - // act - builder.SetItems(new List { 1 }); - - // assert - builder.Build().MatchSnapshot(); - } - - [Fact] - public void ExpectOperationResult() - { - // arrange - IExecutionResult result = OperationResultBuilder.New() - .SetData(new Dictionary { { "a", "b" } }) - .Build(); - - // act - var queryResult = result.ExpectOperationResult(); - - // assert - Assert.NotNull(queryResult); - } - - [Fact] - public void ExpectResponseStream() - { - // arrange - IExecutionResult result = OperationResultBuilder.New() - .SetData(new Dictionary { { "a", "b" } }) - .Build(); - - // act - void Fail() => result.ExpectResponseStream(); - - // assert - Assert.Throws(Fail); - } -} diff --git a/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs b/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs index ebd58cc12eb..f7f6e0f4d28 100644 --- a/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs +++ b/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Collections.Immutable; using HotChocolate.Execution; namespace HotChocolate.CostAnalysis.Utilities; @@ -14,7 +15,7 @@ internal static class ResultHelper public static IExecutionResult CreateError(IError error, CostMetrics? costMetrics) { - IReadOnlyDictionary? extensions = null; + ImmutableDictionary? extensions = null; if (costMetrics is not null) { extensions = AddCostMetrics(extensions, costMetrics); @@ -22,47 +23,24 @@ public static IExecutionResult CreateError(IError error, CostMetrics? costMetric return error is AggregateError aggregateError ? CreateError(aggregateError.Errors, costMetrics) - : new OperationResult( - null, - ImmutableArray.Create(error), - extensions: extensions, - contextData: s_validationError); + : new OperationResult([error], extensions) { ContextData = s_validationError }; } public static IExecutionResult CreateError(IReadOnlyList errors, CostMetrics? costMetrics) { - IReadOnlyDictionary? extensions = null; + ImmutableDictionary? extensions = null; if (costMetrics is not null) { extensions = AddCostMetrics(extensions, costMetrics); } - return new OperationResult( - null, - errors, - extensions: extensions, - contextData: s_validationError); + return new OperationResult([..errors], extensions) { ContextData = s_validationError }; } public static IExecutionResult CreateResult(this CostMetrics costMetrics) { var extensions = AddCostMetrics(ImmutableDictionary.Empty, costMetrics); - - return new OperationResult( - data: null, - errors: null, - extensions: extensions, - contextData: s_ok, - items: null, - incremental: null, - label: null, - path: null, - hasNext: null, - cleanupTasks: ([], 0), - isDataSet: false, - requestIndex: null, - variableIndex: null, - skipValidation: true); + return new OperationResult(extensions: extensions) { ContextData = s_ok }; } public static IExecutionResult AddCostMetrics( @@ -78,17 +56,14 @@ public static IExecutionResult AddCostMetrics( return AddCostMetrics(r, costMetrics); case OperationResultBatch r: - var results = new IExecutionResult[r.Results.Count]; - IImmutableDictionary? costMetricsMap = null; - - for (var i = 0; i < r.Results.Count; i++) + ImmutableOrderedDictionary? costMetricsMap = null; + foreach (var current in r.Results) { - switch (r.Results[i]) + switch (current) { case OperationResult operationResult: costMetricsMap ??= CreateCostMetricsMap(costMetrics); - results[i] = operationResult.WithExtensions( - AddCostMetrics(operationResult.Extensions, costMetricsMap)); + operationResult.Extensions = AddCostMetrics(operationResult.Extensions, costMetricsMap); break; case ResponseStream responseStream: @@ -99,7 +74,7 @@ public static IExecutionResult AddCostMetrics( } } - return new OperationResultBatch(results); + return r; default: throw new NotSupportedException(); @@ -111,7 +86,8 @@ private static OperationResult AddCostMetrics( CostMetrics costMetrics) { var extensions = AddCostMetrics(operationResult.Extensions, costMetrics); - return operationResult.WithExtensions(extensions); + operationResult.Extensions = extensions; + return operationResult; } private static ResponseStream AddCostMetrics( @@ -120,47 +96,42 @@ private static ResponseStream AddCostMetrics( { var onFirstResult = responseStream.OnFirstResult; - if (onFirstResult.Count == 0) + if (onFirstResult.IsEmpty) { onFirstResult = - ImmutableArray.Create>( - result => result is OperationResult operationResult - ? operationResult.WithExtensions(AddCostMetrics(operationResult.Extensions, costMetrics)) - : result); - - return responseStream.WithOnFirstResult(onFirstResult); + ImmutableList.Create>( + result => + { + result.Extensions = AddCostMetrics(result.Extensions, costMetrics); + return result; + }); } - - if (onFirstResult is ImmutableArray> immutable) + else { - onFirstResult = immutable.Add( - result => result is OperationResult operationResult - ? operationResult.WithExtensions(AddCostMetrics(operationResult.Extensions, costMetrics)) - : result); - - return responseStream.WithOnFirstResult(onFirstResult); + onFirstResult = + onFirstResult.Add( + result => + { + result.Extensions = AddCostMetrics(result.Extensions, costMetrics); + return result; + }); } - var builder = ImmutableArray.CreateBuilder>(); - builder.AddRange(onFirstResult); - builder.Add( - result => result is OperationResult operationResult - ? operationResult.WithExtensions(AddCostMetrics(operationResult.Extensions, costMetrics)) - : result); - return responseStream.WithOnFirstResult(builder.ToImmutable()); + responseStream.OnFirstResult = onFirstResult; + return responseStream; } - private static IReadOnlyDictionary AddCostMetrics( - IReadOnlyDictionary? extensions, + private static ImmutableDictionary AddCostMetrics( + ImmutableDictionary? extensions, CostMetrics costMetrics) { var costMetricsMap = CreateCostMetricsMap(costMetrics); return AddCostMetrics(extensions, costMetricsMap); } - private static IReadOnlyDictionary AddCostMetrics( - IReadOnlyDictionary? extensions, - IImmutableDictionary costMetrics) + private static ImmutableDictionary AddCostMetrics( + ImmutableDictionary? extensions, + ImmutableOrderedDictionary costMetrics) { const string costKey = "operationCost"; @@ -169,28 +140,20 @@ private static ResponseStream AddCostMetrics( return ImmutableDictionary.Empty.Add(costKey, costMetrics); } - if (extensions is ImmutableDictionary immutable) - { - return immutable.Add(costKey, costMetrics); - } - - var builder = ImmutableDictionary.CreateBuilder(); - builder.AddRange(extensions); - builder.Add(costKey, costMetrics); - return builder.ToImmutable(); + return extensions.Add(costKey, costMetrics); } - private static IImmutableDictionary CreateCostMetricsMap( + private static ImmutableOrderedDictionary CreateCostMetricsMap( CostMetrics costMetrics) { - var builder = ImmutableSortedDictionary.CreateBuilder(StringComparer.Ordinal); + var builder = ImmutableOrderedDictionary.CreateBuilder(); builder.Add("fieldCost", costMetrics.FieldCost); builder.Add("typeCost", costMetrics.TypeCost); return builder.ToImmutable(); } - public static IOperationResult StateInvalidForCostAnalysis() => - OperationResultBuilder.CreateError( + public static OperationResult StateInvalidForCostAnalysis() + => OperationResult.FromError( ErrorBuilder.New() .SetMessage("The query request contains no document or no document id.") .SetCode(ErrorCodes.Execution.OperationDocumentNotFound) diff --git a/src/HotChocolate/Data/test/Data.Sorting.SqlLite.Tests/SortVisitorTestBase.cs b/src/HotChocolate/Data/test/Data.Sorting.SqlLite.Tests/SortVisitorTestBase.cs index 1b0a08a2282..3d1f24d93bf 100644 --- a/src/HotChocolate/Data/test/Data.Sorting.SqlLite.Tests/SortVisitorTestBase.cs +++ b/src/HotChocolate/Data/test/Data.Sorting.SqlLite.Tests/SortVisitorTestBase.cs @@ -74,11 +74,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs b/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs index 988c5231a84..3db175520fb 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/ActivityEnricher.cs @@ -344,7 +344,7 @@ public virtual void EnrichExecuteRequest(RequestContext context, Activity activi activity.SetTag("graphql.document.body", documentInfo.Document.Print()); } - if (context.Result is IOperationResult result) + if (context.Result is OperationResult result) { var errorCount = result.Errors?.Count ?? 0; activity.SetTag("graphql.errors.count", errorCount); diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/Listeners/ActivityServerDiagnosticListener.cs b/src/HotChocolate/Diagnostics/src/Diagnostics/Listeners/ActivityServerDiagnosticListener.cs index 36f60d17378..7f803428364 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/Listeners/ActivityServerDiagnosticListener.cs +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/Listeners/ActivityServerDiagnosticListener.cs @@ -134,7 +134,7 @@ public override void ParserErrors(HttpContext context, IReadOnlyList err } } - public override IDisposable FormatHttpResponse(HttpContext context, IOperationResult result) + public override IDisposable FormatHttpResponse(HttpContext context, OperationResult result) { if (_options.SkipFormatHttpResponse) { @@ -154,8 +154,4 @@ public override IDisposable FormatHttpResponse(HttpContext context, IOperationRe return activity; } - - // removed for 12.5 public override IDisposable WebSocketSession(HttpContext context) - // removed for 12.5public override void WebSocketSessionError( - // HttpContext context, Exception exception) } diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteOperationScope.cs b/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteOperationScope.cs index 35f0faa5890..2c7915ad6d0 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteOperationScope.cs +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteOperationScope.cs @@ -19,7 +19,7 @@ protected override void EnrichActivity() protected override void SetStatus() { - if (Context.Result is null or IOperationResult { Errors: [_, ..] }) + if (Context.Result is null or OperationResult { Errors: [_, ..] }) { Activity.SetStatus(Status.Error); Activity.SetStatus(ActivityStatusCode.Error); diff --git a/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteRequestScope.cs b/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteRequestScope.cs index b91757f61c7..32c4affad3f 100644 --- a/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteRequestScope.cs +++ b/src/HotChocolate/Diagnostics/src/Diagnostics/Scopes/ExecuteRequestScope.cs @@ -19,7 +19,7 @@ protected override void EnrichActivity() protected override void SetStatus() { - if (Context.Result is null or IOperationResult { Errors: [_, ..] }) + if (Context.Result is null or OperationResult { Errors: [_, ..] }) { Activity.SetStatus(Status.Error); Activity.SetStatus(ActivityStatusCode.Error); diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Projections.Tests/ProjectionVisitorTestBase.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Projections.Tests/ProjectionVisitorTestBase.cs index 9b89e976fdd..e7896ad2ad3 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Projections.Tests/ProjectionVisitorTestBase.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Projections.Tests/ProjectionVisitorTestBase.cs @@ -17,8 +17,8 @@ private Func> BuildResolver( mongoResource.CreateCollection("data_" + Guid.NewGuid().ToString("N")); collection.InsertMany(results); - - return ctx => collection.AsExecutable(); + + return _ => collection.AsExecutable(); } protected T[] CreateEntity(params T[] entities) => entities; @@ -64,11 +64,8 @@ public IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/SortVisitorTestBase.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/SortVisitorTestBase.cs index e45da8c26bf..30c5a572c0e 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/SortVisitorTestBase.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/SortVisitorTestBase.cs @@ -57,11 +57,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs index fc43d72714e..11e810b9198 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs @@ -37,12 +37,9 @@ await storage.SaveAsync( { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument() && c.Result is OperationResult result) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + result.ContextData = result.ContextData.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.FileSystem.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.FileSystem.Tests/IntegrationTests.cs index 522db01b12c..3e3054ce0e4 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.FileSystem.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.FileSystem.Tests/IntegrationTests.cs @@ -27,12 +27,9 @@ public async Task ExecutePersistedOperation() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument() && c.Result is OperationResult result) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + result.ContextData = result.ContextData.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -65,12 +62,9 @@ public async Task ExecutePersistedOperation_NotFound() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument() && c.Result is OperationResult result) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + result.ContextData = result.ContextData.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -100,12 +94,9 @@ public async Task ExecuteAutomaticPersistedOperation() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument() && c.Result is OperationResult result) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + result.ContextData = result.ContextData.SetItem("persistedDocument", true); } }) .UseAutomaticPersistedOperationPipeline() diff --git a/src/HotChocolate/Spatial/test/Data.Projections.SqlServer.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/Spatial/test/Data.Projections.SqlServer.Tests/FilterVisitorTestBase.cs index a07847b7d07..d1ed266dcb8 100644 --- a/src/HotChocolate/Spatial/test/Data.Projections.SqlServer.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/Spatial/test/Data.Projections.SqlServer.Tests/FilterVisitorTestBase.cs @@ -28,7 +28,7 @@ private async Task>> BuildResolverAsync await dbContext.SaveChangesAsync(); } - return ctx => dbContext.Data.AsQueryable(); + return _ => dbContext.Data.AsQueryable(); } protected async Task CreateSchemaAsync( @@ -72,11 +72,8 @@ protected async Task CreateSchemaAsync( if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline() diff --git a/src/StrawberryShake/Client/src/Transport.InMemory/InMemoryConnection.cs b/src/StrawberryShake/Client/src/Transport.InMemory/InMemoryConnection.cs index 04ad6d5d0ba..9f664c9094f 100644 --- a/src/StrawberryShake/Client/src/Transport.InMemory/InMemoryConnection.cs +++ b/src/StrawberryShake/Client/src/Transport.InMemory/InMemoryConnection.cs @@ -12,41 +12,32 @@ public class InMemoryConnection : IInMemoryConnection { private readonly Func> _createClientAsync; - public InMemoryConnection( - Func> createClientAsync) + public InMemoryConnection(Func> createClientAsync) { - _createClientAsync = createClientAsync ?? - throw new ArgumentNullException(nameof(createClientAsync)); + ArgumentNullException.ThrowIfNull(createClientAsync); + _createClientAsync = createClientAsync; } public IAsyncEnumerable> ExecuteAsync( OperationRequest request) => new ResponseStream(_createClientAsync, request); - private sealed class ResponseStream : IAsyncEnumerable> + private sealed class ResponseStream( + Func> createClient, + OperationRequest request) + : IAsyncEnumerable> { - private readonly Func> _createClientAsync; - private readonly OperationRequest _request; - - public ResponseStream( - Func> createClientAsync, - OperationRequest request) - { - _createClientAsync = createClientAsync; - _request = request; - } - public async IAsyncEnumerator> GetAsyncEnumerator( CancellationToken cancellationToken = default) { - var client = await _createClientAsync(cancellationToken); + var client = await createClient(cancellationToken); Exception? exception = null; IExecutionResult? result = null; try { - result = await client.ExecuteAsync(_request, cancellationToken); + result = await client.ExecuteAsync(request, cancellationToken); } catch (Exception ex) { @@ -78,7 +69,7 @@ private async IAsyncEnumerable> ProcessResultAsync( switch (executionResult) { - case HotChocolate.Execution.IOperationResult queryResult: + case OperationResult queryResult: queryResult.WriteTo(writer); yield return new Response(Parse(writer.GetWrittenMemory()), null); break; From f7d6975bf7d972cd132edf72f739b4a51739a1e2 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 21:19:57 +0100 Subject: [PATCH 37/42] wip --- .../AnnotationBased/CertificationTests.cs | 26 ++++++++------ .../CodeFirst/CertificationTests.cs | 12 ++++--- .../ExecutionOperationResultExtensions.cs | 32 +++++++++++++++++ .../Extensions/ExecutionSchemaExtensions.cs | 1 - .../DateTimeZoneTypeTests.cs | 26 +++++++------- ...rationTypeJsonRoundtripIntegrationTests.cs | 36 +++++++++---------- .../Types.NodaTime.Tests/DurationTypeTests.cs | 28 +++++++-------- ...stantTypeDateTimeOffsetIntegrationTests.cs | 10 +++--- .../InstantTypeGeneralIntegrationTests.cs | 6 ++-- .../Types.NodaTime.Tests/InstantTypeTests.cs | 6 ++-- .../IsoDayOfWeekTypeTests.cs | 10 +++--- ...teTimeTypeFullRoundtripIntegrationTests.cs | 6 ++-- ...lDateTimeTypeGeneralIsoIntegrationTests.cs | 6 ++-- .../LocalDateTimeTypeTests.cs | 6 ++-- ...alDateTypeFullRoundtripIntegrationTests.cs | 6 ++-- .../LocalDateTypeTests.cs | 6 ++-- ...LocalTimeTypeGeneralIsoIntegrationTests.cs | 6 ++-- .../LocalTimeTypeIntegrationTests.cs | 10 +++--- ...setDateTimeTypeExtendedIntegrationTests.cs | 12 +++---- ...fsetDateTimeTypeGeneralIntegrationTests.cs | 12 +++---- ...fsetDateTimeTypeRfc3339IntegrationTests.cs | 12 +++---- .../OffsetDateTimeTypeTests.cs | 12 +++---- ...etDateTypeFullRoundtripIntegrationTests.cs | 12 +++---- .../OffsetDateTypeTests.cs | 12 +++---- .../OffsetTimeTypeExtendedIntegrationTests.cs | 12 +++---- .../OffsetTimeTypeRfc3339IntegrationTests.cs | 12 +++---- .../OffsetTimeTypeTests.cs | 12 +++---- ...eneralInvariantWithoutZIntegrationTests.cs | 16 ++++----- .../Types.NodaTime.Tests/OffsetTypeTests.cs | 16 ++++----- ...eriodTypeNormalizingIsoIntegrationTests.cs | 6 ++-- .../Types.NodaTime.Tests/PeriodTypeTests.cs | 6 ++-- ...ZonedDateTimeTypeCustomIntegrationTests.cs | 12 +++---- .../ZonedDateTimeTypeTests.cs | 12 +++---- .../Core/test/Utilities/SnapshotExtensions.cs | 2 +- .../Core/test/Utilities/TestHelper.cs | 2 +- .../FilterVisitorTestBase.cs | 7 ++-- 36 files changed, 230 insertions(+), 196 deletions(-) create mode 100644 src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionOperationResultExtensions.cs diff --git a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/AnnotationBased/CertificationTests.cs b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/AnnotationBased/CertificationTests.cs index daec97a0ca5..1c778cfceb2 100644 --- a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/AnnotationBased/CertificationTests.cs +++ b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/AnnotationBased/CertificationTests.cs @@ -1,5 +1,4 @@ using HotChocolate.Execution; -using HotChocolate.Execution.Processing; using HotChocolate.Language; namespace HotChocolate.ApolloFederation.CertificationSchema.AnnotationBased; @@ -21,19 +20,22 @@ public async Task Subgraph_SDL() // act var result = await executor.ExecuteAsync( - @"{ + """ + { _service { sdl } - }"); + } + """); // assert - Assert.IsType( - Assert.IsType( - Assert.IsType(result).Data) - .GetValueOrDefault("_service")) - .GetValueOrDefault("sdl") - .MatchSnapshot(); + result + .ExpectOperationResult() + .UnwrapData() + .GetProperty("_service") + .GetProperty("sdl") + .GetString() + .MatchSnapshot(); } [Fact] @@ -44,13 +46,15 @@ public async Task Product_By_Id() // act var result = await executor.ExecuteAsync( - @"query ($representations: [_Any!]!) { + """ + query ($representations: [_Any!]!) { _entities(representations: $representations) { ... on Product { sku } } - }", + } + """, new Dictionary { ["representations"] = new List diff --git a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/CodeFirst/CertificationTests.cs b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/CodeFirst/CertificationTests.cs index 5eabd160994..2ec9e488dc2 100644 --- a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/CodeFirst/CertificationTests.cs +++ b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/CertificationSchema/CodeFirst/CertificationTests.cs @@ -1,5 +1,4 @@ using HotChocolate.Execution; -using HotChocolate.Execution.Processing; using HotChocolate.Language; namespace HotChocolate.ApolloFederation.CertificationSchema.CodeFirst; @@ -30,10 +29,13 @@ public async Task Subgraph_SDL() """); // assert - var queryResult = Assert.IsType(result); - var data = Assert.IsType(queryResult.Data); - var service = Assert.IsType(data.GetValueOrDefault("_service")); - service.GetValueOrDefault("sdl").MatchSnapshot(); + result + .ExpectOperationResult() + .UnwrapData() + .GetProperty("_service") + .GetProperty("sdl") + .GetString() + .MatchSnapshot(); } [Fact] diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionOperationResultExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionOperationResultExtensions.cs new file mode 100644 index 00000000000..54d3b2e774d --- /dev/null +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionOperationResultExtensions.cs @@ -0,0 +1,32 @@ +using HotChocolate.Text.Json; + +namespace HotChocolate.Execution; + +/// +/// Provides extension methods for . +/// +public static class ExecutionOperationResultExtensions +{ + extension(OperationResult result) + { + /// + /// Unwraps the data from the operation result and returns the underlying . + /// + /// + /// The containing the operation result data. + /// + /// + /// Thrown when the data object is not of type . + /// + public ResultElement UnwrapData() + { + if (result.Data is not ResultDocument resultDocument) + { + throw new InvalidOperationException( + "Unexpected data object type."); + } + + return resultDocument.Data; + } + } +} diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs index 65d04b09b9e..16de45eeaae 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/ExecutionSchemaExtensions.cs @@ -1,6 +1,5 @@ using HotChocolate.Execution; using HotChocolate.Execution.Options; -using Microsoft.Extensions.DependencyInjection; // ReSharper disable once CheckNamespace namespace HotChocolate; diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DateTimeZoneTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DateTimeZoneTypeTests.cs index 4c5cf1802af..63ca2190d94 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DateTimeZoneTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DateTimeZoneTypeTests.cs @@ -34,21 +34,21 @@ public string Test(DateTimeZone arg) public void QueryReturnsUtc() { var result = _testExecutor.Execute("query { test: utc }"); - Assert.Equal("UTC", Assert.IsType(result).Data!["test"]); + Assert.Equal("UTC", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsRome() { var result = _testExecutor.Execute("query { test: rome }"); - Assert.Equal("Europe/Rome", Assert.IsType(result).Data!["test"]); + Assert.Equal("Europe/Rome", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsChihuahua() { var result = _testExecutor.Execute("query { test: chihuahua }"); - Assert.Equal("America/Chihuahua", Assert.IsType(result).Data!["test"]); + Assert.Equal("America/Chihuahua", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -59,19 +59,19 @@ public void ParsesVariable() .SetDocument("mutation($arg: DateTimeZone!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "Europe/Amsterdam" } }) .Build()); - Assert.Equal("Europe/Amsterdam", Assert.IsType(result).Data!["test"]); + Assert.Equal("Europe/Amsterdam", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] - public void DoesntParseIncorrectVariable() + public void DoesNotParseIncorrectVariable() { var result = _testExecutor .Execute(OperationRequestBuilder.New() .SetDocument("mutation($arg: DateTimeZone!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "Europe/Hamster" } }) .Build()); - Assert.Null(Assert.IsType(result).Data); - Assert.Single(Assert.IsType(result).Errors!); + Assert.True(result.ExpectOperationResult().IsDataNull); + Assert.Single(result.ExpectOperationResult().Errors!); } [Fact] @@ -81,21 +81,21 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"Europe/Amsterdam\") }") .Build()); - Assert.Equal("Europe/Amsterdam", Assert.IsType(result).Data!["test"]); + Assert.Equal("Europe/Amsterdam", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] - public void DoesntParseIncorrectLiteral() + public void DoesNotParseIncorrectLiteral() { var result = _testExecutor .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"Europe/Hamster\") }") .Build()); - Assert.Null(Assert.IsType(result).Data); - Assert.Single(Assert.IsType(result).Errors!); - Assert.Null(Assert.IsType(result).Errors!.First().Code); + Assert.Null(result.ExpectOperationResult().Data); + Assert.Single(result.ExpectOperationResult().Errors!); + Assert.Null(result.ExpectOperationResult().Errors![0].Code); Assert.Equal( "Unable to deserialize string to DateTimeZone", - Assert.IsType(result).Errors!.First().Message); + result.ExpectOperationResult().Errors![0].Message); } } diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeJsonRoundtripIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeJsonRoundtripIntegrationTests.cs index 9e08d1e8a50..93f1e5b7123 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeJsonRoundtripIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeJsonRoundtripIntegrationTests.cs @@ -48,42 +48,42 @@ public Duration Test(Duration arg) public void QueryReturnsSerializedDataWithDecimals() { var result = _testExecutor.Execute("query { test: positiveWithDecimals }"); - Assert.Equal("2959:53:10.019", Assert.IsType(result).Data!["test"]); + Assert.Equal("2959:53:10.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithNegativeValue() { var result = _testExecutor.Execute("query { test: negativeWithDecimals }"); - Assert.Equal("-2959:53:10.019", Assert.IsType(result).Data!["test"]); + Assert.Equal("-2959:53:10.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutDecimals() { var result = _testExecutor.Execute("query { test: positiveWithoutDecimals }"); - Assert.Equal("2959:53:10", Assert.IsType(result).Data!["test"]); + Assert.Equal("2959:53:10", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutSeconds() { var result = _testExecutor.Execute("query { test: positiveWithoutSeconds }"); - Assert.Equal("2959:53:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("2959:53:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutMinutes() { var result = _testExecutor.Execute("query { test: positiveWithoutMinutes }"); - Assert.Equal("2959:00:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("2959:00:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithRoundtrip() { var result = _testExecutor.Execute("query { test: positiveWithRoundtrip }"); - Assert.Equal("2978:01:10", Assert.IsType(result).Data!["test"]); + Assert.Equal("2978:01:10", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -94,7 +94,7 @@ public void MutationParsesInputWithDecimals() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "238:01:00.019" } }) .Build()); - Assert.Equal("238:11:00.019", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -105,7 +105,7 @@ public void MutationParsesInputWithoutDecimals() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "238:01:00" } }) .Build()); - Assert.Equal("238:11:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -116,7 +116,7 @@ public void MutationParsesInputWithoutLeadingZero() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "238:01:00" } }) .Build()); - Assert.Equal("238:11:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -127,7 +127,7 @@ public void MutationParsesInputWithNegativeValue() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "-238:01:00" } }) .Build()); - Assert.Equal("-237:51:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("-237:51:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -138,8 +138,8 @@ public void MutationDoesntParseInputWithPlusSign() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "+09:22:01:00" } }) .Build()); - Assert.Null(Assert.IsType(result).Data); - Assert.Single(Assert.IsType(result).Errors!); + Assert.Null(result.ExpectOperationResult().Data); + Assert.Single(result.ExpectOperationResult().Errors!); } [Fact] @@ -149,7 +149,7 @@ public void MutationParsesLiteralWithDecimals() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"238:01:00.019\") }") .Build()); - Assert.Equal("238:11:00.019", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -159,7 +159,7 @@ public void MutationParsesLiteralWithoutDecimals() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"238:01:00\") }") .Build()); - Assert.Equal("238:11:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -169,7 +169,7 @@ public void MutationParsesLiteralWithoutLeadingZero() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"238:01:00\") }") .Build()); - Assert.Equal("238:11:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("238:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -179,7 +179,7 @@ public void MutationParsesLiteralWithNegativeValue() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"-238:01:00\") }") .Build()); - Assert.Equal("-237:51:00", Assert.IsType(result).Data!["test"]); + Assert.Equal("-237:51:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -189,7 +189,7 @@ public void MutationDoesntParseLiteralWithPlusSign() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"+238:01:00\") }") .Build()); - Assert.Null(Assert.IsType(result).Data); - Assert.Single(Assert.IsType(result).Errors!); + Assert.Null(result.ExpectOperationResult().Data); + Assert.Single(result.ExpectOperationResult().Errors!); } } diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeTests.cs index c03b5c21d77..da5e4049842 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/DurationTypeTests.cs @@ -43,42 +43,42 @@ public Duration Test(Duration arg) public void QueryReturnsSerializedDataWithDecimals() { var result = _testExecutor.Execute("query { test: positiveWithDecimals }"); - Assert.Equal("123:07:53:10.019", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("123:07:53:10.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithNegativeValue() { var result = _testExecutor.Execute("query{test: negativeWithDecimals}"); - Assert.Equal("-123:07:53:10.019", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("-123:07:53:10.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutDecimals() { var result = _testExecutor.Execute("query{test: positiveWithoutDecimals}"); - Assert.Equal("123:07:53:10", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("123:07:53:10", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutSeconds() { var result = _testExecutor.Execute("query{test:positiveWithoutSeconds}"); - Assert.Equal("123:07:53:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("123:07:53:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithoutMinutes() { var result = _testExecutor.Execute("query{test:positiveWithoutMinutes}"); - Assert.Equal("123:07:00:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("123:07:00:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsSerializedDataWithRoundtrip() { var result = _testExecutor.Execute("query{test:positiveWithRoundtrip}"); - Assert.Equal("124:02:01:10", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("124:02:01:10", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -89,7 +89,7 @@ public void MutationParsesInputWithDecimals() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "09:22:01:00.019" } }) .Build()); - Assert.Equal("9:22:11:00.019", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -100,7 +100,7 @@ public void MutationParsesInputWithoutDecimals() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "09:22:01:00" } }) .Build()); - Assert.Equal("9:22:11:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -111,7 +111,7 @@ public void MutationParsesInputWithoutLeadingZero() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "9:22:01:00" } }) .Build()); - Assert.Equal("9:22:11:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -122,7 +122,7 @@ public void MutationParsesInputWithNegativeValue() .SetDocument("mutation($arg: Duration!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "-9:22:01:00" } }) .Build()); - Assert.Equal("-9:21:51:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("-9:21:51:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -157,7 +157,7 @@ public void MutationParsesLiteralWithDecimals() .SetDocument("mutation { test(arg: \"09:22:01:00.019\") }") .Build()); - Assert.Equal("9:22:11:00.019", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00.019", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -168,7 +168,7 @@ public void MutationParsesLiteralWithoutDecimals() .SetDocument("mutation { test(arg: \"09:22:01:00\") }") .Build()); - Assert.Equal("9:22:11:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -179,7 +179,7 @@ public void MutationParsesLiteralWithoutLeadingZero() .SetDocument("mutation { test(arg: \"09:22:01:00\") }") .Build()); - Assert.Equal("9:22:11:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("9:22:11:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -190,7 +190,7 @@ public void MutationParsesLiteralWithNegativeValue() .SetDocument("mutation { test(arg: \"-9:22:01:00\") }") .Build()); - Assert.Equal("-9:21:51:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("-9:21:51:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeDateTimeOffsetIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeDateTimeOffsetIntegrationTests.cs index a611ec5d8dd..dc31f468026 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeDateTimeOffsetIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeDateTimeOffsetIntegrationTests.cs @@ -50,7 +50,7 @@ public void QueryReturnsUtc() Assert.Equal( "2020-02-20T17:42:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -64,7 +64,7 @@ public void ParsesVariable() Assert.Equal( "2020-02-21T17:52:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -76,7 +76,7 @@ public void DoesParseAnIncorrectExtendedVariableAsDateTimeOffset() .SetVariableValues(new Dictionary { { "arg", "2020-02-20T17:42:59" } }) .Build()); - Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -89,7 +89,7 @@ public void ParsesLiteral() Assert.Equal( "2020-02-20T17:52:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -100,6 +100,6 @@ public void DoesParseIncorrectExtendedLiteralAsDateTimeOffset() .SetDocument("mutation { test(arg: \"2020-02-20T17:42:59\") }") .Build()); - Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } } diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeGeneralIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeGeneralIntegrationTests.cs index 4f5c46bb632..1d042285f01 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeGeneralIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeGeneralIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturnsUtc() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("2020-02-20T17:42:59Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:42:59Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -31,7 +31,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-02-21T17:42:59Z" } }) .Build()); - Assert.Equal("2020-02-21T17:52:59Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-21T17:52:59Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -55,7 +55,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-02-20T17:42:59Z\") }") .Build()); - Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:52:59Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeTests.cs index 7a44df83b48..30b4cde9a5f 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/InstantTypeTests.cs @@ -38,7 +38,7 @@ public void QueryReturnsUtc() Assert.Equal( "2020-02-20T17:42:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -52,7 +52,7 @@ public void ParsesVariable() Assert.Equal( "2020-02-21T17:52:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -78,7 +78,7 @@ public void ParsesLiteral() Assert.Equal( "2020-02-20T17:52:59.000001234Z", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/IsoDayOfWeekTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/IsoDayOfWeekTypeTests.cs index add8ef39acb..0fc3454402f 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/IsoDayOfWeekTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/IsoDayOfWeekTypeTests.cs @@ -39,7 +39,7 @@ public void QueryReturnsMonday() { var result = _testExecutor.Execute("query { test: monday }"); - Assert.Equal(1, result.ExpectOperationResult().Data!["test"]); + Assert.Equal(1, result.ExpectOperationResult().UnwrapData().GetProperty("test").GetInt32()); } [Fact] @@ -47,7 +47,7 @@ public void QueryReturnsSunday() { var result = _testExecutor.Execute("query { test: sunday }"); - Assert.Equal(7, result.ExpectOperationResult().Data!["test"]); + Assert.Equal(7, result.ExpectOperationResult().UnwrapData().GetProperty("test").GetInt32()); } [Fact] @@ -55,7 +55,7 @@ public void QueryReturnsFriday() { var result = _testExecutor.Execute("query { test: friday }"); - Assert.Equal(5, result.ExpectOperationResult().Data!["test"]); + Assert.Equal(5, result.ExpectOperationResult().UnwrapData().GetProperty("test").GetInt32()); } [Fact] @@ -76,7 +76,7 @@ public void MutationParsesMonday() .SetVariableValues(new Dictionary { { "arg", 1 } }) .Build()); - Assert.Equal(2, result.ExpectOperationResult().Data!["test"]); + Assert.Equal(2, result.ExpectOperationResult().UnwrapData().GetProperty("test").GetInt32()); } [Fact] @@ -88,7 +88,7 @@ public void MutationParsesSunday() .SetVariableValues(new Dictionary { { "arg", 7 } }) .Build()); - Assert.Equal(1, result.ExpectOperationResult().Data!["test"]); + Assert.Equal(1, result.ExpectOperationResult().UnwrapData().GetProperty("test").GetInt32()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeFullRoundtripIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeFullRoundtripIntegrationTests.cs index c38887f62e2..f0df5838368 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeFullRoundtripIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeFullRoundtripIntegrationTests.cs @@ -21,7 +21,7 @@ public void QueryReturns() Assert.Equal( "2020-02-07T17:42:59.000001234 (Julian)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -35,7 +35,7 @@ public void ParsesVariable() Assert.Equal( "2020-02-21T17:52:59.000001234 (Julian)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -61,7 +61,7 @@ public void ParsesLiteral() Assert.Equal( "2020-02-20T17:52:59.000001234 (Julian)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeGeneralIsoIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeGeneralIsoIntegrationTests.cs index b8b783cd6a0..3e3b84dd1ef 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeGeneralIsoIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeGeneralIsoIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("2020-02-07T17:42:59", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-07T17:42:59", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -31,7 +31,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-02-21T17:42:59" } }) .Build()); - Assert.Equal("2020-02-21T17:52:59", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-21T17:52:59", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -55,7 +55,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-02-20T17:42:59\") }") .Build()); - Assert.Equal("2020-02-20T17:52:59", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:52:59", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeTests.cs index b13cf4b6d44..e1850cce4a4 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTimeTypeTests.cs @@ -40,7 +40,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("2020-02-07T17:42:59.000001234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-07T17:42:59.000001234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -54,7 +54,7 @@ public void ParsesVariable() new Dictionary { { "arg", "2020-02-21T17:42:59.000001234" } }) .Build()); - Assert.Equal("2020-02-21T17:52:59.000001234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-21T17:52:59.000001234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -81,7 +81,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-02-20T17:42:59.000001234\") }") .Build()); - Assert.Equal("2020-02-20T17:52:59.000001234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-20T17:52:59.000001234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeFullRoundtripIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeFullRoundtripIntegrationTests.cs index 3a3fae2d2e6..754c7ff4adb 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeFullRoundtripIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeFullRoundtripIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("5780-05-25 (Hebrew Civil)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("5780-05-25 (Hebrew Civil)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -32,7 +32,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-02-21 (Hebrew Civil)" } }) .Build()); - Assert.Equal("2020-02-24 (Hebrew Civil)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-24 (Hebrew Civil)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -59,7 +59,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-02-20 (Hebrew Civil)\") }") .Build()); - Assert.Equal("2020-02-23 (Hebrew Civil)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-23 (Hebrew Civil)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeTests.cs index 180d6345b0f..1872c9c08c6 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalDateTypeTests.cs @@ -38,7 +38,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("5780-05-25", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("5780-05-25", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -50,7 +50,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-02-21" } }) .Build()); - Assert.Equal("2020-02-24", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-24", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -74,7 +74,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-02-20\") }") .Build()); - Assert.Equal("2020-02-23", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-02-23", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeGeneralIsoIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeGeneralIsoIntegrationTests.cs index a887a63bd31..e8258154470 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeGeneralIsoIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeGeneralIsoIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("12:42:13", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:42:13", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -31,7 +31,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "12:42:13" } }) .Build()); - Assert.Equal("12:52:13", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -55,7 +55,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"12:42:13\") }") .Build()); - Assert.Equal("12:52:13", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeIntegrationTests.cs index 6bae387e8b0..7a4c395966a 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/LocalTimeTypeIntegrationTests.cs @@ -39,7 +39,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("12:42:13.031011234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:42:13.031011234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -52,7 +52,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "12:42:13.031011234" } }) .Build()); - Assert.Equal("12:52:13.031011234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13.031011234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -65,7 +65,7 @@ public void ParsesVariableWithoutTicks() .SetVariableValues(new Dictionary { { "arg", "12:42:13" } }) .Build()); - Assert.Equal("12:52:13", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -91,7 +91,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"12:42:13.031011234\") }") .Build()); - Assert.Equal("12:52:13.031011234", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13.031011234", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -103,7 +103,7 @@ public void ParsesLiteralWithoutTick() .SetDocument("mutation { test(arg: \"12:42:13\") }") .Build()); - Assert.Equal("12:52:13", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("12:52:13", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeExtendedIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeExtendedIntegrationTests.cs index 03e5e863c40..ac2d1323f9c 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeExtendedIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeExtendedIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("2020-12-31T18:30:13.000001234+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13.000001234+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -27,7 +27,7 @@ public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("2020-12-31T18:30:13.000001234+02:30", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13.000001234+02:30", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -40,7 +40,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -53,7 +53,7 @@ public void ParsesVariableWithMinutes() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02:35" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -79,7 +79,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -91,7 +91,7 @@ public void ParsesLiteralWithMinutes() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02:35\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeGeneralIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeGeneralIntegrationTests.cs index d7132f4918e..a8b768beaf1 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeGeneralIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeGeneralIntegrationTests.cs @@ -18,14 +18,14 @@ public class OffsetDateTimeTypeGeneralIntegrationTests public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("2020-12-31T18:30:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("2020-12-31T18:30:13+02:30", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13+02:30", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -36,7 +36,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: OffsetDateTime!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -47,7 +47,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: OffsetDateTime!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02:35" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -69,7 +69,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -79,7 +79,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02:35\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeRfc3339IntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeRfc3339IntegrationTests.cs index a8b24741009..5a8308d216c 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeRfc3339IntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeRfc3339IntegrationTests.cs @@ -21,7 +21,7 @@ public void QueryReturns() Assert.Equal( "2020-12-31T18:30:13.000001234+02:00", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -31,7 +31,7 @@ public void QueryReturnsWithMinutes() Assert.Equal( "2020-12-31T18:30:13.000001234+02:30", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -45,7 +45,7 @@ public void ParsesVariable() Assert.Equal( "2020-12-31T18:40:13.000001234+02:00", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -57,7 +57,7 @@ public void ParsesVariableWithMinutes() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02:35" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -83,7 +83,7 @@ public void ParsesLiteral() Assert.Equal( "2020-12-31T18:40:13.000001234+02:00", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -94,7 +94,7 @@ public void ParsesLiteralWithMinutes() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02:35\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeTests.cs index 28c13d1deb6..d0eb97f3ecb 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTimeTypeTests.cs @@ -60,7 +60,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("2020-12-31T18:30:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -68,7 +68,7 @@ public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("2020-12-31T18:30:13+02:30", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13+02:30", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -81,7 +81,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -94,7 +94,7 @@ public void ParsesVariableWithMinutes() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T18:30:13+02:35" } }) .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -120,7 +120,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -132,7 +132,7 @@ public void ParsesLiteralWithMinutes() .SetDocument("mutation { test(arg: \"2020-12-31T18:30:13+02:35\") }") .Build()); - Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:40:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeFullRoundtripIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeFullRoundtripIntegrationTests.cs index e36a4e5a3b2..bec9334efa4 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeFullRoundtripIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeFullRoundtripIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -27,7 +27,7 @@ public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -39,7 +39,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "2020-12-31+02 (Gregorian)" } }) .Build()); - Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -51,7 +51,7 @@ public void ParsesVariableWithMinutes() .SetVariableValues(new Dictionary { { "arg", "2020-12-31+02:35 (Gregorian)" } }) .Build()); - Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -75,7 +75,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"2020-12-31+02 (Gregorian)\") }") .Build()); - Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -86,7 +86,7 @@ public void ParsesLiteralWithMinutes() .SetDocument("mutation { test(arg: \"2020-12-31+02:35 (Gregorian)\") }") .Build()); - Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35 (Gregorian)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeTests.cs index 19b6c2fba6e..79232fa3ca6 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetDateTypeTests.cs @@ -40,14 +40,14 @@ public class Mutation public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("2020-12-31+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -58,7 +58,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: OffsetDate!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "2020-12-31+02" } }) .Build()); - Assert.Equal("2020-12-31+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -69,7 +69,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: OffsetDate!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "2020-12-31+02:35" } }) .Build()); - Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -91,7 +91,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"2020-12-31+02\") }") .Build()); - Assert.Equal("2020-12-31+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -101,7 +101,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"2020-12-31+02:35\") }") .Build()); - Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeExtendedIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeExtendedIntegrationTests.cs index 2f6cc0c2ebc..18bc3d6beb4 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeExtendedIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeExtendedIntegrationTests.cs @@ -19,7 +19,7 @@ public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -27,7 +27,7 @@ public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -39,7 +39,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "18:30:13.010011234+02" } }) .Build()); - Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -51,7 +51,7 @@ public void ParsesVariableWithMinutes() .SetVariableValues(new Dictionary { { "arg", "18:30:13.010011234+02:35" } }) .Build()); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -75,7 +75,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"18:30:13.010011234+02\") }") .Build()); - Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -86,7 +86,7 @@ public void ParsesLiteralWithMinutes() .SetDocument("mutation { test(arg: \"18:30:13.010011234+02:35\") }") .Build()); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeRfc3339IntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeRfc3339IntegrationTests.cs index cc5f640c312..66f6d28bcff 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeRfc3339IntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeRfc3339IntegrationTests.cs @@ -17,14 +17,14 @@ public class OffsetTimeTypeRfc3339IntegrationTests public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -36,7 +36,7 @@ public void ParsesVariable() .SetVariableValues(new Dictionary { { "arg", "18:30:13.010011234+02:00" } }) .Build()); - Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -47,7 +47,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: OffsetTime!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "18:30:13.010011234+02:35" } }) .Build()); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -69,7 +69,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"18:30:13.010011234+02:00\") }") .Build()); - Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -79,7 +79,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"18:30:13.010011234+02:35\") }") .Build()); - Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13.010011234+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeTests.cs index eb373d29a9b..0ce34098950 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTimeTypeTests.cs @@ -44,14 +44,14 @@ public class Mutation public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("18:30:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -62,7 +62,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: OffsetTime!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "18:30:13+02" } }) .Build()); - Assert.Equal("18:30:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -73,7 +73,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: OffsetTime!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "18:30:13+02:35" } }) .Build()); - Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -95,7 +95,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"18:30:13+02\") }") .Build()); - Assert.Equal("18:30:13+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -105,7 +105,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"18:30:13+02:35\") }") .Build()); - Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("18:30:13+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeGeneralInvariantWithoutZIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeGeneralInvariantWithoutZIntegrationTests.cs index d4838742fb9..1474c1efa91 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeGeneralInvariantWithoutZIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeGeneralInvariantWithoutZIntegrationTests.cs @@ -18,21 +18,21 @@ public class OffsetTypeGeneralInvariantWithoutZIntegrationTests public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithZ() { var result = _testExecutor.Execute("query { test: zOffset }"); - Assert.Equal("+00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -43,7 +43,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: Offset!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "+02" } }) .Build()); - Assert.Equal("+03:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -54,7 +54,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: Offset!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "+02:35" } }) .Build()); - Assert.Equal("+03:40", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:40", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -77,7 +77,7 @@ public void ParsesLiteral() .SetDocument("mutation { test(arg: \"+02\") }") .Build()); - Assert.Equal("+03:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -87,7 +87,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"+02:35\") }") .Build()); - Assert.Equal("+03:40", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:40", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -97,7 +97,7 @@ public void ParsesLiteralWithZero() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"+00\") }") .Build()); - Assert.Equal("+01:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+01:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeTests.cs index 99c9f80d9ba..7b717fdbf47 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/OffsetTypeTests.cs @@ -34,21 +34,21 @@ public Offset Test(Offset arg) public void QueryReturns() { var result = _testExecutor.Execute("query { test: hours }"); - Assert.Equal("+02", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+02", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithMinutes() { var result = _testExecutor.Execute("query { test: hoursAndMinutes }"); - Assert.Equal("+02:35", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+02:35", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsWithZ() { var result = _testExecutor.Execute("query { test: zOffset }"); - Assert.Equal("Z", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("Z", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -59,7 +59,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: Offset!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "+02" } }) .Build()); - Assert.Equal("+03:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -70,7 +70,7 @@ public void ParsesVariableWithMinutes() .SetDocument("mutation($arg: Offset!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "+02:35" } }) .Build()); - Assert.Equal("+03:40", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:40", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -92,7 +92,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"+02\") }") .Build()); - Assert.Equal("+03:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -102,7 +102,7 @@ public void ParsesLiteralWithMinutes() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"+02:35\") }") .Build()); - Assert.Equal("+03:40", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+03:40", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -112,7 +112,7 @@ public void ParsesLiteralWithZ() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"Z\") }") .Build()); - Assert.Equal("+01:05", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("+01:05", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeNormalizingIsoIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeNormalizingIsoIntegrationTests.cs index 21b6fee42c1..7b8111df88b 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeNormalizingIsoIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeNormalizingIsoIntegrationTests.cs @@ -17,7 +17,7 @@ public class PeriodTypeNormalizingIsoIntegrationTests public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("P-17DT-23H-59M-59.9999861S", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-17DT-23H-59M-59.9999861S", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -28,7 +28,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: Period!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "P-17DT-23H-59M-59.9999861S" } }) .Build()); - Assert.Equal("P-18DT-9M-59.9999861S", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-18DT-9M-59.9999861S", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -50,7 +50,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"P-17DT-23H-59M-59.9999861S\") }") .Build()); - Assert.Equal("P-18DT-9M-59.9999861S", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-18DT-9M-59.9999861S", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeTests.cs index fca2029be53..47ce66fd346 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/PeriodTypeTests.cs @@ -32,7 +32,7 @@ public Period Test(Period arg) public void QueryReturns() { var result = _testExecutor.Execute("query { test: one }"); - Assert.Equal("P-3W3DT139t", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-3W3DT139t", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -43,7 +43,7 @@ public void ParsesVariable() .SetDocument("mutation($arg: Period!) { test(arg: $arg) }") .SetVariableValues(new Dictionary { { "arg", "P-3W15DT139t" } }) .Build()); - Assert.Equal("P-3W15DT-10M139t", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-3W15DT-10M139t", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -65,7 +65,7 @@ public void ParsesLiteral() .Execute(OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"P-3W15DT139t\") }") .Build()); - Assert.Equal("P-3W15DT-10M139t", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("P-3W15DT-10M139t", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeCustomIntegrationTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeCustomIntegrationTests.cs index 1c3d21e2915..7486c6ee2a7 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeCustomIntegrationTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeCustomIntegrationTests.cs @@ -29,14 +29,14 @@ public void QueryReturns() var result = _testExecutor.Execute("query { test: rome }"); Assert.Equal( "2020-12-31T18:30:13 Asia/Kathmandu (+05:45)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] public void QueryReturnsUtc() { var result = _testExecutor.Execute("query { test: utc }"); - Assert.Equal("2020-12-31T18:30:13 UTC (+00)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T18:30:13 UTC (+00)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -50,7 +50,7 @@ public void ParsesVariable() Assert.Equal( "2020-12-31T19:40:13 Asia/Kathmandu (+05:45)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -62,7 +62,7 @@ public void ParsesVariableWithUTC() .SetVariableValues(new Dictionary { { "arg", "2020-12-31T19:30:13 UTC (+00)" } }) .Build()); - Assert.Equal("2020-12-31T19:40:13 UTC (+00)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T19:40:13 UTC (+00)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -93,7 +93,7 @@ public void ParsesLiteral() Assert.Equal( "2020-12-31T19:40:13 Asia/Kathmandu (+05:45)", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -104,7 +104,7 @@ public void ParsesLiteralWithUtc() .SetDocument("mutation { test(arg: \"2020-12-31T19:30:13 UTC (+00)\") }") .Build()); - Assert.Equal("2020-12-31T19:40:13 UTC (+00)", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T19:40:13 UTC (+00)", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeTests.cs index 6f0d1d2d245..0782923e2bd 100644 --- a/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.NodaTime.Tests/ZonedDateTimeTypeTests.cs @@ -47,7 +47,7 @@ public void QueryReturns() var result = _testExecutor.Execute("query { test: rome }"); Assert.Equal( "2020-12-31T18:30:13 Asia/Kathmandu +05:45", - Assert.IsType(result).Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -56,7 +56,7 @@ public void QueryReturnsUtc() var result = _testExecutor.Execute("query { test: utc }"); Assert.Equal( "2020-12-31T18:30:13 UTC +00", - Assert.IsType(result).Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -74,7 +74,7 @@ public void ParsesVariable() .Build()); Assert.Equal( "2020-12-31T19:40:13 Asia/Kathmandu +05:45", - Assert.IsType(result).Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -92,7 +92,7 @@ public void ParsesVariableWithUtc() .Build()); Assert.Equal( "2020-12-31T19:40:13 UTC +00", - Assert.IsType(result).Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -122,7 +122,7 @@ public void ParsesLiteral() .Build()); Assert.Equal( "2020-12-31T19:40:13 Asia/Kathmandu +05:45", - result.ExpectOperationResult().Data!["test"]); + result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] @@ -133,7 +133,7 @@ public void ParsesLiteralWithUtc() OperationRequestBuilder.New() .SetDocument("mutation { test(arg: \"2020-12-31T19:30:13 UTC +00\") }") .Build()); - Assert.Equal("2020-12-31T19:40:13 UTC +00", result.ExpectOperationResult().Data!["test"]); + Assert.Equal("2020-12-31T19:40:13 UTC +00", result.ExpectOperationResult().UnwrapData().GetProperty("test").GetString()); } [Fact] diff --git a/src/HotChocolate/Core/test/Utilities/SnapshotExtensions.cs b/src/HotChocolate/Core/test/Utilities/SnapshotExtensions.cs index cf41547db1b..646bbb90ea1 100644 --- a/src/HotChocolate/Core/test/Utilities/SnapshotExtensions.cs +++ b/src/HotChocolate/Core/test/Utilities/SnapshotExtensions.cs @@ -48,6 +48,6 @@ public static async Task ToJsonAsync(this Task task) public static void MatchSnapshot(this GraphQLException ex) { - OperationResultBuilder.CreateError(ex.Errors).MatchSnapshot(); + OperationResult.FromError([.. ex.Errors]).MatchSnapshot(); } } diff --git a/src/HotChocolate/Core/test/Utilities/TestHelper.cs b/src/HotChocolate/Core/test/Utilities/TestHelper.cs index e8668a22650..ad00599406c 100644 --- a/src/HotChocolate/Core/test/Utilities/TestHelper.cs +++ b/src/HotChocolate/Core/test/Utilities/TestHelper.cs @@ -104,7 +104,7 @@ public static async Task ExpectError( var result = await executor.ExecuteAsync(request); // assert - IOperationResult operationResult = Assert.IsType(result); + var operationResult = Assert.IsType(result); Assert.NotNull(operationResult.Errors); if (elementInspectors.Length > 0) diff --git a/src/HotChocolate/Data/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/Data/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs index 78f7b5ffb76..bfa3767a340 100644 --- a/src/HotChocolate/Data/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/Data/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs @@ -85,11 +85,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline() From 3e44243165eb08d6763059e510cac3f0e9d8beb2 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 21:44:59 +0100 Subject: [PATCH 38/42] wip --- .../ProjectionVisitorTestBase.cs | 6 +- .../FusionTestBase.MatchSnapshot.cs | 8 +-- .../test/Fusion.AspNetCore.Tests/NullTests.cs | 20 +++--- .../SourceSchemaErrorTests.cs | 6 +- .../FusionRequestExecutorManagerTests.cs | 15 ++--- .../Text/Json/CompositeResultDocumentTests.cs | 19 +++++- .../FilterVisitorTestBase.cs | 7 +-- .../SortVisitorTestBase.cs | 7 +-- .../FilterVisitorTestBase.cs | 7 +-- .../MongoDbAggregateFluentTests.cs | 7 +-- .../MongoDbCollectionTests.cs | 7 +-- .../MongoDbFindFluentTests.cs | 7 +-- ...MongoDbCursorPagingAggregateFluentTests.cs | 7 +-- .../MongoDbCursorPagingFindFluentTests.cs | 7 +-- .../MongoDbOffsetPagingAggregateTests.cs | 7 +-- .../MongoDbOffsetPagingFindFluentTests.cs | 7 +-- .../VisitorTestBase.cs | 7 +-- .../MongoDbAggregateFluentTests.cs | 7 +-- .../MongoDbFindFluentTests.cs | 7 +-- .../MongoDbSortCollectionTests.cs | 7 +-- .../IntegrationTests.cs | 9 ++- .../IntegrationTests.cs | 19 +++--- .../IntegrationTests.cs | 63 ++++++++----------- 23 files changed, 112 insertions(+), 151 deletions(-) diff --git a/src/HotChocolate/Data/test/Data.Projections.SqlServer.Tests/ProjectionVisitorTestBase.cs b/src/HotChocolate/Data/test/Data.Projections.SqlServer.Tests/ProjectionVisitorTestBase.cs index 53a3ebeb55e..11aa719c4b1 100644 --- a/src/HotChocolate/Data/test/Data.Projections.SqlServer.Tests/ProjectionVisitorTestBase.cs +++ b/src/HotChocolate/Data/test/Data.Projections.SqlServer.Tests/ProjectionVisitorTestBase.cs @@ -100,10 +100,8 @@ public IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs index c4ac83b5bc7..7ef9ea1992e 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/FusionTestBase.MatchSnapshot.cs @@ -27,7 +27,7 @@ protected async Task MatchSnapshotAsync( { var snapshot = new Snapshot(postFix, ".yaml"); - var results = new List(); + var results = new List(); // We first wait and capture all possible gateway responses. await foreach (var result in response.ReadAsResultStreamAsync()) @@ -78,7 +78,7 @@ protected async Task MatchSnapshotAsync( private static async Task TryWriteOperationPlanAsync( CodeWriter writer, Gateway gateway, - List results) + List results) { foreach (var result in results) { @@ -121,7 +121,7 @@ private static async Task TryWriteOperationPlanAsync( } } - private void WriteResults(CodeWriter writer, List results) + private void WriteResults(CodeWriter writer, List results) { if (results is [{ } singleResult]) { @@ -154,7 +154,7 @@ private void WriteResults(CodeWriter writer, List b.AddQueryType() - .InsertUseRequest(WellKnownRequestMiddleware.OperationExecutionMiddleware, (_, _) => context => - { - context.Result = OperationResultBuilder.New() - .SetData(new Dictionary { ["nonNullString"] = null }) - .Build(); - - return ValueTask.CompletedTask; - }, key: "SetNull")); + .InsertUseRequest( + WellKnownRequestMiddleware.OperationExecutionMiddleware, + (_, _) => context => + { + context.Result = new OperationResult( + new Dictionary + { + ["nonNullString"] = null + }); + return ValueTask.CompletedTask; + }, + key: "SetNull")); // act using var gateway = await CreateCompositeSchemaAsync( diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs index f21788c237a..d85fbf88573 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/SourceSchemaErrorTests.cs @@ -139,7 +139,7 @@ public async Task No_Data_And_Error_Without_Path_For_Root_Field(ErrorHandlingMod { return context => { - context.Result = OperationResultBuilder.CreateError( + context.Result = OperationResult.FromError( ErrorBuilder.New() .SetMessage("A global error") .Build()); @@ -191,7 +191,7 @@ public async Task No_Data_And_Error_Without_Path_For_Root_Field_NonNull(ErrorHan { return context => { - context.Result = OperationResultBuilder.CreateError( + context.Result = OperationResult.FromError( ErrorBuilder.New() .SetMessage("A global error") .Build()); @@ -671,7 +671,7 @@ public async Task No_Data_And_Error_Without_Path_For_Lookup_Field_NonNull(ErrorH { return context => { - context.Result = OperationResultBuilder.CreateError( + context.Result = OperationResult.FromError( ErrorBuilder.New() .SetMessage("A global error") .Build()); diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs index 3bee9767122..738a80bdc17 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Execution/FusionRequestExecutorManagerTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution; using HotChocolate.Fusion.Configuration; using HotChocolate.Fusion.Execution.Nodes; @@ -89,18 +90,14 @@ type Query { { var plan = context.GetOperationPlan(); context.Result = - OperationResultBuilder.New() - .SetData( - new Dictionary + new OperationResult( + new Dictionary { { "foo", null } }) - .SetContextData( - new Dictionary - { - { "operationPlan", plan } - }) - .Build(); + { + ContextData = ImmutableDictionary.Empty.Add("operationPlan", plan) + }; return ValueTask.CompletedTask; }; }) diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Text/Json/CompositeResultDocumentTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Text/Json/CompositeResultDocumentTests.cs index 5ebd3b067e4..191fa13e4bf 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Text/Json/CompositeResultDocumentTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/Text/Json/CompositeResultDocumentTests.cs @@ -2,6 +2,7 @@ using System.Text; using System.Text.Json; using HotChocolate.Buffers; +using HotChocolate.Execution; namespace HotChocolate.Fusion.Text.Json; @@ -467,7 +468,14 @@ public void Write_Document_To_BufferWriter() } // act - compositeResult.WriteTo(buffer, indented: true); + var operationResultData = new OperationResultData( + compositeResult, + compositeResult.Data.IsNullOrInvalidated, + compositeResult, + compositeResult); + var operationResult = new OperationResult( + operationResultData); + compositeResult.WriteTo(operationResult, buffer, indented: true); // assert var json = Encoding.UTF8.GetString(buffer.WrittenSpan); @@ -527,7 +535,14 @@ public async Task Write_Document_To_PipeWriter() // act await using var memoryStream = new MemoryStream(); var writer = PipeWriter.Create(memoryStream); - compositeResult.WriteTo(writer, indented: true); + var operationResultData = new OperationResultData( + compositeResult, + compositeResult.Data.IsNullOrInvalidated, + compositeResult, + compositeResult); + var operationResult = new OperationResult( + operationResultData); + compositeResult.WriteTo(operationResult, writer, indented: true); await writer.FlushAsync(); await writer.CompleteAsync(); diff --git a/src/HotChocolate/Marten/test/Data.Marten.Filters.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/Marten/test/Data.Marten.Filters.Tests/FilterVisitorTestBase.cs index 91265af3655..1ec43e6b595 100644 --- a/src/HotChocolate/Marten/test/Data.Marten.Filters.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/Marten/test/Data.Marten.Filters.Tests/FilterVisitorTestBase.cs @@ -81,11 +81,8 @@ protected async Task CreateSchemaAsync( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .ModifyPagingOptions(o => o.IncludeTotalCount = true) diff --git a/src/HotChocolate/Marten/test/Data.Marten.Sorting.Tests/SortVisitorTestBase.cs b/src/HotChocolate/Marten/test/Data.Marten.Sorting.Tests/SortVisitorTestBase.cs index 47ec5c4ffb5..95a37374536 100644 --- a/src/HotChocolate/Marten/test/Data.Marten.Sorting.Tests/SortVisitorTestBase.cs +++ b/src/HotChocolate/Marten/test/Data.Marten.Sorting.Tests/SortVisitorTestBase.cs @@ -124,11 +124,8 @@ protected async Task CreateSchemaAsync( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/FilterVisitorTestBase.cs index c5eade6aa65..f5506460ae5 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/FilterVisitorTestBase.cs @@ -59,11 +59,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbAggregateFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbAggregateFluentTests.cs index 4fbbbbf0ae2..aee2ef90293 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbAggregateFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbAggregateFluentTests.cs @@ -147,11 +147,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbCollectionTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbCollectionTests.cs index 2bb57fd0dcd..21b1d527ed4 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbCollectionTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbCollectionTests.cs @@ -146,11 +146,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbFindFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbFindFluentTests.cs index afde657472c..f289e4e279e 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbFindFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Filters.Tests/MongoDbFindFluentTests.cs @@ -193,11 +193,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingAggregateFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingAggregateFluentTests.cs index 14a5119e8f2..c795ffad144 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingAggregateFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingAggregateFluentTests.cs @@ -270,11 +270,8 @@ private ValueTask CreateSchemaAsync() await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingFindFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingFindFluentTests.cs index 3f89247ea4d..dcb5f1e4873 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingFindFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbCursorPagingFindFluentTests.cs @@ -305,11 +305,8 @@ private ValueTask CreateSchemaAsync(bool requiresPagingBoundar await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingAggregateTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingAggregateTests.cs index 234b90df7c8..59a9cc1567b 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingAggregateTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingAggregateTests.cs @@ -213,11 +213,8 @@ private ValueTask CreateSchemaAsync() await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingFindFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingFindFluentTests.cs index f34db3bfb72..ef378d6a5e3 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingFindFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/MongoDbOffsetPagingFindFluentTests.cs @@ -211,11 +211,8 @@ private ValueTask CreateSchemaAsync() await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/VisitorTestBase.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/VisitorTestBase.cs index 369d90cca4f..89c1b865bed 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/VisitorTestBase.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Paging.Tests/VisitorTestBase.cs @@ -64,11 +64,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbAggregateFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbAggregateFluentTests.cs index 66c99e7a846..df579f7a7a4 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbAggregateFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbAggregateFluentTests.cs @@ -142,11 +142,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbFindFluentTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbFindFluentTests.cs index 60ae122018a..12af390a934 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbFindFluentTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbFindFluentTests.cs @@ -207,11 +207,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbSortCollectionTests.cs b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbSortCollectionTests.cs index 98f0d7a122b..944595ba9b6 100644 --- a/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbSortCollectionTests.cs +++ b/src/HotChocolate/MongoDb/test/Data.MongoDb.Sorting.Tests/MongoDbSortCollectionTests.cs @@ -151,11 +151,8 @@ private static IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .UseDefaultPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs index 11e810b9198..518605e4d7c 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs @@ -69,12 +69,11 @@ public async Task ExecutePersistedOperation_NotFound() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument()) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs index 51e88460e8a..7eb3f6c7ba8 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Types; @@ -25,12 +26,11 @@ public async Task ExecutePersistedOperation() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument()) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -63,12 +63,11 @@ public async Task ExecutePersistedOperation_NotFound() { await n(c); - if (c.IsPersistedOperationDocument() && c.Result is IOperationResult r) + if (c.IsPersistedOperationDocument()) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs index 76c9a28b38b..b0fe06d2f02 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs @@ -39,12 +39,11 @@ await storage.SaveAsync( await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -73,12 +72,11 @@ public async Task ExecutePersistedOperation_After_Expiration() await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -122,12 +120,11 @@ public async Task ExecutePersistedOperation_Before_Expiration() await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -163,20 +160,18 @@ public async Task ExecutePersistedOperation_ApplicationDI() await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() .BuildRequestExecutorAsync(); // act - var result = - await executor.ExecuteAsync(OperationRequest.FromId(documentId)); + var result = await executor.ExecuteAsync(OperationRequest.FromId(documentId)); // assert result.MatchSnapshot(); @@ -203,20 +198,18 @@ public async Task ExecutePersistedOperation_ApplicationDI_Default() await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() .BuildRequestExecutorAsync(); // act - var result = - await executor.ExecuteAsync(OperationRequest.FromId(documentId)); + var result = await executor.ExecuteAsync(OperationRequest.FromId(documentId)); // assert result.MatchSnapshot(); @@ -240,20 +233,18 @@ public async Task ExecutePersistedOperation_NotFound() await n(c); var documentInfo = c.OperationDocumentInfo; - if (documentInfo.Id == documentId && c.Result is IOperationResult r) + if (documentInfo.Id == documentId) { - c.Result = OperationResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Build(); + var result = c.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? []; + result.Extensions = extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() .BuildRequestExecutorAsync(); // act - var result = - await executor.ExecuteAsync(OperationRequest.FromId("does_not_exist")); + var result = await executor.ExecuteAsync(OperationRequest.FromId("does_not_exist")); // assert result.MatchSnapshot(); From b304652847012b7d63351131a1c1998387a63a7a Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 22:10:08 +0100 Subject: [PATCH 39/42] Refactor OperationResult usage in tests and remove obsolete ResultBuilderTests --- .../GraphQLOverHttpSpecTests.cs | 1 - .../HttpPostMiddlewareTests.cs | 2 +- .../Subscriptions/OperationManagerTests.cs | 2 +- .../Integration/DataLoader/DataLoaderTests.cs | 42 ++++++++----------- .../StarWarsCodeFirstTests.cs | 8 ++-- .../Processing/Result/ResultBuilderTests.cs | 27 ------------ .../Types/SomeRequestMiddleware.cs | 14 +++---- .../Data.Tests/InterfaceIntegrationTests.cs | 12 ++++-- 8 files changed, 38 insertions(+), 70 deletions(-) delete mode 100644 src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ResultBuilderTests.cs diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs index c0bfcc614dd..799e4afb4cc 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/GraphQLOverHttpSpecTests.cs @@ -10,7 +10,6 @@ using static System.Net.HttpStatusCode; using static HotChocolate.AspNetCore.HttpTransportVersion; using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue; -using OperationResult = HotChocolate.Execution.OperationResult; namespace HotChocolate.AspNetCore; diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs index 9eab856746c..53c885309ad 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/HttpPostMiddlewareTests.cs @@ -229,7 +229,7 @@ await server.PostHttpAsync( private class CustomFormatter : DefaultHttpResponseFormatter { protected override void OnWriteResponseHeaders( - IOperationResult result, + OperationResult result, FormatInfo format, IHeaderDictionary headers) { diff --git a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/Subscriptions/OperationManagerTests.cs b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/Subscriptions/OperationManagerTests.cs index 2edadba5a40..d908a97571b 100644 --- a/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/Subscriptions/OperationManagerTests.cs +++ b/src/HotChocolate/AspNetCore/test/AspNetCore.Tests/Subscriptions/OperationManagerTests.cs @@ -325,7 +325,7 @@ public ValueTask SendKeepAliveMessageAsync( public ValueTask SendResultMessageAsync( ISocketSession session, string operationSessionId, - IOperationResult result, + OperationResult result, CancellationToken cancellationToken) => default; diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs index 7d468dbbea3..d4090096fb5 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs @@ -34,10 +34,9 @@ public async Task ClassDataLoader() .GetRequiredService() .GetDataLoader(_ => throw new Exception()); - context.Result = OperationResultBuilder - .FromResult((IOperationResult)context.Result!) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); @@ -101,10 +100,9 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context_Not_Initialized() .GetRequiredService() .GetDataLoader(_ => throw new Exception()); - context.Result = OperationResultBuilder - .FromResult((IOperationResult)context.Result!) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -136,10 +134,9 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context() .GetRequiredService() .GetDataLoader(_ => throw new Exception()); - context.Result = OperationResultBuilder - .FromResult((IOperationResult)context.Result!) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -174,10 +171,9 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context_Just_Works() .GetRequiredService() .GetDataLoader(_ => throw new Exception()); - context.Result = OperationResultBuilder - .FromResult((IOperationResult)context.Result!) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -259,10 +255,9 @@ public async Task ClassDataLoader_Resolve_From_DependencyInjection() var dataLoader = (TestDataLoader)context.RequestServices.GetRequiredService(); - context.Result = OperationResultBuilder - .FromResult(((IOperationResult)context.Result!)) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); @@ -326,10 +321,9 @@ public async Task ClassDataLoader_Resolve_From_DependencyInjection_Using_Factory var dataLoader = (TestDataLoader)context.RequestServices.GetRequiredService(); - context.Result = OperationResultBuilder - .FromResult((IOperationResult)context.Result!) - .AddExtension("loads", dataLoader.Loads) - .Build(); + var result = context.Result.ExpectOperationResult(); + var extensions = result.Extensions ?? ImmutableDictionary.Empty; + extensions = extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs index 610a421e5ba..e82f4ca6c08 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/StarWarsCodeFirst/StarWarsCodeFirstTests.cs @@ -662,7 +662,7 @@ await executor.ExecuteAsync( } """); - IOperationResult? eventResult = null; + OperationResult? eventResult = null; using (var cts = new CancellationTokenSource(2000)) { @@ -708,7 +708,7 @@ await executor.ExecuteAsync( } """); - IOperationResult? eventResult = null; + OperationResult? eventResult = null; using (var cts = new CancellationTokenSource(2000)) { @@ -756,7 +756,7 @@ await executor.ExecuteAsync( } """); - IOperationResult? eventResult = null; + OperationResult? eventResult = null; using (var cts = new CancellationTokenSource(2000)) { @@ -802,7 +802,7 @@ await executor.ExecuteAsync( } """); - IOperationResult? eventResult = null; + OperationResult? eventResult = null; using (var cts = new CancellationTokenSource(2000)) { diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ResultBuilderTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ResultBuilderTests.cs deleted file mode 100644 index c585f571862..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ResultBuilderTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -public class ResultBuilderTests -{ - [Fact] - public void BuildResult_SimpleResultSet_SnapshotMatches() - { - // arrange - var helper = new ResultBuilder(CreatePool()); - var map = helper.RentObject(1); - map.SetValueUnsafe(0, "abc", "def", false); - helper.SetData(map); - - // act - var result = helper.BuildResult(); - - // assert - result.ToJson().MatchSnapshot(); - } - - private ResultPool CreatePool() - { - return new ResultPool( - new ObjectResultPool(16, 16, 16), - new ListResultPool(16, 16, 16)); - } -} diff --git a/src/HotChocolate/Core/test/Types.Analyzers.Tests/Types/SomeRequestMiddleware.cs b/src/HotChocolate/Core/test/Types.Analyzers.Tests/Types/SomeRequestMiddleware.cs index 914328bf181..4b0466aa0fd 100644 --- a/src/HotChocolate/Core/test/Types.Analyzers.Tests/Types/SomeRequestMiddleware.cs +++ b/src/HotChocolate/Core/test/Types.Analyzers.Tests/Types/SomeRequestMiddleware.cs @@ -9,15 +9,13 @@ public async ValueTask InvokeAsync(RequestContext context, Service3 service3) await next(context); context.Result = - OperationResultBuilder.New() - .SetData( - new Dictionary + new OperationResult( + new Dictionary + { { - { - $"{service1.Say()} {service3.Hello()} {service2.World()}", true - } - }) - .Build(); + $"{service1.Say()} {service3.Hello()} {service2.World()}", true + } + }); } } diff --git a/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs b/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs index c9fd54a6f6c..f9915b1dae1 100644 --- a/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs +++ b/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs @@ -63,11 +63,12 @@ public async Task Query_Owner_Animals() .Build()); var operationResult = result.ExpectOperationResult(); + operationResult.Extensions = ImmutableDictionary.Empty; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) .AddQueries(queries) - .Add(operationResult.WithExtensions(ImmutableDictionary.Empty)) + .Add(operationResult) .MatchMarkdownAsync(); } @@ -115,11 +116,12 @@ public async Task Query_Owner_Animals_With_TotalCount() .Build()); var operationResult = result.ExpectOperationResult(); + operationResult.Extensions = ImmutableDictionary.Empty; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) .AddQueries(queries) - .Add(operationResult.WithExtensions(ImmutableDictionary.Empty)) + .Add(operationResult) .MatchMarkdownAsync(); } @@ -171,11 +173,12 @@ ... on Cat { .Build()); var operationResult = result.ExpectOperationResult(); + operationResult.Extensions = ImmutableDictionary.Empty; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) .AddQueries(queries) - .Add(operationResult.WithExtensions(ImmutableDictionary.Empty)) + .Add(operationResult) .MatchMarkdownAsync(); } @@ -214,6 +217,7 @@ public async Task Query_Pets() .Build()); var operationResult = result.ExpectOperationResult(); + operationResult.Extensions = ImmutableDictionary.Empty; await Snapshot .Create( @@ -221,7 +225,7 @@ await Snapshot ? TestEnvironment.TargetFramework : null) .AddQueries(queries) - .Add(operationResult.WithExtensions(ImmutableDictionary.Empty)) + .Add(operationResult) .MatchMarkdownAsync(); } From 3bcb7c8584697904713721f56d984eb2fc106d78 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Tue, 16 Dec 2025 22:43:52 +0100 Subject: [PATCH 40/42] Enhance ImmutableOrderedDictionary and OperationResult with new Create method; refactor extensions handling in various tests --- .../Immutable/ImmutableOrderedDictionary.cs | 34 +++ .../Execution/OperationResult.cs | 36 +-- .../Execution.Tests/MiddlewareContextTests.cs | 8 +- .../Result/ObjectFieldResultTests.cs | 67 ------ .../Processing/Result/ObjectResultTests.cs | 213 ------------------ ...esult_SimpleResultSet_SnapshotMatches.snap | 5 - .../Execution.Tests/WarmupRequestTests.cs | 4 +- .../PagingHelperIntegrationTests.cs | 3 +- .../WritePersistedOperationMiddleware.cs | 3 +- .../IntegrationTests.cs | 12 +- .../FilterVisitorTestBase.cs | 7 +- .../RavenAsyncDocumentQueryTests.cs | 7 +- 12 files changed, 73 insertions(+), 326 deletions(-) delete mode 100644 src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectFieldResultTests.cs delete mode 100644 src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectResultTests.cs delete mode 100644 src/HotChocolate/Core/test/Execution.Tests/Processing/Result/__snapshots__/ResultBuilderTests.BuildResult_SimpleResultSet_SnapshotMatches.snap diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs index a5615e7dd8a..f330a177dc8 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace HotChocolate.Collections.Immutable; @@ -20,6 +21,7 @@ namespace HotChocolate.Collections.Immutable; /// which does not guarantee any particular order. /// /// +[CollectionBuilder(typeof(ImmutableOrderedDictionary), nameof(ImmutableOrderedDictionary.Create))] public sealed class ImmutableOrderedDictionary : IImmutableDictionary where TKey : IEquatable { @@ -472,6 +474,26 @@ public bool ContainsKey(TKey key) public ImmutableOrderedDictionary ToImmutable() => new([.. _dictionary.Keys], ImmutableDictionary.CreateRange(_dictionary)); } + + internal static ImmutableOrderedDictionary Create( + ReadOnlySpan> items) + { + if (items.Length == 0) + { + return Empty; + } + + var keys = ImmutableList.CreateBuilder(); + var map = ImmutableDictionary.CreateBuilder(); + + foreach (var item in items) + { + keys.Add(item.Key); + map.Add(item.Key, item.Value); + } + + return new ImmutableOrderedDictionary(keys.ToImmutable(), map.ToImmutable()); + } } /// @@ -488,4 +510,16 @@ public static class ImmutableOrderedDictionary public static ImmutableOrderedDictionary.Builder CreateBuilder() where TKey : IEquatable => new(); + + /// + /// Creates an immutable ordered dictionary from the specified key-value pairs. + /// + /// The type of keys in the dictionary. + /// The type of values in the dictionary. + /// The key-value pairs to include in the dictionary. + /// An immutable ordered dictionary containing the specified key-value pairs. + public static ImmutableOrderedDictionary Create( + ReadOnlySpan> items) + where TKey : IEquatable + => ImmutableOrderedDictionary.Create(items); } diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs index 2d6904a02be..9a84eee2be6 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Collections.Immutable; namespace HotChocolate.Execution; @@ -27,7 +28,7 @@ public sealed class OperationResult : ExecutionResult public OperationResult( OperationResultData data, ImmutableList? errors = null, - ImmutableDictionary? extensions = null) + ImmutableOrderedDictionary? extensions = null) { if (data.Value is not null && data.Formatter is not null) { @@ -43,8 +44,8 @@ public OperationResult( ? DataFlags.DataIsSet | DataFlags.DataIsNull : DataFlags.DataIsSet; Data = data.Value; - Errors = errors; - Extensions = extensions; + Errors = errors ?? []; + Extensions = extensions ?? []; Features.Set(data.Formatter); @@ -76,7 +77,7 @@ public OperationResult( public OperationResult( IReadOnlyDictionary? data, ImmutableList? errors = null, - ImmutableDictionary? extensions = null) + ImmutableOrderedDictionary? extensions = null) { if (data is null && errors is null or { Count: 0 } && extensions is null or { Count: 0 }) { @@ -88,8 +89,8 @@ public OperationResult( : DataFlags.DataIsSet; Data = data; - Errors = errors; - Extensions = extensions; + Errors = errors ?? []; + Extensions = extensions ?? []; } /// @@ -107,7 +108,7 @@ public OperationResult( /// /// Thrown when the errors list is empty. /// - public OperationResult(ImmutableList errors, ImmutableDictionary? extensions = null) + public OperationResult(ImmutableList errors, ImmutableOrderedDictionary? extensions = null) { ArgumentNullException.ThrowIfNull(errors); @@ -118,7 +119,7 @@ public OperationResult(ImmutableList errors, ImmutableDictionary @@ -133,7 +134,7 @@ public OperationResult(ImmutableList errors, ImmutableDictionary /// Thrown when the extensions dictionary is empty. /// - public OperationResult(ImmutableDictionary extensions) + public OperationResult(ImmutableOrderedDictionary extensions) { ArgumentNullException.ThrowIfNull(extensions); @@ -143,6 +144,7 @@ public OperationResult(ImmutableDictionary extensions) } _dataFlags = DataFlags.DataIsNull; + Errors = []; Extensions = extensions; } @@ -198,7 +200,7 @@ public Path? Path /// /// Gets the GraphQL errors that occurred during execution. /// - public ImmutableList? Errors { get; } + public ImmutableList Errors { get; } /// /// Gets or sets additional information passed along with the result. @@ -206,7 +208,7 @@ public Path? Path /// /// Thrown when setting to null or empty when data and errors are also null or empty. /// - public ImmutableDictionary? Extensions + public ImmutableOrderedDictionary Extensions { get; set @@ -224,9 +226,9 @@ public Path? Path /// Gets or sets the list of pending incremental delivery operations. /// Each pending result announces data that will be delivered incrementally in subsequent payloads. /// - public ImmutableList? Pending + public ImmutableList Pending { - get => Features.Get()?.Pending; + get => Features.Get()?.Pending ?? []; set { var feature = Features.Get() ?? new IncrementalDataFeature(); @@ -239,9 +241,9 @@ public ImmutableList? Pending /// Gets or sets the list of incremental results containing data from @defer or @stream directives. /// Contains the actual data for previously announced pending operations. /// - public ImmutableList? Incremental + public ImmutableList Incremental { - get => Features.Get()?.Incremental; + get => Features.Get()?.Incremental ?? []; set { var feature = Features.Get() ?? new IncrementalDataFeature(); @@ -254,9 +256,9 @@ public ImmutableList? Incremental /// Gets or sets the list of completed incremental delivery operations. /// Each completed result indicates that all data for a pending operation has been delivered. /// - public ImmutableList? Completed + public ImmutableList Completed { - get => Features.Get()?.Completed; + get => Features.Get()?.Completed ?? []; set { var feature = Features.Get() ?? new IncrementalDataFeature(); diff --git a/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs b/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs index a798cdb7f4f..8dfeebff4b2 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/MiddlewareContextTests.cs @@ -334,9 +334,11 @@ public async Task SetResultContextData_Delegate_IntValue_When_Deferred() continue; } - Assert.NotNull(queryResult.Incremental?[0].ContextData); - Assert.True(queryResult.Incremental[0].ContextData!.TryGetValue("abc", out var value)); - Assert.Equal(2, value); + // TODO : FIX THIS TEST + throw new InvalidOperationException(); + // Assert.NotNull(queryResult.Incremental?[0].ContextData); + // Assert.True(queryResult.Incremental[0].ContextData!.TryGetValue("abc", out var value)); + // Assert.Equal(2, value); } } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectFieldResultTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectFieldResultTests.cs deleted file mode 100644 index af5e1df90c9..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectFieldResultTests.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -public class ObjectFieldResultTests -{ - [Fact] - public void SetNullable() - { - // arrange - var field = new ObjectFieldResult(); - - // act - field.Set("abc", "def", true); - - // assert - Assert.Equal("abc", field.Name); - Assert.Equal("def", field.Value); - Assert.True(field.IsNullable); - Assert.True(field.IsInitialized); - } - - [Fact] - public void SetNonNullable() - { - // arrange - var field = new ObjectFieldResult(); - - // act - field.Set("abc", "def", false); - - // assert - Assert.Equal("abc", field.Name); - Assert.Equal("def", field.Value); - Assert.False(field.IsNullable); - Assert.True(field.IsInitialized); - } - - [Fact] - public void NewInstance() - { - // arrange - // act - var field = new ObjectFieldResult(); - - // assert - Assert.Null(field.Name); - Assert.Null(field.Value); - Assert.True(field.IsNullable); - Assert.False(field.IsInitialized); - } - - [Fact] - public void ResetInstance() - { - // arrange - var field = new ObjectFieldResult(); - field.Set("abc", "def", false); - - // act - field.Reset(); - - // assert - Assert.Null(field.Name); - Assert.Null(field.Value); - Assert.True(field.IsNullable); - Assert.False(field.IsInitialized); - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectResultTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectResultTests.cs deleted file mode 100644 index 1925df6ed4f..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/ObjectResultTests.cs +++ /dev/null @@ -1,213 +0,0 @@ -namespace HotChocolate.Execution.Processing; - -public class ObjectResultTests -{ - [InlineData(8)] - [InlineData(4)] - [InlineData(2)] - [Theory] - public void EnsureCapacity(int size) - { - // arrange - var resultMap = new ObjectResult(); - - // act - resultMap.EnsureCapacity(size); - - // assert - Assert.Equal(size, resultMap.Capacity); - } - - [Fact] - public void SetValue() - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(1); - - // act - objectResult.SetValueUnsafe(0, "abc", "def"); - - // assert - Assert.Collection( - (IEnumerable)objectResult, - t => - { - Assert.Equal("abc", t.Name); - Assert.Equal("def", t.Value); - }); - } - - [InlineData(9)] - [InlineData(8)] - [InlineData(7)] - [InlineData(5)] - [InlineData(4)] - [InlineData(3)] - [Theory] - public void GetValue_ValueIsFound(int capacity) - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(capacity); - objectResult.SetValueUnsafe(0, "abc", "def"); - objectResult.SetValueUnsafe(capacity / 2, "def", "def"); - objectResult.SetValueUnsafe(capacity - 1, "ghi", "def"); - - // act - var value = objectResult.TryGetValue("def", out var index); - - // assert - Assert.Equal("def", value?.Name); - Assert.Equal(capacity / 2, index); - } - - [InlineData(9)] - [InlineData(8)] - [InlineData(7)] - [InlineData(5)] - [InlineData(4)] - [InlineData(3)] - [Theory] - public void TryGetValue_ValueIsFound(int capacity) - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(capacity); - objectResult.SetValueUnsafe(0, "abc", "def"); - objectResult.SetValueUnsafe(capacity / 2, "def", "def"); - objectResult.SetValueUnsafe(capacity - 1, "ghi", "def"); - - IReadOnlyDictionary dict = objectResult; - - // act - var found = dict.TryGetValue("def", out var value); - - // assert - Assert.True(found); - Assert.Equal("def", value); - } - - [InlineData(9)] - [InlineData(8)] - [InlineData(7)] - [InlineData(5)] - [InlineData(4)] - [InlineData(3)] - [Theory] - public void TryGetValue_ValueIsNotFound(int capacity) - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(capacity); - objectResult.SetValueUnsafe(0, "abc", "def"); - objectResult.SetValueUnsafe(capacity / 2, "def", "def"); - objectResult.SetValueUnsafe(capacity - 1, "ghi", "def"); - - IReadOnlyDictionary dict = objectResult; - - // act - var found = dict.TryGetValue("jkl", out var value); - - // assert - Assert.False(found); - Assert.Null(value); - } - - [InlineData(9)] - [InlineData(8)] - [InlineData(7)] - [InlineData(5)] - [InlineData(4)] - [InlineData(3)] - [Theory] - public void ContainsKey(int capacity) - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(capacity); - objectResult.SetValueUnsafe(0, "abc", "def"); - objectResult.SetValueUnsafe(capacity / 2, "def", "def"); - objectResult.SetValueUnsafe(capacity - 1, "ghi", "def"); - - IReadOnlyDictionary dict = objectResult; - - // act - var found = dict.ContainsKey("def"); - - // assert - Assert.True(found); - } - - [Fact] - public void EnumerateResultValue() - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(5); - - // act - objectResult.SetValueUnsafe(0, "abc1", "def"); - objectResult.SetValueUnsafe(2, "abc2", "def"); - objectResult.SetValueUnsafe(4, "abc3", "def"); - - // assert - Assert.Collection( - (IEnumerable)objectResult, - t => - { - Assert.Equal("abc1", t.Name); - Assert.Equal("def", t.Value); - }, - t => - { - Assert.Equal("abc2", t.Name); - Assert.Equal("def", t.Value); - }, - t => - { - Assert.Equal("abc3", t.Name); - Assert.Equal("def", t.Value); - }); - } - - [Fact] - public void EnumerateKeys() - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(5); - - // act - objectResult.SetValueUnsafe(0, "abc1", "def"); - objectResult.SetValueUnsafe(2, "abc2", "def"); - objectResult.SetValueUnsafe(4, "abc3", "def"); - - // assert - Assert.Collection( - ((IReadOnlyDictionary)objectResult).Keys, - t => Assert.Equal("abc1", t), - t => Assert.Equal("abc2", t), - t => Assert.Equal("abc3", t)); - } - - [Fact] - public void EnumerateValues() - { - // arrange - var objectResult = new ObjectResult(); - objectResult.EnsureCapacity(5); - - // act - objectResult.SetValueUnsafe(0, "abc1", "def"); - objectResult.SetValueUnsafe(2, "abc2", "def"); - objectResult.SetValueUnsafe(4, "abc3", "def"); - - // assert - Assert.Collection( - ((IReadOnlyDictionary)objectResult).Values, - t => Assert.Equal("def", t), - t => Assert.Equal("def", t), - t => Assert.Equal("def", t)); - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/__snapshots__/ResultBuilderTests.BuildResult_SimpleResultSet_SnapshotMatches.snap b/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/__snapshots__/ResultBuilderTests.BuildResult_SimpleResultSet_SnapshotMatches.snap deleted file mode 100644 index 769cd361886..00000000000 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/Result/__snapshots__/ResultBuilderTests.BuildResult_SimpleResultSet_SnapshotMatches.snap +++ /dev/null @@ -1,5 +0,0 @@ -{ - "data": { - "abc": "def" - } -} diff --git a/src/HotChocolate/Core/test/Execution.Tests/WarmupRequestTests.cs b/src/HotChocolate/Core/test/Execution.Tests/WarmupRequestTests.cs index 9274f7f9d17..56dfcd88f37 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/WarmupRequestTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/WarmupRequestTests.cs @@ -47,8 +47,8 @@ public async Task Warmup_Request_Warms_Up_Caches() // assert 2 Assert.Null(regularOperationResult.Errors); - Assert.NotNull(regularOperationResult.Data); - Assert.NotEmpty(regularOperationResult.Data); + Assert.False(regularOperationResult.IsDataNull); + Assert.True(regularOperationResult.UnwrapData().EnumerateObject().Any()); Assert.True(documentCache.TryGetDocument(documentId, out _)); Assert.Equal(1, operationCache.Count); diff --git a/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs b/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs index 2b7530a0bfb..fafd08dd6e9 100644 --- a/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs +++ b/src/HotChocolate/Data/test/Data.Tests/PagingHelperIntegrationTests.cs @@ -544,11 +544,12 @@ public async Task Nested_Paging_First_2() // Assert var operationResult = result.ExpectOperationResult(); + operationResult.Extensions = []; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) .AddQueries(queries) - .Add(operationResult.WithExtensions(ImmutableDictionary.Empty)) + .Add(operationResult) .MatchMarkdownAsync(); } diff --git a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs index 0188ef4d7a8..43abffb803a 100644 --- a/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs +++ b/src/HotChocolate/PersistedOperations/src/PersistedOperations.Pipeline/Execution/Pipeline/WritePersistedOperationMiddleware.cs @@ -1,4 +1,3 @@ -using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using HotChocolate.Language; using HotChocolate.PersistedOperations; @@ -47,7 +46,7 @@ public async ValueTask InvokeAsync(RequestContext context) && context.Request.Extensions.TryGetValue(PersistedQuery, out var s) && s is IReadOnlyDictionary settings) { - var extensions = result.Extensions ?? ImmutableDictionary.Empty; + var extensions = result.Extensions; // hash is found and matches the query key -> store the query if (DoHashesMatch(settings, documentInfo.Id, _hashProvider.Name, out var userHash)) diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs index b0fe06d2f02..4aed775bc78 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.Redis.Tests/IntegrationTests.cs @@ -42,7 +42,7 @@ await storage.SaveAsync( if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) @@ -75,7 +75,7 @@ public async Task ExecutePersistedOperation_After_Expiration() if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) @@ -123,7 +123,7 @@ public async Task ExecutePersistedOperation_Before_Expiration() if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) @@ -163,7 +163,7 @@ public async Task ExecutePersistedOperation_ApplicationDI() if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) @@ -201,7 +201,7 @@ public async Task ExecutePersistedOperation_ApplicationDI_Default() if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) @@ -236,7 +236,7 @@ public async Task ExecutePersistedOperation_NotFound() if (documentInfo.Id == documentId) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; + var extensions = result.Extensions; result.Extensions = extensions.SetItem("persistedDocument", true); } }) diff --git a/src/HotChocolate/Raven/test/Data.Raven.Filters.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/Raven/test/Data.Raven.Filters.Tests/FilterVisitorTestBase.cs index 2069863dba2..c75e5728e4d 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Filters.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Filters.Tests/FilterVisitorTestBase.cs @@ -60,11 +60,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenAsyncDocumentQueryTests.cs b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenAsyncDocumentQueryTests.cs index 5165a5e5dee..9e2eb9bcc5d 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenAsyncDocumentQueryTests.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenAsyncDocumentQueryTests.cs @@ -435,11 +435,8 @@ private ValueTask CreateSchemaAsync() await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) From a1d18d0563930ba80d988a7bc21586809de65f4e Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Wed, 17 Dec 2025 14:56:51 +0100 Subject: [PATCH 41/42] Add Create method to ImmutableOrderedDictionary; refactor OperationResult and related tests to use ImmutableOrderedDictionary for extensions --- .../Immutable/ImmutableOrderedDictionary.cs | 38 ++++++++++++ .../Execution/OperationResult.cs | 38 ++++++++++++ .../Extensions/OperationContextExtensions.cs | 6 +- .../Processing/OperationResultBuilder.cs | 31 +++++----- .../Integration/DataLoader/DataLoaderTests.cs | 18 ++---- .../TransactionScopeHandlerTests.cs | 2 +- .../CostAnalysis/Utilities/ResultHelper.cs | 23 +++---- .../Data.Tests/InterfaceIntegrationTests.cs | 8 +-- .../Execution/OperationPlanContext.cs | 3 +- .../Text/Json/CompositeResultDocument.cs | 4 +- .../IntegrationTests.cs | 3 +- .../IntegrationTests.cs | 7 +-- .../RavenQueryableTests.cs | 6 +- .../VisitorTestBase.cs | 7 +-- .../ProjectionVisitorTestBase.cs | 7 +-- .../SortVisitorTestBase.cs | 7 +-- .../FilterVisitorTestBase.cs | 7 +-- .../TestHelper/TestServerHelper.cs | 61 +++++++++---------- 18 files changed, 163 insertions(+), 113 deletions(-) diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs index f330a177dc8..ec770f6b299 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Collections/Immutable/ImmutableOrderedDictionary.cs @@ -494,6 +494,26 @@ internal static ImmutableOrderedDictionary Create( return new ImmutableOrderedDictionary(keys.ToImmutable(), map.ToImmutable()); } + + internal static ImmutableOrderedDictionary Create( + OrderedDictionary items) + { + if (items.Count == 0) + { + return Empty; + } + + var keys = ImmutableList.CreateBuilder(); + var map = ImmutableDictionary.CreateBuilder(); + + foreach (var item in items) + { + keys.Add(item.Key); + map.Add(item.Key, item.Value); + } + + return new ImmutableOrderedDictionary(keys.ToImmutable(), map.ToImmutable()); + } } /// @@ -523,3 +543,21 @@ public static ImmutableOrderedDictionary Create( where TKey : IEquatable => ImmutableOrderedDictionary.Create(items); } + +/// +/// Provides extension methods for immutable ordered dictionaries. +/// +public static class ImmutableOrderedDictionaryExtensions +{ + /// + /// Converts the specified ordered dictionary to an immutable ordered dictionary. + /// + /// The type of keys in the dictionary. + /// The type of values in the dictionary. + /// The ordered dictionary to convert. + /// An immutable ordered dictionary containing the same key-value pairs as the input dictionary. + public static ImmutableOrderedDictionary ToImmutableOrderedDictionary( + this OrderedDictionary dictionary) + where TKey : IEquatable + => ImmutableOrderedDictionary.Create(dictionary); +} diff --git a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs index 9a84eee2be6..c6231291388 100644 --- a/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs +++ b/src/HotChocolate/Core/src/Execution.Abstractions/Execution/OperationResult.cs @@ -148,6 +148,23 @@ public OperationResult(ImmutableOrderedDictionary extensions) Extensions = extensions; } + private OperationResult( + object? data, + DataFlags dataFlags, + IRawJsonFormatter? dataFormatter, + ImmutableList? errors, + ImmutableOrderedDictionary? extensions, + IAsyncDisposable resourceOwner) + { + _dataFlags = dataFlags; + Data = data; + Errors = errors ?? []; + Extensions = extensions ?? []; + Features.Set(dataFormatter); + + RegisterForCleanup(resourceOwner.DisposeAsync); + } + /// /// Gets the kind of execution result. /// @@ -289,6 +306,27 @@ public bool? HasNext /// public IRawJsonFormatter? JsonFormatter => Features.Get(); + /// + /// Creates a new operation result with the specified error added. + /// + /// The errors to add to the result. + /// A new operation result with the added errors. + public OperationResult WithErrors(ImmutableList errors) + { + ArgumentNullException.ThrowIfNull(errors); + + return new OperationResult(Data, _dataFlags, JsonFormatter, errors, Extensions, this) + { + RequestIndex = RequestIndex, + VariableIndex = VariableIndex, + Path = Path, + Pending = Pending, + Incremental = Incremental, + Completed = Completed, + HasNext = HasNext + }; + } + /// /// Creates an operation result containing a single error. /// diff --git a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs index 229eeb2d74e..eaa7d29fffe 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Extensions/OperationContextExtensions.cs @@ -70,11 +70,11 @@ public OperationResult BuildResult() resultBuilder.Data.Data.IsNullOrInvalidated, resultBuilder.Data, resultBuilder.Data), - resultBuilder.Errors is { Count: > 0 } errors ? errors : null, - resultBuilder.Extensions is { Count: > 0 } extensions ? extensions : null) + resultBuilder.Errors, + resultBuilder.Extensions) { RequestIndex = resultBuilder.RequestIndex > -1 ? resultBuilder.RequestIndex : 0, - VariableIndex = resultBuilder.VariableIndex > -1 ? resultBuilder.VariableIndex : 0, + VariableIndex = resultBuilder.VariableIndex > -1 ? resultBuilder.VariableIndex : 0, ContextData = resultBuilder.ContextData }; diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs index f5b8376561d..e93b073b0d8 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationResultBuilder.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using HotChocolate.Collections.Immutable; using HotChocolate.Resolvers; using HotChocolate.Text.Json; @@ -16,22 +17,22 @@ internal sealed class OperationResultBuilder : IOperationResultBuilder public ResultDocument Data { get; set; } = null!; - public ImmutableList Errors { get; set; } = ImmutableList.Empty; + public ImmutableList Errors { get; set; } = []; - public ImmutableDictionary Extensions { get; set; } = ImmutableDictionary.Empty; + public ImmutableOrderedDictionary Extensions { get; set; } = []; public ImmutableDictionary ContextData { get; set; } = ImmutableDictionary.Empty; - public ImmutableList? Pending { get; set; } + public ImmutableList Pending { get; set; } = []; - public ImmutableList? Incremental { get; set; } + public ImmutableList Incremental { get; set; } = []; - public ImmutableList? Completed { get; set; } + public ImmutableList Completed { get; set; } = []; - public ImmutableList> CleanupTasks { get; set; } = ImmutableList>.Empty; + public ImmutableList> CleanupTasks { get; set; } = []; // TODO : Is this still needed? - public ImmutableHashSet NonNullViolations { get; set; } = ImmutableHashSet.Empty; + public ImmutableHashSet NonNullViolations { get; set; } = []; public bool? HasNext { get; set; } @@ -157,14 +158,14 @@ public void Reset() VariableIndex = -1; Path = null; Data = null!; - Errors = ImmutableList.Empty; - Pending = ImmutableList.Empty; - Extensions = ImmutableDictionary.Empty; - CleanupTasks = ImmutableList>.Empty; - NonNullViolations = ImmutableHashSet.Empty; - Pending = null; - Incremental = null; - Completed = null; + Errors = []; + Extensions = []; + ContextData = ImmutableDictionary.Empty; + CleanupTasks = []; + NonNullViolations = []; + Pending = []; + Incremental = []; + Completed = []; HasNext = null; } } diff --git a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs index d4090096fb5..2580c3577bc 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Integration/DataLoader/DataLoaderTests.cs @@ -35,8 +35,7 @@ public async Task ClassDataLoader() .GetDataLoader(_ => throw new Exception()); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); @@ -101,8 +100,7 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context_Not_Initialized() .GetDataLoader(_ => throw new Exception()); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -135,8 +133,7 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context() .GetDataLoader(_ => throw new Exception()); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -172,8 +169,7 @@ public async Task ClassDataLoader_Out_Off_GraphQL_Context_Just_Works() .GetDataLoader(_ => throw new Exception()); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline() .Services @@ -256,8 +252,7 @@ public async Task ClassDataLoader_Resolve_From_DependencyInjection() var dataLoader = (TestDataLoader)context.RequestServices.GetRequiredService(); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); @@ -322,8 +317,7 @@ public async Task ClassDataLoader_Resolve_From_DependencyInjection_Using_Factory var dataLoader = (TestDataLoader)context.RequestServices.GetRequiredService(); var result = context.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - extensions = extensions.SetItem("loads", dataLoader.Loads); + result.Extensions = result.Extensions.SetItem("loads", dataLoader.Loads); }) .UseDefaultPipeline()); diff --git a/src/HotChocolate/Core/test/Execution.Tests/TransactionScopeHandlerTests.cs b/src/HotChocolate/Core/test/Execution.Tests/TransactionScopeHandlerTests.cs index bacec108e9f..b08e86b3b1f 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/TransactionScopeHandlerTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/TransactionScopeHandlerTests.cs @@ -95,7 +95,7 @@ public class MockTransactionScope(Action complete, Action dispose, RequestContex { public void Complete() { - if (context.Result is IOperationResult { Data: not null, Errors: null or { Count: 0 } }) + if (context.Result is OperationResult { Data: not null, Errors: null or { Count: 0 } }) { complete(); } diff --git a/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs b/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs index f7f6e0f4d28..4f4f0f29e59 100644 --- a/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs +++ b/src/HotChocolate/CostAnalysis/src/CostAnalysis/Utilities/ResultHelper.cs @@ -15,7 +15,7 @@ internal static class ResultHelper public static IExecutionResult CreateError(IError error, CostMetrics? costMetrics) { - ImmutableDictionary? extensions = null; + ImmutableOrderedDictionary? extensions = null; if (costMetrics is not null) { extensions = AddCostMetrics(extensions, costMetrics); @@ -28,18 +28,18 @@ public static IExecutionResult CreateError(IError error, CostMetrics? costMetric public static IExecutionResult CreateError(IReadOnlyList errors, CostMetrics? costMetrics) { - ImmutableDictionary? extensions = null; + ImmutableOrderedDictionary? extensions = null; if (costMetrics is not null) { extensions = AddCostMetrics(extensions, costMetrics); } - return new OperationResult([..errors], extensions) { ContextData = s_validationError }; + return new OperationResult([.. errors], extensions) { ContextData = s_validationError }; } public static IExecutionResult CreateResult(this CostMetrics costMetrics) { - var extensions = AddCostMetrics(ImmutableDictionary.Empty, costMetrics); + var extensions = AddCostMetrics([], costMetrics); return new OperationResult(extensions: extensions) { ContextData = s_ok }; } @@ -99,12 +99,13 @@ private static ResponseStream AddCostMetrics( if (onFirstResult.IsEmpty) { onFirstResult = - ImmutableList.Create>( + [ result => { result.Extensions = AddCostMetrics(result.Extensions, costMetrics); return result; - }); + } + ]; } else { @@ -121,23 +122,23 @@ private static ResponseStream AddCostMetrics( return responseStream; } - private static ImmutableDictionary AddCostMetrics( - ImmutableDictionary? extensions, + private static ImmutableOrderedDictionary AddCostMetrics( + ImmutableOrderedDictionary? extensions, CostMetrics costMetrics) { var costMetricsMap = CreateCostMetricsMap(costMetrics); return AddCostMetrics(extensions, costMetricsMap); } - private static ImmutableDictionary AddCostMetrics( - ImmutableDictionary? extensions, + private static ImmutableOrderedDictionary AddCostMetrics( + ImmutableOrderedDictionary? extensions, ImmutableOrderedDictionary costMetrics) { const string costKey = "operationCost"; if (extensions is null || extensions.Count == 0) { - return ImmutableDictionary.Empty.Add(costKey, costMetrics); + return ImmutableOrderedDictionary.Empty.Add(costKey, costMetrics); } return extensions.Add(costKey, costMetrics); diff --git a/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs b/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs index f9915b1dae1..f9cb5802e37 100644 --- a/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs +++ b/src/HotChocolate/Data/test/Data.Tests/InterfaceIntegrationTests.cs @@ -63,7 +63,7 @@ public async Task Query_Owner_Animals() .Build()); var operationResult = result.ExpectOperationResult(); - operationResult.Extensions = ImmutableDictionary.Empty; + operationResult.Extensions = []; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) @@ -116,7 +116,7 @@ public async Task Query_Owner_Animals_With_TotalCount() .Build()); var operationResult = result.ExpectOperationResult(); - operationResult.Extensions = ImmutableDictionary.Empty; + operationResult.Extensions = []; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) @@ -173,7 +173,7 @@ ... on Cat { .Build()); var operationResult = result.ExpectOperationResult(); - operationResult.Extensions = ImmutableDictionary.Empty; + operationResult.Extensions = []; await Snapshot .Create(postFix: TestEnvironment.TargetFramework) @@ -217,7 +217,7 @@ public async Task Query_Pets() .Build()); var operationResult = result.ExpectOperationResult(); - operationResult.Extensions = ImmutableDictionary.Empty; + operationResult.Extensions = []; await Snapshot .Create( diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs index eeb6ddfb7ad..bb1f55e0f45 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Execution/OperationPlanContext.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using HotChocolate.Buffers; +using HotChocolate.Collections.Immutable; using HotChocolate.Execution; using HotChocolate.Features; using HotChocolate.Fusion.Diagnostics; @@ -284,7 +285,7 @@ internal OperationResult Complete(bool reusable = false) result, result), result.Errors?.ToImmutableList(), - result.Extensions?.ToImmutableDictionary()); + result.Extensions?.ToImmutableOrderedDictionary()); // we take over the memory owners from the result context // and store them on the response so that the server can diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.cs index 8521ed61412..8cfccd0c18e 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution/Text/Json/CompositeResultDocument.cs @@ -14,7 +14,7 @@ public sealed partial class CompositeResultDocument : IDisposable private readonly Operation _operation; private readonly ulong _includeFlags; private List? _errors; - private Dictionary? _extensions; + private OrderedDictionary? _extensions; internal MetaDb _metaDb; private bool _disposed; @@ -35,7 +35,7 @@ public List? Errors internal set => _errors = value; } - public Dictionary? Extensions + public OrderedDictionary? Extensions { get => _extensions; internal set => _extensions = value; diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs index 518605e4d7c..f5e3dd7b082 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.AzureBlobStorage.Tests/IntegrationTests.cs @@ -72,8 +72,7 @@ public async Task ExecutePersistedOperation_NotFound() if (c.IsPersistedOperationDocument()) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? []; - result.Extensions = extensions.SetItem("persistedDocument", true); + result.Extensions = result.Extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() diff --git a/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs index 7eb3f6c7ba8..2dc428eec53 100644 --- a/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedOperations/test/PersistedOperations.InMemory.Tests/IntegrationTests.cs @@ -1,4 +1,3 @@ -using System.Collections.Immutable; using HotChocolate.Execution; using HotChocolate.Language; using HotChocolate.Types; @@ -29,8 +28,7 @@ public async Task ExecutePersistedOperation() if (c.IsPersistedOperationDocument()) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - result.Extensions = extensions.SetItem("persistedDocument", true); + result.Extensions = result.Extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() @@ -66,8 +64,7 @@ public async Task ExecutePersistedOperation_NotFound() if (c.IsPersistedOperationDocument()) { var result = c.Result.ExpectOperationResult(); - var extensions = result.Extensions ?? ImmutableDictionary.Empty; - result.Extensions = extensions.SetItem("persistedDocument", true); + result.Extensions = result.Extensions.SetItem("persistedDocument", true); } }) .UsePersistedOperationPipeline() diff --git a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenQueryableTests.cs b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenQueryableTests.cs index b20b15ae833..42a61ea61cd 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenQueryableTests.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/RavenQueryableTests.cs @@ -431,10 +431,8 @@ private ValueTask CreateSchemaAsync() await next(context); if (context.ContextData.TryGetValue("query", out var queryString)) { - context.Result = OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("query", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("query", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/VisitorTestBase.cs b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/VisitorTestBase.cs index d0b2213fd41..39f4819ce7d 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/VisitorTestBase.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Paging.Tests/VisitorTestBase.cs @@ -66,11 +66,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/Raven/test/Data.Raven.Projections.Tests/ProjectionVisitorTestBase.cs b/src/HotChocolate/Raven/test/Data.Raven.Projections.Tests/ProjectionVisitorTestBase.cs index 8a95cb3ffbc..a0a3ebbae85 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Projections.Tests/ProjectionVisitorTestBase.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Projections.Tests/ProjectionVisitorTestBase.cs @@ -103,11 +103,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline(); diff --git a/src/HotChocolate/Raven/test/Data.Raven.Sorting.Tests/SortVisitorTestBase.cs b/src/HotChocolate/Raven/test/Data.Raven.Sorting.Tests/SortVisitorTestBase.cs index 5168c664e66..1b2ced78e07 100644 --- a/src/HotChocolate/Raven/test/Data.Raven.Sorting.Tests/SortVisitorTestBase.cs +++ b/src/HotChocolate/Raven/test/Data.Raven.Sorting.Tests/SortVisitorTestBase.cs @@ -80,11 +80,8 @@ protected IRequestExecutor CreateSchema( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .ModifyRequestOptions(x => x.IncludeExceptionDetails = true) diff --git a/src/HotChocolate/Spatial/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs b/src/HotChocolate/Spatial/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs index 6c805e55f30..3679c0850ae 100644 --- a/src/HotChocolate/Spatial/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs +++ b/src/HotChocolate/Spatial/test/Data.Filters.SqlServer.Tests/FilterVisitorTestBase.cs @@ -84,11 +84,8 @@ protected async Task CreateSchemaAsync( await next(context); if (context.ContextData.TryGetValue("sql", out var queryString)) { - context.Result = - OperationResultBuilder - .FromResult(context.Result!.ExpectOperationResult()) - .SetContextData("sql", queryString) - .Build(); + var result = context.Result.ExpectOperationResult(); + result.ContextData = result.ContextData.SetItem("sql", queryString); } }) .UseDefaultPipeline() diff --git a/src/StrawberryShake/Client/test/Transport.WebSocket.Tests/TestHelper/TestServerHelper.cs b/src/StrawberryShake/Client/test/Transport.WebSocket.Tests/TestHelper/TestServerHelper.cs index 4f045f285b6..be35f7b7c5e 100644 --- a/src/StrawberryShake/Client/test/Transport.WebSocket.Tests/TestHelper/TestServerHelper.cs +++ b/src/StrawberryShake/Client/test/Transport.WebSocket.Tests/TestHelper/TestServerHelper.cs @@ -51,25 +51,21 @@ public static IWebHost CreateServer(Action configure, o nameof(HttpContext), out var value) && value is HttpContext httpContext - && context.Result is HotChocolate.Execution.IOperationResult result) + && context.Result is OperationResult result) { var headers = httpContext.Request.Headers; if (headers.ContainsKey("sendErrorStatusCode")) { - context.Result = result = - OperationResultBuilder - .FromResult(result) - .SetContextData(ExecutionContextData.HttpStatusCode, 403) - .Build(); + result.ContextData = + result.ContextData.SetItem( + ExecutionContextData.HttpStatusCode, + 403); } if (headers.ContainsKey("sendError")) { - context.Result = - OperationResultBuilder - .FromResult(result) - .AddError(new Error { Message = "Some error!" }) - .Build(); + var errors = result.Errors.Add(new Error { Message = "Some error!" }); + context.Result = result.WithErrors(errors); } } @@ -78,30 +74,29 @@ public static IWebHost CreateServer(Action configure, o }) .Configure( app => - app.Use( - async (ct, next) => + app.Use(async (ct, next) => + { + try + { + // Kestrel does not return proper error responses: + // https://github.com/aspnet/KestrelHttpServer/issues/43 + await next(); + } + catch (Exception ex) + { + if (ct.Response.HasStarted) { - try - { - // Kestrel does not return proper error responses: - // https://github.com/aspnet/KestrelHttpServer/issues/43 - await next(); - } - catch (Exception ex) - { - if (ct.Response.HasStarted) - { - throw; - } + throw; + } - ct.Response.StatusCode = 500; - ct.Response.Headers.Clear(); - await ct.Response.WriteAsync(ex.ToString()); - } - }) - .UseWebSockets() - .UseRouting() - .UseEndpoints(e => e.MapGraphQL())) + ct.Response.StatusCode = 500; + ct.Response.Headers.Clear(); + await ct.Response.WriteAsync(ex.ToString()); + } + }) + .UseWebSockets() + .UseRouting() + .UseEndpoints(e => e.MapGraphQL())) .Build(); host.Start(); From f3c99bd9d34f1222a4e4d27ac64a7e561c01ad62 Mon Sep 17 00:00:00 2001 From: Michael Staib Date: Fri, 19 Dec 2025 08:40:29 +0100 Subject: [PATCH 42/42] Refactor GeoJSON serialization tests to throw LeafCoercionException instead of SerializationException - Updated multiple test cases across various GeoJSON input and serializer tests to assert LeafCoercionException for invalid inputs instead of SerializationException. - Changed method calls from ParseLiteral and Serialize to their respective CoerceInputLiteral and CoerceOutputValue methods where applicable. - Ensured consistency in exception handling across all GeoJSON related tests. --- .../Resolvers/ArgumentParser.cs | 4 +- .../src/ApolloFederation/ThrowHelper.cs | 12 +- .../ApolloFederation/Types/FieldSetType.cs | 2 +- .../src/ApolloFederation/Types/PolicyType.cs | 2 +- .../src/ApolloFederation/Types/ScopeType.cs | 2 +- .../src/ApolloFederation/Types/_AnyType.cs | 4 +- .../FieldSetTypeTests.cs | 12 +- .../ApolloFederation.Tests/_AnyTypeTests.cs | 22 +- .../Types/IScalarTypeDefinition.cs | 2 +- .../BaseTypes/IntToStructBaseType.cs | 14 +- .../BaseTypes/StringToClassBaseType.cs | 12 +- .../BaseTypes/StringToStructBaseType.cs | 12 +- .../src/Types.NodaTime/DateTimeZoneType.cs | 2 +- .../Core/src/Types.NodaTime/DurationType.cs | 2 +- .../Core/src/Types.NodaTime/InstantType.cs | 2 +- .../src/Types.NodaTime/IsoDayOfWeekType.cs | 2 +- .../src/Types.NodaTime/LocalDateTimeType.cs | 2 +- .../Core/src/Types.NodaTime/LocalDateType.cs | 2 +- .../Core/src/Types.NodaTime/LocalTimeType.cs | 2 +- .../src/Types.NodaTime/OffsetDateTimeType.cs | 2 +- .../Core/src/Types.NodaTime/OffsetDateType.cs | 2 +- .../Core/src/Types.NodaTime/OffsetTimeType.cs | 2 +- .../Core/src/Types.NodaTime/OffsetType.cs | 2 +- .../Core/src/Types.NodaTime/PeriodType.cs | 2 +- .../src/Types.NodaTime/ZonedDateTimeType.cs | 2 +- .../src/Types.Scalars.Upload/UploadType.cs | 2 +- .../src/Types.Scalars/EmailAddressType.cs | 4 +- .../Core/src/Types.Scalars/HexColorType.cs | 4 +- .../Core/src/Types.Scalars/HslType.cs | 4 +- .../Core/src/Types.Scalars/HslaType.cs | 4 +- .../Core/src/Types.Scalars/IPv4Type.cs | 4 +- .../Core/src/Types.Scalars/IPv6Type.cs | 4 +- .../Core/src/Types.Scalars/IsbnType.cs | 4 +- .../Core/src/Types.Scalars/LatitudeType.cs | 4 +- .../src/Types.Scalars/LocalCurrencyType.cs | 2 +- .../Core/src/Types.Scalars/LongitudeType.cs | 4 +- .../Core/src/Types.Scalars/MacAddressType.cs | 4 +- .../src/Types.Scalars/NegativeFloatType.cs | 6 +- .../Core/src/Types.Scalars/NegativeIntType.cs | 6 +- .../src/Types.Scalars/NonEmptyStringType.cs | 6 +- .../src/Types.Scalars/NonNegativeFloatType.cs | 6 +- .../src/Types.Scalars/NonNegativeIntType.cs | 6 +- .../src/Types.Scalars/NonPositiveFloatType.cs | 6 +- .../src/Types.Scalars/NonPositiveIntType.cs | 6 +- .../Core/src/Types.Scalars/PhoneNumberType.cs | 4 +- .../Core/src/Types.Scalars/PortType.cs | 6 +- .../Core/src/Types.Scalars/PositiveIntType.cs | 4 +- .../Core/src/Types.Scalars/PostalCodeType.cs | 6 +- .../Core/src/Types.Scalars/RegexType.cs | 6 +- .../Core/src/Types.Scalars/RgbType.cs | 4 +- .../Core/src/Types.Scalars/RgbaType.cs | 4 +- .../Core/src/Types.Scalars/SignedByteType.cs | 6 +- .../Core/src/Types.Scalars/ThrowHelper.cs | 240 +++---- .../Core/src/Types.Scalars/UnsignedIntType.cs | 6 +- .../src/Types.Scalars/UnsignedLongType.cs | 6 +- .../src/Types.Scalars/UnsignedShortType.cs | 6 +- .../Core/src/Types.Scalars/UtcOffsetType.cs | 2 +- .../Processing/MiddlewareContext.Arguments.cs | 4 +- .../OperationCompiler.CoerceArgumentValues.cs | 2 +- .../OperationCompiler.CompileResolver.cs | 4 +- .../Processing/ValueCompletion.Leaf.cs | 6 +- .../Execution/Processing/ValueCompletion.cs | 2 +- .../Core/src/Types/Execution/ThrowHelper.cs | 2 +- .../Properties/TypeResources.Designer.cs | 672 +++++++++--------- .../src/Types/Properties/TypeResources.resx | 4 +- .../Properties/TypeResourcesExtensions.cs | 39 +- .../Composite/Types/FieldSelectionMapType.cs | 4 +- .../Composite/Types/FieldSelectionSetType.cs | 4 +- .../src/Types/Types/Contracts/ILeafType.cs | 158 ++-- ...nException.cs => LeafCoercionException.cs} | 10 +- .../src/Types/Types/DirectiveCollection.cs | 2 +- .../Core/src/Types/Types/EnumType.cs | 20 +- .../Types/Types/Extensions/TypeExtensions.cs | 2 +- .../Core/src/Types/Types/InputFormatter.cs | 12 +- .../Core/src/Types/Types/InputParser.cs | 14 +- .../Core/src/Types/Types/Scalars/AnyType.cs | 137 ++-- .../src/Types/Types/Scalars/BooleanType.cs | 51 +- .../src/Types/Types/Scalars/ByteArrayType.cs | 4 +- .../src/Types/Types/Scalars/DateTimeType.cs | 8 +- .../Core/src/Types/Types/Scalars/DateType.cs | 8 +- .../src/Types/Types/Scalars/FloatTypeBase.cs | 20 +- .../Core/src/Types/Types/Scalars/IdType.cs | 18 +- .../Types/Types/Scalars/IntegerTypeBase.cs | 4 +- .../Core/src/Types/Types/Scalars/JsonType.cs | 12 +- .../Types/Types/Scalars/LocalDateTimeType.cs | 8 +- .../src/Types/Types/Scalars/LocalDateType.cs | 8 +- .../src/Types/Types/Scalars/LocalTimeType.cs | 8 +- .../src/Types/Types/Scalars/ScalarType.cs | 255 +++---- .../src/Types/Types/Scalars/ScalarType~1.cs | 84 ++- .../src/Types/Types/Scalars/ScalarType~2.cs | 199 +++--- .../src/Types/Types/Scalars/StringType.cs | 2 +- .../src/Types/Types/Scalars/TimeSpanType.cs | 10 +- .../Core/src/Types/Types/Scalars/UrlType.cs | 8 +- .../Core/src/Types/Types/Scalars/UuidType.cs | 14 +- .../Core/src/Types/Utilities/ErrorHelper.cs | 2 +- .../Core/src/Types/Utilities/ThrowHelper.cs | 52 +- .../Processing/VariableCoercionHelperTests.cs | 6 +- .../ScalarExecutionErrorTests.cs | 20 +- .../Types.Scalars.Tests/LatitudeTypeTests.cs | 42 +- .../LocalCurrencyTypeTests.cs | 30 +- .../Types.Scalars.Tests/LongitudeTypeTests.cs | 42 +- .../Types.Scalars.Tests/ScalarTypeTestBase.cs | 20 +- .../Types.Scalars.Tests/UtcOffsetTypeTests.cs | 24 +- .../Configuration/SchemaTypeDiscoveryTests.cs | 8 +- .../test/Types.Tests/Types/EnumTypeTests.cs | 2 +- .../Types.Tests/Types/InputCoercionTests.cs | 12 +- .../Types.Tests/Types/InputParserTests.cs | 18 +- .../Types.Tests/Types/Scalars/AnyTypeTests.cs | 38 +- .../Types/Scalars/BooleanTypeTests.cs | 12 +- .../Types/Scalars/ByteArrayTypeTests.cs | 24 +- .../Types/Scalars/ByteTypeTests.cs | 34 +- .../Types/Scalars/DateTimeTypeTests.cs | 16 +- .../Types/Scalars/DateTypeTests.cs | 12 +- .../Types/Scalars/DecimalTypeTests.cs | 40 +- .../Types/Scalars/FloatTypeTests.cs | 40 +- .../Types.Tests/Types/Scalars/IdTypeTests.cs | 32 +- .../Types.Tests/Types/Scalars/IntTypeTests.cs | 34 +- .../Types/Scalars/LocalDateTimeTypeTests.cs | 12 +- .../Types/Scalars/LocalDateTypeTests.cs | 18 +- .../Types/Scalars/LocalTimeTypeTests.cs | 12 +- .../Types/Scalars/LongTypeTests.cs | 34 +- .../Types/Scalars/ScalarBindingTests.cs | 12 +- .../Types/Scalars/ShortTypeTests.cs | 34 +- .../Types/Scalars/StringTypeTests.cs | 26 +- .../Types/Scalars/TimeSpanTypeTests.cs | 8 +- .../Types.Tests/Types/Scalars/UrlTypeTests.cs | 20 +- .../Types/Scalars/UuidTypeTests.cs | 44 +- .../Validation.Tests/Types/InvalidScalar.cs | 6 +- .../Data/src/Data/Sorting/SortEnumType.cs | 2 +- .../FusionScalarTypeDefinition.cs | 2 +- .../InaccessibleTests.cs | 8 +- .../MongoDb/src/Types/BsonType.cs | 16 +- .../MongoDb/src/Types/ObjectIdType.cs | 2 +- .../MongoDb/src/Types/ThrowHelper.cs | 4 +- .../test/Types.MongoDb/BsonTypeTests.cs | 30 +- .../MutableScalarTypeDefinition.cs | 2 +- .../src/Types/GeoJsonCoordinatesType.cs | 8 +- .../Spatial/src/Types/GeoJsonPositionType.cs | 8 +- .../Spatial/src/Types/GeometryType.cs | 8 +- .../Types/Serialization/IGeoJsonSerializer.cs | 6 +- .../Spatial/src/Types/ThrowHelper.cs | 48 +- .../GeoJsonLineStringInputTests.cs | 8 +- .../GeoJsonLineStringSerializerTests.cs | 20 +- .../GeoJsonMultiLineStringInputTests.cs | 8 +- .../GeoJsonMultiLineStringSerializerTests.cs | 20 +- .../GeoJsonMultiPointInputTests.cs | 8 +- .../GeoJsonMultiPointSerializerTests.cs | 20 +- .../GeoJsonMultiPolygonInputTests.cs | 8 +- .../GeoJsonMultiPolygonSerializerTests.cs | 20 +- .../Types.Tests/GeoJsonPointInputTests.cs | 10 +- .../GeoJsonPointSerializerTests.cs | 22 +- .../Types.Tests/GeoJsonPolygonInputTests.cs | 8 +- .../GeoJsonPolygonSerializerTests.cs | 20 +- .../Types.Tests/GeoJsonPositionScalarTest.cs | 40 +- .../Types.Tests/GeoJsonTypeSerializerTests.cs | 4 +- 155 files changed, 1675 insertions(+), 1802 deletions(-) rename src/HotChocolate/Core/src/Types/Types/Contracts/{SerializationException.cs => LeafCoercionException.cs} (78%) diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Resolvers/ArgumentParser.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Resolvers/ArgumentParser.cs index d61e7af3b56..01db89dec51 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Resolvers/ArgumentParser.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Resolvers/ArgumentParser.cs @@ -69,7 +69,7 @@ private static bool TryGetValue( break; } - var literal = scalarType.ParseLiteral(valueNode)!; + var literal = scalarType.CoerceInputLiteral(valueNode)!; if (DefaultTypeConverter.Default.TryConvert(typeof(T), literal, out var converted)) { @@ -85,7 +85,7 @@ private static bool TryGetValue( break; } - value = (T)enumType.ParseLiteral(valueNode)!; + value = (T)enumType.CoerceInputLiteral(valueNode)!; return true; } diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/ThrowHelper.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/ThrowHelper.cs index 41ff2c52ef4..fbaf9dec6a8 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/ThrowHelper.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/ThrowHelper.cs @@ -14,9 +14,9 @@ internal static class ThrowHelper /// Either the syntax node is invalid when parsing the literal or the syntax /// node value has an invalid format. /// - public static SerializationException FieldSet_InvalidFormat( + public static LeafCoercionException FieldSet_InvalidFormat( FieldSetType fieldSetType) => - new SerializationException( + new LeafCoercionException( ErrorBuilder.New() .SetMessage(ThrowHelper_FieldSet_HasInvalidFormat) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -27,9 +27,9 @@ public static SerializationException FieldSet_InvalidFormat( /// Either the syntax node is invalid when parsing the literal or the syntax /// node value has an invalid format. /// - public static SerializationException Any_InvalidFormat( + public static LeafCoercionException Any_InvalidFormat( _AnyType anyType) => - new SerializationException( + new LeafCoercionException( ErrorBuilder.New() .SetMessage(ThrowHelper_Any_HasInvalidFormat) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -70,10 +70,10 @@ public static SchemaException ReferenceResolverAttribute_EntityResolverNotFound( /// /// The runtime type is not supported by the scalars ParseValue method. /// - public static SerializationException Scalar_CannotParseValue( + public static LeafCoercionException Scalar_CannotParseValue( ScalarType scalarType, Type valueType) => - new SerializationException( + new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_Scalar_CannotParseValue, diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/FieldSetType.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/FieldSetType.cs index 2c71e547780..babcb23d4e3 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/FieldSetType.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/FieldSetType.cs @@ -78,7 +78,7 @@ public override IValueNode ParseResult(object? resultValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/PolicyType.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/PolicyType.cs index 182e03f3718..bc3c331a409 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/PolicyType.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/PolicyType.cs @@ -34,7 +34,7 @@ protected override Policy ParseLiteral(StringValueNode valueSyntax) => new(valueSyntax.Value); public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); protected override StringValueNode ParseValue(Policy runtimeValue) => new(runtimeValue.Value); diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/ScopeType.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/ScopeType.cs index bedf8f2c8f0..fd89000a6bc 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/ScopeType.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/ScopeType.cs @@ -34,7 +34,7 @@ protected override Scope ParseLiteral(StringValueNode valueSyntax) => new(valueSyntax.Value); public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); protected override StringValueNode ParseValue(Scope runtimeValue) => new(runtimeValue.Value); diff --git a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/_AnyType.cs b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/_AnyType.cs index 5e81e1403c4..0c64385f22f 100644 --- a/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/_AnyType.cs +++ b/src/HotChocolate/ApolloFederation/src/ApolloFederation/Types/_AnyType.cs @@ -73,7 +73,7 @@ protected override Representation ParseLiteral(ObjectValueNode valueSyntax) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -83,7 +83,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) if (runtimeValue is Representation) { - resultValue = ParseValue(runtimeValue); + resultValue = CoerceInputValue(runtimeValue); return true; } diff --git a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/FieldSetTypeTests.cs b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/FieldSetTypeTests.cs index 9e4130a489a..400e959b62f 100644 --- a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/FieldSetTypeTests.cs +++ b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/FieldSetTypeTests.cs @@ -44,7 +44,7 @@ public void Deserialize_Invalid_Format() void Action() => type.Deserialize(serialized); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -131,7 +131,7 @@ public void Serialize_Invalid_Format() void Action() => type.Serialize(1); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -143,7 +143,7 @@ public void TrySerialize() var selectionSet = Syntax.ParseSelectionSet(Braces(selection)); // act - var success = type.TrySerialize(selectionSet, out var serialized); + var success = type.TryCoerceOutputValue(selectionSet, out var serialized); // assert Assert.True(success); @@ -157,7 +157,7 @@ public void TrySerialize_Invalid_Format() var type = new FieldSetType(); // act - var success = type.TrySerialize(1, out var serialized); + var success = type.TryCoerceOutputValue(1, out var serialized); // assert Assert.False(success); @@ -203,9 +203,9 @@ public void ParseValue_InvalidValue() var type = new FieldSetType(); // act - void Action() => type.ParseValue(1); + void Action() => type.CoerceInputValue(1); // assert - Assert.Throws(Action); + Assert.Throws(Action); } } diff --git a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/_AnyTypeTests.cs b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/_AnyTypeTests.cs index 57571e2f770..f2722ea7256 100644 --- a/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/_AnyTypeTests.cs +++ b/src/HotChocolate/ApolloFederation/test/ApolloFederation.Tests/_AnyTypeTests.cs @@ -80,7 +80,7 @@ public void Deserialize_Invalid_Format() void Action() => type.Deserialize(serialized); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -166,7 +166,7 @@ public void Serialize_Invalid_Format() void Action() => type.Serialize(1); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -187,7 +187,7 @@ public void TrySerialize() var representation = new Representation("test", objectValueNode); // act - var success = type.TrySerialize(representation, out var serialized); + var success = type.TryCoerceOutputValue(representation, out var serialized); // assert Assert.True(success); @@ -204,7 +204,7 @@ public void TrySerialize_Invalid_Type() var type = new AnyType(); // act - var success = type.TrySerialize(1, out var serialized); + var success = type.TryCoerceOutputValue(1, out var serialized); // assert Assert.False(success); @@ -218,7 +218,7 @@ public void TrySerialize_Invalid_Null() var type = new AnyType(); // act - var success = type.TrySerialize(null, out var serialized); + var success = type.TryCoerceOutputValue(null, out var serialized); // assert Assert.True(success); @@ -269,7 +269,7 @@ public void ParseLiteral() ); // act - var valueSyntax = type.ParseLiteral(objectValueNode); + var valueSyntax = type.CoerceInputLiteral(objectValueNode); // assert var parsedRepresentation = Assert.IsType(valueSyntax); @@ -284,10 +284,10 @@ public void ParseLiteral_InvalidValue() var type = new AnyType(); // act - void Action() => type.ParseLiteral(new ObjectValueNode()); + void Action() => type.CoerceInputLiteral(new ObjectValueNode()); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -340,7 +340,7 @@ public void ParseResult_InvalidValue() void Action() => type.ParseResult(new ObjectValueNode()); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -363,9 +363,9 @@ public void ParseValue_InvalidValue() var type = new AnyType(); // act - void Action() => type.ParseValue(1); + void Action() => type.CoerceInputValue(1); // assert - Assert.Throws(Action); + Assert.Throws(Action); } } diff --git a/src/HotChocolate/Core/src/Types.Abstractions/Types/IScalarTypeDefinition.cs b/src/HotChocolate/Core/src/Types.Abstractions/Types/IScalarTypeDefinition.cs index e12e053baf7..7b69a7c29dc 100644 --- a/src/HotChocolate/Core/src/Types.Abstractions/Types/IScalarTypeDefinition.cs +++ b/src/HotChocolate/Core/src/Types.Abstractions/Types/IScalarTypeDefinition.cs @@ -33,5 +33,5 @@ public interface IScalarTypeDefinition /// /// true if the value is an instance of this type; otherwise, false. /// - bool IsInstanceOfType(IValueNode value); + bool IsValueCompatible(IValueNode value); } diff --git a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/IntToStructBaseType.cs b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/IntToStructBaseType.cs index 1eba389ac97..6f09d37f8c6 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/IntToStructBaseType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/IntToStructBaseType.cs @@ -34,7 +34,7 @@ protected override TRuntimeType ParseLiteral(IntValueNode literal) return value.Value; } - throw new SerializationException( + throw new LeafCoercionException( string.Format(IntToStructBaseType_ParseLiteral_UnableToDeserializeInt, Name), this); } @@ -42,12 +42,12 @@ protected override TRuntimeType ParseLiteral(IntValueNode literal) /// protected override IntValueNode ParseValue(TRuntimeType value) { - if (TrySerialize(value, out var val)) + if (TryCoerceOutputValue(value, out var val)) { return new IntValueNode(val.Value); } - throw new SerializationException( + throw new LeafCoercionException( string.Format(IntToStructBaseType_ParseLiteral_UnableToDeserializeInt, Name), this); } @@ -70,13 +70,13 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(v); } - throw new SerializationException( + throw new LeafCoercionException( string.Format(IntToStructBaseType_ParseLiteral_UnableToDeserializeInt, Name), this); } /// - public override bool TrySerialize( + public override bool TryCoerceOutputValue( object? runtimeValue, out object? resultValue) { @@ -86,7 +86,7 @@ public override bool TrySerialize( return true; } - if (runtimeValue is TRuntimeType dt && TrySerialize(dt, out var val)) + if (runtimeValue is TRuntimeType dt && TryCoerceOutputValue(dt, out var val)) { resultValue = val.Value; return true; @@ -109,7 +109,7 @@ public override bool TrySerialize( /// /// Returns the serialized result value. /// - protected abstract bool TrySerialize( + protected abstract bool TryCoerceOutputValue( TRuntimeType runtimeValue, [NotNullWhen(true)] out int? resultValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToClassBaseType.cs b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToClassBaseType.cs index 7e176ff5698..8dfeac1194c 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToClassBaseType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToClassBaseType.cs @@ -34,14 +34,14 @@ protected override TRuntimeType ParseLiteral(StringValueNode literal) return value; } - throw new SerializationException( + throw new LeafCoercionException( string.Format(StringToClassBaseType_ParseLiteral_UnableToDeserializeString, Name), this); } /// protected override StringValueNode ParseValue(TRuntimeType value) => - new(Serialize(value)); + new(CoerceOutputValue(value)); /// public override IValueNode ParseResult(object? resultValue) @@ -61,13 +61,13 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(v); } - throw new SerializationException( + throw new LeafCoercionException( string.Format(StringToClassBaseType_ParseLiteral_UnableToDeserializeString, Name), this); } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -77,7 +77,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) if (runtimeValue is TRuntimeType dt) { - resultValue = Serialize(dt); + resultValue = CoerceOutputValue(dt); return true; } @@ -94,7 +94,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) /// /// Returns the serialized result value. /// - protected abstract string Serialize(TRuntimeType runtimeValue); + protected abstract string CoerceOutputValue(TRuntimeType runtimeValue); /// public override bool TryDeserialize(object? resultValue, out object? runtimeValue) diff --git a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToStructBaseType.cs b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToStructBaseType.cs index b8b93e28a5c..565bccc72c5 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToStructBaseType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/BaseTypes/StringToStructBaseType.cs @@ -35,7 +35,7 @@ protected override TRuntimeType ParseLiteral(StringValueNode literal) return value.Value; } - throw new SerializationException( + throw new LeafCoercionException( string.Format(StringToStructBaseType_ParseLiteral_UnableToDeserializeString, Name), this); } @@ -43,7 +43,7 @@ protected override TRuntimeType ParseLiteral(StringValueNode literal) /// protected override StringValueNode ParseValue(TRuntimeType value) { - return new(Serialize(value)); + return new(CoerceOutputValue(value)); } /// @@ -64,13 +64,13 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(v); } - throw new SerializationException( + throw new LeafCoercionException( string.Format(StringToStructBaseType_ParseLiteral_UnableToDeserializeString, Name), this); } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -80,7 +80,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) if (runtimeValue is TRuntimeType dt) { - resultValue = Serialize(dt); + resultValue = CoerceOutputValue(dt); return true; } @@ -97,7 +97,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) /// /// Returns the serialized result value. /// - protected abstract string Serialize(TRuntimeType runtimeValue); + protected abstract string CoerceOutputValue(TRuntimeType runtimeValue); /// public override bool TryDeserialize(object? resultValue, out object? runtimeValue) diff --git a/src/HotChocolate/Core/src/Types.NodaTime/DateTimeZoneType.cs b/src/HotChocolate/Core/src/Types.NodaTime/DateTimeZoneType.cs index 195f1b765ca..3e621af3e6f 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/DateTimeZoneType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/DateTimeZoneType.cs @@ -22,7 +22,7 @@ public DateTimeZoneType() : base("DateTimeZone") } /// - protected override string Serialize(DateTimeZone runtimeValue) + protected override string CoerceOutputValue(DateTimeZone runtimeValue) => runtimeValue.Id; /// diff --git a/src/HotChocolate/Core/src/Types.NodaTime/DurationType.cs b/src/HotChocolate/Core/src/Types.NodaTime/DurationType.cs index 0bc26920264..4e6e31af7d9 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/DurationType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/DurationType.cs @@ -42,7 +42,7 @@ public DurationType() : this(DurationPattern.Roundtrip) } /// - protected override string Serialize(Duration runtimeValue) + protected override string CoerceOutputValue(Duration runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/InstantType.cs b/src/HotChocolate/Core/src/Types.NodaTime/InstantType.cs index 2eaa2e30f0b..eefe7634e91 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/InstantType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/InstantType.cs @@ -42,7 +42,7 @@ public InstantType() : this(InstantPattern.ExtendedIso) } /// - protected override string Serialize(Instant runtimeValue) + protected override string CoerceOutputValue(Instant runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/IsoDayOfWeekType.cs b/src/HotChocolate/Core/src/Types.NodaTime/IsoDayOfWeekType.cs index cb6c12d558b..fab77c48e20 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/IsoDayOfWeekType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/IsoDayOfWeekType.cs @@ -21,7 +21,7 @@ public IsoDayOfWeekType() : base("IsoDayOfWeek") } /// - protected override bool TrySerialize( + protected override bool TryCoerceOutputValue( IsoDayOfWeek runtimeValue, [NotNullWhen(true)] out int? resultValue) { diff --git a/src/HotChocolate/Core/src/Types.NodaTime/LocalDateTimeType.cs b/src/HotChocolate/Core/src/Types.NodaTime/LocalDateTimeType.cs index 346456a3fa8..263b6b6c843 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/LocalDateTimeType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/LocalDateTimeType.cs @@ -42,7 +42,7 @@ public LocalDateTimeType() : this(LocalDateTimePattern.ExtendedIso) } /// - protected override string Serialize(LocalDateTime runtimeValue) + protected override string CoerceOutputValue(LocalDateTime runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/LocalDateType.cs b/src/HotChocolate/Core/src/Types.NodaTime/LocalDateType.cs index aa45c479de2..264776a39d9 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/LocalDateType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/LocalDateType.cs @@ -43,7 +43,7 @@ public LocalDateType() : this(LocalDatePattern.Iso) } /// - protected override string Serialize(LocalDate runtimeValue) + protected override string CoerceOutputValue(LocalDate runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/LocalTimeType.cs b/src/HotChocolate/Core/src/Types.NodaTime/LocalTimeType.cs index d516e4c3780..f64c4bf2849 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/LocalTimeType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/LocalTimeType.cs @@ -43,7 +43,7 @@ public LocalTimeType() : this(LocalTimePattern.ExtendedIso) } /// - protected override string Serialize(LocalTime runtimeValue) + protected override string CoerceOutputValue(LocalTime runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateTimeType.cs b/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateTimeType.cs index cb21cb74611..371c1705810 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateTimeType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateTimeType.cs @@ -46,7 +46,7 @@ public OffsetDateTimeType() : this(OffsetDateTimePattern.ExtendedIso) } /// - protected override string Serialize(OffsetDateTime runtimeValue) + protected override string CoerceOutputValue(OffsetDateTime runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateType.cs b/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateType.cs index 435c596a609..d12fc4aa279 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/OffsetDateType.cs @@ -44,7 +44,7 @@ public OffsetDateType() : this(OffsetDatePattern.GeneralIso) } /// - protected override string Serialize(OffsetDate runtimeValue) + protected override string CoerceOutputValue(OffsetDate runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/OffsetTimeType.cs b/src/HotChocolate/Core/src/Types.NodaTime/OffsetTimeType.cs index aecc2c79c78..48ae0b99ef5 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/OffsetTimeType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/OffsetTimeType.cs @@ -43,7 +43,7 @@ public OffsetTimeType() : this(OffsetTimePattern.GeneralIso) } /// - protected override string Serialize(OffsetTime runtimeValue) + protected override string CoerceOutputValue(OffsetTime runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/OffsetType.cs b/src/HotChocolate/Core/src/Types.NodaTime/OffsetType.cs index c6a36d32458..2974bcd6c2b 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/OffsetType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/OffsetType.cs @@ -44,7 +44,7 @@ public OffsetType() : this(OffsetPattern.GeneralInvariantWithZ) } /// - protected override string Serialize(Offset runtimeValue) + protected override string CoerceOutputValue(Offset runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.NodaTime/PeriodType.cs b/src/HotChocolate/Core/src/Types.NodaTime/PeriodType.cs index 7c346cd814c..5364fb9f291 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/PeriodType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/PeriodType.cs @@ -39,7 +39,7 @@ public PeriodType() : this(PeriodPattern.Roundtrip) } /// - protected override string Serialize(Period runtimeValue) + protected override string CoerceOutputValue(Period runtimeValue) => _serializationPattern.Format(runtimeValue); /// diff --git a/src/HotChocolate/Core/src/Types.NodaTime/ZonedDateTimeType.cs b/src/HotChocolate/Core/src/Types.NodaTime/ZonedDateTimeType.cs index 33b93edae13..17e27b31935 100644 --- a/src/HotChocolate/Core/src/Types.NodaTime/ZonedDateTimeType.cs +++ b/src/HotChocolate/Core/src/Types.NodaTime/ZonedDateTimeType.cs @@ -49,7 +49,7 @@ public ZonedDateTimeType() : this(s_default) } /// - protected override string Serialize(ZonedDateTime runtimeValue) + protected override string CoerceOutputValue(ZonedDateTime runtimeValue) => _serializationPattern .Format(runtimeValue); diff --git a/src/HotChocolate/Core/src/Types.Scalars.Upload/UploadType.cs b/src/HotChocolate/Core/src/Types.Scalars.Upload/UploadType.cs index be90ec49db3..069495feaef 100644 --- a/src/HotChocolate/Core/src/Types.Scalars.Upload/UploadType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars.Upload/UploadType.cs @@ -54,7 +54,7 @@ protected override IFile ParseLiteral(FileValueNode valueSyntax) => protected override FileValueNode ParseValue(IFile runtimeValue) => new(runtimeValue); - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { throw new GraphQLException( UploadResources.UploadType_TrySerialize_NotSupported); diff --git a/src/HotChocolate/Core/src/Types.Scalars/EmailAddressType.cs b/src/HotChocolate/Core/src/Types.Scalars/EmailAddressType.cs index b30e35b6f9f..6af11a10714 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/EmailAddressType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/EmailAddressType.cs @@ -45,10 +45,10 @@ public EmailAddressType() { } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) => ThrowHelper.EmailAddressType_ParseLiteral_IsInvalid(this); /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) => ThrowHelper.EmailAddressType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/HexColorType.cs b/src/HotChocolate/Core/src/Types.Scalars/HexColorType.cs index 67c7b7bb872..2ba59e5a306 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/HexColorType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/HexColorType.cs @@ -42,13 +42,13 @@ public HexColorType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.HexColorType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.HexColorType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/HslType.cs b/src/HotChocolate/Core/src/Types.Scalars/HslType.cs index 66f40f9ca8e..61f000cde83 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/HslType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/HslType.cs @@ -42,13 +42,13 @@ public HslType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.HslType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.HslType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/HslaType.cs b/src/HotChocolate/Core/src/Types.Scalars/HslaType.cs index c5e65cbbf56..ae1c9dbdbdc 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/HslaType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/HslaType.cs @@ -42,13 +42,13 @@ public HslaType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.HslaType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.HslaType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/IPv4Type.cs b/src/HotChocolate/Core/src/Types.Scalars/IPv4Type.cs index 958369860e6..207f56d2f57 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/IPv4Type.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/IPv4Type.cs @@ -44,13 +44,13 @@ public IPv4Type() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.IPv4Type_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.IPv4Type_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/IPv6Type.cs b/src/HotChocolate/Core/src/Types.Scalars/IPv6Type.cs index b33c66c89e4..d5ad1972d48 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/IPv6Type.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/IPv6Type.cs @@ -63,10 +63,10 @@ public IPv6Type() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) => ThrowHelper.IPv6Type_ParseLiteral_IsInvalid(this); /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) => ThrowHelper.IPv6Type_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/IsbnType.cs b/src/HotChocolate/Core/src/Types.Scalars/IsbnType.cs index 2883ef4d8fa..2e68950fb04 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/IsbnType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/IsbnType.cs @@ -47,13 +47,13 @@ public IsbnType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.IsbnType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.IsbnType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/LatitudeType.cs b/src/HotChocolate/Core/src/Types.Scalars/LatitudeType.cs index 46dd5e1f75d..0f3d989ee1b 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/LatitudeType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/LatitudeType.cs @@ -46,7 +46,7 @@ public override IValueNode ParseResult(object? resultValue) null => NullValueNode.Default, string s when Latitude.TryDeserialize(s, out var runtimeValue) => - ParseValue(runtimeValue), + CoerceInputValue(runtimeValue), int i => ParseValue(i), @@ -79,7 +79,7 @@ protected override StringValueNode ParseValue(double runtimeValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types.Scalars/LocalCurrencyType.cs b/src/HotChocolate/Core/src/Types.Scalars/LocalCurrencyType.cs index 0995384f83b..1d18658a3e1 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/LocalCurrencyType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/LocalCurrencyType.cs @@ -67,7 +67,7 @@ protected override StringValueNode ParseValue(decimal runtimeValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types.Scalars/LongitudeType.cs b/src/HotChocolate/Core/src/Types.Scalars/LongitudeType.cs index e359270416d..f327853435b 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/LongitudeType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/LongitudeType.cs @@ -46,7 +46,7 @@ public override IValueNode ParseResult(object? resultValue) null => NullValueNode.Default, string s when Longitude.TryDeserialize(s, out var runtimeValue) => - ParseValue(runtimeValue), + CoerceInputValue(runtimeValue), int i => ParseValue(i), @@ -79,7 +79,7 @@ protected override StringValueNode ParseValue(double runtimeValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types.Scalars/MacAddressType.cs b/src/HotChocolate/Core/src/Types.Scalars/MacAddressType.cs index 70e78496963..d1e6244cbc6 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/MacAddressType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/MacAddressType.cs @@ -58,13 +58,13 @@ public MacAddressType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.MacAddressType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.MacAddressType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NegativeFloatType.cs b/src/HotChocolate/Core/src/Types.Scalars/NegativeFloatType.cs index bd884ae247e..6564cc96ff1 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NegativeFloatType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NegativeFloatType.cs @@ -42,19 +42,19 @@ protected override bool IsInstanceOfType(IFloatValueLiteral valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateParseLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NegativeFloatType_ParseLiteral_IsNotNegative(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NegativeFloatType_ParseValue_IsNotNegative(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NegativeFloatType_ParseValue_IsNotNegative(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NegativeIntType.cs b/src/HotChocolate/Core/src/Types.Scalars/NegativeIntType.cs index eccc5106f63..467e8125b87 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NegativeIntType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NegativeIntType.cs @@ -44,19 +44,19 @@ protected override bool IsInstanceOfType(IntValueNode valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NegativeIntType_ParseLiteral_IsNotNegative(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NegativeIntType_ParseValue_IsNotNegative(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NegativeIntType_ParseValue_IsNotNegative(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NonEmptyStringType.cs b/src/HotChocolate/Core/src/Types.Scalars/NonEmptyStringType.cs index a297a163525..41e480e22f1 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NonEmptyStringType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NonEmptyStringType.cs @@ -43,7 +43,7 @@ protected override bool IsInstanceOfType(StringValueNode valueSyntax) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is string s && s == string.Empty) { @@ -71,13 +71,13 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NonEmptyStringType_ParseLiteral_IsEmpty(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NonEmptyStringType_ParseValue_IsEmpty(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NonNegativeFloatType.cs b/src/HotChocolate/Core/src/Types.Scalars/NonNegativeFloatType.cs index c438b551f13..08b7f3c6822 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NonNegativeFloatType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NonNegativeFloatType.cs @@ -43,19 +43,19 @@ protected override bool IsInstanceOfType(IFloatValueLiteral valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateParseLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NonNegativeFloatType_ParseLiteral_IsNotNonNegative(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NonNegativeFloatType_ParseValue_IsNotNonNegative(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NonNegativeFloatType_ParseValue_IsNotNonNegative(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NonNegativeIntType.cs b/src/HotChocolate/Core/src/Types.Scalars/NonNegativeIntType.cs index 197d55138df..ce4e47421b2 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NonNegativeIntType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NonNegativeIntType.cs @@ -43,19 +43,19 @@ protected override bool IsInstanceOfType(IntValueNode valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NonNegativeIntType_ParseLiteral_IsNotNonNegative(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NonNegativeIntType_ParseValue_IsNotNonNegative(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NonNegativeIntType_ParseValue_IsNotNonNegative(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NonPositiveFloatType.cs b/src/HotChocolate/Core/src/Types.Scalars/NonPositiveFloatType.cs index ee7bb982a77..055a4e9f2f2 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NonPositiveFloatType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NonPositiveFloatType.cs @@ -43,19 +43,19 @@ protected override bool IsInstanceOfType(IFloatValueLiteral valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateParseLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NonPositiveFloatType_ParseLiteral_IsNotNonPositive(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NonPositiveFloatType_ParseValue_IsNotNonPositive(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NonPositiveFloatType_ParseValue_IsNotNonPositive(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/NonPositiveIntType.cs b/src/HotChocolate/Core/src/Types.Scalars/NonPositiveIntType.cs index 37fc786d7f4..19077bd6ac9 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/NonPositiveIntType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/NonPositiveIntType.cs @@ -43,19 +43,19 @@ protected override bool IsInstanceOfType(IntValueNode valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.NonPositiveIntType_ParseLiteral_IsNotNonPositive(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.NonPositiveIntType_ParseValue_IsNotNonPositive(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.NonPositiveIntType_ParseValue_IsNotNonPositive(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/PhoneNumberType.cs b/src/HotChocolate/Core/src/Types.Scalars/PhoneNumberType.cs index d7eb96b52d1..62cd8163647 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/PhoneNumberType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/PhoneNumberType.cs @@ -44,13 +44,13 @@ public PhoneNumberType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.PhoneNumber_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.PhoneNumber_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/PortType.cs b/src/HotChocolate/Core/src/Types.Scalars/PortType.cs index a63ed3c21bd..bc00e0de99e 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/PortType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/PortType.cs @@ -46,19 +46,19 @@ protected override bool IsInstanceOfType(IntValueNode valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.PortType_ParseLiteral_OutOfRange(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.PortType_ParseValue_OutOfRange(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.PortType_ParseValue_OutOfRange(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/PositiveIntType.cs b/src/HotChocolate/Core/src/Types.Scalars/PositiveIntType.cs index 97423ffa952..bd07e6ddc0e 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/PositiveIntType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/PositiveIntType.cs @@ -37,13 +37,13 @@ protected override bool IsInstanceOfType(IntValueNode valueSyntax) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.PositiveIntType_ParseLiteral_ZeroOrLess(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.PositiveIntType_ParseValue_ZeroOrLess(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/PostalCodeType.cs b/src/HotChocolate/Core/src/Types.Scalars/PostalCodeType.cs index d6a984fae1e..a7d6a1e600e 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/PostalCodeType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/PostalCodeType.cs @@ -183,7 +183,7 @@ protected override bool IsInstanceOfType(StringValueNode valueSyntax) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -223,13 +223,13 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.PostalCodeType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.PostalCodeType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/RegexType.cs b/src/HotChocolate/Core/src/Types.Scalars/RegexType.cs index a55a4b09b5c..c353f80e68f 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/RegexType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/RegexType.cs @@ -55,7 +55,7 @@ protected override bool IsInstanceOfType(StringValueNode valueSyntax) => _validationRegex.IsMatch(valueSyntax.Value); /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -95,10 +95,10 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) => ThrowHelper.RegexType_ParseLiteral_IsInvalid(this, Name); /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) => ThrowHelper.RegexType_ParseValue_IsInvalid(this, Name); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/RgbType.cs b/src/HotChocolate/Core/src/Types.Scalars/RgbType.cs index 86a4ea9375c..ff1cc9f42f8 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/RgbType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/RgbType.cs @@ -44,13 +44,13 @@ public RgbType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.RgbType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.RgbType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/RgbaType.cs b/src/HotChocolate/Core/src/Types.Scalars/RgbaType.cs index 5ee38b1f5fb..e6b41cc85f7 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/RgbaType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/RgbaType.cs @@ -42,13 +42,13 @@ public RgbaType() } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { return ThrowHelper.RgbaType_ParseLiteral_IsInvalid(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { return ThrowHelper.RgbaType_ParseValue_IsInvalid(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/SignedByteType.cs b/src/HotChocolate/Core/src/Types.Scalars/SignedByteType.cs index 7b526d715f2..a645ef8968c 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/SignedByteType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/SignedByteType.cs @@ -56,19 +56,19 @@ protected override IntValueNode ParseValue(sbyte runtimeValue) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.UnsignedIntType_ParseLiteral_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.UnsignedIntType_ParseValue_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.UnsignedIntType_ParseValue_IsNotUnsigned(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/ThrowHelper.cs b/src/HotChocolate/Core/src/Types.Scalars/ThrowHelper.cs index 620bf41dc56..95c19763292 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/ThrowHelper.cs @@ -2,9 +2,9 @@ namespace HotChocolate.Types; internal static class ThrowHelper { - public static SerializationException EmailAddressType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException EmailAddressType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.EmailAddressType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -13,9 +13,9 @@ public static SerializationException EmailAddressType_ParseLiteral_IsInvalid(ITy type); } - public static SerializationException EmailAddressType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException EmailAddressType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.EmailAddressType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -24,9 +24,9 @@ public static SerializationException EmailAddressType_ParseValue_IsInvalid(IType type); } - public static SerializationException HexColorType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException HexColorType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HexColorType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -35,9 +35,9 @@ public static SerializationException HexColorType_ParseValue_IsInvalid(IType typ type); } - public static SerializationException HexColorType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException HexColorType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HexColorType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -46,9 +46,9 @@ public static SerializationException HexColorType_ParseLiteral_IsInvalid(IType t type); } - public static SerializationException HslType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException HslType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HslType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -57,9 +57,9 @@ public static SerializationException HslType_ParseValue_IsInvalid(IType type) type); } - public static SerializationException HslType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException HslType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HslType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -68,9 +68,9 @@ public static SerializationException HslType_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException HslaType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException HslaType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HslaType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -79,9 +79,9 @@ public static SerializationException HslaType_ParseValue_IsInvalid(IType type) type); } - public static SerializationException HslaType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException HslaType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.HslaType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -90,9 +90,9 @@ public static SerializationException HslaType_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException IPv4Type_ParseValue_IsInvalid(IType type) + public static LeafCoercionException IPv4Type_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IPv4Type_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -101,9 +101,9 @@ public static SerializationException IPv4Type_ParseValue_IsInvalid(IType type) type); } - public static SerializationException IPv4Type_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException IPv4Type_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IPv4Type_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -112,9 +112,9 @@ public static SerializationException IPv4Type_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException IPv6Type_ParseValue_IsInvalid(IType type) + public static LeafCoercionException IPv6Type_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IPv6Type_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -123,9 +123,9 @@ public static SerializationException IPv6Type_ParseValue_IsInvalid(IType type) type); } - public static SerializationException IPv6Type_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException IPv6Type_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IPv6Type_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -134,9 +134,9 @@ public static SerializationException IPv6Type_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException IsbnType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException IsbnType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IsbnType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -145,9 +145,9 @@ public static SerializationException IsbnType_ParseValue_IsInvalid(IType type) type); } - public static SerializationException IsbnType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException IsbnType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.IsbnType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -156,9 +156,9 @@ public static SerializationException IsbnType_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException LatitudeType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException LatitudeType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LatitudeType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -167,9 +167,9 @@ public static SerializationException LatitudeType_ParseValue_IsInvalid(IType typ type); } - public static SerializationException LatitudeType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException LatitudeType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LatitudeType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -178,9 +178,9 @@ public static SerializationException LatitudeType_ParseLiteral_IsInvalid(IType t type); } - public static SerializationException LocalCurrencyType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException LocalCurrencyType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LocalCurrencyType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -189,9 +189,9 @@ public static SerializationException LocalCurrencyType_ParseValue_IsInvalid(ITyp type); } - public static SerializationException LocalCurrencyType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException LocalCurrencyType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LocalCurrencyType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -200,9 +200,9 @@ public static SerializationException LocalCurrencyType_ParseLiteral_IsInvalid(IT type); } - public static SerializationException LongitudeType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException LongitudeType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LongitudeType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -211,9 +211,9 @@ public static SerializationException LongitudeType_ParseValue_IsInvalid(IType ty type); } - public static SerializationException LongitudeType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException LongitudeType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.LongitudeType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -222,9 +222,9 @@ public static SerializationException LongitudeType_ParseLiteral_IsInvalid(IType type); } - public static SerializationException MacAddressType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException MacAddressType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.MacAddressType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -233,9 +233,9 @@ public static SerializationException MacAddressType_ParseValue_IsInvalid(IType t type); } - public static SerializationException MacAddressType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException MacAddressType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.MacAddressType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -244,10 +244,10 @@ public static SerializationException MacAddressType_ParseLiteral_IsInvalid(IType type); } - public static SerializationException NegativeFloatType_ParseLiteral_IsNotNegative( + public static LeafCoercionException NegativeFloatType_ParseLiteral_IsNotNegative( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NegativeFloatType_IsNotNegative_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -256,9 +256,9 @@ public static SerializationException NegativeFloatType_ParseLiteral_IsNotNegativ type); } - public static SerializationException NegativeFloatType_ParseValue_IsNotNegative(IType type) + public static LeafCoercionException NegativeFloatType_ParseValue_IsNotNegative(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NegativeFloatType_IsNotNegative_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -267,9 +267,9 @@ public static SerializationException NegativeFloatType_ParseValue_IsNotNegative( type); } - public static SerializationException NegativeIntType_ParseLiteral_IsNotNegative(IType type) + public static LeafCoercionException NegativeIntType_ParseLiteral_IsNotNegative(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NegativeIntType_IsNotNegative_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -278,9 +278,9 @@ public static SerializationException NegativeIntType_ParseLiteral_IsNotNegative( type); } - public static SerializationException NegativeIntType_ParseValue_IsNotNegative(IType type) + public static LeafCoercionException NegativeIntType_ParseValue_IsNotNegative(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NegativeIntType_IsNotNegative_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -289,9 +289,9 @@ public static SerializationException NegativeIntType_ParseValue_IsNotNegative(IT type); } - public static SerializationException NonEmptyStringType_ParseLiteral_IsEmpty(IType type) + public static LeafCoercionException NonEmptyStringType_ParseLiteral_IsEmpty(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonEmptyStringType_IsEmpty_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -300,9 +300,9 @@ public static SerializationException NonEmptyStringType_ParseLiteral_IsEmpty(ITy type); } - public static SerializationException NonEmptyStringType_ParseValue_IsEmpty(IType type) + public static LeafCoercionException NonEmptyStringType_ParseValue_IsEmpty(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonEmptyStringType_IsEmpty_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -311,10 +311,10 @@ public static SerializationException NonEmptyStringType_ParseValue_IsEmpty(IType type); } - public static SerializationException NonNegativeIntType_ParseLiteral_IsNotNonNegative( + public static LeafCoercionException NonNegativeIntType_ParseLiteral_IsNotNonNegative( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonNegativeIntType_IsNotNonNegative_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -323,10 +323,10 @@ public static SerializationException NonNegativeIntType_ParseLiteral_IsNotNonNeg type); } - public static SerializationException NonNegativeIntType_ParseValue_IsNotNonNegative( + public static LeafCoercionException NonNegativeIntType_ParseValue_IsNotNonNegative( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonNegativeIntType_IsNotNonNegative_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -335,10 +335,10 @@ public static SerializationException NonNegativeIntType_ParseValue_IsNotNonNegat type); } - public static SerializationException NonPositiveIntType_ParseLiteral_IsNotNonPositive( + public static LeafCoercionException NonPositiveIntType_ParseLiteral_IsNotNonPositive( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonPositiveIntType_IsNotNonPositive_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -347,10 +347,10 @@ public static SerializationException NonPositiveIntType_ParseLiteral_IsNotNonPos type); } - public static SerializationException NonPositiveFloatType_ParseLiteral_IsNotNonPositive( + public static LeafCoercionException NonPositiveFloatType_ParseLiteral_IsNotNonPositive( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonPositiveFloatType_IsNotNonPositive_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -359,10 +359,10 @@ public static SerializationException NonPositiveFloatType_ParseLiteral_IsNotNonP type); } - public static SerializationException NonPositiveFloatType_ParseValue_IsNotNonPositive( + public static LeafCoercionException NonPositiveFloatType_ParseValue_IsNotNonPositive( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonPositiveFloatType_IsNotNonPositive_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -371,10 +371,10 @@ public static SerializationException NonPositiveFloatType_ParseValue_IsNotNonPos type); } - public static SerializationException NonPositiveIntType_ParseValue_IsNotNonPositive( + public static LeafCoercionException NonPositiveIntType_ParseValue_IsNotNonPositive( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonPositiveIntType_IsNotNonPositive_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -383,10 +383,10 @@ public static SerializationException NonPositiveIntType_ParseValue_IsNotNonPosit type); } - public static SerializationException NonNegativeFloatType_ParseLiteral_IsNotNonNegative( + public static LeafCoercionException NonNegativeFloatType_ParseLiteral_IsNotNonNegative( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonNegativeFloatType_IsNotNonNegative_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -395,10 +395,10 @@ public static SerializationException NonNegativeFloatType_ParseLiteral_IsNotNonN type); } - public static SerializationException NonNegativeFloatType_ParseValue_IsNotNonNegative( + public static LeafCoercionException NonNegativeFloatType_ParseValue_IsNotNonNegative( IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.NonNegativeFloatType_IsNotNonNegative_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -407,9 +407,9 @@ public static SerializationException NonNegativeFloatType_ParseValue_IsNotNonNeg type); } - public static SerializationException PhoneNumber_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException PhoneNumber_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PhoneNumberType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -418,9 +418,9 @@ public static SerializationException PhoneNumber_ParseLiteral_IsInvalid(IType ty type); } - public static SerializationException PhoneNumber_ParseValue_IsInvalid(IType type) + public static LeafCoercionException PhoneNumber_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PhoneNumberType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -429,9 +429,9 @@ public static SerializationException PhoneNumber_ParseValue_IsInvalid(IType type type); } - public static SerializationException PortType_ParseLiteral_OutOfRange(IType type) + public static LeafCoercionException PortType_ParseLiteral_OutOfRange(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PortType_OutOfRange_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -440,9 +440,9 @@ public static SerializationException PortType_ParseLiteral_OutOfRange(IType type type); } - public static SerializationException PortType_ParseValue_OutOfRange(IType type) + public static LeafCoercionException PortType_ParseValue_OutOfRange(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PortType_OutOfRange_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -451,9 +451,9 @@ public static SerializationException PortType_ParseValue_OutOfRange(IType type) type); } - public static SerializationException PositiveIntType_ParseLiteral_ZeroOrLess(IType type) + public static LeafCoercionException PositiveIntType_ParseLiteral_ZeroOrLess(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PositiveIntType_ZeroOrLess_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -462,9 +462,9 @@ public static SerializationException PositiveIntType_ParseLiteral_ZeroOrLess(ITy type); } - public static SerializationException PositiveIntType_ParseValue_ZeroOrLess(IType type) + public static LeafCoercionException PositiveIntType_ParseValue_ZeroOrLess(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PositiveIntType_ZeroOrLess_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -473,9 +473,9 @@ public static SerializationException PositiveIntType_ParseValue_ZeroOrLess(IType type); } - public static SerializationException PostalCodeType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException PostalCodeType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PostalCodeType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -484,9 +484,9 @@ public static SerializationException PostalCodeType_ParseLiteral_IsInvalid(IType type); } - public static SerializationException PostalCodeType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException PostalCodeType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.PostalCodeType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -495,11 +495,11 @@ public static SerializationException PostalCodeType_ParseValue_IsInvalid(IType t type); } - public static SerializationException RegexType_ParseValue_IsInvalid( + public static LeafCoercionException RegexType_ParseValue_IsInvalid( IType type, string name) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage( string.Format( @@ -510,11 +510,11 @@ public static SerializationException RegexType_ParseValue_IsInvalid( type); } - public static SerializationException RegexType_ParseLiteral_IsInvalid( + public static LeafCoercionException RegexType_ParseLiteral_IsInvalid( IType type, string name) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage( string.Format( @@ -525,9 +525,9 @@ public static SerializationException RegexType_ParseLiteral_IsInvalid( type); } - public static SerializationException RgbType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException RgbType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.RgbType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -536,9 +536,9 @@ public static SerializationException RgbType_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException RgbType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException RgbType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.RgbType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -547,9 +547,9 @@ public static SerializationException RgbType_ParseValue_IsInvalid(IType type) type); } - public static SerializationException RgbaType_ParseValue_IsInvalid(IType type) + public static LeafCoercionException RgbaType_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.RgbaType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -558,9 +558,9 @@ public static SerializationException RgbaType_ParseValue_IsInvalid(IType type) type); } - public static SerializationException RgbaType_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException RgbaType_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.RgbaType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -569,9 +569,9 @@ public static SerializationException RgbaType_ParseLiteral_IsInvalid(IType type) type); } - public static SerializationException UnsignedShortType_ParseValue_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedShortType_ParseValue_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedShortType_IsNotUnsigned_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -580,9 +580,9 @@ public static SerializationException UnsignedShortType_ParseValue_IsNotUnsigned( type); } - public static SerializationException UnsignedShortType_ParseLiteral_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedShortType_ParseLiteral_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedShortType_IsNotUnsigned_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -591,9 +591,9 @@ public static SerializationException UnsignedShortType_ParseLiteral_IsNotUnsigne type); } - public static SerializationException SignedByteType_ParseValue_IsNotSigned(IType type) + public static LeafCoercionException SignedByteType_ParseValue_IsNotSigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.SignedByteType_IsNotSigned_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -602,9 +602,9 @@ public static SerializationException SignedByteType_ParseValue_IsNotSigned(IType type); } - public static SerializationException SignedByteType_ParseLiteral_IsNotSigned(IType type) + public static LeafCoercionException SignedByteType_ParseLiteral_IsNotSigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.SignedByteType_IsNotSigned_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -613,9 +613,9 @@ public static SerializationException SignedByteType_ParseLiteral_IsNotSigned(ITy type); } - public static SerializationException UnsignedIntType_ParseValue_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedIntType_ParseValue_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedIntType_IsNotUnsigned_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -624,9 +624,9 @@ public static SerializationException UnsignedIntType_ParseValue_IsNotUnsigned(IT type); } - public static SerializationException UnsignedIntType_ParseLiteral_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedIntType_ParseLiteral_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedIntType_IsNotUnsigned_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -635,9 +635,9 @@ public static SerializationException UnsignedIntType_ParseLiteral_IsNotUnsigned( type); } - public static SerializationException UnsignedLongType_ParseValue_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedLongType_ParseValue_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedLongType_IsNotUnsigned_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -646,9 +646,9 @@ public static SerializationException UnsignedLongType_ParseValue_IsNotUnsigned(I type); } - public static SerializationException UnsignedLongType_ParseLiteral_IsNotUnsigned(IType type) + public static LeafCoercionException UnsignedLongType_ParseLiteral_IsNotUnsigned(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UnsignedLongType_IsNotUnsigned_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) @@ -657,9 +657,9 @@ public static SerializationException UnsignedLongType_ParseLiteral_IsNotUnsigned type); } - public static SerializationException UtcOffset_ParseValue_IsInvalid(IType type) + public static LeafCoercionException UtcOffset_ParseValue_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UtcOffsetType_IsInvalid_ParseValue) .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -668,9 +668,9 @@ public static SerializationException UtcOffset_ParseValue_IsInvalid(IType type) type); } - public static SerializationException UtcOffset_ParseLiteral_IsInvalid(IType type) + public static LeafCoercionException UtcOffset_ParseLiteral_IsInvalid(IType type) { - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage(ScalarResources.UtcOffsetType_IsInvalid_ParseLiteral) .SetCode(ErrorCodes.Scalars.InvalidSyntaxFormat) diff --git a/src/HotChocolate/Core/src/Types.Scalars/UnsignedIntType.cs b/src/HotChocolate/Core/src/Types.Scalars/UnsignedIntType.cs index f734734556e..2eb81910492 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/UnsignedIntType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/UnsignedIntType.cs @@ -56,19 +56,19 @@ protected override IntValueNode ParseValue(uint runtimeValue) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.UnsignedIntType_ParseLiteral_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.UnsignedIntType_ParseValue_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.UnsignedIntType_ParseValue_IsNotUnsigned(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/UnsignedLongType.cs b/src/HotChocolate/Core/src/Types.Scalars/UnsignedLongType.cs index 4d3b566069e..113e4b67204 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/UnsignedLongType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/UnsignedLongType.cs @@ -56,19 +56,19 @@ protected override IntValueNode ParseValue(ulong runtimeValue) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.UnsignedLongType_ParseLiteral_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.UnsignedLongType_ParseValue_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.UnsignedLongType_ParseValue_IsNotUnsigned(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/UnsignedShortType.cs b/src/HotChocolate/Core/src/Types.Scalars/UnsignedShortType.cs index 7d6b823f2fc..9018f5f99d6 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/UnsignedShortType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/UnsignedShortType.cs @@ -56,19 +56,19 @@ protected override IntValueNode ParseValue(ushort runtimeValue) } /// - protected override SerializationException CreateParseLiteralError(IValueNode valueSyntax) + protected override LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) { throw ThrowHelper.UnsignedShortType_ParseLiteral_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseValueError(object runtimeValue) + protected override LeafCoercionException CreateParseValueError(object runtimeValue) { throw ThrowHelper.UnsignedShortType_ParseValue_IsNotUnsigned(this); } /// - protected override SerializationException CreateParseResultError(object runtimeValue) + protected override LeafCoercionException CreateParseResultError(object runtimeValue) { throw ThrowHelper.UnsignedShortType_ParseValue_IsNotUnsigned(this); } diff --git a/src/HotChocolate/Core/src/Types.Scalars/UtcOffsetType.cs b/src/HotChocolate/Core/src/Types.Scalars/UtcOffsetType.cs index b51d25fcd6f..4805b280fe1 100644 --- a/src/HotChocolate/Core/src/Types.Scalars/UtcOffsetType.cs +++ b/src/HotChocolate/Core/src/Types.Scalars/UtcOffsetType.cs @@ -70,7 +70,7 @@ protected override StringValueNode ParseValue(TimeSpan runtimeValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs index 16bca1ca7b7..6a42cba2e78 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/MiddlewareContext.Arguments.cs @@ -24,10 +24,10 @@ public T ArgumentValue(string name) { return CoerceArgumentValue(argument); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { var syntaxNode = Selection.Arguments[argument.Name].ValueLiteral; - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.FromError(ex.Errors[0]).SetPath(Path).TryAddLocation(syntaxNode).Build(), ex.Type, Path); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs index 62b09006798..f520c494b78 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CoerceArgumentValues.cs @@ -74,7 +74,7 @@ private ArgumentValue CreateArgumentValue( _inputValueParser.ParseLiteral(value, argument), value); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { return new ArgumentValue( argument, diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs index ef36b6e2d52..e635c3ddeee 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/OperationCompiler.CompileResolver.cs @@ -80,9 +80,9 @@ private static void BuildDirectivePipeline( directiveNode, directiveType.Parse(directiveNode)); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.FromError(ex.Errors[0]) .TryAddLocation(directiveNode) .Build(), diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs index 297eb489584..b314d6a3139 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.Leaf.cs @@ -10,7 +10,7 @@ internal static partial class ValueCompletion private static void CompleteLeafValue( ValueCompletionContext context, Selection selection, - ILeafType2 type, + ILeafType type, ResultElement resultValue, object? runtimeValue) { @@ -27,10 +27,10 @@ private static void CompleteLeafValue( runtimeValue = c; } - type.Serialize(runtimeValue, resultValue); + type.CoerceOutputValue(runtimeValue, resultValue); return; } - catch (SerializationException ex) + catch (LeafCoercionException ex) { var errorPath = resultValue.Path; var error = InvalidLeafValue(ex, selection, errorPath); diff --git a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs index 87b48c2572b..e4aa5a98674 100644 --- a/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs +++ b/src/HotChocolate/Core/src/Types/Execution/Processing/ValueCompletion.cs @@ -37,7 +37,7 @@ public static void Complete( switch (typeKind) { case TypeKind.Scalar or TypeKind.Enum: - CompleteLeafValue(context, selection, (ILeafType2)type, resultValue, result); + CompleteLeafValue(context, selection, (ILeafType)type, resultValue, result); break; case TypeKind.List: diff --git a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs index 81cd8a172c0..925033daf15 100644 --- a/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Execution/ThrowHelper.cs @@ -45,7 +45,7 @@ public static GraphQLException VariableValueInvalidType( VariableDefinitionNode variableDefinition, Exception? exception = null) { - var underlyingError = exception is SerializationException serializationException + var underlyingError = exception is LeafCoercionException serializationException ? serializationException.Message : null; diff --git a/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs b/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs index e91ea8d0d67..df986f14505 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs +++ b/src/HotChocolate/Core/src/Types/Properties/TypeResources.Designer.cs @@ -9,21 +9,21 @@ namespace HotChocolate.Properties { using System; - - + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.Diagnostics.DebuggerNonUserCodeAttribute()] [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class TypeResources { - + private static System.Resources.ResourceManager resourceMan; - + private static System.Globalization.CultureInfo resourceCulture; - + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal TypeResources() { } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Resources.ResourceManager ResourceManager { get { @@ -34,7 +34,7 @@ internal static System.Resources.ResourceManager ResourceManager { return resourceMan; } } - + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] internal static System.Globalization.CultureInfo Culture { get { @@ -44,67 +44,67 @@ internal static System.Globalization.CultureInfo Culture { resourceCulture = value; } } - + internal static string ThrowHelper_MissingDirectiveIfArgument { get { return ResourceManager.GetString("ThrowHelper_MissingDirectiveIfArgument", resourceCulture); } } - + internal static string ArgumentDescriptor_InputTypeViolation { get { return ResourceManager.GetString("ArgumentDescriptor_InputTypeViolation", resourceCulture); } } - + internal static string ArgumentValueBuilder_NonNull { get { return ResourceManager.GetString("ArgumentValueBuilder_NonNull", resourceCulture); } } - + internal static string BooleanType_Description { get { return ResourceManager.GetString("BooleanType_Description", resourceCulture); } } - + internal static string ByteType_Description { get { return ResourceManager.GetString("ByteType_Description", resourceCulture); } } - + internal static string ComplexTypeBindingBuilder_FieldBuilderNotSupported { get { return ResourceManager.GetString("ComplexTypeBindingBuilder_FieldBuilderNotSupported", resourceCulture); } } - + internal static string ComplexTypeBindingBuilder_FieldNotComplete { get { return ResourceManager.GetString("ComplexTypeBindingBuilder_FieldNotComplete", resourceCulture); } } - + internal static string DataLoaderRegistry_KeyNullOrEmpty { get { return ResourceManager.GetString("DataLoaderRegistry_KeyNullOrEmpty", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_RegistryIsNull { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_RegistryIsNull", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_UnableToRegister { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_UnableToRegister", resourceCulture); } } - + /// /// Looks up a localized string similar to The `DateTime` scalar represents an exact point in time. This point in time is specified by having an offset to UTC and does not use a time zone.. /// @@ -113,1885 +113,1885 @@ internal static string DateTimeType_Description { return ResourceManager.GetString("DateTimeType_Description", resourceCulture); } } - + internal static string DateType_Description { get { return ResourceManager.GetString("DateType_Description", resourceCulture); } } - + internal static string DecimalType_Description { get { return ResourceManager.GetString("DecimalType_Description", resourceCulture); } } - + internal static string DefaultTypeInspector_MemberInvalid { get { return ResourceManager.GetString("DefaultTypeInspector_MemberInvalid", resourceCulture); } } - + internal static string DependencyDescriptorBase_OnlyTsoIsAllowed { get { return ResourceManager.GetString("DependencyDescriptorBase_OnlyTsoIsAllowed", resourceCulture); } } - + internal static string DirectiveCollection_DirectiveIsUnique { get { return ResourceManager.GetString("DirectiveCollection_DirectiveIsUnique", resourceCulture); } } - + internal static string DirectiveCollection_LocationNotAllowed { get { return ResourceManager.GetString("DirectiveCollection_LocationNotAllowed", resourceCulture); } } - + internal static string DirectiveLocation_ArgumentDefinition { get { return ResourceManager.GetString("DirectiveLocation_ArgumentDefinition", resourceCulture); } } - + internal static string DirectiveLocation_Description { get { return ResourceManager.GetString("DirectiveLocation_Description", resourceCulture); } } - + internal static string DirectiveLocation_Enum { get { return ResourceManager.GetString("DirectiveLocation_Enum", resourceCulture); } } - + internal static string DirectiveLocation_EnumValue { get { return ResourceManager.GetString("DirectiveLocation_EnumValue", resourceCulture); } } - + internal static string DirectiveLocation_Field { get { return ResourceManager.GetString("DirectiveLocation_Field", resourceCulture); } } - + internal static string DirectiveLocation_FieldDefinition { get { return ResourceManager.GetString("DirectiveLocation_FieldDefinition", resourceCulture); } } - + internal static string DirectiveLocation_FragmentDefinition { get { return ResourceManager.GetString("DirectiveLocation_FragmentDefinition", resourceCulture); } } - + internal static string DirectiveLocation_FragmentSpread { get { return ResourceManager.GetString("DirectiveLocation_FragmentSpread", resourceCulture); } } - + internal static string DirectiveLocation_InlineFragment { get { return ResourceManager.GetString("DirectiveLocation_InlineFragment", resourceCulture); } } - + internal static string DirectiveLocation_InputFieldDefinition { get { return ResourceManager.GetString("DirectiveLocation_InputFieldDefinition", resourceCulture); } } - + internal static string DirectiveLocation_InputObject { get { return ResourceManager.GetString("DirectiveLocation_InputObject", resourceCulture); } } - + internal static string DirectiveLocation_Interface { get { return ResourceManager.GetString("DirectiveLocation_Interface", resourceCulture); } } - + internal static string DirectiveLocation_Mutation { get { return ResourceManager.GetString("DirectiveLocation_Mutation", resourceCulture); } } - + internal static string DirectiveLocation_Object { get { return ResourceManager.GetString("DirectiveLocation_Object", resourceCulture); } } - + internal static string DirectiveLocation_Query { get { return ResourceManager.GetString("DirectiveLocation_Query", resourceCulture); } } - + internal static string DirectiveLocation_Scalar { get { return ResourceManager.GetString("DirectiveLocation_Scalar", resourceCulture); } } - + internal static string DirectiveLocation_Schema { get { return ResourceManager.GetString("DirectiveLocation_Schema", resourceCulture); } } - + internal static string DirectiveLocation_Subscription { get { return ResourceManager.GetString("DirectiveLocation_Subscription", resourceCulture); } } - + internal static string DirectiveLocation_Union { get { return ResourceManager.GetString("DirectiveLocation_Union", resourceCulture); } } - + internal static string DirectiveTypeDescriptor_OnlyProperties { get { return ResourceManager.GetString("DirectiveTypeDescriptor_OnlyProperties", resourceCulture); } } - + internal static string DirectiveType_NoLocations { get { return ResourceManager.GetString("DirectiveType_NoLocations", resourceCulture); } } - + internal static string DirectiveType_ReplaceWithUse { get { return ResourceManager.GetString("DirectiveType_ReplaceWithUse", resourceCulture); } } - + internal static string DirectiveType_UnableToConvert { get { return ResourceManager.GetString("DirectiveType_UnableToConvert", resourceCulture); } } - + internal static string Directive_Description { get { return ResourceManager.GetString("Directive_Description", resourceCulture); } } - + internal static string Directive_UseLocation { get { return ResourceManager.GetString("Directive_UseLocation", resourceCulture); } } - + internal static string EnumTypeExtension_CannotMerge { get { return ResourceManager.GetString("EnumTypeExtension_CannotMerge", resourceCulture); } } - + internal static string EnumTypeExtension_ValueTypeInvalid { get { return ResourceManager.GetString("EnumTypeExtension_ValueTypeInvalid", resourceCulture); } } - + internal static string EnumType_NoValues { get { return ResourceManager.GetString("EnumType_NoValues", resourceCulture); } } - + internal static string EnumValue_Description { get { return ResourceManager.GetString("EnumValue_Description", resourceCulture); } } - + internal static string EnumValue_ValueIsNull { get { return ResourceManager.GetString("EnumValue_ValueIsNull", resourceCulture); } } - + internal static string FieldInitHelper_InvalidDefaultValue { get { return ResourceManager.GetString("FieldInitHelper_InvalidDefaultValue", resourceCulture); } } - + internal static string FieldInitHelper_NoFields { get { return ResourceManager.GetString("FieldInitHelper_NoFields", resourceCulture); } } - + internal static string Field_Description { get { return ResourceManager.GetString("Field_Description", resourceCulture); } } - + internal static string FloatType_Description { get { return ResourceManager.GetString("FloatType_Description", resourceCulture); } } - + internal static string IdType_Description { get { return ResourceManager.GetString("IdType_Description", resourceCulture); } } - + internal static string InputField_CannotSetValue { get { return ResourceManager.GetString("InputField_CannotSetValue", resourceCulture); } } - + internal static string InputObjectTypeExtension_CannotMerge { get { return ResourceManager.GetString("InputObjectTypeExtension_CannotMerge", resourceCulture); } } - + internal static string InputObjectType_CannotParseLiteral { get { return ResourceManager.GetString("InputObjectType_CannotParseLiteral", resourceCulture); } } - + internal static string InputObjectType_NoFields { get { return ResourceManager.GetString("InputObjectType_NoFields", resourceCulture); } } - + internal static string InputTypeNonNullCheck_ValueIsNull { get { return ResourceManager.GetString("InputTypeNonNullCheck_ValueIsNull", resourceCulture); } } - + internal static string InputValue_DefaultValue { get { return ResourceManager.GetString("InputValue_DefaultValue", resourceCulture); } } - + internal static string InputValue_Description { get { return ResourceManager.GetString("InputValue_Description", resourceCulture); } } - + internal static string InterfaceImplRule_ArgumentsDoNotMatch { get { return ResourceManager.GetString("InterfaceImplRule_ArgumentsDoNotMatch", resourceCulture); } } - + internal static string InterfaceImplRule_ArgumentsNotImpl { get { return ResourceManager.GetString("InterfaceImplRule_ArgumentsNotImpl", resourceCulture); } } - + internal static string InterfaceImplRule_FieldNotImpl { get { return ResourceManager.GetString("InterfaceImplRule_FieldNotImpl", resourceCulture); } } - + internal static string InterfaceImplRule_FieldTypeInvalid { get { return ResourceManager.GetString("InterfaceImplRule_FieldTypeInvalid", resourceCulture); } } - + internal static string InterfaceImplRule_ReturnTypeInvalid { get { return ResourceManager.GetString("InterfaceImplRule_ReturnTypeInvalid", resourceCulture); } } - + internal static string InterfaceTypeExtension_CannotMerge { get { return ResourceManager.GetString("InterfaceTypeExtension_CannotMerge", resourceCulture); } } - + internal static string IntType_Description { get { return ResourceManager.GetString("IntType_Description", resourceCulture); } } - + internal static string LongType_Description { get { return ResourceManager.GetString("LongType_Description", resourceCulture); } } - + internal static string NameType_Description { get { return ResourceManager.GetString("NameType_Description", resourceCulture); } } - + internal static string Name_Cannot_BeEmpty { get { return ResourceManager.GetString("Name_Cannot_BeEmpty", resourceCulture); } } - + internal static string ObjectFieldDescriptorBase_FieldType { get { return ResourceManager.GetString("ObjectFieldDescriptorBase_FieldType", resourceCulture); } } - + internal static string ObjectTypeDescriptor_InterfaceBaseClass { get { return ResourceManager.GetString("ObjectTypeDescriptor_InterfaceBaseClass", resourceCulture); } } - + internal static string InterfaceTypeDescriptor_InterfaceBaseClass { get { return ResourceManager.GetString("InterfaceTypeDescriptor_InterfaceBaseClass", resourceCulture); } } - + internal static string ObjectTypeDescriptor_MustBePropertyOrMethod { get { return ResourceManager.GetString("ObjectTypeDescriptor_MustBePropertyOrMethod", resourceCulture); } } - + internal static string ObjectTypeDescriptor_ResolveWith_NonAbstract { get { return ResourceManager.GetString("ObjectTypeDescriptor_ResolveWith_NonAbstract", resourceCulture); } } - + internal static string NodeDescriptor_MustBeMethod { get { return ResourceManager.GetString("NodeDescriptor_MustBeMethod", resourceCulture); } } - + internal static string NodeDescriptor_IdMember { get { return ResourceManager.GetString("NodeDescriptor_IdMember", resourceCulture); } } - + internal static string ObjectTypeDescriptor_Resolver_SchemaType { get { return ResourceManager.GetString("ObjectTypeDescriptor_Resolver_SchemaType", resourceCulture); } } - + internal static string Reflection_MemberMust_BeMethodOrProperty { get { return ResourceManager.GetString("Reflection_MemberMust_BeMethodOrProperty", resourceCulture); } } - + internal static string ResolverCompiler_UnknownParameterType { get { return ResourceManager.GetString("ResolverCompiler_UnknownParameterType", resourceCulture); } } - + internal static string ResolverTypeBindingBuilder_FieldBuilderNotSupported { get { return ResourceManager.GetString("ResolverTypeBindingBuilder_FieldBuilderNotSupported", resourceCulture); } } - + internal static string ResolverTypeBindingBuilder_FieldNotComplete { get { return ResourceManager.GetString("ResolverTypeBindingBuilder_FieldNotComplete", resourceCulture); } } - + internal static string Scalar_Cannot_Deserialize { get { return ResourceManager.GetString("Scalar_Cannot_Deserialize", resourceCulture); } } - - internal static string Scalar_Cannot_ParseLiteral { + + internal static string Scalar_Cannot_CoerceInputLiteral { get { - return ResourceManager.GetString("Scalar_Cannot_ParseLiteral", resourceCulture); + return ResourceManager.GetString("Scalar_Cannot_CoerceInputLiteral", resourceCulture); } } - - internal static string Scalar_Cannot_ParseValue { + + internal static string Scalar_Cannot_CoerceInputValue { get { - return ResourceManager.GetString("Scalar_Cannot_ParseValue", resourceCulture); + return ResourceManager.GetString("Scalar_Cannot_CoerceInputValue", resourceCulture); } } - + internal static string Scalar_Cannot_Serialize { get { return ResourceManager.GetString("Scalar_Cannot_Serialize", resourceCulture); } } - + internal static string SchemaBuilderExtensions_DirectiveTypeIsBaseType { get { return ResourceManager.GetString("SchemaBuilderExtensions_DirectiveTypeIsBaseType", resourceCulture); } } - + internal static string SchemaBuilderExtensions_MustBeDirectiveType { get { return ResourceManager.GetString("SchemaBuilderExtensions_MustBeDirectiveType", resourceCulture); } } - + internal static string SchemaBuilder_Binding_CannotBeHandled { get { return ResourceManager.GetString("SchemaBuilder_Binding_CannotBeHandled", resourceCulture); } } - + internal static string SchemaBuilder_Binding_Invalid { get { return ResourceManager.GetString("SchemaBuilder_Binding_Invalid", resourceCulture); } } - + internal static string SchemaBuilder_NoQueryType { get { return ResourceManager.GetString("SchemaBuilder_NoQueryType", resourceCulture); } } - + internal static string SchemaBuilder_RootType_MustBeClass { get { return ResourceManager.GetString("SchemaBuilder_RootType_MustBeClass", resourceCulture); } } - + internal static string SchemaBuilder_RootType_MustBeObjectType { get { return ResourceManager.GetString("SchemaBuilder_RootType_MustBeObjectType", resourceCulture); } } - + internal static string SchemaBuilder_RootType_NonGenericType { get { return ResourceManager.GetString("SchemaBuilder_RootType_NonGenericType", resourceCulture); } } - + internal static string SchemaBuilder_SchemaTypeInvalid { get { return ResourceManager.GetString("SchemaBuilder_SchemaTypeInvalid", resourceCulture); } } - + internal static string SchemaField_Description { get { return ResourceManager.GetString("SchemaField_Description", resourceCulture); } } - + internal static string SchemaSyntaxVisitor_UnknownOperationType { get { return ResourceManager.GetString("SchemaSyntaxVisitor_UnknownOperationType", resourceCulture); } } - + internal static string Schema_Description { get { return ResourceManager.GetString("Schema_Description", resourceCulture); } } - + internal static string Schema_Directives { get { return ResourceManager.GetString("Schema_Directives", resourceCulture); } } - + internal static string Schema_MutationType { get { return ResourceManager.GetString("Schema_MutationType", resourceCulture); } } - + internal static string Schema_QueryType { get { return ResourceManager.GetString("Schema_QueryType", resourceCulture); } } - + internal static string Schema_SubscriptionType { get { return ResourceManager.GetString("Schema_SubscriptionType", resourceCulture); } } - + internal static string Schema_Types { get { return ResourceManager.GetString("Schema_Types", resourceCulture); } } - + internal static string ShortType_Description { get { return ResourceManager.GetString("ShortType_Description", resourceCulture); } } - + internal static string StringType_Description { get { return ResourceManager.GetString("StringType_Description", resourceCulture); } } - + internal static string String_Argument_NullOrEmpty { get { return ResourceManager.GetString("String_Argument_NullOrEmpty", resourceCulture); } } - + internal static string TypeConfiguration_ConfigureIsNull { get { return ResourceManager.GetString("TypeConfiguration_ConfigureIsNull", resourceCulture); } } - + internal static string TypeConfiguration_DefinitionIsNull { get { return ResourceManager.GetString("TypeConfiguration_DefinitionIsNull", resourceCulture); } } - + internal static string TypeDependency_MustBeSchemaType { get { return ResourceManager.GetString("TypeDependency_MustBeSchemaType", resourceCulture); } } - + internal static string TypeExtensions_NoListType { get { return ResourceManager.GetString("TypeExtensions_NoListType", resourceCulture); } } - + internal static string TypeExtensions_TypeIsNotOfT { get { return ResourceManager.GetString("TypeExtensions_TypeIsNotOfT", resourceCulture); } } - + internal static string TypeField_Description { get { return ResourceManager.GetString("TypeField_Description", resourceCulture); } } - + internal static string TypeInitializer_CannotResolveDependency { get { return ResourceManager.GetString("TypeInitializer_CannotResolveDependency", resourceCulture); } } - + internal static string TypeInitializer_CompleteName_Duplicate { get { return ResourceManager.GetString("TypeInitializer_CompleteName_Duplicate", resourceCulture); } } - + internal static string TypeInitializer_Merge_KindDoesNotMatch { get { return ResourceManager.GetString("TypeInitializer_Merge_KindDoesNotMatch", resourceCulture); } } - + internal static string TypeKind_Description { get { return ResourceManager.GetString("TypeKind_Description", resourceCulture); } } - + internal static string TypeKind_Enum { get { return ResourceManager.GetString("TypeKind_Enum", resourceCulture); } } - + internal static string TypeKind_InputObject { get { return ResourceManager.GetString("TypeKind_InputObject", resourceCulture); } } - + internal static string TypeKind_Interface { get { return ResourceManager.GetString("TypeKind_Interface", resourceCulture); } } - + internal static string TypeKind_List { get { return ResourceManager.GetString("TypeKind_List", resourceCulture); } } - + internal static string TypeKind_NonNull { get { return ResourceManager.GetString("TypeKind_NonNull", resourceCulture); } } - + internal static string TypeKind_Object { get { return ResourceManager.GetString("TypeKind_Object", resourceCulture); } } - + internal static string TypeKind_Scalar { get { return ResourceManager.GetString("TypeKind_Scalar", resourceCulture); } } - + internal static string TypeKind_Union { get { return ResourceManager.GetString("TypeKind_Union", resourceCulture); } } - + internal static string TypeNameField_Description { get { return ResourceManager.GetString("TypeNameField_Description", resourceCulture); } } - + internal static string TypeNameHelper_InvalidTypeStructure { get { return ResourceManager.GetString("TypeNameHelper_InvalidTypeStructure", resourceCulture); } } - + internal static string TypeNameHelper_OnlyTypeSystemObjectsAreAllowed { get { return ResourceManager.GetString("TypeNameHelper_OnlyTypeSystemObjectsAreAllowed", resourceCulture); } } - + internal static string Type_Description { get { return ResourceManager.GetString("Type_Description", resourceCulture); } } - + internal static string UnionTypeExtension_CannotMerge { get { return ResourceManager.GetString("UnionTypeExtension_CannotMerge", resourceCulture); } } - + internal static string VariableValueBuilder_InputType { get { return ResourceManager.GetString("VariableValueBuilder_InputType", resourceCulture); } } - + internal static string VariableValueBuilder_InvalidValue { get { return ResourceManager.GetString("VariableValueBuilder_InvalidValue", resourceCulture); } } - + internal static string VariableValueBuilder_NodeKind { get { return ResourceManager.GetString("VariableValueBuilder_NodeKind", resourceCulture); } } - + internal static string VariableValueBuilder_NonNull { get { return ResourceManager.GetString("VariableValueBuilder_NonNull", resourceCulture); } } - + internal static string VariableValueBuilder_NonNull_In_Graph { get { return ResourceManager.GetString("VariableValueBuilder_NonNull_In_Graph", resourceCulture); } } - + internal static string VariableValueBuilder_VarNameEmpty { get { return ResourceManager.GetString("VariableValueBuilder_VarNameEmpty", resourceCulture); } } - + internal static string Argument_TypeIsNull { get { return ResourceManager.GetString("Argument_TypeIsNull", resourceCulture); } } - + internal static string NonNullType_NotAnInputType { get { return ResourceManager.GetString("NonNullType_NotAnInputType", resourceCulture); } } - + internal static string NonNullType_TypeIsNunNullType { get { return ResourceManager.GetString("NonNullType_TypeIsNunNullType", resourceCulture); } } - + internal static string NonNullType_ValueIsNull { get { return ResourceManager.GetString("NonNullType_ValueIsNull", resourceCulture); } } - + internal static string ObjectTypeExtension_CannotMerge { get { return ResourceManager.GetString("ObjectTypeExtension_CannotMerge", resourceCulture); } } - + internal static string TypeSystemObjectBase_DefinitionIsNull { get { return ResourceManager.GetString("TypeSystemObjectBase_DefinitionIsNull", resourceCulture); } } - + internal static string TypeSystemObjectBase_NameIsNull { get { return ResourceManager.GetString("TypeSystemObjectBase_NameIsNull", resourceCulture); } } - + internal static string TypeSystemObject_DescriptionImmutable { get { return ResourceManager.GetString("TypeSystemObject_DescriptionImmutable", resourceCulture); } } - + internal static string TypeSystem_Immutable { get { return ResourceManager.GetString("TypeSystem_Immutable", resourceCulture); } } - + internal static string TypeSystemObject_NameImmutable { get { return ResourceManager.GetString("TypeSystemObject_NameImmutable", resourceCulture); } } - + internal static string UnionType_MustHaveTypes { get { return ResourceManager.GetString("UnionType_MustHaveTypes", resourceCulture); } } - + internal static string UnionType_UnableToResolveType { get { return ResourceManager.GetString("UnionType_UnableToResolveType", resourceCulture); } } - + internal static string SchemaBuilder_MustBeSchemaType { get { return ResourceManager.GetString("SchemaBuilder_MustBeSchemaType", resourceCulture); } } - + internal static string TypeRegistrar_TypesInconsistent { get { return ResourceManager.GetString("TypeRegistrar_TypesInconsistent", resourceCulture); } } - + internal static string TypeConversion_ConvertNotSupported { get { return ResourceManager.GetString("TypeConversion_ConvertNotSupported", resourceCulture); } } - + internal static string SchemaBuilder_Interceptor_NotSupported { get { return ResourceManager.GetString("SchemaBuilder_Interceptor_NotSupported", resourceCulture); } } - + internal static string IdSerializer_UnableToEncode { get { return ResourceManager.GetString("IdSerializer_UnableToEncode", resourceCulture); } } - + internal static string IdSerializer_UnableToDecode { get { return ResourceManager.GetString("IdSerializer_UnableToDecode", resourceCulture); } } - + internal static string SchemaBuilder_Convention_NotSupported { get { return ResourceManager.GetString("SchemaBuilder_Convention_NotSupported", resourceCulture); } } - + internal static string TimeSpanType_Description { get { return ResourceManager.GetString("TimeSpanType_Description", resourceCulture); } } - + internal static string DefaultDataLoaderRegistry_GetOrRegister { get { return ResourceManager.GetString("DefaultDataLoaderRegistry_GetOrRegister", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_AbstractType", resourceCulture); } } - + internal static string DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate { get { return ResourceManager.GetString("DataLoaderResolverContextExtensions_CreateDataLoader_UnableToCreate", resourceCulture); } } - + internal static string NonNamedType_IsInstanceOfType_NotAnInputType { get { return ResourceManager.GetString("NonNamedType_IsInstanceOfType_NotAnInputType", resourceCulture); } } - + internal static string RegisteredType_CompletionContext_Not_Initialized { get { return ResourceManager.GetString("RegisteredType_CompletionContext_Not_Initialized", resourceCulture); } } - + internal static string RegisteredType_CompletionContext_Already_Set { get { return ResourceManager.GetString("RegisteredType_CompletionContext_Already_Set", resourceCulture); } } - + internal static string DeferDirectiveType_Description { get { return ResourceManager.GetString("DeferDirectiveType_Description", resourceCulture); } } - + internal static string DeferDirectiveType_Label_Description { get { return ResourceManager.GetString("DeferDirectiveType_Label_Description", resourceCulture); } } - + internal static string DeferDirectiveType_If_Description { get { return ResourceManager.GetString("DeferDirectiveType_If_Description", resourceCulture); } } - + internal static string StreamDirectiveType_Description { get { return ResourceManager.GetString("StreamDirectiveType_Description", resourceCulture); } } - + internal static string StreamDirectiveType_Label_Description { get { return ResourceManager.GetString("StreamDirectiveType_Label_Description", resourceCulture); } } - + internal static string StreamDirectiveType_InitialCount_Description { get { return ResourceManager.GetString("StreamDirectiveType_InitialCount_Description", resourceCulture); } } - + internal static string StreamDirectiveType_If_Description { get { return ResourceManager.GetString("StreamDirectiveType_If_Description", resourceCulture); } } - + internal static string SchemaBuilder_AddRootType_TypeAlreadyRegistered { get { return ResourceManager.GetString("SchemaBuilder_AddRootType_TypeAlreadyRegistered", resourceCulture); } } - + internal static string NodeDescriptor_IdField_MustBePropertyOrMethod { get { return ResourceManager.GetString("NodeDescriptor_IdField_MustBePropertyOrMethod", resourceCulture); } } - + internal static string DeprecatedDirectiveType_TypeDescription { get { return ResourceManager.GetString("DeprecatedDirectiveType_TypeDescription", resourceCulture); } } - + internal static string DeprecatedDirectiveType_ReasonDescription { get { return ResourceManager.GetString("DeprecatedDirectiveType_ReasonDescription", resourceCulture); } } - + internal static string IncludeDirectiveType_TypeDescription { get { return ResourceManager.GetString("IncludeDirectiveType_TypeDescription", resourceCulture); } } - + internal static string IncludeDirectiveType_IfDescription { get { return ResourceManager.GetString("IncludeDirectiveType_IfDescription", resourceCulture); } } - + internal static string SkipDirectiveType_TypeDescription { get { return ResourceManager.GetString("SkipDirectiveType_TypeDescription", resourceCulture); } } - + internal static string SkipDirectiveType_IfDescription { get { return ResourceManager.GetString("SkipDirectiveType_IfDescription", resourceCulture); } } - + internal static string SpecifiedByDirectiveType_TypeDescription { get { return ResourceManager.GetString("SpecifiedByDirectiveType_TypeDescription", resourceCulture); } } - + internal static string SpecifiedByDirectiveType_UrlDescription { get { return ResourceManager.GetString("SpecifiedByDirectiveType_UrlDescription", resourceCulture); } } - + internal static string NodeType_TypeDescription { get { return ResourceManager.GetString("NodeType_TypeDescription", resourceCulture); } } - + internal static string AnyType_CycleInObjectGraph { get { return ResourceManager.GetString("AnyType_CycleInObjectGraph", resourceCulture); } } - + internal static string UuidType_FormatUnknown { get { return ResourceManager.GetString("UuidType_FormatUnknown", resourceCulture); } } - + internal static string Directive_GetArgument_ArgumentNameIsInvalid { get { return ResourceManager.GetString("Directive_GetArgument_ArgumentNameIsInvalid", resourceCulture); } } - + internal static string AppliedDirective_Description { get { return ResourceManager.GetString("AppliedDirective_Description", resourceCulture); } } - + internal static string DirectiveArgument_Description { get { return ResourceManager.GetString("DirectiveArgument_Description", resourceCulture); } } - + internal static string ThrowHelper_UsePagingAttribute_NodeTypeUnknown { get { return ResourceManager.GetString("ThrowHelper_UsePagingAttribute_NodeTypeUnknown", resourceCulture); } } - + internal static string ErrorHelper_ObjectField_HasNoResolver { get { return ResourceManager.GetString("ErrorHelper_ObjectField_HasNoResolver", resourceCulture); } } - + internal static string ExtendedTypeReferenceHandler_NonGenericExecutableNotAllowed { get { return ResourceManager.GetString("ExtendedTypeReferenceHandler_NonGenericExecutableNotAllowed", resourceCulture); } } - + internal static string BindingCompiler_AddBinding_BindingCannotBeHandled { get { return ResourceManager.GetString("BindingCompiler_AddBinding_BindingCannotBeHandled", resourceCulture); } } - + internal static string Type_SpecifiedByUrl_Description { get { return ResourceManager.GetString("Type_SpecifiedByUrl_Description", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddObjectType_TIsSchemaType { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddObjectType_TIsSchemaType", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddUnionType_TIsSchemaType { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddUnionType_TIsSchemaType", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddEnumType_TIsSchemaType { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddEnumType_TIsSchemaType", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddInterfaceType_TIsSchemaType { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddInterfaceType_TIsSchemaType", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddInputObjectType_TIsSchemaType { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddInputObjectType_TIsSchemaType", resourceCulture); } } - + internal static string EventMessageParameterExpressionBuilder_MessageNotFound { get { return ResourceManager.GetString("EventMessageParameterExpressionBuilder_MessageNotFound", resourceCulture); } } - + internal static string DefaultResolverCompilerService_CreateResolver_ArgumentValidationError { get { return ResourceManager.GetString("DefaultResolverCompilerService_CreateResolver_ArgumentValidationError", resourceCulture); } } - + internal static string DefaultResolverCompilerService_CompileSubscribe_OnlyMethodsAllowed { get { return ResourceManager.GetString("DefaultResolverCompilerService_CompileSubscribe_OnlyMethodsAllowed", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddResolverConfig_ContextInvalid { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddResolverConfig_ContextInvalid", resourceCulture); } } - + internal static string ExpressionHelper_GetGlobalStateWithDefault_NoDefaults { get { return ResourceManager.GetString("ExpressionHelper_GetGlobalStateWithDefault_NoDefaults", resourceCulture); } } - + internal static string ExpressionHelper_ResolveScopedContextData_KeyDoesNotExist { get { return ResourceManager.GetString("ExpressionHelper_ResolveScopedContextData_KeyDoesNotExist", resourceCulture); } } - + internal static string ExpressionHelper_GetScopedStateWithDefault_NoDefaultValue { get { return ResourceManager.GetString("ExpressionHelper_GetScopedStateWithDefault_NoDefaultValue", resourceCulture); } } - + internal static string ClaimsPrincipalParameterExpressionBuilder_NoClaimsFound { get { return ResourceManager.GetString("ClaimsPrincipalParameterExpressionBuilder_NoClaimsFound", resourceCulture); } } - + internal static string DirectiveLocation_VariableDefinition { get { return ResourceManager.GetString("DirectiveLocation_VariableDefinition", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddResolver_TypeConditionNotMet { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddResolver_TypeConditionNotMet", resourceCulture); } } - + internal static string SchemaBuilderExtensions_AddRootResolver_NeedsToBeClassOrInterface { get { return ResourceManager.GetString("SchemaBuilderExtensions_AddRootResolver_NeedsToBeClassOrInterface", resourceCulture); } } - + internal static string Relay_NodeField_Description { get { return ResourceManager.GetString("Relay_NodeField_Description", resourceCulture); } } - + internal static string Relay_NodeField_Id_Description { get { return ResourceManager.GetString("Relay_NodeField_Id_Description", resourceCulture); } } - + internal static string Relay_NodesField_Description { get { return ResourceManager.GetString("Relay_NodesField_Description", resourceCulture); } } - + internal static string Relay_NodesField_Ids_Description { get { return ResourceManager.GetString("Relay_NodesField_Ids_Description", resourceCulture); } } - + internal static string ErrorHelper_MiddlewareOrderInvalid { get { return ResourceManager.GetString("ErrorHelper_MiddlewareOrderInvalid", resourceCulture); } } - + internal static string ErrorHelper_NoSchemaTypesAllowedAsRuntimeType { get { return ResourceManager.GetString("ErrorHelper_NoSchemaTypesAllowedAsRuntimeType", resourceCulture); } } - + internal static string FieldInitHelper_CompleteFields_MaxFieldCountToSmall { get { return ResourceManager.GetString("FieldInitHelper_CompleteFields_MaxFieldCountToSmall", resourceCulture); } } - + internal static string RegisteredType_Completion_NotYetReady { get { return ResourceManager.GetString("RegisteredType_Completion_NotYetReady", resourceCulture); } } - + internal static string EdgeType_IsInstanceOfType_NonObject { get { return ResourceManager.GetString("EdgeType_IsInstanceOfType_NonObject", resourceCulture); } } - + internal static string EdgeType_Description { get { return ResourceManager.GetString("EdgeType_Description", resourceCulture); } } - + internal static string EdgeType_Cursor_Description { get { return ResourceManager.GetString("EdgeType_Cursor_Description", resourceCulture); } } - + internal static string EdgeType_Node_Description { get { return ResourceManager.GetString("EdgeType_Node_Description", resourceCulture); } } - + internal static string ConnectionType_Description { get { return ResourceManager.GetString("ConnectionType_Description", resourceCulture); } } - + internal static string ConnectionType_PageInfo_Description { get { return ResourceManager.GetString("ConnectionType_PageInfo_Description", resourceCulture); } } - + internal static string ConnectionType_Edges_Description { get { return ResourceManager.GetString("ConnectionType_Edges_Description", resourceCulture); } } - + internal static string ConnectionType_TotalCount_Description { get { return ResourceManager.GetString("ConnectionType_TotalCount_Description", resourceCulture); } } - + internal static string CollectionSegmentType_PageInfo_Description { get { return ResourceManager.GetString("CollectionSegmentType_PageInfo_Description", resourceCulture); } } - + internal static string CollectionSegmentType_Description { get { return ResourceManager.GetString("CollectionSegmentType_Description", resourceCulture); } } - + internal static string CollectionSegmentType_Items_Description { get { return ResourceManager.GetString("CollectionSegmentType_Items_Description", resourceCulture); } } - + internal static string ConnectionType_Nodes_Description { get { return ResourceManager.GetString("ConnectionType_Nodes_Description", resourceCulture); } } - + internal static string ServiceHelper_UseResolverServiceInternal_Order { get { return ResourceManager.GetString("ServiceHelper_UseResolverServiceInternal_Order", resourceCulture); } } - + internal static string DefaultNamingConventions_FormatFieldName_EmptyOrNull { get { return ResourceManager.GetString("DefaultNamingConventions_FormatFieldName_EmptyOrNull", resourceCulture); } } - + internal static string OneOfDirectiveType_Description { get { return ResourceManager.GetString("OneOfDirectiveType_Description", resourceCulture); } } - + internal static string ThrowHelper_OneOfNoFieldSet { get { return ResourceManager.GetString("ThrowHelper_OneOfNoFieldSet", resourceCulture); } } - + internal static string ThrowHelper_OneOfMoreThanOneFieldSet { get { return ResourceManager.GetString("ThrowHelper_OneOfMoreThanOneFieldSet", resourceCulture); } } - + internal static string ThrowHelper_OneOfFieldIsNull { get { return ResourceManager.GetString("ThrowHelper_OneOfFieldIsNull", resourceCulture); } } - + internal static string ReflectionUtils_ExtractMethod_MethodExpected { get { return ResourceManager.GetString("ReflectionUtils_ExtractMethod_MethodExpected", resourceCulture); } } - + internal static string ResolverContextExtensions_ScopedContextData_KeyNotFound { get { return ResourceManager.GetString("ResolverContextExtensions_ScopedContextData_KeyNotFound", resourceCulture); } } - + internal static string ResolverContextExtensions_LocalContextData_KeyNotFound { get { return ResourceManager.GetString("ResolverContextExtensions_LocalContextData_KeyNotFound", resourceCulture); } } - + internal static string ResolverContextExtensions_ContextData_KeyNotFound { get { return ResourceManager.GetString("ResolverContextExtensions_ContextData_KeyNotFound", resourceCulture); } } - + internal static string SchemaTypes_GetType_DoesNotExist { get { return ResourceManager.GetString("SchemaTypes_GetType_DoesNotExist", resourceCulture); } } - + internal static string SchemaTypes_DefinitionInvalid { get { return ResourceManager.GetString("SchemaTypes_DefinitionInvalid", resourceCulture); } } - + internal static string InputObjectTypeDescriptor_OnlyProperties { get { return ResourceManager.GetString("InputObjectTypeDescriptor_OnlyProperties", resourceCulture); } } - + internal static string InterfaceTypeDescriptor_MustBePropertyOrMethod { get { return ResourceManager.GetString("InterfaceTypeDescriptor_MustBePropertyOrMethod", resourceCulture); } } - + internal static string ThrowHelper_FieldBase_Sealed { get { return ResourceManager.GetString("ThrowHelper_FieldBase_Sealed", resourceCulture); } } - + internal static string TypeInitializer_CannotFindType { get { return ResourceManager.GetString("TypeInitializer_CannotFindType", resourceCulture); } } - + internal static string ThrowHelper_RelayIdFieldHelpers_NoFieldType { get { return ResourceManager.GetString("ThrowHelper_RelayIdFieldHelpers_NoFieldType", resourceCulture); } } - + internal static string ThrowHelper_NodeResolver_ObjNoDefinition { get { return ResourceManager.GetString("ThrowHelper_NodeResolver_ObjNoDefinition", resourceCulture); } } - + internal static string ThrowHelper_NodeResolver_ArgumentTypeMissing { get { return ResourceManager.GetString("ThrowHelper_NodeResolver_ArgumentTypeMissing", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_TypeNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_TypeNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_FieldNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_FieldNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_FieldArgNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_FieldArgNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_InvalidCoordinate { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_InvalidCoordinate", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_InputFieldNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_InputFieldNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_EnumValueNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_EnumValueNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_DirectiveNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_DirectiveNotFound", resourceCulture); } } - + internal static string ThrowHelper_Schema_GetMember_DirectiveArgumentNotFound { get { return ResourceManager.GetString("ThrowHelper_Schema_GetMember_DirectiveArgumentNotFound", resourceCulture); } } - + internal static string ThrowHelper_FormatResultLeaf_InvalidSyntaxKind { get { return ResourceManager.GetString("ThrowHelper_FormatResultLeaf_InvalidSyntaxKind", resourceCulture); } } - + internal static string ThrowHelper_FormatResultList_InvalidObjectKind { get { return ResourceManager.GetString("ThrowHelper_FormatResultList_InvalidObjectKind", resourceCulture); } } - + internal static string ThrowHelper_FormatResultObject_InvalidObjectKind { get { return ResourceManager.GetString("ThrowHelper_FormatResultObject_InvalidObjectKind", resourceCulture); } } - + internal static string ThrowHelper_FormatValueList_InvalidObjectKind { get { return ResourceManager.GetString("ThrowHelper_FormatValueList_InvalidObjectKind", resourceCulture); } } - + internal static string ThrowHelper_ParseList_InvalidObjectKind { get { return ResourceManager.GetString("ThrowHelper_ParseList_InvalidObjectKind", resourceCulture); } } - + internal static string ThrowHelper_ParseNestedList_InvalidSyntaxKind { get { return ResourceManager.GetString("ThrowHelper_ParseNestedList_InvalidSyntaxKind", resourceCulture); } } - + internal static string ThrowHelper_ParseInputObject_InvalidObjectKind { get { return ResourceManager.GetString("ThrowHelper_ParseInputObject_InvalidObjectKind", resourceCulture); } } - + internal static string ThrowHelper_ParseInputObject_InvalidSyntaxKind { get { return ResourceManager.GetString("ThrowHelper_ParseInputObject_InvalidSyntaxKind", resourceCulture); } } - + internal static string ThrowHelper_NonNullInputViolation { get { return ResourceManager.GetString("ThrowHelper_NonNullInputViolation", resourceCulture); } } - + internal static string ThrowHelper_InvalidInputFieldNames { get { return ResourceManager.GetString("ThrowHelper_InvalidInputFieldNames", resourceCulture); } } - + internal static string ThrowHelper_RequiredInputFieldIsMissing { get { return ResourceManager.GetString("ThrowHelper_RequiredInputFieldIsMissing", resourceCulture); } } - + internal static string ThrowHelper_DataLoader_InvalidType { get { return ResourceManager.GetString("ThrowHelper_DataLoader_InvalidType", resourceCulture); } } - + internal static string ThrowHelper_Convention_ConventionCouldNotBeCreated { get { return ResourceManager.GetString("ThrowHelper_Convention_ConventionCouldNotBeCreated", resourceCulture); } } - + internal static string ThrowHelper_Convention_TwoConventionsRegisteredForScope { get { return ResourceManager.GetString("ThrowHelper_Convention_TwoConventionsRegisteredForScope", resourceCulture); } } - + internal static string ThrowHelper_NodeAttribute_IdFieldNotFound { get { return ResourceManager.GetString("ThrowHelper_NodeAttribute_IdFieldNotFound", resourceCulture); } } - + internal static string ThrowHelper_TypeCompletionContext_UnableToResolveType { get { return ResourceManager.GetString("ThrowHelper_TypeCompletionContext_UnableToResolveType", resourceCulture); } } - + internal static string ThrowHelper_TypeRegistrar_CreateInstanceFailed { get { return ResourceManager.GetString("ThrowHelper_TypeRegistrar_CreateInstanceFailed", resourceCulture); } } - + internal static string ThrowHelper_Convention_UnableToCreateConvention { get { return ResourceManager.GetString("ThrowHelper_Convention_UnableToCreateConvention", resourceCulture); } } - + internal static string ThrowHelper_SubscribeAttribute_SubscribeResolverNotFound { get { return ResourceManager.GetString("ThrowHelper_SubscribeAttribute_SubscribeResolverNotFound", resourceCulture); } } - + internal static string ThrowHelper_SubscribeAttribute_TopicTypeUnspecified { get { return ResourceManager.GetString("ThrowHelper_SubscribeAttribute_TopicTypeUnspecified", resourceCulture); } } - + internal static string ThrowHelper_SubscribeAttribute_MessageTypeUnspecified { get { return ResourceManager.GetString("ThrowHelper_SubscribeAttribute_MessageTypeUnspecified", resourceCulture); } } - + internal static string ThrowHelper_EventMessage_NotFound { get { return ResourceManager.GetString("ThrowHelper_EventMessage_NotFound", resourceCulture); } } - + internal static string ThrowHelper_EventMessage_InvalidCast { get { return ResourceManager.GetString("ThrowHelper_EventMessage_InvalidCast", resourceCulture); } } - + internal static string ErrorHelper_NeedsOneAtLeastField { get { return ResourceManager.GetString("ErrorHelper_NeedsOneAtLeastField", resourceCulture); } } - + internal static string ErrorHelper_TwoUnderscoresNotAllowedField { get { return ResourceManager.GetString("ErrorHelper_TwoUnderscoresNotAllowedField", resourceCulture); } } - + internal static string ErrorHelper_TwoUnderscoresNotAllowedOnArgument { get { return ResourceManager.GetString("ErrorHelper_TwoUnderscoresNotAllowedOnArgument", resourceCulture); } } - + internal static string ErrorHelper_TwoUnderscoresNotAllowedOnDirectiveName { get { return ResourceManager.GetString("ErrorHelper_TwoUnderscoresNotAllowedOnDirectiveName", resourceCulture); } } - + internal static string ErrorHelper_NotTransitivelyImplemented { get { return ResourceManager.GetString("ErrorHelper_NotTransitivelyImplemented", resourceCulture); } } - + internal static string ErrorHelper_InvalidFieldDeprecation { get { return ResourceManager.GetString("ErrorHelper_InvalidFieldDeprecation", resourceCulture); } } - + internal static string ErrorHelper_InvalidFieldType { get { return ResourceManager.GetString("ErrorHelper_InvalidFieldType", resourceCulture); } } - + internal static string ErrorHelper_FieldNotImplemented { get { return ResourceManager.GetString("ErrorHelper_FieldNotImplemented", resourceCulture); } } - + internal static string ErrorHelper_InvalidArgumentType { get { return ResourceManager.GetString("ErrorHelper_InvalidArgumentType", resourceCulture); } } - + internal static string ErrorHelper_AdditionalArgumentNotNullable { get { return ResourceManager.GetString("ErrorHelper_AdditionalArgumentNotNullable", resourceCulture); } } - + internal static string ErrorHelper_ArgumentNotImplemented { get { return ResourceManager.GetString("ErrorHelper_ArgumentNotImplemented", resourceCulture); } } - + internal static string ErrorHelper_OneOfInputObjectMustHaveNullableFieldsWithoutDefaults { get { return ResourceManager.GetString("ErrorHelper_OneOfInputObjectMustHaveNullableFieldsWithoutDefaults", resourceCulture); } } - + internal static string ErrorHelper_InputObjectMustNotHaveRecursiveNonNullableReferencesToSelf { get { return ResourceManager.GetString("ErrorHelper_InputObjectMustNotHaveRecursiveNonNullableReferencesToSelf", resourceCulture); } } - + internal static string ErrorHelper_RequiredArgumentCannotBeDeprecated { get { return ResourceManager.GetString("ErrorHelper_RequiredArgumentCannotBeDeprecated", resourceCulture); } } - + internal static string ErrorHelper_RequiredFieldCannotBeDeprecated { get { return ResourceManager.GetString("ErrorHelper_RequiredFieldCannotBeDeprecated", resourceCulture); } } - + internal static string ErrorHelper_InterfaceHasNoImplementation { get { return ResourceManager.GetString("ErrorHelper_InterfaceHasNoImplementation", resourceCulture); } } - + internal static string ErrorHelper_CompleteInterfacesHelper_UnableToResolveInterface { get { return ResourceManager.GetString("ErrorHelper_CompleteInterfacesHelper_UnableToResolveInterface", resourceCulture); } } - + internal static string ErrorHelper_DirectiveCollection_ArgumentDoesNotExist { get { return ResourceManager.GetString("ErrorHelper_DirectiveCollection_ArgumentDoesNotExist", resourceCulture); } } - + internal static string ErrorHelper_DirectiveCollection_ArgumentNonNullViolation { get { return ResourceManager.GetString("ErrorHelper_DirectiveCollection_ArgumentNonNullViolation", resourceCulture); } } - + internal static string ErrorHelper_ObjectType_UnableToInferOrResolveType { get { return ResourceManager.GetString("ErrorHelper_ObjectType_UnableToInferOrResolveType", resourceCulture); } } - + internal static string ErrorHelper_Relay_NoNodeResolver { get { return ResourceManager.GetString("ErrorHelper_Relay_NoNodeResolver", resourceCulture); } } - + internal static string ErrorHelper_NodeResolver_MustHaveExactlyOneIdArg { get { return ResourceManager.GetString("ErrorHelper_NodeResolver_MustHaveExactlyOneIdArg", resourceCulture); } } - + internal static string ErrorHelper_NodeResolver_MustReturnObject { get { return ResourceManager.GetString("ErrorHelper_NodeResolver_MustReturnObject", resourceCulture); } } - + internal static string ErrorHelper_NodeResolver_NodeTypeHasNoId { get { return ResourceManager.GetString("ErrorHelper_NodeResolver_NodeTypeHasNoId", resourceCulture); } } - + internal static string ThrowHelper_InvalidInputFieldNames_Single { get { return ResourceManager.GetString("ThrowHelper_InvalidInputFieldNames_Single", resourceCulture); } } - + internal static string ThrowHelper_MutationDuplicateErrorName { get { return ResourceManager.GetString("ThrowHelper_MutationDuplicateErrorName", resourceCulture); } } - + internal static string ErrorHelper_NodeResolverMissing { get { return ResourceManager.GetString("ErrorHelper_NodeResolverMissing", resourceCulture); } } - + internal static string ThrowHelper_Flags_Enum_Shape_Unknown { get { return ResourceManager.GetString("ThrowHelper_Flags_Enum_Shape_Unknown", resourceCulture); } } - + internal static string ThrowHelper_Flags_Parser_NoSelection { get { return ResourceManager.GetString("ThrowHelper_Flags_Parser_NoSelection", resourceCulture); } } - + internal static string ThrowHelper_Flags_Parser_UnknownSelection { get { return ResourceManager.GetString("ThrowHelper_Flags_Parser_UnknownSelection", resourceCulture); } } - + internal static string ThrowHelper_Flags_IllegalFlagEnumName { get { return ResourceManager.GetString("ThrowHelper_Flags_IllegalFlagEnumName", resourceCulture); } } - + internal static string Directive_GetArgumentValue_UnknownArgument { get { return ResourceManager.GetString("Directive_GetArgumentValue_UnknownArgument", resourceCulture); } } - + internal static string ErrorHelper_DirectiveCollection_ArgumentValueTypeIsWrong { get { return ResourceManager.GetString("ErrorHelper_DirectiveCollection_ArgumentValueTypeIsWrong", resourceCulture); } } - + internal static string TypeDiscoveryInfo_TypeRefKindNotSupported { get { return ResourceManager.GetString("TypeDiscoveryInfo_TypeRefKindNotSupported", resourceCulture); } } - + internal static string ErrorHelper_FetchedToManyNodesAtOnce { get { return ResourceManager.GetString("ErrorHelper_FetchedToManyNodesAtOnce", resourceCulture); } } - + internal static string ThrowHelper_InputTypeExpected_Message { get { return ResourceManager.GetString("ThrowHelper_InputTypeExpected_Message", resourceCulture); } } - + internal static string ThrowHelper_OutputTypeExpected_Message { get { return ResourceManager.GetString("ThrowHelper_OutputTypeExpected_Message", resourceCulture); } } - + internal static string TagDirective_Name_NotValid { get { return ResourceManager.GetString("TagDirective_Name_NotValid", resourceCulture); } } - + internal static string TagDirective_Descriptor_NotSupported { get { return ResourceManager.GetString("TagDirective_Descriptor_NotSupported", resourceCulture); } } - + internal static string ErrorHelper_DuplicateFieldName_Message { get { return ResourceManager.GetString("ErrorHelper_DuplicateFieldName_Message", resourceCulture); } } - + internal static string ErrorHelper_DuplicateDataMiddlewareDetected_Message { get { return ResourceManager.GetString("ErrorHelper_DuplicateDataMiddlewareDetected_Message", resourceCulture); } } - + internal static string SchemaException_UnexpectedError { get { return ResourceManager.GetString("SchemaException_UnexpectedError", resourceCulture); } } - + internal static string SchemaException_ErrorSummaryText { get { return ResourceManager.GetString("SchemaException_ErrorSummaryText", resourceCulture); } } - + internal static string ResolverContextExtensions_IsSelected_FieldNameEmpty { get { return ResourceManager.GetString("ResolverContextExtensions_IsSelected_FieldNameEmpty", resourceCulture); } } - + internal static string ObjectToDictionaryConverter_CycleInObjectGraph { get { return ResourceManager.GetString("ObjectToDictionaryConverter_CycleInObjectGraph", resourceCulture); } } - + internal static string LocalDateTimeType_Description { get { return ResourceManager.GetString("LocalDateTimeType_Description", resourceCulture); } } - + internal static string LocalDateType_Description { get { return ResourceManager.GetString("LocalDateType_Description", resourceCulture); } } - + internal static string LocalTimeType_Description { get { return ResourceManager.GetString("LocalTimeType_Description", resourceCulture); } } - + internal static string SchemaBuilder_BindRuntimeType_ObjectNotAllowed { get { return ResourceManager.GetString("SchemaBuilder_BindRuntimeType_ObjectNotAllowed", resourceCulture); } } - + internal static string TypeExtensions_KindIsNotSupported { get { return ResourceManager.GetString("TypeExtensions_KindIsNotSupported", resourceCulture); } } - + internal static string ThrowHelper_InvalidTypeConversion { get { return ResourceManager.GetString("ThrowHelper_InvalidTypeConversion", resourceCulture); diff --git a/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx b/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx index 4b97a51592d..e81860474d7 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx +++ b/src/HotChocolate/Core/src/Types/Properties/TypeResources.resx @@ -266,10 +266,10 @@ In some cases, you need to provide options to alter GraphQL's execution behavior {0} cannot deserialize the given value. - + {0} cannot parse the given literal of type `{1}`. - + {0} cannot parse the given value of type `{1}`. diff --git a/src/HotChocolate/Core/src/Types/Properties/TypeResourcesExtensions.cs b/src/HotChocolate/Core/src/Types/Properties/TypeResourcesExtensions.cs index 29424f1d424..f7a043adb79 100644 --- a/src/HotChocolate/Core/src/Types/Properties/TypeResourcesExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Properties/TypeResourcesExtensions.cs @@ -4,10 +4,16 @@ namespace HotChocolate.Properties; internal static class TypeResourceHelper { - public static string Scalar_Cannot_Serialize(string typeName) + public static string Scalar_Cannot_ConvertValueToLiteral(Type actualType, string actualValue) { - ArgumentException.ThrowIfNullOrEmpty(typeName); + return string.Format( + CultureInfo.InvariantCulture, + TypeResources.Scalar_Cannot_Deserialize, + typeName); + } + public static string Scalar_Cannot_Serialize(string typeName) + { return string.Format( CultureInfo.InvariantCulture, TypeResources.Scalar_Cannot_Serialize, @@ -16,49 +22,35 @@ public static string Scalar_Cannot_Serialize(string typeName) public static string Scalar_Cannot_Deserialize(string typeName) { - ArgumentException.ThrowIfNullOrEmpty(typeName); - return string.Format( CultureInfo.InvariantCulture, TypeResources.Scalar_Cannot_Deserialize, typeName); } - public static string Scalar_Cannot_ParseLiteral( - string typeName, Type literalType) + public static string Scalar_Cannot_CoerceInputLiteral(string typeName, Type literalType) { - ArgumentException.ThrowIfNullOrEmpty(typeName); - ArgumentNullException.ThrowIfNull(literalType); - return string.Format( CultureInfo.InvariantCulture, - TypeResources.Scalar_Cannot_ParseLiteral, + TypeResources.Scalar_Cannot_CoerceInputLiteral, typeName, literalType.Name); } - public static string Scalar_Cannot_ParseValue( - string typeName, Type valueType) + public static string Scalar_Cannot_CoerceInputValue(string typeName, Type valueType) { - ArgumentException.ThrowIfNullOrEmpty(typeName); - ArgumentNullException.ThrowIfNull(valueType); - return string.Format( CultureInfo.InvariantCulture, - TypeResources.Scalar_Cannot_ParseValue, + TypeResources.Scalar_Cannot_CoerceInputValue, typeName, valueType.FullName); } - public static string Scalar_Cannot_ParseResult( - string typeName, Type valueType) + public static string Scalar_Cannot_ParseResult(string typeName, Type valueType) { - ArgumentException.ThrowIfNullOrEmpty(typeName); - ArgumentNullException.ThrowIfNull(valueType); - return string.Format( CultureInfo.InvariantCulture, - TypeResources.Scalar_Cannot_ParseValue, + TypeResources.Scalar_Cannot_CoerceInputValue, typeName, valueType.FullName); } @@ -66,7 +58,6 @@ public static string Scalar_Cannot_ParseResult( public static string Type_Name_IsNotValid(string typeName) { var name = typeName ?? "null"; - return $"`{name}` is not a valid " - + "GraphQL type name."; + return $"`{name}` is not a valid GraphQL type name."; } } diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionMapType.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionMapType.cs index 0126705a663..44a3642753c 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionMapType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionMapType.cs @@ -52,7 +52,7 @@ public override IValueNode ParseResult(object? resultValue) return new StringValueNode(FormatValueSelection(valueSelection)); } - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.New() .SetMessage("The field selection set syntax is invalid.") .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -61,7 +61,7 @@ public override IValueNode ParseResult(object? resultValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionSetType.cs b/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionSetType.cs index 0ede9912dcd..03a4449044d 100644 --- a/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionSetType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Composite/Types/FieldSelectionSetType.cs @@ -51,7 +51,7 @@ public override IValueNode ParseResult(object? resultValue) return new StringValueNode(SerializeSelectionSet(selectionSet)); } - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.New() .SetMessage("The field selection set syntax is invalid.") .SetCode(ErrorCodes.Scalars.InvalidRuntimeType) @@ -60,7 +60,7 @@ public override IValueNode ParseResult(object? resultValue) } /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs b/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs index 1703bffc19d..41bedd1dd3c 100644 --- a/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Contracts/ILeafType.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using HotChocolate.Language; using HotChocolate.Text.Json; @@ -10,164 +11,93 @@ namespace HotChocolate.Types; public interface ILeafType : IInputTypeDefinition, IOutputTypeDefinition { /// - /// Defines if the given is possibly of this type. + /// Determines if the given is compatible with this type. /// - /// - /// The GraphQL value syntax which shall be validated. + /// + /// The GraphQL literal to validate. /// /// - /// true if the given is possibly of this type. + /// true if the given is compatible with this type. /// - bool IsInstanceOfType(IValueNode valueSyntax); + bool IsValueCompatible(IValueNode valueLiteral); /// - /// Defines if the given is possibly of this type. + /// Determines if the given is compatible with this type. /// - /// - /// The runtime value which shall be validated. + /// + /// The deserialized JSON input value to validate. /// /// - /// true if the given is possibly of this type. + /// true if the given is compatible with this type. /// - bool IsInstanceOfType(object? runtimeValue); + bool IsValueCompatible(JsonElement inputValue); /// - /// Parses the GraphQL value syntax of this type into a runtime value representation. - /// - /// - /// A GraphQL value syntax representation of this type. - /// - /// - /// Returns a runtime value representation of this type. - /// - object? ParseLiteral(IValueNode valueSyntax); - - /// - /// Parses a runtime value of this type into a GraphQL value syntax representation. + /// Determines if the given is an instance of this type. /// /// - /// A result value representation of this type. + /// The runtime value to validate. /// /// - /// Returns a GraphQL value syntax representation of the . + /// true if the given is an instance of this type. /// - /// - /// Unable to parse the given - /// into a GraphQL value syntax representation of this type. - /// - IValueNode ParseValue(object? runtimeValue); + bool IsInstanceOfType(object? runtimeValue); /// - /// Parses a result value of this into a GraphQL value syntax representation. + /// Coerces a GraphQL literal (AST value node) into a runtime value. /// - /// - /// A result value representation of this type. + /// + /// The GraphQL literal to coerce. /// /// - /// Returns a GraphQL value syntax representation of the . + /// Returns the runtime value representation. /// - /// - /// Unable to parse the given - /// into a GraphQL value syntax representation of this type. + /// + /// Unable to coerce the given into a runtime value. /// - IValueNode ParseResult(object? resultValue); + object? CoerceInputLiteral(IValueNode valueLiteral); /// - /// Serializes a runtime value of this type to the result value format. + /// Coerces an external input value (deserialized JSON) into a runtime value. /// - /// - /// A runtime value representation of this type. + /// + /// The deserialized JSON input value to coerce. /// /// - /// Returns a result value representation of this type. + /// Returns the runtime value representation. /// - /// - /// Unable to serialize the given . + /// + /// Unable to coerce the given into a runtime value. /// - object? Serialize(object? runtimeValue); - - /// - /// Deserializes a result value of this type to the runtime value format. - /// - /// - /// A result value representation of this type. - /// - /// - /// Returns a runtime value representation of this type. - /// - object? Deserialize(object? resultValue); + object? CoerceInputValue(JsonElement inputValue); /// - /// Deserializes a result value of this type to the runtime value format. + /// Coerces a runtime value into an external output representation + /// and writes it to the result. /// - /// - /// A result value representation of this type. - /// /// - /// The runtime value representation of this type. + /// The runtime value to coerce. /// - /// - /// true if the deserialization was successful; otherwise, false. - /// - bool TryDeserialize(object? resultValue, out object? runtimeValue); -} - -/// -/// Represents a GraphQL leaf-type e.g., scalar or enum. -/// -public interface ILeafType2 : IInputTypeDefinition, IOutputTypeDefinition -{ - /// - /// Defines if the given is possibly of this type. - /// - /// - /// The runtime value which shall be validated. - /// - /// - /// true if the given is possibly of this type. - /// - bool IsInstanceOfType(object? runtimeValue); - - /// - /// Parses the GraphQL value syntax of this type into a runtime value representation. - /// - /// - /// A GraphQL value syntax representation of this type. - /// - /// - /// Returns a runtime value representation of this type. - /// - object? ParseLiteral(IValueNode valueSyntax); - - /// - /// Parses a runtime value of this type into a GraphQL value syntax representation. - /// - /// - /// A result value representation of this type. + /// + /// The result element to write the output value to. /// - /// - /// Returns a GraphQL value syntax representation of the . - /// - /// - /// Unable to parse the given - /// into a GraphQL value syntax representation of this type. + /// + /// Unable to coerce the given into an output value. /// - IValueNode ParseValue(object? runtimeValue); + void CoerceOutputValue(object? runtimeValue, ResultElement resultValue); /// - /// Serializes a runtime value of this type to the result value format. + /// Converts a runtime value into a GraphQL literal (AST value node). + /// Used for default value representation in SDL and introspection. /// /// - /// A runtime value representation of this type. - /// - /// - /// + /// The runtime value to convert. /// /// - /// Returns a result value representation of this type. + /// Returns a GraphQL literal representation of the runtime value. /// - /// - /// Unable to serialize the given . + /// + /// Unable to convert the given into a literal. /// - void Serialize(object? runtimeValue, ResultElement resultValue); + IValueNode ValueToLiteral(object? runtimeValue); } diff --git a/src/HotChocolate/Core/src/Types/Types/Contracts/SerializationException.cs b/src/HotChocolate/Core/src/Types/Types/Contracts/LeafCoercionException.cs similarity index 78% rename from src/HotChocolate/Core/src/Types/Types/Contracts/SerializationException.cs rename to src/HotChocolate/Core/src/Types/Types/Contracts/LeafCoercionException.cs index b1ee88cddc1..b27ba2a4b60 100644 --- a/src/HotChocolate/Core/src/Types/Types/Contracts/SerializationException.cs +++ b/src/HotChocolate/Core/src/Types/Types/Contracts/LeafCoercionException.cs @@ -4,10 +4,10 @@ namespace HotChocolate.Types; /// The serialization exception is thrown whenever a type cannot /// serialize, deserialize or parse a value. /// -public class SerializationException : GraphQLException +public class LeafCoercionException : GraphQLException { /// - /// Initializes the . + /// Initializes the . /// /// /// The error message. @@ -18,7 +18,7 @@ public class SerializationException : GraphQLException /// /// The field path that points to the exact field causing the exception. /// - public SerializationException(string message, ITypeSystemMember type, Path? path = null) + public LeafCoercionException(string message, ITypeSystemMember type, Path? path = null) : base(message) { Type = type; @@ -26,7 +26,7 @@ public SerializationException(string message, ITypeSystemMember type, Path? path } /// - /// Initializes the . + /// Initializes the . /// /// /// The serialization error object. @@ -37,7 +37,7 @@ public SerializationException(string message, ITypeSystemMember type, Path? path /// /// The field path that points to the exact field causing the exception. /// - public SerializationException(IError error, ITypeSystemMember type, Path? path = null) + public LeafCoercionException(IError error, ITypeSystemMember type, Path? path = null) : base(error) { Type = type; diff --git a/src/HotChocolate/Core/src/Types/Types/DirectiveCollection.cs b/src/HotChocolate/Core/src/Types/Types/DirectiveCollection.cs index a66e332e232..deb8ae74ac2 100644 --- a/src/HotChocolate/Core/src/Types/Types/DirectiveCollection.cs +++ b/src/HotChocolate/Core/src/Types/Types/DirectiveCollection.cs @@ -247,7 +247,7 @@ internal static DirectiveCollection CreateAndComplete( runtimeValue = value; } } - catch (SerializationException ex) + catch (LeafCoercionException ex) { hasErrors = true; diff --git a/src/HotChocolate/Core/src/Types/Types/EnumType.cs b/src/HotChocolate/Core/src/Types/Types/EnumType.cs index 27381c065f4..4d60433e75b 100644 --- a/src/HotChocolate/Core/src/Types/Types/EnumType.cs +++ b/src/HotChocolate/Core/src/Types/Types/EnumType.cs @@ -69,7 +69,7 @@ public bool TryGetRuntimeValue(string name, [NotNullWhen(true)] out object? runt } /// - public bool IsInstanceOfType(IValueNode valueSyntax) + public bool IsValueCompatible(IValueNode valueSyntax) { ArgumentNullException.ThrowIfNull(valueSyntax); @@ -96,7 +96,7 @@ public bool IsInstanceOfType(object? runtimeValue) => runtimeValue is null || RuntimeType.IsInstanceOfType(runtimeValue); /// - public object? ParseLiteral(IValueNode valueSyntax) + public object? CoerceInputLiteral(IValueNode valueSyntax) { ArgumentNullException.ThrowIfNull(valueSyntax); @@ -117,13 +117,13 @@ public bool IsInstanceOfType(object? runtimeValue) return null; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } /// - public IValueNode ParseValue(object? runtimeValue) + public IValueNode CoerceInputValue(object? runtimeValue) { if (runtimeValue is null) { @@ -135,8 +135,8 @@ public IValueNode ParseValue(object? runtimeValue) return new EnumValueNode(enumValue.Name); } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseValue(Name, runtimeValue.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputValue(Name, runtimeValue.GetType()), this); } @@ -159,7 +159,7 @@ public IValueNode ParseResult(object? resultValue) return new EnumValueNode(enumValue.Name); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } @@ -188,7 +188,7 @@ public IValueNode ParseResult(object? resultValue) } } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_Serialize(Name), this); } @@ -201,7 +201,7 @@ public IValueNode ParseResult(object? resultValue) return runtimeValue; } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_Deserialize(Name), this); } diff --git a/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs b/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs index 4751b4964cf..d1ce603e430 100644 --- a/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs +++ b/src/HotChocolate/Core/src/Types/Types/Extensions/TypeExtensions.cs @@ -119,7 +119,7 @@ public static bool IsInstanceOfType(this IInputType type, IValueNode literal) return literal.Kind == SyntaxKind.ObjectValue; default: - return ((ILeafType)type).IsInstanceOfType(literal); + return ((ILeafType)type).IsValueCompatible(literal); } } } diff --git a/src/HotChocolate/Core/src/Types/Types/InputFormatter.cs b/src/HotChocolate/Core/src/Types/Types/InputFormatter.cs index bda31fcf0a1..70a80a97f7b 100644 --- a/src/HotChocolate/Core/src/Types/Types/InputFormatter.cs +++ b/src/HotChocolate/Core/src/Types/Types/InputFormatter.cs @@ -129,11 +129,11 @@ private IValueNode FormatValueLeaf(object runtimeValue, ILeafType type, Path pat runtimeValue = converted; } - return type.ParseValue(runtimeValue); + return type.CoerceInputValue(runtimeValue); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { - throw new SerializationException(ex.Errors[0], ex.Type, path); + throw new LeafCoercionException(ex.Errors[0], ex.Type, path); } } @@ -295,7 +295,7 @@ private static IValueNode FormatResultLeaf(object resultValue, ILeafType type, P { if (resultValue is IValueNode node) { - if (type.IsInstanceOfType(node)) + if (type.IsValueCompatible(node)) { return node; } @@ -307,9 +307,9 @@ private static IValueNode FormatResultLeaf(object resultValue, ILeafType type, P { return type.ParseResult(resultValue); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { - throw new SerializationException(ex.Errors[0], ex.Type, path); + throw new LeafCoercionException(ex.Errors[0], ex.Type, path); } } } diff --git a/src/HotChocolate/Core/src/Types/Types/InputParser.cs b/src/HotChocolate/Core/src/Types/Types/InputParser.cs index 3067f926142..3fd57afca3a 100644 --- a/src/HotChocolate/Core/src/Types/Types/InputParser.cs +++ b/src/HotChocolate/Core/src/Types/Types/InputParser.cs @@ -293,13 +293,13 @@ private object ParseObject( { try { - return type.ParseLiteral(resultValue); + return type.CoerceInputLiteral(resultValue); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { if (field is null) { - throw new SerializationException(ex.Errors[0].WithPath(path), ex.Type, path); + throw new LeafCoercionException(ex.Errors[0].WithPath(path), ex.Type, path); } var error = ErrorBuilder.FromError(ex.Errors[0]) @@ -308,7 +308,7 @@ private object ParseObject( .SetExtension("fieldType", type.Name) .Build(); - throw new SerializationException(error, ex.Type, path); + throw new LeafCoercionException(error, ex.Type, path); } } @@ -587,11 +587,11 @@ private object DeserializeObject(object resultValue, InputObjectType type, Path { return type.Deserialize(resultValue); } - catch (SerializationException ex) + catch (LeafCoercionException ex) { if (field is null) { - throw new SerializationException(ex.Errors[0].WithPath(path), ex.Type, path); + throw new LeafCoercionException(ex.Errors[0].WithPath(path), ex.Type, path); } var error = ErrorBuilder.FromError(ex.Errors[0]) @@ -600,7 +600,7 @@ private object DeserializeObject(object resultValue, InputObjectType type, Path .SetExtension("fieldType", type.Name) .Build(); - throw new SerializationException(error, ex.Type, path); + throw new LeafCoercionException(error, ex.Type, path); } } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/AnyType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/AnyType.cs index 4459f8640ce..a6b3a7c586f 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/AnyType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/AnyType.cs @@ -3,6 +3,7 @@ using HotChocolate.Configuration; using HotChocolate.Language; using HotChocolate.Properties; +using HotChocolate.Text.Json; using HotChocolate.Types.Descriptors.Configurations; using HotChocolate.Utilities; @@ -44,7 +45,7 @@ protected override void OnCompleteType( _objectToDictConverter = new ObjectToDictionaryConverter(Converter); } - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { ArgumentNullException.ThrowIfNull(literal); @@ -64,7 +65,7 @@ public override bool IsInstanceOfType(IValueNode literal) } } - public override object? ParseLiteral(IValueNode literal) + public override object? CoerceInputLiteral(IValueNode literal) { switch (literal) { @@ -90,20 +91,20 @@ public override bool IsInstanceOfType(IValueNode literal) return null; default: - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, literal.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, literal.GetType()), this); } } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { return value is null ? NullValueNode.Default : ParseValue(value, new HashSet(ReferenceEqualityComparer.Instance)); } - private IValueNode ParseValue(object? value, ISet set) + private IValueNode ParseValue(object? value, HashSet set) { if (value is null) { @@ -180,105 +181,85 @@ private IValueNode ParseValue(object? value, ISet set) return valueNode; } - throw new SerializationException( + throw new LeafCoercionException( TypeResources.AnyType_CycleInObjectGraph, this); } - public override IValueNode ParseResult(object? resultValue) => - ParseValue(resultValue); - - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, ResultElement resultValue) { if (runtimeValue is null) { - resultValue = null; + resultValue.SetNullValue(); return true; } switch (runtimeValue) { - case string: - case short: - case int: - case long: - case float: - case double: - case decimal: - case bool: - case sbyte: - case byte: - resultValue = runtimeValue; + case string castedString: + resultValue.SetStringValue(castedString); return true; - default: - var type = runtimeValue.GetType(); + case short castedShort: + resultValue.SetNumberValue(castedShort); + return true; - if (type.IsValueType - && Converter.TryConvert(type, typeof(string), runtimeValue, out var c, out _) - && c is string casted) - { - resultValue = casted; - return true; - } + case int castedInt: + resultValue.SetNumberValue(castedInt); + return true; - resultValue = _objectToDictConverter.Convert(runtimeValue); + case long castedLong: + resultValue.SetNumberValue(castedLong); return true; - } - } - public override bool TryDeserialize(object? resultValue, out object? runtimeValue) - { - object? elementValue; - runtimeValue = null; - switch (resultValue) - { - case IDictionary dictionary: - { - var result = new Dictionary(); - foreach (var element in dictionary) - { - if (TryDeserialize(element.Value, out elementValue)) - { - result[element.Key] = elementValue; - } - else - { - return false; - } - } + case float castedFloat: + resultValue.SetNumberValue(castedFloat); + return true; - runtimeValue = result; + case double castedDouble: + resultValue.SetNumberValue(castedDouble); return true; - } - case IList list: - { - var result = new object?[list.Count]; - for (var i = 0; i < list.Count; i++) - { - if (TryDeserialize(list[i], out elementValue)) - { - result[i] = elementValue; - } - else - { - return false; - } - } + case decimal castedDecimal: + resultValue.SetNumberValue(castedDecimal); + return true; - runtimeValue = result; + case bool castedBool: + resultValue.SetBooleanValue(castedBool); + return true; + + case sbyte castedSByte: + resultValue.SetNumberValue(castedSByte); + return true; + + case byte castedByte: + resultValue.SetNumberValue(castedByte); + return true; + + case ushort castedUShort: + resultValue.SetNumberValue(castedUShort); + return true; + + case uint castedUInt: + resultValue.SetNumberValue(castedUInt); return true; - } - // TODO: this is only done for a bug in schema stitching and needs to be removed - // once we have release stitching 2. - case IValueNode literal: - runtimeValue = ParseLiteral(literal); + case ulong castedULong: + resultValue.SetNumberValue(castedULong); return true; default: - runtimeValue = resultValue; + var type = runtimeValue.GetType(); + + if (type.IsValueType + && Converter.TryConvert(type, typeof(string), runtimeValue, out var c, out _) + && c is string casted) + { + resultValue = casted; + return true; + } + + resultValue = _objectToDictConverter.Convert(runtimeValue); return true; } } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/BooleanType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/BooleanType.cs index a990945b698..bce932a27df 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/BooleanType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/BooleanType.cs @@ -1,12 +1,17 @@ +using System.Text.Json; using HotChocolate.Language; using HotChocolate.Properties; +using HotChocolate.Text.Json; namespace HotChocolate.Types; /// +/// /// The Boolean scalar type represents true or false. -/// -/// http://facebook.github.io/graphql/June2018/#sec-Boolean +/// +/// +/// https://spec.graphql.org/September2025/#sec-Boolean +/// /// [SpecScalar] public class BooleanType : ScalarType @@ -35,30 +40,32 @@ public BooleanType() { } - protected override bool ParseLiteral(BooleanValueNode valueSyntax) - { - return valueSyntax.Value; - } - - protected override BooleanValueNode ParseValue(bool runtimeValue) - { - return runtimeValue ? BooleanValueNode.True : BooleanValueNode.False; - } + public override object? CoerceInputLiteral(BooleanValueNode valueLiteral) + => valueLiteral.Value; - public override IValueNode ParseResult(object? resultValue) + public override object? CoerceInputValue(JsonElement inputValue) { - if (resultValue is null) + switch (inputValue.ValueKind) { - return NullValueNode.Default; - } + case JsonValueKind.Null: + return null; - if (resultValue is bool b) - { - return b ? BooleanValueNode.True : BooleanValueNode.False; - } + case JsonValueKind.True: + return true; + + case JsonValueKind.False: + return false; - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), - this); + default: + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_ParseValue(Name, inputValue.ValueKind.ToString()), + this); + } } + + public override void CoerceOutputValue(bool runtimeValue, ResultElement resultValue) + => resultValue.SetBooleanValue(runtimeValue); + + public override IValueNode ValueToLiteral(bool runtimeValue) + => runtimeValue ? BooleanValueNode.True : BooleanValueNode.False; } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/ByteArrayType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/ByteArrayType.cs index 6bb21583664..7c2da01cb89 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/ByteArrayType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/ByteArrayType.cs @@ -59,12 +59,12 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(b); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/DateTimeType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/DateTimeType.cs index 0b130984417..5bb6157af90 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/DateTimeType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/DateTimeType.cs @@ -79,8 +79,8 @@ protected override DateTimeOffset ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -111,12 +111,12 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(new DateTimeOffset(dt.ToUniversalTime(), TimeSpan.Zero)); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs index fb933349249..8554dcef57a 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs @@ -53,8 +53,8 @@ protected override DateOnly ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -70,12 +70,12 @@ public override IValueNode ParseResult(object? resultValue) DateOnly d => ParseValue(d), DateTimeOffset o => ParseValue(DateOnly.FromDateTime(o.UtcDateTime)), DateTime dt => ParseValue(DateOnly.FromDateTime(dt.ToUniversalTime())), - _ => throw new SerializationException( + _ => throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this) }; } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/FloatTypeBase.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/FloatTypeBase.cs index e684c5377ed..462902c6608 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/FloatTypeBase.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/FloatTypeBase.cs @@ -22,7 +22,7 @@ protected FloatTypeBase( public TRuntimeType MaxValue { get; } - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) { ArgumentNullException.ThrowIfNull(valueSyntax); @@ -78,7 +78,7 @@ protected virtual bool IsInstanceOfType(TRuntimeType value) return true; } - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) { ArgumentNullException.ThrowIfNull(valueSyntax); @@ -106,7 +106,7 @@ protected virtual bool IsInstanceOfType(TRuntimeType value) protected abstract TRuntimeType ParseLiteral(IFloatValueLiteral valueSyntax); - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) { if (runtimeValue is null) { @@ -144,7 +144,7 @@ public sealed override IValueNode ParseResult(object? resultValue) throw CreateParseResultError(resultValue); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -189,7 +189,7 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu } /// - /// Creates the exception that will be thrown when + /// Creates the exception that will be thrown when /// encountered an invalid runtime value. /// /// @@ -198,11 +198,11 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu /// /// The created exception that should be thrown /// - protected virtual SerializationException CreateParseValueError(object runtimeValue) + protected virtual LeafCoercionException CreateParseValueError(object runtimeValue) => new(TypeResourceHelper.Scalar_Cannot_ParseResult(Name, runtimeValue.GetType()), this); /// - /// Creates the exception that will be thrown when encountered an + /// Creates the exception that will be thrown when encountered an /// invalid /// /// @@ -211,8 +211,8 @@ protected virtual SerializationException CreateParseValueError(object runtimeVal /// /// The created exception that should be thrown /// - protected virtual SerializationException CreateParseLiteralError(IValueNode valueSyntax) - => new(TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), this); + protected virtual LeafCoercionException CreateParseLiteralError(IValueNode valueSyntax) + => new(TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); /// /// Creates the exception that will be thrown when encountered an @@ -224,6 +224,6 @@ protected virtual SerializationException CreateParseLiteralError(IValueNode valu /// /// The created exception that should be thrown /// - protected virtual SerializationException CreateParseResultError(object runtimeValue) + protected virtual LeafCoercionException CreateParseResultError(object runtimeValue) => new(TypeResourceHelper.Scalar_Cannot_ParseResult(Name, runtimeValue.GetType()), this); } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/IdType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/IdType.cs index 995d141d6b1..fa29b4c83e9 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/IdType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/IdType.cs @@ -35,7 +35,7 @@ public IdType() : this(ScalarNames.ID, TypeResources.IdType_Description) { } - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { ArgumentNullException.ThrowIfNull(literal); @@ -44,7 +44,7 @@ public override bool IsInstanceOfType(IValueNode literal) || literal is NullValueNode; } - public override object? ParseLiteral(IValueNode literal) + public override object? CoerceInputLiteral(IValueNode literal) { ArgumentNullException.ThrowIfNull(literal); @@ -63,12 +63,12 @@ public override bool IsInstanceOfType(IValueNode literal) return null; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, literal.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, literal.GetType()), this); } - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) { if (runtimeValue is null) { @@ -80,8 +80,8 @@ public override IValueNode ParseValue(object? runtimeValue) return new StringValueNode(s); } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseValue(Name, runtimeValue.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputValue(Name, runtimeValue.GetType()), this); } @@ -102,12 +102,12 @@ public override IValueNode ParseResult(object? resultValue) return new IntValueNode(i); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/IntegerTypeBase.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/IntegerTypeBase.cs index 6e2d0db3a5a..18ea19331a7 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/IntegerTypeBase.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/IntegerTypeBase.cs @@ -44,7 +44,7 @@ protected override bool IsInstanceOfType(TRuntimeType runtimeValue) return true; } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { @@ -118,7 +118,7 @@ public sealed override IValueNode ParseResult(object? resultValue) /// /// The created exception that should be thrown /// - protected virtual SerializationException CreateParseResultError(object runtimeValue) + protected virtual LeafCoercionException CreateParseResultError(object runtimeValue) { return new( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, runtimeValue.GetType()), diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/JsonType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/JsonType.cs index 22379970a38..b3e2c90c026 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/JsonType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/JsonType.cs @@ -43,7 +43,7 @@ public JsonType() /// true if the specified can be handled /// by the JSON scalar; otherwise false. /// - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) => true; /// @@ -55,7 +55,7 @@ public override bool IsInstanceOfType(IValueNode valueSyntax) /// /// Returns null or a . /// - public override object ParseLiteral(IValueNode valueSyntax) + public override object CoerceInputLiteral(IValueNode valueSyntax) => JsonFormatter.Format(valueSyntax); /// @@ -67,7 +67,7 @@ public override object ParseLiteral(IValueNode valueSyntax) /// /// Returns GraphQL value syntax. /// - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) { if (runtimeValue is null) { @@ -84,10 +84,10 @@ public override IValueNode ParseValue(object? runtimeValue) /// public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); - private SerializationException CreateParseValueError(object runtimeValue) - => new(TypeResourceHelper.Scalar_Cannot_ParseValue(Name, runtimeValue.GetType()), this); + private LeafCoercionException CreateParseValueError(object runtimeValue) + => new(TypeResourceHelper.Scalar_Cannot_CoerceInputValue(Name, runtimeValue.GetType()), this); private static class JsonParser { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateTimeType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateTimeType.cs index eb46c35179e..0a6a0a1504a 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateTimeType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateTimeType.cs @@ -46,7 +46,7 @@ public override IValueNode ParseResult(object? resultValue) string s => new StringValueNode(s), DateTimeOffset o => ParseValue(o.DateTime), DateTime dt => ParseValue(dt), - _ => throw new SerializationException( + _ => throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this) }; } @@ -58,8 +58,8 @@ protected override DateTime ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -68,7 +68,7 @@ protected override StringValueNode ParseValue(DateTime runtimeValue) return new(Serialize(runtimeValue)); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs index 6a5d28bfabb..dbab98ad9e0 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs @@ -70,7 +70,7 @@ public override IValueNode ParseResult(object? resultValue) DateOnly d => ParseValue(d), DateTimeOffset o => ParseValue(DateOnly.FromDateTime(o.DateTime)), DateTime dt => ParseValue(DateOnly.FromDateTime(dt)), - _ => throw new SerializationException( + _ => throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this) }; } @@ -82,8 +82,8 @@ protected override DateOnly ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -92,7 +92,7 @@ protected override StringValueNode ParseValue(DateOnly runtimeValue) return new(Serialize(runtimeValue)); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs index d7f7c0b97d4..0e68d5a6fe4 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs @@ -62,7 +62,7 @@ public override IValueNode ParseResult(object? resultValue) TimeOnly t => ParseValue(t), DateTimeOffset d => ParseValue(TimeOnly.FromDateTime(d.DateTime)), DateTime dt => ParseValue(TimeOnly.FromDateTime(dt)), - _ => throw new SerializationException( + _ => throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this) }; } @@ -74,8 +74,8 @@ protected override TimeOnly ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -84,7 +84,7 @@ protected override StringValueNode ParseValue(TimeOnly runtimeValue) return new(Serialize(runtimeValue)); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { switch (runtimeValue) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType.cs index 90c86c2e09b..0b57471b532 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType.cs @@ -1,5 +1,7 @@ +using System.Text.Json; using HotChocolate.Language; using HotChocolate.Properties; +using HotChocolate.Text.Json; using HotChocolate.Types.Descriptors.Configurations; using HotChocolate.Utilities; using static HotChocolate.Serialization.SchemaDebugFormatter; @@ -18,7 +20,6 @@ public abstract partial class ScalarType , IHasRuntimeType { private Uri? _specifiedBy; - private ScalarSerializationType _serializationType; private string? _pattern; /// @@ -60,19 +61,7 @@ protected set } /// - public ScalarSerializationType SerializationType - { - get => _serializationType; - protected set - { - if (IsExecutable) - { - throw new InvalidOperationException( - TypeResources.TypeSystem_Immutable); - } - _serializationType = value; - } - } + public abstract ScalarSerializationType SerializationType { get; } /// public string? Pattern @@ -115,191 +104,127 @@ IReadOnlyDirectiveCollection IDirectivesProvider.Directives public bool IsAssignableFrom(ITypeDefinition type) => ReferenceEquals(type, this); - public bool Equals(IType? other) => ReferenceEquals(other, this); - /// - /// Defines if the specified - /// can be parsed by this scalar. + /// Defines if the specified is equal to the current . /// - /// - /// The literal that shall be checked. + /// + /// The other scalar type. /// /// - /// true if the literal can be parsed by this scalar; + /// true if the specified is equal to the current ; /// otherwise, false. /// - /// - /// is null. - /// - public abstract bool IsInstanceOfType(IValueNode valueSyntax); + public bool Equals(IType? other) => ReferenceEquals(other, this); - /// - /// Defines if the specified - /// is an instance of this type. - /// - /// - /// A value representation of this type. - /// - /// - /// true if the value is a value of this type; - /// otherwise, false. - /// - public virtual bool IsInstanceOfType(object? runtimeValue) + /// + public virtual bool IsValueCompatible(IValueNode valueLiteral) { - if (runtimeValue is null) + ArgumentNullException.ThrowIfNull(valueLiteral); + + if ((SerializationType & ScalarSerializationType.String) == ScalarSerializationType.String + && valueLiteral.Kind == SyntaxKind.StringValue) { return true; } - return RuntimeType.IsInstanceOfType(runtimeValue); - } + if ((SerializationType & ScalarSerializationType.Int) == ScalarSerializationType.Int + && valueLiteral.Kind == SyntaxKind.IntValue) + { + return true; + } - /// - /// Parses the specified - /// to the .NET representation of this type. - /// - /// - /// The literal that shall be parsed. - /// - /// - /// - /// is null. - /// - /// - /// The specified cannot be parsed - /// by this scalar. - /// - public abstract object? ParseLiteral(IValueNode valueSyntax); + if ((SerializationType & ScalarSerializationType.Float) == ScalarSerializationType.Float + && valueLiteral.Kind == SyntaxKind.FloatValue) + { + return true; + } - /// - /// Parses the .NET value representation to a value literal. - /// - /// - /// The .NET value representation. - /// - /// - /// Returns a GraphQL literal representing the .NET value. - /// - /// - /// The specified cannot be parsed - /// by this scalar. - /// - public abstract IValueNode ParseValue(object? runtimeValue); + if ((SerializationType & ScalarSerializationType.Boolean) == ScalarSerializationType.Boolean + && valueLiteral.Kind == SyntaxKind.BooleanValue) + { + return true; + } - /// - /// Parses a result value of this scalar into a GraphQL value syntax representation. - /// - /// - /// A result value representation of this type. - /// - /// - /// Returns a GraphQL value syntax representation of the . - /// - /// - /// Unable to parse the given - /// into a GraphQL value syntax representation of this type. - /// - public abstract IValueNode ParseResult(object? resultValue); + if ((SerializationType & ScalarSerializationType.List) == ScalarSerializationType.List + && valueLiteral.Kind == SyntaxKind.ListValue) + { + return true; + } - /// - /// Serializes the .NET value representation. - /// - /// - /// The .NET value representation. - /// - /// - /// Returns the serialized value. - /// - /// - /// The specified cannot be serialized - /// by this scalar. - /// - public virtual object? Serialize(object? runtimeValue) - { - if (TrySerialize(runtimeValue, out var s)) + if ((SerializationType & ScalarSerializationType.Object) == ScalarSerializationType.Object + && valueLiteral.Kind == SyntaxKind.ObjectValue) { - return s; + return true; } - throw new SerializationException( - ErrorBuilder.New() - .SetMessage(TypeResourceHelper.Scalar_Cannot_Serialize(Name)) - .SetExtension("actualValue", runtimeValue?.ToString() ?? "null") - .SetExtension("actualType", runtimeValue?.GetType().FullName ?? "null") - .Build(), - this); + return false; } - /// - /// Tries to serializes the .NET value representation to the output format. - /// - /// - /// The .NET value representation. - /// - /// - /// The serialized value. - /// - /// - /// true if the value was correctly serialized; otherwise, false. - /// - public abstract bool TrySerialize(object? runtimeValue, out object? resultValue); - - /// - /// Deserializes the serialized value to it`s .NET value representation. - /// - /// - /// The serialized value representation. - /// - /// - /// Returns the .NET value representation. - /// - /// - /// The specified cannot be deserialized - /// by this scalar. - /// - public virtual object? Deserialize(object? resultValue) + /// + public virtual bool IsValueCompatible(JsonElement inputValue) { - if (TryDeserialize(resultValue, out var v)) + if ((SerializationType & ScalarSerializationType.String) == ScalarSerializationType.String + && inputValue.ValueKind == JsonValueKind.String) { - return v; + return true; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_Deserialize(Name), - this); - } + if ((SerializationType & ScalarSerializationType.Int) == ScalarSerializationType.Int + && inputValue.ValueKind == JsonValueKind.Number) + { + return true; + } - /// - /// Tries to deserializes the value from the output format to the .NET value representation. - /// - /// - /// The serialized value. - /// - /// - /// The .NET value representation. - /// - /// - /// true if the serialized value was correctly deserialized; otherwise, false. - /// - public abstract bool TryDeserialize(object? resultValue, out object? runtimeValue); + if ((SerializationType & ScalarSerializationType.Float) == ScalarSerializationType.Float + && inputValue.ValueKind == JsonValueKind.Number) + { + return true; + } - protected bool TryConvertSerialized( - object serialized, - ValueKind expectedKind, - out T value) - { - if (Scalars.TryGetKind(serialized, out var kind) - && kind == expectedKind - && _converter.TryConvert(serialized, out T c)) + if ((SerializationType & ScalarSerializationType.Boolean) == ScalarSerializationType.Boolean + && inputValue.ValueKind == JsonValueKind.True) + { + return true; + } + + if ((SerializationType & ScalarSerializationType.List) == ScalarSerializationType.List + && inputValue.ValueKind == JsonValueKind.Array) + { + return true; + } + + if ((SerializationType & ScalarSerializationType.Object) == ScalarSerializationType.Object + && inputValue.ValueKind == JsonValueKind.Object) { - value = c; return true; } - value = default!; return false; } + /// + public virtual bool IsInstanceOfType(object? runtimeValue) + { + if (runtimeValue is null) + { + return true; + } + + return RuntimeType.IsInstanceOfType(runtimeValue); + } + + /// + public abstract object? CoerceInputLiteral(IValueNode valueLiteral); + + /// + public abstract object? CoerceInputValue(JsonElement inputValue); + + /// + public abstract void CoerceOutputValue(object? runtimeValue, ResultElement resultValue); + + /// + public abstract IValueNode ValueToLiteral(object? runtimeValue); + /// /// Returns a string that represents the current . /// diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~1.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~1.cs index e335d80e903..04e57ab20ad 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~1.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~1.cs @@ -1,3 +1,7 @@ +using HotChocolate.Language; +using HotChocolate.Properties; +using HotChocolate.Text.Json; + namespace HotChocolate.Types; /// @@ -5,6 +9,9 @@ namespace HotChocolate.Types; /// GraphQL responses take the form of a hierarchical tree; /// the leaves on these trees are GraphQL scalars. /// +/// +/// The .NET runtime type that this scalar represents. +/// public abstract class ScalarType : ScalarType { /// @@ -17,40 +24,85 @@ protected ScalarType(string name, BindingBehavior bind = BindingBehavior.Explici public sealed override Type RuntimeType => typeof(TRuntimeType); /// - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool IsInstanceOfType(object? runtimeValue) { if (runtimeValue is null) { - resultValue = null; return true; } - if (runtimeValue is TRuntimeType) + return RuntimeType.IsInstanceOfType(runtimeValue); + } + + /// + public override void CoerceOutputValue(object? runtimeValue, ResultElement resultValue) + { + if (runtimeValue is null) { - resultValue = runtimeValue; - return true; + resultValue.SetNullValue(); + return; } - resultValue = null; - return false; + if (runtimeValue is TRuntimeType t) + { + CoerceOutputValue(t, resultValue); + return; + } + + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceOutputValue( + runtimeValue.GetType(), + runtimeValue.ToString() ?? "null"), + this); } + /// + /// Coerces a runtime value into an external output representation + /// and writes it to the result. + /// + /// + /// The runtime value to coerce. + /// + /// + /// The result element to write the output value to. + /// + /// + /// Unable to coerce the given into an output value. + /// + public abstract void CoerceOutputValue(TRuntimeType? runtimeValue, ResultElement resultValue); + /// - public override bool TryDeserialize(object? resultValue, out object? runtimeValue) + public override IValueNode ValueToLiteral(object? runtimeValue) { - if (resultValue is null) + if (runtimeValue is null) { - runtimeValue = null; - return true; + return NullValueNode.Default; } - if (resultValue is TRuntimeType) + if (runtimeValue is TRuntimeType runtimeType) { - runtimeValue = resultValue; - return true; + return ValueToLiteral(runtimeType); } - runtimeValue = null; - return false; + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_ConvertValueToLiteral( + runtimeValue.GetType(), + runtimeValue.ToString() ?? "null"), + this); } + + /// + /// Converts a runtime value into a GraphQL literal (AST value node). + /// Used for default value representation in SDL and introspection. + /// + /// + /// The runtime value to convert. + /// + /// + /// Returns a GraphQL literal representation of the runtime value. + /// + /// + /// Unable to convert the given into a literal. + /// + public abstract IValueNode ValueToLiteral(TRuntimeType? runtimeValue); } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~2.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~2.cs index fc9c56503b1..e1d6b76b42b 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~2.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/ScalarType~2.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using HotChocolate.Language; using HotChocolate.Properties; @@ -8,9 +9,7 @@ namespace HotChocolate.Types; /// GraphQL responses take the form of a hierarchical tree; /// the leaves on these trees are GraphQL scalars. /// -public abstract class ScalarType - : ScalarType - where TLiteral : IValueNode +public abstract class ScalarType : ScalarType where TLiteral : IValueNode { /// protected ScalarType(string name, BindingBehavior bind = BindingBehavior.Explicit) @@ -19,125 +18,132 @@ protected ScalarType(string name, BindingBehavior bind = BindingBehavior.Explici } /// - public sealed override bool IsInstanceOfType(IValueNode valueSyntax) + public override ScalarSerializationType SerializationType { - ArgumentNullException.ThrowIfNull(valueSyntax); - - return valueSyntax is TLiteral casted && IsInstanceOfType(casted) - || valueSyntax is NullValueNode; + get + { + if (typeof(TLiteral) == typeof(StringValueNode)) + { + return ScalarSerializationType.String; + } + + if (typeof(TLiteral) == typeof(IntValueNode)) + { + return ScalarSerializationType.Int; + } + + if (typeof(TLiteral) == typeof(FloatValueNode)) + { + return ScalarSerializationType.Float; + } + + if (typeof(TLiteral) == typeof(BooleanValueNode)) + { + return ScalarSerializationType.Boolean; + } + + if (typeof(TLiteral) == typeof(ObjectValueNode)) + { + return ScalarSerializationType.Object; + } + + if (typeof(TLiteral) == typeof(ListValueNode)) + { + return ScalarSerializationType.List; + } + + throw new NotSupportedException(); + } } - /// - /// Defines if the specified - /// can be parsed by this scalar. - /// - /// - /// The literal that shall be checked. - /// - /// - /// true if the literal can be parsed by this scalar; - /// otherwise, false. - /// - /// - /// is null. - /// - protected virtual bool IsInstanceOfType(TLiteral valueSyntax) + /// + public sealed override bool IsValueCompatible(IValueNode valueSyntax) { - return true; + ArgumentNullException.ThrowIfNull(valueSyntax); + + if (valueSyntax.Kind == SyntaxKind.NullValue) + { + return true; + } + + return valueSyntax is TLiteral; } /// - public sealed override bool IsInstanceOfType(object? runtimeValue) + public override bool IsValueCompatible(JsonElement inputValue) { - if (runtimeValue is null) + if (inputValue.ValueKind == JsonValueKind.Undefined) + { + return false; + } + + if (inputValue.ValueKind == JsonValueKind.Null) { return true; } - if (runtimeValue is TRuntimeType t) + if (SerializationType == ScalarSerializationType.String + && inputValue.ValueKind == JsonValueKind.String) { - return IsInstanceOfType(t); + return true; } - return false; - } + if (SerializationType == ScalarSerializationType.Int + && inputValue.ValueKind == JsonValueKind.Number) + { + return true; + } - /// - /// Defines if the specified - /// is an instance of this type. - /// - /// - /// A value representation of this type. - /// - /// - /// true if the value is a value of this type; - /// otherwise, false. - /// - protected virtual bool IsInstanceOfType(TRuntimeType runtimeValue) - { - return true; - } + if (SerializationType == ScalarSerializationType.Float + && inputValue.ValueKind == JsonValueKind.Number) + { + return true; + } - /// - public sealed override object? ParseLiteral(IValueNode valueSyntax) - { - ArgumentNullException.ThrowIfNull(valueSyntax); + if (SerializationType == ScalarSerializationType.Boolean + && (inputValue.ValueKind == JsonValueKind.True + || inputValue.ValueKind == JsonValueKind.False)) + { + return true; + } - if (valueSyntax is TLiteral casted && IsInstanceOfType(casted)) + if (SerializationType == ScalarSerializationType.Object + && inputValue.ValueKind == JsonValueKind.Object) { - return ParseLiteral(casted); + return true; } - if (valueSyntax is NullValueNode) + if (SerializationType == ScalarSerializationType.List + && inputValue.ValueKind == JsonValueKind.Array) { - return null; + return true; } - throw CreateParseLiteralError(valueSyntax); + return false; } - /// - /// Parses the specified - /// to the .net representation of this type. - /// - /// - /// The literal that shall be parsed. - /// - /// - /// - /// is null. - /// - /// - /// The specified cannot be parsed - /// by this scalar. - /// - protected abstract TRuntimeType ParseLiteral(TLiteral valueSyntax); - /// - public sealed override IValueNode ParseValue(object? runtimeValue) + public sealed override object? CoerceInputLiteral(IValueNode valueLiteral) { - if (runtimeValue is null) + ArgumentNullException.ThrowIfNull(valueLiteral); + + if (valueLiteral.Kind is SyntaxKind.NullValue) { - return NullValueNode.Default; + return null; } - if (runtimeValue is TRuntimeType t && IsInstanceOfType(t)) + if (valueLiteral is TLiteral literal) { - return ParseValue(t); + return CoerceInputLiteral(literal); } - throw CreateParseValueError(runtimeValue); + throw CreateCoerceInputLiteralError(valueLiteral); } - /// - /// Parses a runtime value into a valueSyntax. - /// - /// The value to parse - /// The parsed value syntax - protected abstract TLiteral ParseValue(TRuntimeType runtimeValue); + public abstract object? CoerceInputLiteral(TLiteral valueLiteral); /// - /// Creates the exception that will be thrown when encountered an + /// Creates the exception that will be thrown when encountered an /// invalid /// /// @@ -146,27 +152,8 @@ public sealed override IValueNode ParseValue(object? runtimeValue) /// /// The created exception that should be thrown /// - protected virtual SerializationException CreateParseLiteralError(IValueNode valueSyntax) - { - return new( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), - this); - } - - /// - /// Creates the exception that will be thrown when encountered an - /// invalid value. - /// - /// - /// The runtimeValue that should be parsed - /// - /// - /// The created exception that should be thrown - /// - protected virtual SerializationException CreateParseValueError(object runtimeValue) - { - return new( - TypeResourceHelper.Scalar_Cannot_ParseValue(Name, runtimeValue.GetType()), + protected virtual LeafCoercionException CreateCoerceInputLiteralError(IValueNode valueSyntax) + => new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); - } } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/StringType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/StringType.cs index 6d49a5ff361..e1c4e4f76f6 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/StringType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/StringType.cs @@ -44,5 +44,5 @@ protected override StringValueNode ParseValue(string runtimeValue) => new(runtimeValue); public override IValueNode ParseResult(object? resultValue) => - ParseValue(resultValue); + CoerceInputValue(resultValue); } diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/TimeSpanType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/TimeSpanType.cs index ad69758e0fb..4e8a413bc63 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/TimeSpanType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/TimeSpanType.cs @@ -53,8 +53,8 @@ protected override TimeSpan ParseLiteral(StringValueNode valueSyntax) return value.Value; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -75,7 +75,7 @@ public override IValueNode ParseResult(object? resultValue) if (resultValue is string s && TryDeserializeFromString(s, Format, out var timeSpan)) { - return ParseValue(timeSpan); + return CoerceInputValue(timeSpan); } if (resultValue is TimeSpan ts) @@ -83,12 +83,12 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(ts); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/UrlType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/UrlType.cs index 5501d484dc3..5ed9829478d 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/UrlType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/UrlType.cs @@ -43,8 +43,8 @@ protected override Uri ParseLiteral(StringValueNode valueSyntax) return uri; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -70,12 +70,12 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(uri); } - throw new SerializationException( + throw new LeafCoercionException( TypeResourceHelper.Scalar_Cannot_ParseResult(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/UuidType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/UuidType.cs index 87c9c4c1572..cb27a900423 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/UuidType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/UuidType.cs @@ -24,7 +24,7 @@ public class UuidType : ScalarType /// /// /// Specifies if the is enforced and violations will cause - /// a . If set to false and the string + /// a . If set to false and the string /// does not match the the scalar will try to deserialize /// the string using the other formats. /// @@ -55,7 +55,7 @@ public UuidType(char defaultFormat = '\0', bool enforceFormat = false) /// /// /// Specifies if the is enforced and violations will cause - /// a . If set to false and the string + /// a . If set to false and the string /// does not match the the scalar will try to deserialize /// the string using the other formats. /// @@ -132,8 +132,8 @@ protected override Guid ParseLiteral(StringValueNode valueSyntax) return g; } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, valueSyntax.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, valueSyntax.GetType()), this); } @@ -159,12 +159,12 @@ public override IValueNode ParseResult(object? resultValue) return ParseValue(g); } - throw new SerializationException( - TypeResourceHelper.Scalar_Cannot_ParseLiteral(Name, resultValue.GetType()), + throw new LeafCoercionException( + TypeResourceHelper.Scalar_Cannot_CoerceInputLiteral(Name, resultValue.GetType()), this); } - public override bool TrySerialize(object? runtimeValue, out object? resultValue) + public override bool TryCoerceOutputValue(object? runtimeValue, out object? resultValue) { if (runtimeValue is null) { diff --git a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs index 7c90512ef9d..bc573178406 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs @@ -366,7 +366,7 @@ public static ISchemaError DirectiveCollection_ArgumentError( DirectiveNode? syntaxNode, object source, Path path, - SerializationException exception) + LeafCoercionException exception) { var message = string.Format( ErrorHelper_DirectiveCollection_ArgumentValueTypeIsWrong, diff --git a/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs b/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs index 60b2676dcda..e18d471929c 100644 --- a/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs +++ b/src/HotChocolate/Core/src/Types/Utilities/ThrowHelper.cs @@ -189,10 +189,10 @@ public static SchemaException NonGenericExecutableNotAllowed() => .SetMessage(ExtendedTypeReferenceHandler_NonGenericExecutableNotAllowed) .Build()); - public static SerializationException RequiredInputFieldIsMissing( + public static LeafCoercionException RequiredInputFieldIsMissing( IInputValueInfo field, Path fieldPath) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_RequiredInputFieldIsMissing, @@ -203,7 +203,7 @@ public static SerializationException RequiredInputFieldIsMissing( field.Type, fieldPath); - public static SerializationException InvalidInputFieldNames( + public static LeafCoercionException InvalidInputFieldNames( T type, IReadOnlyList invalidFieldNames, Path path) @@ -211,7 +211,7 @@ public static SerializationException InvalidInputFieldNames( { if (invalidFieldNames.Count == 1) { - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_InvalidInputFieldNames_Single, @@ -224,7 +224,7 @@ public static SerializationException InvalidInputFieldNames( path); } - throw new SerializationException( + throw new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_InvalidInputFieldNames, @@ -237,7 +237,7 @@ public static SerializationException InvalidInputFieldNames( path); } - public static SerializationException OneOfNoFieldSet( + public static LeafCoercionException OneOfNoFieldSet( InputObjectType type, Path? path) { @@ -249,7 +249,7 @@ public static SerializationException OneOfNoFieldSet( return new(builder.Build(), type, path); } - public static SerializationException OneOfMoreThanOneFieldSet( + public static LeafCoercionException OneOfMoreThanOneFieldSet( InputObjectType type, Path? path) { @@ -261,7 +261,7 @@ public static SerializationException OneOfMoreThanOneFieldSet( return new(builder.Build(), type, path); } - public static SerializationException OneOfFieldIsNull( + public static LeafCoercionException OneOfFieldIsNull( InputObjectType type, Path? path, InputField field) @@ -275,7 +275,7 @@ public static SerializationException OneOfFieldIsNull( return new(builder.Build(), type, path); } - public static SerializationException NonNullInputViolation( + public static LeafCoercionException NonNullInputViolation( ITypeSystemMember type, Path? path, IInputValueInfo? field = null) @@ -293,11 +293,11 @@ public static SerializationException NonNullInputViolation( return new(builder.Build(), type, path); } - public static SerializationException ParseInputObject_InvalidSyntaxKind( + public static LeafCoercionException ParseInputObject_InvalidSyntaxKind( InputObjectType type, SyntaxKind kind, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_ParseInputObject_InvalidSyntaxKind, @@ -309,11 +309,11 @@ public static SerializationException ParseInputObject_InvalidSyntaxKind( type, path); - public static SerializationException ParseInputObject_InvalidObjectKind( + public static LeafCoercionException ParseInputObject_InvalidObjectKind( InputObjectType type, Type objectType, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_ParseInputObject_InvalidObjectKind, @@ -326,11 +326,11 @@ public static SerializationException ParseInputObject_InvalidObjectKind( type, path); - public static SerializationException ParseNestedList_InvalidSyntaxKind( + public static LeafCoercionException ParseNestedList_InvalidSyntaxKind( ListType type, SyntaxKind kind, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_ParseNestedList_InvalidSyntaxKind, @@ -343,13 +343,13 @@ public static SerializationException ParseNestedList_InvalidSyntaxKind( type, path); - public static SerializationException ParseList_InvalidObjectKind( + public static LeafCoercionException ParseList_InvalidObjectKind( ListType type, Type listType, Path path) { var runtimeType = type.ToRuntimeType(); - return new SerializationException( + return new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_ParseList_InvalidObjectKind, @@ -361,11 +361,11 @@ public static SerializationException ParseList_InvalidObjectKind( path); } - public static SerializationException FormatValueList_InvalidObjectKind( + public static LeafCoercionException FormatValueList_InvalidObjectKind( ListType type, Type listType, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_FormatValueList_InvalidObjectKind, @@ -376,11 +376,11 @@ public static SerializationException FormatValueList_InvalidObjectKind( type, path); - public static SerializationException FormatResultObject_InvalidObjectKind( + public static LeafCoercionException FormatResultObject_InvalidObjectKind( InputObjectType type, Type objectType, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_FormatResultObject_InvalidObjectKind, @@ -393,11 +393,11 @@ public static SerializationException FormatResultObject_InvalidObjectKind( type, path); - public static SerializationException FormatResultList_InvalidObjectKind( + public static LeafCoercionException FormatResultList_InvalidObjectKind( ListType type, Type listType, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_FormatResultList_InvalidObjectKind, @@ -408,11 +408,11 @@ public static SerializationException FormatResultList_InvalidObjectKind( type, path); - public static SerializationException FormatResultLeaf_InvalidSyntaxKind( + public static LeafCoercionException FormatResultLeaf_InvalidSyntaxKind( IType type, SyntaxKind kind, Path path) - => new SerializationException( + => new LeafCoercionException( ErrorBuilder.New() .SetMessage( ThrowHelper_FormatResultLeaf_InvalidSyntaxKind, @@ -586,7 +586,7 @@ public static SchemaException OutputTypeExpected(IType type) .Build()); } - public static SerializationException InvalidTypeConversion( + public static LeafCoercionException InvalidTypeConversion( ITypeSystemMember type, IInputValueInfo inputField, Path inputFieldPath, diff --git a/src/HotChocolate/Core/test/Execution.Tests/Processing/VariableCoercionHelperTests.cs b/src/HotChocolate/Core/test/Execution.Tests/Processing/VariableCoercionHelperTests.cs index e75a9dd2e7d..06cf0cf459d 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/Processing/VariableCoercionHelperTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/Processing/VariableCoercionHelperTests.cs @@ -546,7 +546,7 @@ void Action() => helper.CoerceVariableValues( schema, variableDefinitions, variableValues, coercedValues); // assert - Assert.Throws(Action) + Assert.Throws(Action) .Errors.Select(t => t.WithException(null)) .ToList() .MatchSnapshot(); @@ -581,7 +581,7 @@ void Action() => helper.CoerceVariableValues( schema, variableDefinitions, variableValues, coercedValues); // assert - Assert.Throws(Action).Errors.MatchSnapshot(); + Assert.Throws(Action).Errors.MatchSnapshot(); } [Fact] @@ -645,7 +645,7 @@ void Action() => helper.CoerceVariableValues( schema, variableDefinitions, variableValues, coercedValues); // assert - Assert.Throws(Action) + Assert.Throws(Action) .Errors.Select(t => t.WithException(null)) .ToList() .MatchSnapshot(); diff --git a/src/HotChocolate/Core/test/Execution.Tests/ScalarExecutionErrorTests.cs b/src/HotChocolate/Core/test/Execution.Tests/ScalarExecutionErrorTests.cs index 461fe664510..fb62dc2c5b1 100644 --- a/src/HotChocolate/Core/test/Execution.Tests/ScalarExecutionErrorTests.cs +++ b/src/HotChocolate/Core/test/Execution.Tests/ScalarExecutionErrorTests.cs @@ -123,7 +123,7 @@ public FooType() : base("Foo") public override Type RuntimeType => typeof(string); - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { ArgumentNullException.ThrowIfNull(literal); @@ -145,7 +145,7 @@ public override bool IsInstanceOfType(object? value) return value is "a"; } - public override object? ParseLiteral(IValueNode literal) + public override object? CoerceInputLiteral(IValueNode literal) { ArgumentNullException.ThrowIfNull(literal); @@ -159,10 +159,10 @@ public override bool IsInstanceOfType(object? value) return "a"; } - throw new SerializationException("StringValue is not a.", this); + throw new LeafCoercionException("StringValue is not a.", this); } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { if (value is null) { @@ -174,11 +174,11 @@ public override IValueNode ParseValue(object? value) return new StringValueNode("a"); } - throw new SerializationException("String is not a.", this); + throw new LeafCoercionException("String is not a.", this); } public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); public override bool TrySerialize( object? runtimeValue, @@ -242,7 +242,7 @@ protected override string ParseLiteral(StringValueNode valueSyntax) { if (string.IsNullOrWhiteSpace(valueSyntax.Value)) { - throw new SerializationException("Not a valid name.", this); + throw new LeafCoercionException("Not a valid name.", this); } return valueSyntax.Value; @@ -252,13 +252,13 @@ protected override StringValueNode ParseValue(string runtimeValue) => new(runtimeValue); public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); - public override object? Serialize(object? runtimeValue) + public override object? CoerceOutputValue(object? runtimeValue) { if (runtimeValue is not string s || string.IsNullOrWhiteSpace(s)) { - throw new SerializationException("Name cannot serialize the given value.", this); + throw new LeafCoercionException("Name cannot serialize the given value.", this); } return base.Serialize(runtimeValue); diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/LatitudeTypeTests.cs b/src/HotChocolate/Core/test/Types.Scalars.Tests/LatitudeTypeTests.cs index 105f698c3cb..1d1de21f986 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/LatitudeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/LatitudeTypeTests.cs @@ -37,7 +37,7 @@ protected void Latitude_ExpectIsStringInstanceToMatch() StringValueNode valueSyntax = new("89° 0' 0.000\" S"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -110,7 +110,7 @@ protected void Latitude_ExpectParseResultToThrowOnInvalidString() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -138,7 +138,7 @@ protected void Latitude_ExpectParseResultToThrowOnInvalidInt() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -166,7 +166,7 @@ protected void Latitude_ExpectParseResultToThrowOnInvalidDouble() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -180,7 +180,7 @@ protected void Latitude_ExpectParseResultToThrowOnInvalidType() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Theory] @@ -225,10 +225,10 @@ protected void Latitude_ExpectParseLiteralToThrowSerializationException() StringValueNode valueSyntax = new("foo"); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -239,7 +239,7 @@ public void Latitude_ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = scalar.ParseLiteral(literal)!; + var value = scalar.CoerceInputLiteral(literal)!; // assert Assert.Null(value); @@ -253,7 +253,7 @@ protected void Latitude_ExpectParseValueToMatchType() const double valueSyntax = 74.3; // act - var result = scalar.ParseValue(valueSyntax); + var result = scalar.CoerceInputValue(valueSyntax); // assert Assert.Equal(typeof(StringValueNode), result.GetType()); @@ -283,7 +283,7 @@ protected void Latitude_ExpectParseValueToMatch(double runtime, string literal) StringValueNode expected = new(literal); // act - var result = scalar.ParseValue(runtime); + var result = scalar.CoerceInputValue(runtime); // assert Assert.Equal(expected, result, SyntaxComparer.BySyntax); @@ -297,10 +297,10 @@ protected void Latitude_ExpectParseValueToThrowSerializationException_GreaterTha const double runtimeValue = 91d; // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -311,10 +311,10 @@ protected void Latitude_ExpectParseValueToThrowSerializationException_LessThanMi const double runtimeValue = -91d; // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -345,7 +345,7 @@ protected void Latitude_ExpectDeserializeStringToThrowSerializationException_Les var result = Record.Exception(() => scalar.Deserialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -360,7 +360,7 @@ protected void var result = Record.Exception(() => scalar.Deserialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -389,7 +389,7 @@ protected void Latitude_ExpectSerializeIntToThrowSerializationException_LessThan var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -403,7 +403,7 @@ protected void Latitude_ExpectSerializeIntToThrowSerializationException_GreaterT var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -432,7 +432,7 @@ protected void Latitude_ExpectSerializeDoubleToThrowSerializationException_LessT var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -446,7 +446,7 @@ protected void Latitude_ExpectSerializeDoubleToThrowSerializationException_Great var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -484,7 +484,7 @@ private static double ToPrecision( int precision = 8) { return Math.Round( - (double)scalar.ParseLiteral(valueSyntax)!, + (double)scalar.CoerceInputLiteral(valueSyntax)!, precision, MidpointRounding.AwayFromZero); } diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/LocalCurrencyTypeTests.cs b/src/HotChocolate/Core/test/Types.Scalars.Tests/LocalCurrencyTypeTests.cs index a3e27cb9707..cc174cb8406 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/LocalCurrencyTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/LocalCurrencyTypeTests.cs @@ -52,7 +52,7 @@ protected void LocalCurrency_ExpectIsStringValueToMatch() var valueSyntax = new StringValueNode("$10.99"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -79,7 +79,7 @@ protected void LocalCurrency_ExpectIsStringValueToMatchEuro() var valueSyntax = new StringValueNode("10,99 €"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -93,10 +93,10 @@ protected void LocalCurrency_ExpectIsStringValueToNotMatchEuro() var valueSyntax = new StringValueNode("$10.99"); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -108,7 +108,7 @@ protected void LocalCurrency_ExpectParseLiteralToMatch() const decimal expectedResult = 24.99m; // act - object result = (decimal)scalar.ParseLiteral(valueSyntax)!; + object result = (decimal)scalar.CoerceInputLiteral(valueSyntax)!; // assert Assert.Equal(expectedResult, result); @@ -123,7 +123,7 @@ protected void LocalCurrency_ExpectParseLiteralToMatchEuro() const decimal expectedResult = 24.99m; // act - object result = (decimal)scalar.ParseLiteral(valueSyntax)!; + object result = (decimal)scalar.CoerceInputLiteral(valueSyntax)!; // assert Assert.Equal(expectedResult, result); @@ -142,7 +142,7 @@ public void LocalCurrency_ParseLiteralStringValueDifferentCulture(string name, s const decimal expectedDecimal = 9.99m; // act - var result = (decimal)scalar.ParseLiteral(valueSyntax)!; + var result = (decimal)scalar.CoerceInputLiteral(valueSyntax)!; // assert Assert.Equal(expectedDecimal, result); @@ -156,10 +156,10 @@ protected void LocalCurrency_ExpectParseLiteralToThrowSerializationException() var valueSyntax = new StringValueNode("foo"); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -170,7 +170,7 @@ protected void LocalCurrency_ExpectParseValueToMatchDecimal() const decimal valueSyntax = 24.95m; // act - var result = scalar.ParseValue(valueSyntax); + var result = scalar.CoerceInputValue(valueSyntax); // assert Assert.Equal(typeof(StringValueNode), result.GetType()); @@ -184,10 +184,10 @@ protected void LocalCurrency_ExpectParseValueToThrowSerializationException() var runtimeValue = new StringValueNode("foo"); // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -299,7 +299,7 @@ protected void LocalCurrency_ExpectSerializeToThrowSerializationException() var result = Record.Exception(() => scalar.Serialize("foo")); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -313,7 +313,7 @@ protected void LocalCurrency_ExpectDeserializeToThrowSerializationException() var result = Record.Exception(() => scalar.Deserialize(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -354,7 +354,7 @@ protected void LocalCurrency_ExpectParseResultToThrowSerializationException() var result = Record.Exception(() => scalar.ParseResult(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/LongitudeTypeTests.cs b/src/HotChocolate/Core/test/Types.Scalars.Tests/LongitudeTypeTests.cs index 3f2a6d571a9..4300c408a34 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/LongitudeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/LongitudeTypeTests.cs @@ -38,7 +38,7 @@ protected void Longitude_ExpectIsStringInstanceToMatch() StringValueNode valueSyntax = new("179° 0' 0.000\" E"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -111,7 +111,7 @@ protected void Longitude_ExpectParseResultToThrowOnInvalidString() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -139,7 +139,7 @@ protected void Longitude_ExpectParseResultToThrowOnInvalidInt() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -167,7 +167,7 @@ protected void Longitude_ExpectParseResultToThrowOnInvalidDouble() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -181,7 +181,7 @@ protected void Longitude_ExpectParseResultToThrowOnInvalidType() var result = Record.Exception(() => scalar.ParseResult(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Theory] @@ -226,10 +226,10 @@ protected void Longitude_ExpectParseLiteralToThrowSerializationException() StringValueNode valueSyntax = new("foo"); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -240,7 +240,7 @@ public void Longitude_ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = scalar.ParseLiteral(literal)!; + var value = scalar.CoerceInputLiteral(literal)!; // assert Assert.Null(value); @@ -254,7 +254,7 @@ protected void Longitude_ExpectParseValueToMatchType() const double valueSyntax = 74.3d; // act - var result = scalar.ParseValue(valueSyntax); + var result = scalar.CoerceInputValue(valueSyntax); // assert Assert.Equal(typeof(StringValueNode), result.GetType()); @@ -287,7 +287,7 @@ protected void Longitude_ExpectParseValueToMatch(double runtime, string literal) StringValueNode expected = new(literal); // act - ISyntaxNode result = scalar.ParseValue(runtime); + ISyntaxNode result = scalar.CoerceInputValue(runtime); // assert Assert.Equal(expected, result, BySyntax); @@ -301,10 +301,10 @@ protected void Longitude_ExpectParseValueToThrowSerializationException_GreaterTh const double runtimeValue = 181d; // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -315,10 +315,10 @@ protected void Longitude_ExpectParseValueToThrowSerializationException_LessThanM const double runtimeValue = -181d; // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -349,7 +349,7 @@ protected void Longitude_ExpectDeserializeStringToThrowSerializationException_Le var result = Record.Exception(() => scalar.Deserialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -364,7 +364,7 @@ protected void var result = Record.Exception(() => scalar.Deserialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -393,7 +393,7 @@ protected void Longitude_ExpectSerializeIntToThrowSerializationException_LessTha var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -407,7 +407,7 @@ protected void Longitude_ExpectSerializeIntToThrowSerializationException_Greater var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -436,7 +436,7 @@ protected void Longitude_ExpectSerializeDoubleToThrowSerializationException_Less var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -450,7 +450,7 @@ protected void Longitude_ExpectSerializeDoubleToThrowSerializationException_Grea var result = Record.Exception(() => scalar.Serialize(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -488,7 +488,7 @@ private static double ToPrecision( int precision = 8) { return Math.Round( - (double)scalar.ParseLiteral(valueSyntax)!, + (double)scalar.CoerceInputLiteral(valueSyntax)!, precision, MidpointRounding.AwayFromZero); } diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/ScalarTypeTestBase.cs b/src/HotChocolate/Core/test/Types.Scalars.Tests/ScalarTypeTestBase.cs index 84a80ec6f43..d384d7bdae7 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/ScalarTypeTestBase.cs +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/ScalarTypeTestBase.cs @@ -62,7 +62,7 @@ protected void ExpectIsInstanceOfTypeToMatch( var scalar = CreateType(); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.Equal(expectedResult, result); @@ -92,7 +92,7 @@ protected void ExpectParseLiteralToMatch( var scalar = CreateType(); // act - var result = scalar.ParseLiteral(valueSyntax); + var result = scalar.CoerceInputLiteral(valueSyntax); // assert Assert.Equal(expectedResult, result); @@ -106,10 +106,10 @@ protected void ExpectParseLiteralToThrowSerializationException( var scalar = CreateType(); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } protected void ExpectParseValueToMatchType( @@ -121,7 +121,7 @@ protected void ExpectParseValueToMatchType( var scalar = CreateType(); // act - var result = scalar.ParseValue(valueSyntax); + var result = scalar.CoerceInputValue(valueSyntax); // assert Assert.Equal(type, result.GetType()); @@ -134,10 +134,10 @@ protected void ExpectParseValueToThrowSerializationException(object? runt var scalar = CreateType(); // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } protected void ExpectSerializeToMatch( @@ -180,7 +180,7 @@ protected void ExpectSerializeToThrowSerializationException(object runtim var result = Record.Exception(() => scalar.Serialize(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } protected void ExpectDeserializeToThrowSerializationException(object runtimeValue) @@ -193,7 +193,7 @@ protected void ExpectDeserializeToThrowSerializationException(object runt var result = Record.Exception(() => scalar.Deserialize(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } protected void ExpectParseResultToMatchType( @@ -221,7 +221,7 @@ protected void ExpectParseResultToThrowSerializationException(object? run var result = Record.Exception(() => scalar.ParseResult(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } protected async Task ExpectScalarTypeToBoundImplicityWhenRegistered() diff --git a/src/HotChocolate/Core/test/Types.Scalars.Tests/UtcOffsetTypeTests.cs b/src/HotChocolate/Core/test/Types.Scalars.Tests/UtcOffsetTypeTests.cs index e3132ac2799..eb701dd8cbf 100644 --- a/src/HotChocolate/Core/test/Types.Scalars.Tests/UtcOffsetTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Scalars.Tests/UtcOffsetTypeTests.cs @@ -36,7 +36,7 @@ protected void UtcOffset_ExpectIsStringValueToMatch() var valueSyntax = new StringValueNode("+12:00"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -50,7 +50,7 @@ protected void UtcOffset_ExpectNegativeIsStringValueToMatch() var valueSyntax = new StringValueNode("-12:00"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -64,7 +64,7 @@ protected void UtcOffset_ExpectPositiveIsStringValueToMatch() var valueSyntax = new StringValueNode("-00:00"); // act - var result = scalar.IsInstanceOfType(valueSyntax); + var result = scalar.IsValueCompatible(valueSyntax); // assert Assert.True(result); @@ -93,7 +93,7 @@ protected void UtcOffset_ExpectParseLiteralToMatch() var expectedResult = new TimeSpan(-12, 0, 0); // act - object result = (TimeSpan)scalar.ParseLiteral(valueSyntax)!; + object result = (TimeSpan)scalar.CoerceInputLiteral(valueSyntax)!; // assert Assert.Equal(expectedResult, result); @@ -107,10 +107,10 @@ protected void UtcOffset_ExpectParseLiteralToThrowSerializationException() var valueSyntax = new StringValueNode("+17:00"); // act - var result = Record.Exception(() => scalar.ParseLiteral(valueSyntax)); + var result = Record.Exception(() => scalar.CoerceInputLiteral(valueSyntax)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -121,7 +121,7 @@ protected void UtcOffset_ExpectParseValueToMatchTimeSpan() var valueSyntax = new TimeSpan(0, 0, 0); // act - var result = scalar.ParseValue(valueSyntax); + var result = scalar.CoerceInputValue(valueSyntax); // assert Assert.Equal(typeof(StringValueNode), result.GetType()); @@ -135,10 +135,10 @@ protected void UtcOffset_ExpectParseValueToThrowSerializationException() var runtimeValue = new StringValueNode("foo"); // act - var result = Record.Exception(() => scalar.ParseValue(runtimeValue)); + var result = Record.Exception(() => scalar.CoerceInputValue(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -253,7 +253,7 @@ protected void UtcOffset_ExpectSerializeToThrowSerializationException() var result = Record.Exception(() => scalar.Serialize("foo")); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -267,7 +267,7 @@ protected void UtcOffset_ExpectDeserializeToThrowSerializationException() var result = Record.Exception(() => scalar.Deserialize(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] @@ -308,7 +308,7 @@ protected void UtcOffset_ExpectParseResultToThrowSerializationException() var result = Record.Exception(() => scalar.ParseResult(runtimeValue)); // assert - Assert.IsType(result); + Assert.IsType(result); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Configuration/SchemaTypeDiscoveryTests.cs b/src/HotChocolate/Core/test/Types.Tests/Configuration/SchemaTypeDiscoveryTests.cs index 5cb26ccb374..0d6e49ab8f3 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Configuration/SchemaTypeDiscoveryTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Configuration/SchemaTypeDiscoveryTests.cs @@ -185,17 +185,17 @@ public ByteArrayType() : base("ByteArray", BindingBehavior.Implicit) public override Type RuntimeType => typeof(byte[]); - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { throw new NotSupportedException(); } - public override object ParseLiteral(IValueNode literal) + public override object CoerceInputLiteral(IValueNode literal) { throw new NotSupportedException(); } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { throw new NotSupportedException(); } @@ -205,7 +205,7 @@ public override IValueNode ParseResult(object? resultValue) throw new NotSupportedException(); } - public override object Serialize(object? runtimeValue) + public override object CoerceOutputValue(object? runtimeValue) { throw new NotSupportedException(); } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/EnumTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/EnumTypeTests.cs index 5f21f390c90..f4d420adc70 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/EnumTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/EnumTypeTests.cs @@ -646,7 +646,7 @@ public void EnumName_Set_Name_Comparer() // assert var type = schema.Types.GetType("Foo"); - Assert.True(type.IsInstanceOfType(new EnumValueNode("baz"))); + Assert.True(type.IsValueCompatible(new EnumValueNode("baz"))); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/InputCoercionTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/InputCoercionTests.cs index ea8c3efca01..255940339b4 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/InputCoercionTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/InputCoercionTests.cs @@ -150,7 +150,7 @@ void Action() => inputParser.ParseLiteral(value, type, Path.Root.Append("root")); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -182,7 +182,7 @@ void Action() => inputParser.ParseLiteral(list, type, Path.Root.Append("root")); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -198,7 +198,7 @@ void Action() => inputParser.ParseLiteral(element, type, Path.Root.Append("root")); // assert - Assert.Throws(Action); + Assert.Throws(Action); } private void InputIsCoercedCorrectly( @@ -210,7 +210,7 @@ private void InputIsCoercedCorrectly( var type = new TType(); // act - var coercedValue = type.ParseLiteral(literal); + var coercedValue = type.CoerceInputLiteral(literal); // assert Assert.IsType(coercedValue); @@ -226,9 +226,9 @@ private void InputCannotBeCoercedCorrectly( var type = new TType(); // act - void Action() => type.ParseLiteral(literal); + void Action() => type.CoerceInputLiteral(literal); // assert - Assert.Throws(Action); + Assert.Throws(Action); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/InputParserTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/InputParserTests.cs index e0523c411cd..ea5d8f8e2f8 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/InputParserTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/InputParserTests.cs @@ -125,7 +125,7 @@ public void Deserialize_InputObject_AllIsSet_MissingRequired() void Action() => parser.ParseResult(fieldData, type, Path.Root); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -147,7 +147,7 @@ public void Parse_InputObject_AllIsSet_MissingRequired() void Action() => parser.ParseLiteral(fieldData, type, Path.Root); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -174,7 +174,7 @@ void Action() => parser.ParseResult(fieldData, type, Path.Root.Append("root")); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -199,7 +199,7 @@ void Action() => parser.ParseLiteral(fieldData, type, Path.Root.Append("root")); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -227,7 +227,7 @@ void Action() => parser.ParseResult(fieldData, type, Path.Root.Append("root")); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -253,7 +253,7 @@ void Action() => parser.ParseLiteral(fieldData, type, Path.Root.Append("root")); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -331,7 +331,7 @@ void Action() Path.Root.Append("root")); // assert - Assert.Throws(Action).MatchSnapshot(); + Assert.Throws(Action).MatchSnapshot(); } [Fact] @@ -413,7 +413,7 @@ public void OneOf_A_and_B_Are_Set() void Fail() => parser.ParseLiteral(data, oneOfInput, Path.Root.Append("root")); // assert - Assert.Throws(Fail).Errors.MatchSnapshot(); + Assert.Throws(Fail).Errors.MatchSnapshot(); } [Fact] @@ -440,7 +440,7 @@ void Fail() => parser.ParseLiteral(data, oneOfInput, Path.Root.Append("root")); // assert - Assert.Throws(Fail).Errors.MatchSnapshot(); + Assert.Throws(Fail).Errors.MatchSnapshot(); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/AnyTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/AnyTypeTests.cs index 2ee156a668f..ba9c3daee30 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/AnyTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/AnyTypeTests.cs @@ -776,7 +776,7 @@ public void IsInstanceOfType_EnumValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new EnumValueNode("foo")); + var result = type.IsValueCompatible(new EnumValueNode("foo")); // assert Assert.False(result); @@ -799,7 +799,7 @@ public void IsInstanceOfType_ObjectValue_True() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new ObjectValueNode([])); + var result = type.IsValueCompatible(new ObjectValueNode([])); // assert Assert.True(result); @@ -822,7 +822,7 @@ public void IsInstanceOfType_ListValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new ListValueNode([])); + var result = type.IsValueCompatible(new ListValueNode([])); // assert Assert.True(result); @@ -845,7 +845,7 @@ public void IsInstanceOfType_StringValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new StringValueNode("foo")); + var result = type.IsValueCompatible(new StringValueNode("foo")); // assert Assert.True(result); @@ -868,7 +868,7 @@ public void IsInstanceOfType_IntValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new IntValueNode(123)); + var result = type.IsValueCompatible(new IntValueNode(123)); // assert Assert.True(result); @@ -891,7 +891,7 @@ public void IsInstanceOfType_FloatValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new FloatValueNode(1.2)); + var result = type.IsValueCompatible(new FloatValueNode(1.2)); // assert Assert.True(result); @@ -914,7 +914,7 @@ public void IsInstanceOfType_BooleanValue_False() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(new BooleanValueNode(true)); + var result = type.IsValueCompatible(new BooleanValueNode(true)); // assert Assert.True(result); @@ -937,7 +937,7 @@ public void IsInstanceOfType_NullValue_True() var type = schema.Types.GetType("Any"); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -960,7 +960,7 @@ public void IsInstanceOfType_Null_ArgumentNullException() var type = schema.Types.GetType("Any"); // act - void Action() => type.IsInstanceOfType(null!); + void Action() => type.IsValueCompatible(null!); // assert Assert.Throws(Action); @@ -991,7 +991,7 @@ public void ParseValue_ScalarValues(object value, Type expectedType) var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue(value); + var literal = type.CoerceInputValue(value); // assert Assert.IsType(expectedType, literal); @@ -1014,7 +1014,7 @@ public void ParseValue_Decimal() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue((decimal)1); + var literal = type.CoerceInputValue((decimal)1); // assert Assert.IsType(literal); @@ -1037,7 +1037,7 @@ public void ParseValue_List_Of_Object() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue(new List()); + var literal = type.CoerceInputValue(new List()); // assert Assert.IsType(literal); @@ -1060,7 +1060,7 @@ public void ParseValue_List_Of_String() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue(new List()); + var literal = type.CoerceInputValue(new List()); // assert Assert.IsType(literal); @@ -1087,7 +1087,7 @@ public void ParseValue_List_Of_Foo() foo.Bar2 = bar; // act - var literal = type.ParseValue(new List { foo, foo }); + var literal = type.CoerceInputValue(new List { foo, foo }); // assert Assert.IsType(literal); @@ -1114,7 +1114,7 @@ public void ParseValue_List_Of_FooCyclic() barCyclic.FooCyclic = fooCyclic; // act - void Act() => type.ParseValue(new List { fooCyclic, fooCyclic }); + void Act() => type.CoerceInputValue(new List { fooCyclic, fooCyclic }); // assert Assert.Equal( @@ -1139,7 +1139,7 @@ public void ParseValue_List_Of_FooRecord() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue(new List { new(), new() }); + var literal = type.CoerceInputValue(new List { new(), new() }); // assert Assert.IsType(literal); @@ -1162,7 +1162,7 @@ public void ParseValue_Foo() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue(new Foo()); + var literal = type.CoerceInputValue(new Foo()); // assert Assert.IsType(literal); @@ -1189,7 +1189,7 @@ public void ParseValue_FooCyclic() barCyclic.FooCyclic = fooCyclic; // act - void Act() => type.ParseValue(fooCyclic); + void Act() => type.CoerceInputValue(fooCyclic); // assert Assert.Equal( @@ -1214,7 +1214,7 @@ public void ParseValue_Dictionary() var type = schema.Types.GetType("Any"); // act - var literal = type.ParseValue( + var literal = type.CoerceInputValue( new Dictionary()); // assert diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/BooleanTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/BooleanTypeTests.cs index bac728fa043..028e0daf509 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/BooleanTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/BooleanTypeTests.cs @@ -12,7 +12,7 @@ public void ParseLiteral() // act var booleanType = new BooleanType(); - var result = booleanType.ParseLiteral(literal); + var result = booleanType.CoerceInputLiteral(literal); // assert Assert.IsType(result); @@ -29,9 +29,9 @@ public void IsInstanceOfType() // act var booleanType = new BooleanType(); - var isIntLiteralInstanceOf = booleanType.IsInstanceOfType(boolLiteral); - var isStringLiteralInstanceOf = booleanType.IsInstanceOfType(stringLiteral); - var isNullLiteralInstanceOf = booleanType.IsInstanceOfType(nullLiteral); + var isIntLiteralInstanceOf = booleanType.IsValueCompatible(boolLiteral); + var isStringLiteralInstanceOf = booleanType.IsValueCompatible(stringLiteral); + var isNullLiteralInstanceOf = booleanType.IsValueCompatible(nullLiteral); // assert Assert.True(isIntLiteralInstanceOf); @@ -89,7 +89,7 @@ public void Serialize_String_Exception() Action a = () => booleanType.Serialize("foo"); // assert - Assert.Throws(a); + Assert.Throws(a); } [Fact] @@ -129,6 +129,6 @@ public void Deserialize_String_Exception() Action a = () => booleanType.Serialize("foo"); // assert - Assert.Throws(a); + Assert.Throws(a); } } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteArrayTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteArrayTypeTests.cs index 9958309d372..0bee56f9823 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteArrayTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteArrayTypeTests.cs @@ -26,7 +26,7 @@ public void IsInstanceOfType_NullLiteral() var literal = new NullValueNode(null); // act - var isOfType = byteArrayType.IsInstanceOfType(literal); + var isOfType = byteArrayType.IsValueCompatible(literal); // assert Assert.True(isOfType); @@ -41,7 +41,7 @@ public void IsInstanceOfType_IntLiteral() var literal = new IntValueNode(123); // act - var isOfType = byteArrayType.IsInstanceOfType(literal); + var isOfType = byteArrayType.IsValueCompatible(literal); // assert Assert.False(isOfType); @@ -55,7 +55,7 @@ public void IsInstanceOfType_Null() var guid = Guid.NewGuid(); // act - Action action = () => byteArrayType.IsInstanceOfType(null!); + Action action = () => byteArrayType.IsValueCompatible(null!); // assert Assert.Throws(action); @@ -102,7 +102,7 @@ public void Serialize_Int() Action action = () => byteArrayType.Serialize(value); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -190,7 +190,7 @@ public void ParseLiteral_StringValueNode() // act var actual = (byte[]?)byteArrayType - .ParseLiteral(literal); + .CoerceInputLiteral(literal); // assert Assert.Equal(expected, actual); @@ -204,10 +204,10 @@ public void ParseLiteral_IntValueNode() var literal = new IntValueNode(123); // act - Action action = () => byteArrayType.ParseLiteral(literal); + Action action = () => byteArrayType.CoerceInputLiteral(literal); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -218,7 +218,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = byteArrayType.ParseLiteral(literal); + var value = byteArrayType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -231,7 +231,7 @@ public void ParseLiteral_Null() var byteArrayType = new ByteArrayType(); // act - Action action = () => byteArrayType.ParseLiteral(null!); + Action action = () => byteArrayType.CoerceInputLiteral(null!); // assert Assert.Throws(action); @@ -262,7 +262,7 @@ public void ParseValue_Null() // act var stringLiteral = - byteArrayType.ParseValue(guid); + byteArrayType.CoerceInputValue(guid); // assert Assert.True(stringLiteral is NullValueNode); @@ -277,10 +277,10 @@ public void ParseValue_Int() const int value = 123; // act - Action action = () => byteArrayType.ParseValue(value); + Action action = () => byteArrayType.CoerceInputValue(value); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteTypeTests.cs index 04cfe8e5353..0001db5df67 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ByteTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var literal = new IntValueNode(1); // act - var result = type.IsInstanceOfType(literal); + var result = type.IsValueCompatible(literal); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new ByteType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new ByteType(); // act - var result = type.IsInstanceOfType(new FloatValueNode(1M)); + var result = type.IsValueCompatible(new FloatValueNode(1M)); // assert Assert.False(result); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -93,7 +93,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -106,7 +106,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -118,7 +118,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(1); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -132,7 +132,7 @@ public void ParseLiteral_NullValueNode() var type = new ByteType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -147,8 +147,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -160,7 +160,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -188,7 +188,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -216,7 +216,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -228,8 +228,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -240,7 +240,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -254,7 +254,7 @@ public void ParseValue_Nullable() byte? input = 123; // act - var output = (IntValueNode)type.ParseValue(input); + var output = (IntValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123, output.ToDouble()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTimeTypeTests.cs index ca4744a9516..b27f4da5255 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTimeTypeTests.cs @@ -70,7 +70,7 @@ public void Serialize_String_Exception() Action a = () => dateTimeType.Serialize("foo"); // assert - Assert.Throws(a); + Assert.Throws(a); } [Fact] @@ -85,7 +85,7 @@ public void ParseLiteral_StringValueNode() new TimeSpan(4, 0, 0)); // act - var dateTime = (DateTimeOffset)dateTimeType.ParseLiteral(literal)!; + var dateTime = (DateTimeOffset)dateTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -100,7 +100,7 @@ public void ParseLiteral_StringValueNode_Valid(string dateTime, DateTimeOffset r var literal = new StringValueNode(dateTime); // act - var dateTimeOffset = (DateTimeOffset?)dateTimeType.ParseLiteral(literal); + var dateTimeOffset = (DateTimeOffset?)dateTimeType.CoerceInputLiteral(literal); // assert Assert.Equal(result, dateTimeOffset); @@ -117,13 +117,13 @@ public void ParseLiteral_StringValueNode_Invalid(string dateTime) // act void Act() { - dateTimeType.ParseLiteral(literal); + dateTimeType.CoerceInputLiteral(literal); } // assert Assert.Equal( "DateTime cannot parse the given literal of type `StringValueNode`.", - Assert.Throws(Act).Message); + Assert.Throws(Act).Message); } [InlineData("en-US")] @@ -146,7 +146,7 @@ public void ParseLiteral_StringValueNode_DifferentCulture(string cultureName) new TimeSpan(4, 0, 0)); // act - var dateTime = (DateTimeOffset)dateTimeType.ParseLiteral(literal)!; + var dateTime = (DateTimeOffset)dateTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -326,7 +326,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = dateTimeType.ParseLiteral(literal); + var value = dateTimeType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -374,7 +374,7 @@ public void ParseValue_Null() var dateTimeType = new DateTimeType(); // act - var literal = dateTimeType.ParseValue(null); + var literal = dateTimeType.CoerceInputValue(null); // assert Assert.IsType(literal); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs index 43edaea3640..b90f9b198f6 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs @@ -78,7 +78,7 @@ public void Serialize_String_Exception() void Action() => dateType.Serialize("foo"); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -223,7 +223,7 @@ public void ParseLiteral_StringValueNode() var expectedDateTime = new DateOnly(2018, 6, 29); // act - var dateTime = (DateOnly)dateType.ParseLiteral(literal)!; + var dateTime = (DateOnly)dateType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -247,7 +247,7 @@ public void ParseLiteral_StringValueNode_DifferentCulture( var expectedDateTime = new DateOnly(2018, 6, 29); // act - var dateTime = (DateOnly)dateType.ParseLiteral(literal)!; + var dateTime = (DateOnly)dateType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -261,7 +261,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = dateType.ParseLiteral(literal); + var value = dateType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -290,7 +290,7 @@ public void ParseValue_Null() var dateType = new DateType(); // act - var literal = dateType.ParseValue(null); + var literal = dateType.CoerceInputValue(null); // assert Assert.Equal(NullValueNode.Default, literal); @@ -384,7 +384,7 @@ public void ParseResult_SerializationException() var exception = Record.Exception(() => dateType.ParseResult(resultValue)); // assert - Assert.IsType(exception); + Assert.IsType(exception); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DecimalTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DecimalTypeTests.cs index ae35dccacb0..dc848e743e1 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DecimalTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DecimalTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var type = new DecimalType(); // act - var result = type.IsInstanceOfType(CreateExponentialLiteral()); + var result = type.IsValueCompatible(CreateExponentialLiteral()); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new DecimalType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_IntLiteral_True() var type = new DecimalType(); // act - var result = type.IsInstanceOfType(new IntValueNode(123)); + var result = type.IsValueCompatible(new IntValueNode(123)); // assert Assert.True(result); @@ -51,7 +51,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new DecimalType(); // act - var result = type.IsInstanceOfType(new StringValueNode("123")); + var result = type.IsValueCompatible(new StringValueNode("123")); // assert Assert.False(result); @@ -66,7 +66,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -106,7 +106,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -119,7 +119,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -131,7 +131,7 @@ public void ParseLiteral_FixedPointLiteral() var literal = CreateFixedPointLiteral(); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -146,7 +146,7 @@ public void ParseLiteral_ExponentialLiteral() var literal = CreateExponentialLiteral(); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -161,7 +161,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(123); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -175,7 +175,7 @@ public void ParseLiteral_NullValueNode() var type = new DecimalType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -190,8 +190,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -203,7 +203,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -231,7 +231,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -259,7 +259,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -271,8 +271,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -283,7 +283,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -297,7 +297,7 @@ public void ParseValue_Nullable() decimal? input = 123M; // act - var output = (FloatValueNode)type.ParseValue(input); + var output = (FloatValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123M, output.ToDecimal()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/FloatTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/FloatTypeTests.cs index 39b5aa5a8e0..0365fcbf2b3 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/FloatTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/FloatTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var type = new FloatType(); // act - var result = type.IsInstanceOfType(CreateExponentialLiteral()); + var result = type.IsValueCompatible(CreateExponentialLiteral()); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new FloatType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_IntLiteral_True() var type = new FloatType(); // act - var result = type.IsInstanceOfType(new IntValueNode(123)); + var result = type.IsValueCompatible(new IntValueNode(123)); // assert Assert.True(result); @@ -51,7 +51,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new FloatType(); // act - var result = type.IsInstanceOfType(new StringValueNode("123")); + var result = type.IsValueCompatible(new StringValueNode("123")); // assert Assert.False(result); @@ -66,7 +66,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -106,7 +106,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -119,7 +119,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -131,7 +131,7 @@ public void ParseLiteral_FixedPointLiteral() var literal = CreateFixedPointLiteral(); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -146,7 +146,7 @@ public void ParseLiteral_ExponentialLiteral() var literal = CreateExponentialLiteral(); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -161,7 +161,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(123); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -175,7 +175,7 @@ public void ParseLiteral_NullValueNode() var type = new FloatType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -190,8 +190,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -203,7 +203,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -231,7 +231,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -259,7 +259,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -271,8 +271,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -283,7 +283,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -297,7 +297,7 @@ public void ParseValue_Nullable() double? input = 123; // act - var output = (FloatValueNode)type.ParseValue(input); + var output = (FloatValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123, output.ToDouble()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IdTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IdTypeTests.cs index 74ac07800b5..b413c61e6a3 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IdTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IdTypeTests.cs @@ -59,7 +59,7 @@ public void IsInstanceOfType_StringValueNode() var input = new StringValueNode("123456"); // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.True(result); @@ -73,7 +73,7 @@ public void IsInstanceOfType_IntValueNode() var input = new IntValueNode(123456); // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.True(result); @@ -87,7 +87,7 @@ public void IsInstanceOfType_NullValueNode() var input = NullValueNode.Default; // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.True(result); @@ -101,7 +101,7 @@ public void IsInstanceOfType_Wrong_ValueNode() var input = new FloatValueNode(123456.0); // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.False(result); @@ -116,7 +116,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -222,7 +222,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -234,7 +234,7 @@ public void ParseLiteral_StringValueNode() var input = new StringValueNode("123456"); // act - var output = type.ParseLiteral(input); + var output = type.CoerceInputLiteral(input); // assert Assert.IsType(output); @@ -249,7 +249,7 @@ public void ParseLiteral_IntValueNode() var input = new IntValueNode(123456); // act - var output = type.ParseLiteral(input); + var output = type.CoerceInputLiteral(input); // assert Assert.IsType(output); @@ -264,7 +264,7 @@ public void ParseLiteral_NullValueNode() var input = NullValueNode.Default; // act - var output = type.ParseLiteral(input); + var output = type.CoerceInputLiteral(input); // assert Assert.Null(output); @@ -279,8 +279,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -292,7 +292,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws(() => - type.ParseLiteral(null!)); + type.CoerceInputLiteral(null!)); } [Fact] @@ -304,8 +304,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(input)); + Assert.Throws( + () => type.CoerceInputValue(input)); } [Fact] @@ -316,7 +316,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -330,7 +330,7 @@ public void ParseValue_String() object input = "hello"; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IntTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IntTypeTests.cs index 37f33245ca2..e86440dba97 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IntTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/IntTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var literal = new IntValueNode(1); // act - var result = type.IsInstanceOfType(literal); + var result = type.IsValueCompatible(literal); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new IntType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new IntType(); // act - var result = type.IsInstanceOfType(new FloatValueNode(1M)); + var result = type.IsValueCompatible(new FloatValueNode(1M)); // assert Assert.False(result); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -93,7 +93,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -106,7 +106,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -118,7 +118,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(1); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -132,7 +132,7 @@ public void ParseLiteral_NullValueNode() var type = new IntType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -147,8 +147,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -160,7 +160,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -188,7 +188,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -216,7 +216,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -228,8 +228,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -240,7 +240,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -254,7 +254,7 @@ public void ParseValue_Nullable() int? input = 123; // act - var output = (IntValueNode)type.ParseValue(input); + var output = (IntValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123, output.ToDouble()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTimeTypeTests.cs index 1952f0a1eda..31a9b50917e 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTimeTypeTests.cs @@ -63,7 +63,7 @@ public void Serialize_String_Exception() void Action() => localDateTimeType.Serialize("foo"); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -191,7 +191,7 @@ public void ParseLiteral_StringValueNode() var expectedDateTime = new DateTime(2018, 6, 29, 8, 46, 14); // act - var dateTime = (DateTime)localDateTimeType.ParseLiteral(literal)!; + var dateTime = (DateTime)localDateTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -215,7 +215,7 @@ public void ParseLiteral_StringValueNode_DifferentCulture( var expectedDateTime = new DateTime(2018, 6, 29, 8, 46, 14); // act - var dateTime = (DateTime)localDateTimeType.ParseLiteral(literal)!; + var dateTime = (DateTime)localDateTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateTime, dateTime); @@ -229,7 +229,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = localDateTimeType.ParseLiteral(literal); + var value = localDateTimeType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -258,7 +258,7 @@ public void ParseValue_Null() var localDateTimeType = new LocalDateTimeType(); // act - var literal = localDateTimeType.ParseValue(null); + var literal = localDateTimeType.CoerceInputValue(null); // assert Assert.Equal(NullValueNode.Default, literal); @@ -336,7 +336,7 @@ public void ParseResult_SerializationException() var exception = Record.Exception(() => localDateTimeType.ParseResult(resultValue)); // assert - Assert.IsType(exception); + Assert.IsType(exception); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs index f3451621c0b..016f60655d4 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs @@ -78,7 +78,7 @@ public void Serialize_String_Exception() void Action() => localDateType.Serialize("foo"); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -223,7 +223,7 @@ public void ParseLiteral_StringValueNode() var expectedDateOnly = new DateOnly(2018, 6, 29); // act - var dateOnly = (DateOnly)localDateType.ParseLiteral(literal)!; + var dateOnly = (DateOnly)localDateType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateOnly, dateOnly); @@ -238,7 +238,7 @@ public void ParseLiteral_StringValueNode_Valid(string dateTime, DateOnly result) var literal = new StringValueNode(dateTime); // act - var dateTimeOffset = (DateOnly?)localDateType.ParseLiteral(literal); + var dateTimeOffset = (DateOnly?)localDateType.CoerceInputLiteral(literal); // assert Assert.Equal(result, dateTimeOffset); @@ -255,13 +255,13 @@ public void ParseLiteral_StringValueNode_Invalid(string dateTime) // act void Act() { - localDateType.ParseLiteral(literal); + localDateType.CoerceInputLiteral(literal); } // assert Assert.Equal( "LocalDate cannot parse the given literal of type `StringValueNode`.", - Assert.Throws(Act).Message); + Assert.Throws(Act).Message); } [InlineData("en-US")] @@ -282,7 +282,7 @@ public void ParseLiteral_StringValueNode_DifferentCulture( var expectedDateOnly = new DateOnly(2018, 6, 29); // act - var dateOnly = (DateOnly)localDateType.ParseLiteral(literal)!; + var dateOnly = (DateOnly)localDateType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedDateOnly, dateOnly); @@ -296,7 +296,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = localDateType.ParseLiteral(literal); + var value = localDateType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -325,7 +325,7 @@ public void ParseValue_Null() var localDateType = new LocalDateType(); // act - var literal = localDateType.ParseValue(null); + var literal = localDateType.CoerceInputValue(null); // assert Assert.Equal(NullValueNode.Default, literal); @@ -419,7 +419,7 @@ public void ParseResult_SerializationException() var exception = Record.Exception(() => localDateType.ParseResult(resultValue)); // assert - Assert.IsType(exception); + Assert.IsType(exception); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs index 4472b8ed5c5..24b56053724 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs @@ -78,7 +78,7 @@ public void Serialize_String_Exception() void Action() => localTimeType.Serialize("foo"); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -223,7 +223,7 @@ public void ParseLiteral_StringValueNode() var expectedTimeOnly = new TimeOnly(8, 46, 14); // act - var timeOnly = (TimeOnly)localTimeType.ParseLiteral(literal)!; + var timeOnly = (TimeOnly)localTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedTimeOnly, timeOnly); @@ -247,7 +247,7 @@ public void ParseLiteral_StringValueNode_DifferentCulture( var expectedTimeOnly = new TimeOnly(8, 46, 14); // act - var timeOnly = (TimeOnly)localTimeType.ParseLiteral(literal)!; + var timeOnly = (TimeOnly)localTimeType.CoerceInputLiteral(literal)!; // assert Assert.Equal(expectedTimeOnly, timeOnly); @@ -261,7 +261,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = localTimeType.ParseLiteral(literal); + var value = localTimeType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -290,7 +290,7 @@ public void ParseValue_Null() var localTimeType = new LocalTimeType(); // act - var literal = localTimeType.ParseValue(null); + var literal = localTimeType.CoerceInputValue(null); // assert Assert.Equal(NullValueNode.Default, literal); @@ -384,7 +384,7 @@ public void ParseResult_SerializationException() var exception = Record.Exception(() => localTimeType.ParseResult(resultValue)); // assert - Assert.IsType(exception); + Assert.IsType(exception); } [Fact] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LongTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LongTypeTests.cs index 4aa9984c850..38f4e5e6d8c 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LongTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LongTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var literal = new IntValueNode(1); // act - var result = type.IsInstanceOfType(literal); + var result = type.IsValueCompatible(literal); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new LongType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new LongType(); // act - var result = type.IsInstanceOfType(new FloatValueNode(1M)); + var result = type.IsValueCompatible(new FloatValueNode(1M)); // assert Assert.False(result); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -93,7 +93,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -106,7 +106,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -118,7 +118,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(1); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -132,7 +132,7 @@ public void ParseLiteral_NullValueNode() var type = new LongType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -147,8 +147,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -160,7 +160,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -188,7 +188,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -216,7 +216,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -228,8 +228,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -240,7 +240,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -254,7 +254,7 @@ public void ParseValue_Nullable() long? input = 123; // act - var output = (IntValueNode)type.ParseValue(input); + var output = (IntValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123, output.ToDouble()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ScalarBindingTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ScalarBindingTests.cs index 34bab5fc6fa..91f754185bd 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ScalarBindingTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ScalarBindingTests.cs @@ -57,17 +57,17 @@ public ImplicitBindingScalar() { } - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { throw new NotImplementedException(); } - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) { throw new NotImplementedException(); } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { throw new NotImplementedException(); } @@ -85,17 +85,17 @@ public ExplicitBindingScalar() { } - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { throw new NotImplementedException(); } - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) { throw new NotImplementedException(); } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { throw new NotImplementedException(); } diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ShortTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ShortTypeTests.cs index a7a4f7938fd..65636dc8dc1 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ShortTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/ShortTypeTests.cs @@ -12,7 +12,7 @@ public void IsInstanceOfType_FloatLiteral_True() var literal = new IntValueNode(1); // act - var result = type.IsInstanceOfType(literal); + var result = type.IsValueCompatible(literal); // assert Assert.True(result); @@ -25,7 +25,7 @@ public void IsInstanceOfType_NullLiteral_True() var type = new ShortType(); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -38,7 +38,7 @@ public void IsInstanceOfType_StringLiteral_False() var type = new ShortType(); // act - var result = type.IsInstanceOfType(new FloatValueNode(1M)); + var result = type.IsValueCompatible(new FloatValueNode(1M)); // assert Assert.False(result); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert Assert.Throws( - () => type.IsInstanceOfType(null!)); + () => type.IsValueCompatible(null!)); } [Fact] @@ -93,7 +93,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -106,7 +106,7 @@ public void Serialize_MaxValue_Violation() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(value)); } @@ -118,7 +118,7 @@ public void ParseLiteral_IntLiteral() var literal = new IntValueNode(1); // act - var value = type.ParseLiteral(literal); + var value = type.CoerceInputLiteral(literal); // assert Assert.IsType(value); @@ -132,7 +132,7 @@ public void ParseLiteral_NullValueNode() var type = new ShortType(); // act - var output = type.ParseLiteral(NullValueNode.Default); + var output = type.CoerceInputLiteral(NullValueNode.Default); // assert Assert.Null(output); @@ -147,8 +147,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -160,7 +160,7 @@ public void ParseLiteral_Null_Throws() // act // assert Assert.Throws( - () => type.ParseLiteral(null!)); + () => type.CoerceInputLiteral(null!)); } [Fact] @@ -188,7 +188,7 @@ public void ParseValue_MaxValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -216,7 +216,7 @@ public void ParseValue_MinValue_Violation() Action action = () => type.ParseValue(input); // assert - Assert.Throws(action); + Assert.Throws(action); } [Fact] @@ -228,8 +228,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(value)); + Assert.Throws( + () => type.CoerceInputValue(value)); } [Fact] @@ -240,7 +240,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); @@ -254,7 +254,7 @@ public void ParseValue_Nullable() short? input = 123; // act - var output = (IntValueNode)type.ParseValue(input); + var output = (IntValueNode)type.CoerceInputValue(input); // assert Assert.Equal(123, output.ToDouble()); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/StringTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/StringTypeTests.cs index d43d1bf2192..4ac26187369 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/StringTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/StringTypeTests.cs @@ -25,7 +25,7 @@ public void IsInstanceOfType_ValueNode() var input = new StringValueNode("123456"); // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.True(result); @@ -39,7 +39,7 @@ public void IsInstanceOfType_NullValueNode() var input = NullValueNode.Default; // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.True(result); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Wrong_ValueNode() var input = new IntValueNode(123456); // act - var result = type.IsInstanceOfType(input); + var result = type.IsValueCompatible(input); // assert Assert.False(result); @@ -67,7 +67,7 @@ public void IsInstanceOfType_Null_Throws() // act // assert - Assert.Throws(() => type.IsInstanceOfType(null!)); + Assert.Throws(() => type.IsValueCompatible(null!)); } [Fact] @@ -107,7 +107,7 @@ public void Serialize_Wrong_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => type.Serialize(input)); } @@ -119,7 +119,7 @@ public void ParseLiteral_ValueNode() var input = new StringValueNode("123456"); // act - var output = type.ParseLiteral(input); + var output = type.CoerceInputLiteral(input); // assert Assert.IsType(output); @@ -134,7 +134,7 @@ public void ParseLiteral_NullValueNode() var input = NullValueNode.Default; // act - var output = type.ParseLiteral(input); + var output = type.CoerceInputLiteral(input); // assert Assert.Null(output); @@ -149,8 +149,8 @@ public void ParseLiteral_Wrong_ValueNode_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -161,7 +161,7 @@ public void ParseLiteral_Null_Throws() // act // assert - Assert.Throws(() => type.ParseLiteral(null!)); + Assert.Throws(() => type.CoerceInputLiteral(null!)); } [Fact] @@ -173,8 +173,8 @@ public void ParseValue_Wrong_Value_Throws() // act // assert - Assert.Throws( - () => type.ParseValue(input)); + Assert.Throws( + () => type.CoerceInputValue(input)); } [Fact] @@ -185,7 +185,7 @@ public void ParseValue_Null() object input = null!; // act - object output = type.ParseValue(input); + object output = type.CoerceInputValue(input); // assert Assert.IsType(output); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/TimeSpanTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/TimeSpanTypeTests.cs index 7b648ec3784..81327aa50e7 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/TimeSpanTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/TimeSpanTypeTests.cs @@ -93,7 +93,7 @@ public void Serialize_String_Exception() Action a = () => timeSpanType.Serialize("bad"); // assert - Assert.Throws(a); + Assert.Throws(a); } [Theory] @@ -108,7 +108,7 @@ public void ParseLiteral_StringValueNode(TimeSpanFormat format, string literalVa // act var timeSpan = (TimeSpan?)timeSpanType - .ParseLiteral(literal); + .CoerceInputLiteral(literal); // assert Assert.Equal(expectedTimeSpan, timeSpan); @@ -231,7 +231,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = timeSpanType.ParseLiteral(literal); + var value = timeSpanType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -244,7 +244,7 @@ public void ParseValue_Null() var timeSpanType = new TimeSpanType(); // act - var literal = timeSpanType.ParseValue(null); + var literal = timeSpanType.CoerceInputValue(null); // assert Assert.IsType(literal); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UrlTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UrlTypeTests.cs index a2048d25899..5774f5b2961 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UrlTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UrlTypeTests.cs @@ -24,7 +24,7 @@ public void ParseLiteral_StringValueNode() var literal = new StringValueNode(expected.AbsoluteUri); // act - var actual = (Uri?)urlType.ParseLiteral(literal); + var actual = (Uri?)urlType.CoerceInputLiteral(literal); // assert Assert.Equal(expected, actual); @@ -38,7 +38,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = urlType.ParseLiteral(literal); + var value = urlType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -53,7 +53,7 @@ public void ParseLiteral_RelativeUrl() var literal = new StringValueNode($"{expected}"); // act - var actual = (Uri?)urlType.ParseLiteral(literal); + var actual = (Uri?)urlType.CoerceInputLiteral(literal); // Assert Assert.Equal(expected, actual); @@ -68,8 +68,8 @@ public void ParseLiteral_Invalid_Url_Throws() // act // assert - Assert.Throws( - () => type.ParseLiteral(input)); + Assert.Throws( + () => type.CoerceInputLiteral(input)); } [Fact] @@ -153,7 +153,7 @@ public void IsInstanceOfType_GivenUriAsStringValueNode_ReturnsTrue() var uri = new Uri("http://domain.test/url"); // Act - var isUrlType = urlType.IsInstanceOfType(new StringValueNode(uri.AbsoluteUri)); + var isUrlType = urlType.IsValueCompatible(new StringValueNode(uri.AbsoluteUri)); // Assert Assert.True(isUrlType); @@ -166,7 +166,7 @@ public void IsInstanceOfType_GivenNullValueNode_ReturnsTrue() var urlType = new UrlType(); // act - var isUrlType = urlType.IsInstanceOfType(new NullValueNode(null)); + var isUrlType = urlType.IsValueCompatible(new NullValueNode(null)); // assert Assert.True(isUrlType); @@ -179,7 +179,7 @@ public void IsInstanceOfType_GivenInvalidUriAsStringLiteral_False() var urlType = new UrlType(); // act - var isUrlType = urlType.IsInstanceOfType( + var isUrlType = urlType.IsValueCompatible( new StringValueNode("$*^domain.test")); // assert @@ -193,7 +193,7 @@ public void IsInstanceOfType_GivenNull_ThrowsArgumentException() var urlType = new UrlType(); // act - Action action = () => urlType.IsInstanceOfType(null!); + Action action = () => urlType.IsValueCompatible(null!); // assert Assert.Throws(action); @@ -207,7 +207,7 @@ public void IsInstanceOfType_GivenNonUrlValueNode_ReturnsFalse() var intValue = new IntValueNode(1); // act - var isUrlType = urlType.IsInstanceOfType(intValue); + var isUrlType = urlType.IsValueCompatible(intValue); // assert Assert.False(isUrlType); diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UuidTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UuidTypeTests.cs index e674e02687a..79dc5140c63 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UuidTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/UuidTypeTests.cs @@ -26,7 +26,7 @@ public void IsInstanceOfType_NullLiteral() var literal = new NullValueNode(null); // act - var isOfType = uuidType.IsInstanceOfType(literal); + var isOfType = uuidType.IsValueCompatible(literal); // assert Assert.True(isOfType); @@ -40,7 +40,7 @@ public void IsInstanceOfType_IntLiteral() var literal = new IntValueNode(123); // act - var isOfType = uuidType.IsInstanceOfType(literal); + var isOfType = uuidType.IsValueCompatible(literal); // assert Assert.False(isOfType); @@ -53,7 +53,7 @@ public void IsInstanceOfType_Null() var uuidType = new UuidType(); // act - void Action() => uuidType.IsInstanceOfType(null!); + void Action() => uuidType.IsValueCompatible(null!); // assert Assert.Throws(Action); @@ -97,7 +97,7 @@ public void Serialize_Int() void Action() => uuidType.Serialize(value); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -168,8 +168,8 @@ public void ParseLiteral_StringValueNode() var literalB = new StringValueNode(expected.ToString("P")); // act - var runtimeValueA = (Guid)uuidType.ParseLiteral(literalA)!; - var runtimeValueB = (Guid)uuidType.ParseLiteral(literalB)!; + var runtimeValueA = (Guid)uuidType.CoerceInputLiteral(literalA)!; + var runtimeValueB = (Guid)uuidType.CoerceInputLiteral(literalB)!; // assert Assert.Equal(expected, runtimeValueA); @@ -185,10 +185,10 @@ public void ParseLiteral_StringValueNode_Enforce_Format() var literal = new StringValueNode(expected.ToString("N")); // act - void Action() => uuidType.ParseLiteral(literal); + void Action() => uuidType.CoerceInputLiteral(literal); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -199,10 +199,10 @@ public void ParseLiteral_IntValueNode() var literal = new IntValueNode(123); // act - void Action() => uuidType.ParseLiteral(literal); + void Action() => uuidType.CoerceInputLiteral(literal); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -213,7 +213,7 @@ public void ParseLiteral_NullValueNode() var literal = NullValueNode.Default; // act - var value = uuidType.ParseLiteral(literal); + var value = uuidType.CoerceInputLiteral(literal); // assert Assert.Null(value); @@ -226,7 +226,7 @@ public void ParseLiteral_Null() var uuidType = new UuidType(); // act - void Action() => uuidType.ParseLiteral(null!); + void Action() => uuidType.CoerceInputLiteral(null!); // assert Assert.Throws(Action); @@ -255,7 +255,7 @@ public void ParseValue_Null() Guid? guid = null; // act - var stringLiteral = uuidType.ParseValue(guid); + var stringLiteral = uuidType.CoerceInputValue(guid); // assert Assert.True(stringLiteral is NullValueNode); @@ -270,10 +270,10 @@ public void ParseValue_Int() const int value = 123; // act - void Action() => uuidType.ParseValue(value); + void Action() => uuidType.CoerceInputValue(value); // assert - Assert.Throws(Action); + Assert.Throws(Action); } [Fact] @@ -354,7 +354,7 @@ public void ParseLiteral_With_Format(char format) var literal = new StringValueNode(guid.ToString(format.ToString())); // act - var deserialized = (Guid)uuidType.ParseLiteral(literal)!; + var deserialized = (Guid)uuidType.CoerceInputLiteral(literal)!; // assert Assert.Equal(guid, deserialized); @@ -381,10 +381,10 @@ public void Parse_Guid_String_With_Appended_String(bool enforceFormat) var uuidType = new UuidType(defaultFormat: 'D', enforceFormat: enforceFormat); // act - void Fail() => uuidType.ParseLiteral(input); + void Fail() => uuidType.CoerceInputLiteral(input); // assert - Assert.Throws(Fail); + Assert.Throws(Fail); } [InlineData(false)] @@ -397,7 +397,7 @@ public void Parse_Guid_Valid_Input(bool enforceFormat) var uuidType = new UuidType(defaultFormat: 'D', enforceFormat: enforceFormat); // act - var guid = (Guid)uuidType.ParseLiteral(input)!; + var guid = (Guid)uuidType.CoerceInputLiteral(input)!; // assert Assert.Equal(input.Value, guid.ToString("D")); @@ -416,7 +416,7 @@ public void Deserialize_Guid_String_With_Appended_String(bool enforceFormat) void Fail() => uuidType.Deserialize(input); // assert - Assert.Throws(Fail); + Assert.Throws(Fail); } [InlineData(false)] @@ -445,7 +445,7 @@ public void IsInstanceOf_Guid_String_With_Appended_String(bool enforceFormat) var uuidType = new UuidType(defaultFormat: 'D', enforceFormat: enforceFormat); // act - var result = uuidType.IsInstanceOfType(input); + var result = uuidType.IsValueCompatible(input); // assert Assert.False(result); @@ -461,7 +461,7 @@ public void IsInstanceOf_Guid_Valid_Format(bool enforceFormat) var uuidType = new UuidType(defaultFormat: 'D', enforceFormat: enforceFormat); // act - var result = uuidType.IsInstanceOfType(input); + var result = uuidType.IsValueCompatible(input); // assert Assert.True(result); diff --git a/src/HotChocolate/Core/test/Validation.Tests/Types/InvalidScalar.cs b/src/HotChocolate/Core/test/Validation.Tests/Types/InvalidScalar.cs index de4191d1c72..36fac03e9f4 100644 --- a/src/HotChocolate/Core/test/Validation.Tests/Types/InvalidScalar.cs +++ b/src/HotChocolate/Core/test/Validation.Tests/Types/InvalidScalar.cs @@ -10,17 +10,17 @@ public InvalidScalar() { } - public override bool IsInstanceOfType(IValueNode literal) + public override bool IsValueCompatible(IValueNode literal) { return false; } - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) { throw new InvalidOperationException(); } - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) { throw new InvalidOperationException(); } diff --git a/src/HotChocolate/Data/src/Data/Sorting/SortEnumType.cs b/src/HotChocolate/Data/src/Data/Sorting/SortEnumType.cs index 866a6c301c5..e81bb1ed1d0 100644 --- a/src/HotChocolate/Data/src/Data/Sorting/SortEnumType.cs +++ b/src/HotChocolate/Data/src/Data/Sorting/SortEnumType.cs @@ -78,7 +78,7 @@ protected override bool TryCreateEnumValue( return null; } - throw new SerializationException( + throw new LeafCoercionException( string.Format( CultureInfo.InvariantCulture, DataResources.SortingEnumType_Cannot_ParseLiteral, diff --git a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/FusionScalarTypeDefinition.cs b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/FusionScalarTypeDefinition.cs index 18f481ab633..e8bd71549c6 100644 --- a/src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/FusionScalarTypeDefinition.cs +++ b/src/HotChocolate/Fusion-vnext/src/Fusion.Execution.Types/FusionScalarTypeDefinition.cs @@ -160,7 +160,7 @@ public bool IsAssignableFrom(ITypeDefinition type) } /// - public bool IsInstanceOfType(IValueNode value) + public bool IsValueCompatible(IValueNode value) { ArgumentNullException.ThrowIfNull(value); diff --git a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/InaccessibleTests.cs b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/InaccessibleTests.cs index 96a5462d8f6..9afea311c87 100644 --- a/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/InaccessibleTests.cs +++ b/src/HotChocolate/Fusion-vnext/test/Fusion.AspNetCore.Tests/InaccessibleTests.cs @@ -1015,17 +1015,17 @@ public InternalScalarType() : base("InternalScalar") public override Type RuntimeType => typeof(string); - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) => valueSyntax is StringValueNode; - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) => valueSyntax is StringValueNode s ? s.Value : null; - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) => new StringValueNode(runtimeValue?.ToString() ?? ""); public override IValueNode ParseResult(object? resultValue) - => ParseValue(resultValue); + => CoerceInputValue(resultValue); public override bool TrySerialize(object? runtimeValue, out object? resultValue) { diff --git a/src/HotChocolate/MongoDb/src/Types/BsonType.cs b/src/HotChocolate/MongoDb/src/Types/BsonType.cs index b14c44e6d3e..c3a75b2b74a 100644 --- a/src/HotChocolate/MongoDb/src/Types/BsonType.cs +++ b/src/HotChocolate/MongoDb/src/Types/BsonType.cs @@ -44,7 +44,7 @@ public BsonType() public override Type RuntimeType => typeof(BsonValue); /// - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) { ArgumentNullException.ThrowIfNull(valueSyntax); @@ -115,13 +115,13 @@ when double.TryParse(fvn.Value, } /// - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) { return ParseLiteralToBson(valueSyntax); } /// - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) { if (runtimeValue is null) { @@ -175,7 +175,7 @@ public override IValueNode ParseValue(object? runtimeValue) List fields = []; foreach (var field in doc) { - fields.Add(new ObjectFieldNode(field.Name, ParseValue(field.Value))); + fields.Add(new ObjectFieldNode(field.Name, CoerceInputValue(field.Value))); } return new ObjectValueNode(fields); @@ -186,7 +186,7 @@ public override IValueNode ParseValue(object? runtimeValue) List valueList = []; foreach (var element in arr) { - valueList.Add(ParseValue(element)); + valueList.Add(CoerceInputValue(element)); } return new ListValueNode(valueList); @@ -207,7 +207,7 @@ public override IValueNode ParseValue(object? runtimeValue) /// public override IValueNode ParseResult(object? resultValue) => - ParseValue(resultValue); + CoerceInputValue(resultValue); public override bool TrySerialize(object? runtimeValue, out object? resultValue) { @@ -315,7 +315,7 @@ public override bool TrySerialize(object? runtimeValue, out object? resultValue) return false; case IValueNode literal: - resultValue = ParseLiteral(literal); + resultValue = CoerceInputLiteral(literal); return true; default: @@ -370,7 +370,7 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu } case IValueNode literal: - runtimeValue = ParseLiteral(literal); + runtimeValue = CoerceInputLiteral(literal); return true; default: diff --git a/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs b/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs index af6e6bd4146..a7140839529 100644 --- a/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs +++ b/src/HotChocolate/MongoDb/src/Types/ObjectIdType.cs @@ -45,5 +45,5 @@ protected override StringValueNode ParseValue(ObjectId runtimeValue) => /// public override IValueNode ParseResult(object? resultValue) => - ParseValue(resultValue); + CoerceInputValue(resultValue); } diff --git a/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs b/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs index 8f7acfee534..94d980d69ad 100644 --- a/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs +++ b/src/HotChocolate/MongoDb/src/Types/ThrowHelper.cs @@ -7,7 +7,7 @@ namespace HotChocolate.Types.MongoDb; internal static class ThrowHelper { - public static SerializationException Bson_CouldNotParseValue( + public static LeafCoercionException Bson_CouldNotParseValue( ScalarType type, object? value) => new( @@ -17,7 +17,7 @@ public static SerializationException Bson_CouldNotParseValue( value?.ToString() ?? "null"), type); - public static SerializationException Bson_CouldNotParseLiteral( + public static LeafCoercionException Bson_CouldNotParseLiteral( ScalarType type, IValueNode literal) => new( diff --git a/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs b/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs index 8801f8b976a..e9b34419c7b 100644 --- a/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs +++ b/src/HotChocolate/MongoDb/test/Types.MongoDb/BsonTypeTests.cs @@ -789,7 +789,7 @@ public void IsInstanceOfType_EnumValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new EnumValueNode("foo")); + var result = type.IsValueCompatible(new EnumValueNode("foo")); // assert Assert.False(result); @@ -812,7 +812,7 @@ public void IsInstanceOfType_ObjectValue_True() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new ObjectValueNode([])); + var result = type.IsValueCompatible(new ObjectValueNode([])); // assert Assert.True(result); @@ -835,7 +835,7 @@ public void IsInstanceOfType_ListValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new ListValueNode([])); + var result = type.IsValueCompatible(new ListValueNode([])); // assert Assert.True(result); @@ -858,7 +858,7 @@ public void IsInstanceOfType_StringValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new StringValueNode("foo")); + var result = type.IsValueCompatible(new StringValueNode("foo")); // assert Assert.True(result); @@ -881,7 +881,7 @@ public void IsInstanceOfType_IntValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new IntValueNode(123)); + var result = type.IsValueCompatible(new IntValueNode(123)); // assert Assert.True(result); @@ -904,7 +904,7 @@ public void IsInstanceOfType_FloatValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new FloatValueNode(1.2)); + var result = type.IsValueCompatible(new FloatValueNode(1.2)); // assert Assert.True(result); @@ -927,7 +927,7 @@ public void IsInstanceOfType_BooleanValue_False() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(new BooleanValueNode(true)); + var result = type.IsValueCompatible(new BooleanValueNode(true)); // assert Assert.True(result); @@ -950,7 +950,7 @@ public void IsInstanceOfType_NullValue_True() var type = schema.Types.GetType("Bson"); // act - var result = type.IsInstanceOfType(NullValueNode.Default); + var result = type.IsValueCompatible(NullValueNode.Default); // assert Assert.True(result); @@ -973,7 +973,7 @@ public void IsInstanceOfType_Null_ArgumentNullException() var type = schema.Types.GetType("Bson"); // act - void Action() => type.IsInstanceOfType(null!); + void Action() => type.IsValueCompatible(null!); // assert Assert.Throws(Action); @@ -1004,7 +1004,7 @@ public void ParseValue_ScalarValues(object value, Type expectedType) var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue(value); + var literal = type.CoerceInputValue(value); // assert Assert.IsType(expectedType, literal); @@ -1027,7 +1027,7 @@ public void ParseValue_Decimal() var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue((decimal)1); + var literal = type.CoerceInputValue((decimal)1); // assert Assert.IsType(literal); @@ -1050,7 +1050,7 @@ public void ParseValue_List_Of_Object() var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue(new List()); + var literal = type.CoerceInputValue(new List()); // assert Assert.IsType(literal); @@ -1073,7 +1073,7 @@ public void ParseValue_List_Of_String() var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue(new List()); + var literal = type.CoerceInputValue(new List()); // assert Assert.IsType(literal); @@ -1096,7 +1096,7 @@ public void ParseValue_List_Of_Foo() var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue(new List()); + var literal = type.CoerceInputValue(new List()); // assert Assert.IsType(literal); @@ -1119,7 +1119,7 @@ public void ParseValue_Dictionary() var type = schema.Types.GetType("Bson"); // act - var literal = type.ParseValue( + var literal = type.CoerceInputValue( new Dictionary()); // assert diff --git a/src/HotChocolate/Mutable/src/Types.Mutable/MutableScalarTypeDefinition.cs b/src/HotChocolate/Mutable/src/Types.Mutable/MutableScalarTypeDefinition.cs index 04fa9ab327b..50fa30dc119 100644 --- a/src/HotChocolate/Mutable/src/Types.Mutable/MutableScalarTypeDefinition.cs +++ b/src/HotChocolate/Mutable/src/Types.Mutable/MutableScalarTypeDefinition.cs @@ -116,7 +116,7 @@ public Uri? SpecifiedBy public string? Pattern { get; set; } /// - public bool IsInstanceOfType(IValueNode value) + public bool IsValueCompatible(IValueNode value) { ArgumentNullException.ThrowIfNull(value); return true; diff --git a/src/HotChocolate/Spatial/src/Types/GeoJsonCoordinatesType.cs b/src/HotChocolate/Spatial/src/Types/GeoJsonCoordinatesType.cs index c6452462bee..905efa19c61 100644 --- a/src/HotChocolate/Spatial/src/Types/GeoJsonCoordinatesType.cs +++ b/src/HotChocolate/Spatial/src/Types/GeoJsonCoordinatesType.cs @@ -16,13 +16,13 @@ public GeoJsonCoordinatesType() : base(WellKnownTypeNames.CoordinatesTypeName) Description = Resources.GeoJsonCoordinatesScalar_Description; } - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) => GeoJsonCoordinatesSerializer.Default.IsInstanceOfType(this, valueSyntax); - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) => GeoJsonCoordinatesSerializer.Default.ParseLiteral(this, valueSyntax); - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) => GeoJsonCoordinatesSerializer.Default.ParseValue(this, value); public override IValueNode ParseResult(object? resultValue) @@ -31,6 +31,6 @@ public override IValueNode ParseResult(object? resultValue) public override bool TryDeserialize(object? serialized, out object? value) => GeoJsonCoordinatesSerializer.Default.TryDeserialize(this, serialized, out value); - public override bool TrySerialize(object? value, out object? serialized) + public override bool TryCoerceOutputValue(object? value, out object? serialized) => GeoJsonCoordinatesSerializer.Default.TrySerialize(this, value, out serialized); } diff --git a/src/HotChocolate/Spatial/src/Types/GeoJsonPositionType.cs b/src/HotChocolate/Spatial/src/Types/GeoJsonPositionType.cs index 0c87f7ef413..70ac6c1234f 100644 --- a/src/HotChocolate/Spatial/src/Types/GeoJsonPositionType.cs +++ b/src/HotChocolate/Spatial/src/Types/GeoJsonPositionType.cs @@ -21,13 +21,13 @@ public GeoJsonPositionType() : base(PositionTypeName) Description = Resources.GeoJsonPositionScalar_Description; } - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) => GeoJsonPositionSerializer.Default.IsInstanceOfType(this, valueSyntax); - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) => GeoJsonPositionSerializer.Default.ParseLiteral(this, valueSyntax); - public override IValueNode ParseValue(object? value) + public override IValueNode CoerceInputValue(object? value) => GeoJsonPositionSerializer.Default.ParseValue(this, value); public override IValueNode ParseResult(object? resultValue) @@ -36,6 +36,6 @@ public override IValueNode ParseResult(object? resultValue) public override bool TryDeserialize(object? serialized, out object? value) => GeoJsonPositionSerializer.Default.TryDeserialize(this, serialized, out value); - public override bool TrySerialize(object? value, out object? serialized) + public override bool TryCoerceOutputValue(object? value, out object? serialized) => GeoJsonPositionSerializer.Default.TrySerialize(this, value, out serialized); } diff --git a/src/HotChocolate/Spatial/src/Types/GeometryType.cs b/src/HotChocolate/Spatial/src/Types/GeometryType.cs index 624f6d7f6ec..cd8b2872b1c 100644 --- a/src/HotChocolate/Spatial/src/Types/GeometryType.cs +++ b/src/HotChocolate/Spatial/src/Types/GeometryType.cs @@ -26,19 +26,19 @@ public GeometryType() : base(GeometryTypeName) public override object? Deserialize(object? resultValue) => GeoJsonGeometrySerializer.Default.Deserialize(this, resultValue); - public override object? Serialize(object? runtimeValue) + public override object? CoerceOutputValue(object? runtimeValue) => GeoJsonGeometrySerializer.Default.Serialize(this, runtimeValue); - public override bool IsInstanceOfType(IValueNode valueSyntax) + public override bool IsValueCompatible(IValueNode valueSyntax) => GeoJsonGeometrySerializer.Default.IsInstanceOfType(this, valueSyntax); public override bool IsInstanceOfType(object? runtimeValue) => GeoJsonGeometrySerializer.Default.IsInstanceOfType(this, runtimeValue); - public override object? ParseLiteral(IValueNode valueSyntax) + public override object? CoerceInputLiteral(IValueNode valueSyntax) => GeoJsonGeometrySerializer.Default.ParseLiteral(this, valueSyntax); - public override IValueNode ParseValue(object? runtimeValue) + public override IValueNode CoerceInputValue(object? runtimeValue) => GeoJsonGeometrySerializer.Default.ParseValue(this, runtimeValue); public override IValueNode ParseResult(object? resultValue) diff --git a/src/HotChocolate/Spatial/src/Types/Serialization/IGeoJsonSerializer.cs b/src/HotChocolate/Spatial/src/Types/Serialization/IGeoJsonSerializer.cs index 0466396da3f..d681532bd2b 100644 --- a/src/HotChocolate/Spatial/src/Types/Serialization/IGeoJsonSerializer.cs +++ b/src/HotChocolate/Spatial/src/Types/Serialization/IGeoJsonSerializer.cs @@ -48,7 +48,7 @@ internal interface IGeoJsonSerializer /// /// Returns a result value representation of this type. /// - /// + /// /// Unable to serialize the given . /// object? Serialize(IType type, object? runtimeValue); @@ -126,7 +126,7 @@ bool TrySerialize( /// /// Returns a GraphQL value syntax representation of the . /// - /// + /// /// Unable to parse the given /// into a GraphQL value syntax representation of this type. /// @@ -144,7 +144,7 @@ bool TrySerialize( /// /// Returns a GraphQL value syntax representation of the . /// - /// + /// /// Unable to parse the given /// into a GraphQL value syntax representation of this type. /// diff --git a/src/HotChocolate/Spatial/src/Types/ThrowHelper.cs b/src/HotChocolate/Spatial/src/Types/ThrowHelper.cs index 156172e6a6a..434ddbfa1be 100644 --- a/src/HotChocolate/Spatial/src/Types/ThrowHelper.cs +++ b/src/HotChocolate/Spatial/src/Types/ThrowHelper.cs @@ -6,108 +6,108 @@ namespace HotChocolate.Types.Spatial; internal static class ThrowHelper { - public static SerializationException CoordinatesScalar_InvalidCoordinatesObject(IType type) + public static LeafCoercionException CoordinatesScalar_InvalidCoordinatesObject(IType type) => new(Resources.CoordinatesScalar_InvalidCoordinatesObject, type); - public static SerializationException CoordinatesScalar_CoordinatesCannotBeNull(IType type) + public static LeafCoercionException CoordinatesScalar_CoordinatesCannotBeNull(IType type) => new(Resources.CoordinatesScalar_CoordinatesCannotBeNull, type); - public static SerializationException PositionScalar_InvalidPositionObject(IType type) + public static LeafCoercionException PositionScalar_InvalidPositionObject(IType type) => new(Resources.PositionScalar_InvalidPositionObject, type); - public static SerializationException PositionScalar_CoordinatesCannotBeNull(IType type) + public static LeafCoercionException PositionScalar_CoordinatesCannotBeNull(IType type) => new(Resources.PositionScalar_CoordinatesCannotBeNull, type); public static ArgumentException Resolver_Type_InvalidGeometryType() => new(Resources.Resolver_Type_InvalidGeometryType); - public static SerializationException Serializer_CouldNotSerialize(IType type) + public static LeafCoercionException Serializer_CouldNotSerialize(IType type) => new(Resources.Serializer_CouldNotSerialize, type); - public static SerializationException Serializer_CouldNotDeserialize(IType type) + public static LeafCoercionException Serializer_CouldNotDeserialize(IType type) => new(Resources.Serializer_CouldNotDeserialize, type); - public static SerializationException Serializer_Parse_TypeIsInvalid(IType type) + public static LeafCoercionException Serializer_Parse_TypeIsInvalid(IType type) => new(Resources.Serializer_Parse_TypeIsInvalid, type); - public static SerializationException Serializer_Parse_ValueKindInvalid( + public static LeafCoercionException Serializer_Parse_ValueKindInvalid( IType type, SyntaxKind syntaxKind) => new("Resources.Serializer_Parse_TypeIsInvalid", type); - public static SerializationException Serializer_CoordinatesIsMissing(IType type) + public static LeafCoercionException Serializer_CoordinatesIsMissing(IType type) => new(Resources.Serializer_Parse_CoordinatesIsMissing, type); - public static SerializationException Serializer_TypeIsMissing(IType type) + public static LeafCoercionException Serializer_TypeIsMissing(IType type) => new(Resources.Serializer_Parse_TypeIsMissing, type); - public static SerializationException Serializer_Parse_CoordinatesIsInvalid(IType type) + public static LeafCoercionException Serializer_Parse_CoordinatesIsInvalid(IType type) => new(Resources.Serializer_Parse_CoordinatesIsInvalid, type); - public static SerializationException Serializer_CouldNotParseLiteral(IType type) + public static LeafCoercionException Serializer_CouldNotParseLiteral(IType type) => new(Resources.Serializer_CouldNotParseLiteral, type); - public static SerializationException Serializer_CouldNotParseValue(IType type) + public static LeafCoercionException Serializer_CouldNotParseValue(IType type) => new(Resources.Serializer_CouldNotParseValue, type); - public static SerializationException Geometry_Deserialize_TypeIsUnknown( + public static LeafCoercionException Geometry_Deserialize_TypeIsUnknown( IType type, string typeName) => new(string.Format(Resources.Geometry_Deserialize_TypeIsUnknown, typeName), type); - public static SerializationException Geometry_Deserialize_TypeIsMissing(IType type) + public static LeafCoercionException Geometry_Deserialize_TypeIsMissing(IType type) => new(Resources.Geometry_Deserialize_TypeIsMissing, type); - public static SerializationException Geometry_Serialize_InvalidGeometryType( + public static LeafCoercionException Geometry_Serialize_InvalidGeometryType( IType type, Type runtimeType) => new( string.Format(Resources.Geometry_Serialize_InvalidGeometryType, runtimeType.Name), type); - public static SerializationException Geometry_Parse_InvalidGeometryType( + public static LeafCoercionException Geometry_Parse_InvalidGeometryType( IType type, Type runtimeType) => new( string.Format(Resources.Geometry_Parse_InvalidGeometryType, runtimeType.Name), type); - public static SerializationException Geometry_Serialize_TypeIsUnknown( + public static LeafCoercionException Geometry_Serialize_TypeIsUnknown( IType type, string typeName) => new( string.Format(Resources.Geometry_Serialize_TypeIsUnknown, typeName), type); - public static SerializationException Geometry_Parse_TypeIsUnknown( + public static LeafCoercionException Geometry_Parse_TypeIsUnknown( IType type, string typeName) => new( string.Format(Resources.Geometry_Parse_TypeIsUnknown, typeName), type); - public static SerializationException Geometry_Serializer_NotFound( + public static LeafCoercionException Geometry_Serializer_NotFound( IType type, GeoJsonGeometryType geometryType) => new( string.Format(Resources.Geometry_Serializer_NotFound, geometryType), type); - public static SerializationException Geometry_Serializer_NotFound( + public static LeafCoercionException Geometry_Serializer_NotFound( IType type, string geometryType) => new( string.Format(Resources.Geometry_Serializer_NotFound, geometryType), type); - public static SerializationException Geometry_Parse_InvalidGeometryKind( + public static LeafCoercionException Geometry_Parse_InvalidGeometryKind( IType type, string typeName) => new( string.Format(Resources.Geometry_Parse_InvalidGeometryKind, typeName), type); - public static SerializationException Geometry_Parse_InvalidType(IType type) + public static LeafCoercionException Geometry_Parse_InvalidType(IType type) => new(Resources.Geometry_Parse_InvalidType, type); public static GraphQLException Transformation_UnknownCRS(int srid) => @@ -130,7 +130,7 @@ public static GraphQLException Transformation_CoordinateMNotSupported() => .SetCode(ErrorCodes.Spatial.CoordinateMNotSupported) .Build()); - public static SerializationException Serializer_OperationIsNotSupported( + public static LeafCoercionException Serializer_OperationIsNotSupported( IType type, IGeoJsonSerializer serializer, string method) => diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringInputTests.cs index 28974b8f354..fb8e5f20a9a 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringInputTests.cs @@ -107,7 +107,7 @@ public void ParseLiteral_LineString_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -120,7 +120,7 @@ public void ParseLiteral_LineString_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("coordinates", _linestring), @@ -137,7 +137,7 @@ public void ParseLiteral_LineString_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode( @@ -156,7 +156,7 @@ public void ParseLiteral_LineString_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode("POLYGON")), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringSerializerTests.cs index 0ad354333e5..defc9c00b8b 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonLineStringSerializerTests.cs @@ -65,7 +65,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -170,7 +170,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -212,7 +212,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -229,7 +229,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -309,7 +309,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -353,7 +353,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -408,7 +408,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -470,7 +470,7 @@ public void Deserialize_Should_Fail_When_TypeNameIsMissing(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseResult(serialized, type)); } @@ -490,7 +490,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseResult(serialized, type)); } @@ -512,7 +512,7 @@ public void LineString_IsCoordinateValid_Should_Fail_When_LessThanTwoPoint(strin // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(valueNode, type)); } diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringInputTests.cs index 4152ed8661c..e5b670ae97e 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringInputTests.cs @@ -114,7 +114,7 @@ public void ParseLiteral_MultiLineString_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -127,7 +127,7 @@ public void ParseLiteral_MultiLineString_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("coordinates", _multiLinestring), @@ -144,7 +144,7 @@ public void ParseLiteral_MultiLineString_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode( @@ -163,7 +163,7 @@ public void ParseLiteral_MultiLineString_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Polygon)), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringSerializerTests.cs index d7878a18a2d..64d59708d7b 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiLineStringSerializerTests.cs @@ -117,7 +117,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -222,7 +222,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -264,7 +264,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -281,7 +281,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -361,7 +361,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -420,7 +420,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -475,7 +475,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -540,7 +540,7 @@ public void Deserialize_Should_Fail_WhenTypeNameIsMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -560,7 +560,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -581,7 +581,7 @@ public void MultiLine_IsCoordinateValid_Should_Fail_When_Point(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } private static Schema CreateSchema() diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointInputTests.cs index 3ab1d63cd81..2500d81a712 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointInputTests.cs @@ -99,7 +99,7 @@ public void ParseLiteral_MultiPoint_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -112,7 +112,7 @@ public void ParseLiteral_MultiPoint_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("missingType", new StringValueNode("ignored")), @@ -129,7 +129,7 @@ public void ParseLiteral_MultiPoint_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode("MultiPoint")), @@ -146,7 +146,7 @@ public void ParseLiteral_MultiPoint_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Point)), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointSerializerTests.cs index 80cf73ca564..06db80d6f20 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPointSerializerTests.cs @@ -74,7 +74,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -179,7 +179,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -221,7 +221,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -238,7 +238,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -318,7 +318,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -362,7 +362,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -421,7 +421,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -483,7 +483,7 @@ public void Deserialize_Should_Fail_WhentypeNameIsMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -502,7 +502,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -522,7 +522,7 @@ public void MultiPoint_IsCoordinateValid_Should_Fail_When_Point(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } private Schema CreateSchema() => SchemaBuilder.New() diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonInputTests.cs index 41ed24e3ad4..353815a51ca 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonInputTests.cs @@ -123,7 +123,7 @@ public void ParseLiteral_MultiPolygon_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -136,7 +136,7 @@ public void ParseLiteral_MultiPolygon_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("coordinates", _multiPolygon), @@ -153,7 +153,7 @@ public void ParseLiteral_MultiPolygon_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode("MultiPolygon")), @@ -170,7 +170,7 @@ public void ParseLiteral_MultiPolygon_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Point)), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonSerializerTests.cs index 244270dec06..13c25a8b1c2 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonMultiPolygonSerializerTests.cs @@ -136,7 +136,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -241,7 +241,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -282,7 +282,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) var valueNode = new ObjectValueNode(coordField, crsField); // act - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(valueNode, type)); } @@ -299,7 +299,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) var valueNode = new ObjectValueNode(typeField, crsField); // act - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(valueNode, type)); } @@ -380,7 +380,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -439,7 +439,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -494,7 +494,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -556,7 +556,7 @@ public void Deserialize_Should_Fail_WhenTypeNameIsMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -575,7 +575,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -593,7 +593,7 @@ public void MultiPolygon_IsCoordinateValid_Should_Fail_When_Point(string typeNam // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } private Schema CreateSchema() => SchemaBuilder.New() diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointInputTests.cs index 72cc94f379b..d2f5a9b14f7 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointInputTests.cs @@ -42,7 +42,7 @@ public void ParseLiteral_Point_With_Valid_Coordinates_Scalar() var type = CreateScalarType(); // act - var result = type.ParseLiteral( + var result = type.CoerceInputLiteral( new ObjectValueNode( new ObjectFieldNode( "type", @@ -121,7 +121,7 @@ public void ParseLiteral_Point_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -134,7 +134,7 @@ public void ParseLiteral_Point_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("missingType", new StringValueNode("ignored")), @@ -151,7 +151,7 @@ public void ParseLiteral_Point_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Point)), @@ -168,7 +168,7 @@ public void ParseLiteral_Point_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Polygon)), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointSerializerTests.cs index c6c84bb6f47..200840b27bb 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPointSerializerTests.cs @@ -67,7 +67,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -156,7 +156,7 @@ public void ParseLiteral_Should_Pass_When_NullValueNode(string typeName) // act // assert - Assert.Null(type.ParseLiteral(NullValueNode.Default)); + Assert.Null(type.CoerceInputLiteral(NullValueNode.Default)); } [Theory] @@ -170,7 +170,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -212,7 +212,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -229,7 +229,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -309,7 +309,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -368,7 +368,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -427,7 +427,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -489,7 +489,7 @@ public void Deserialize_Should_Fail_WhenTypeNameIsMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -508,7 +508,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -529,7 +529,7 @@ public void Point_IsCoordinateValid_Should_Fail_When_MultiArray(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } private Schema CreateSchema() => SchemaBuilder.New() diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonInputTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonInputTests.cs index 90c63689c3e..13d82d28498 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonInputTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonInputTests.cs @@ -108,7 +108,7 @@ public void ParseLiteral_Polygon_Is_Not_ObjectType_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -121,7 +121,7 @@ public void ParseLiteral_Polygon_With_Missing_Fields_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("coordinates", _polygon), @@ -138,7 +138,7 @@ public void ParseLiteral_Polygon_With_Empty_Coordinates_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Polygon)), @@ -155,7 +155,7 @@ public void ParseLiteral_Polygon_With_Wrong_Geometry_Type_Throws() // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral( new ObjectValueNode( new ObjectFieldNode("type", new EnumValueNode(GeoJsonGeometryType.Point)), diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonSerializerTests.cs index 5e0a951a520..4e98e1bf73c 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPolygonSerializerTests.cs @@ -115,7 +115,7 @@ public void Serialize_Should_Throw_When_InvalidObjectShouldThrow(string typeName // act // assert - Assert.Throws(() => type.Serialize("")); + Assert.Throws(() => type.Serialize("")); } [Theory] @@ -222,7 +222,7 @@ public void ParseLiteral_Should_Throw_When_NotObjectValueNode(string typeName) // act // assert - Assert.Throws( + Assert.Throws( () => inputParser.ParseLiteral(new ListValueNode(), type)); } @@ -264,7 +264,7 @@ public void ParseLiteral_Should_Throw_When_NoGeometryType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -281,7 +281,7 @@ public void ParseLiteral_Should_Throw_When_NoCoordinates(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } [Theory] @@ -362,7 +362,7 @@ public void ParseResult_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatResult("", type)); + Assert.Throws(() => inputFormatter.FormatResult("", type)); } [Theory] @@ -421,7 +421,7 @@ public void ParseValue_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputFormatter.FormatValue("", type)); + Assert.Throws(() => inputFormatter.FormatValue("", type)); } [Theory] @@ -480,7 +480,7 @@ public void Deserialize_Should_Throw_When_InvalidType(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult("", type)); + Assert.Throws(() => inputParser.ParseResult("", type)); } [Theory] @@ -542,7 +542,7 @@ public void Deserialize_Should_Fail_WhentypeNameIsMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -561,7 +561,7 @@ public void Deserialize_Should_When_CoordinatesAreMissing(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseResult(serialized, type)); + Assert.Throws(() => inputParser.ParseResult(serialized, type)); } [Theory] @@ -581,7 +581,7 @@ public void Polygon_IsCoordinateValid_Should_Fail_When_Point(string typeName) // act // assert - Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); + Assert.Throws(() => inputParser.ParseLiteral(valueNode, type)); } private Schema CreateSchema() => SchemaBuilder.New() diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPositionScalarTest.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPositionScalarTest.cs index 0980816d916..1ebd3055694 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPositionScalarTest.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonPositionScalarTest.cs @@ -15,7 +15,7 @@ public void IsInstanceOfType_Valid2ElementCoordinate_True() new FloatValueNode(1.2)); // act - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); // assert Assert.True(result); @@ -32,7 +32,7 @@ public void IsInstanceOfType_Valid3ElementCoordinate_True() new FloatValueNode(3.2)); // act - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); // assert Assert.True(result); @@ -46,7 +46,7 @@ public void IsInstanceOfType_NullType_True() var coordinate = NullValueNode.Default; // act - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); // assert Assert.True(result); @@ -62,7 +62,7 @@ public void IsInstanceOfType_Invalid2ElementCoordinate_False() new FloatValueNode(1.2)); // act - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); // assert Assert.False(result); @@ -79,7 +79,7 @@ public void IsInstanceOfType_Invalid3ElementCoordinate_False() new StringValueNode("2")); // act - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); // assert Assert.False(result); @@ -96,7 +96,7 @@ public void IsInstanceOfType_List2ElementCoordinate_False() new FloatValueNode(1.2))); // act - var result = type.IsInstanceOfType(coordinate); + var result = type.IsValueCompatible(coordinate); // assert Assert.False(result); @@ -116,7 +116,7 @@ public void IsInstanceOfType_2ListElementCoordinate_False() new FloatValueNode(1.2))); // act - var result = type.IsInstanceOfType(coordinate); + var result = type.IsValueCompatible(coordinate); // assert Assert.False(result); @@ -132,7 +132,7 @@ public void IsInstanceOfType_Invalid4ElementCoordinate_False() new IntValueNode(3), new IntValueNode(4)); - bool? result = type.IsInstanceOfType(coordinate); + bool? result = type.IsValueCompatible(coordinate); Assert.False(result); } @@ -143,7 +143,7 @@ public void ParseLiteral_Null_Throws() var type = new GeoJsonPositionType(); IValueNode? coordinate = null; - Assert.Throws(() => type.ParseLiteral(coordinate!)); + Assert.Throws(() => type.CoerceInputLiteral(coordinate!)); } [Fact] @@ -152,7 +152,7 @@ public void ParseLiteral_NullType_Null() var type = new GeoJsonPositionType(); var coordinate = NullValueNode.Default; - var result = type.ParseLiteral(coordinate); + var result = type.CoerceInputLiteral(coordinate); Assert.Null(result); } @@ -166,7 +166,7 @@ public void ParseLiteral_With_2Valid_Coordinates() new IntValueNode(2) ); - var result = type.ParseLiteral(coordinate); + var result = type.CoerceInputLiteral(coordinate); Assert.Equal(1.0, Assert.IsType(result).X); Assert.Equal(2, Assert.IsType(result).Y); @@ -182,7 +182,7 @@ public void ParseLiteral_With_3Valid_Coordinates() new IntValueNode(100) ); - var result = type.ParseLiteral(coordinate); + var result = type.CoerceInputLiteral(coordinate); Assert.Equal(1.0, Assert.IsType(result).X); Assert.Equal(2.2, Assert.IsType(result).Y); @@ -198,7 +198,7 @@ public void ParseLiteral_With_2Invalid_Coordinates_Throws() new StringValueNode("2.2") ); - Assert.Throws(() => type.ParseLiteral(coordinate)); + Assert.Throws(() => type.CoerceInputLiteral(coordinate)); } [Fact] @@ -211,7 +211,7 @@ public void ParseLiteral_With_3Invalid_Coordinates_Throws() new StringValueNode("2.2") ); - Assert.Throws(() => type.ParseLiteral(coordinate)); + Assert.Throws(() => type.CoerceInputLiteral(coordinate)); } [Fact] @@ -220,7 +220,7 @@ public void ParseLiteral_With_Invalid_Coordinates_Throws() var type = new GeoJsonPositionType(); var coordinate = new StringValueNode("2.2"); - Assert.Throws(() => type.ParseLiteral(coordinate)); + Assert.Throws(() => type.CoerceInputLiteral(coordinate)); } [Fact] @@ -229,7 +229,7 @@ public void ParseValue_With_Noncoordinate_Throws() var type = new GeoJsonPositionType(); const string item = "this is not a coordinate"; - Assert.Throws(() => type.ParseValue(item)); + Assert.Throws(() => type.CoerceInputValue(item)); } [Fact] @@ -419,7 +419,7 @@ public void TrySerialize_With_Invalid_Object() var type = new GeoJsonPositionType(); const string input = "not a coordinate"; - var result = type.TrySerialize(input, out var value); + var result = type.TryCoerceOutputValue(input, out var value); Assert.False(result); Assert.Null(value); @@ -431,7 +431,7 @@ public void TrySerialize_With_Valid_2dCoordinate() var type = new GeoJsonPositionType(); var input = new Coordinate(1, 2); - var result = type.TrySerialize(input, out var value); + var result = type.TryCoerceOutputValue(input, out var value); Assert.True(result); Assert.Equal(2, Assert.IsType(value).Length); @@ -444,7 +444,7 @@ public void TrySerialize_With_Valid_3dCoordinate() var type = new GeoJsonPositionType(); var input = new CoordinateZ(1, 2, 100); - var result = type.TrySerialize(input, out var value); + var result = type.TryCoerceOutputValue(input, out var value); Assert.True(result); Assert.Equal(3, Assert.IsType(value).Length); @@ -457,7 +457,7 @@ public void TrySerialize_With_Nan_3dCoordinate() var type = new GeoJsonPositionType(); var input = new CoordinateZ(1, 2, double.NaN); - var result = type.TrySerialize(input, out var value); + var result = type.TryCoerceOutputValue(input, out var value); Assert.True(result); Assert.Equal(2, Assert.IsType(value).Length); diff --git a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonTypeSerializerTests.cs b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonTypeSerializerTests.cs index 3e01b50b168..6ef69a02e33 100644 --- a/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonTypeSerializerTests.cs +++ b/src/HotChocolate/Spatial/test/Types.Tests/GeoJsonTypeSerializerTests.cs @@ -232,7 +232,7 @@ public void ParseValue_Should_Throw_OnInvalidValue() // act // assert - Assert.Throws( + Assert.Throws( () => serializer.ParseValue(type.Object, "")); } @@ -324,7 +324,7 @@ public void ParseResult_Should_Throw_OnInvalidValue() // act // assert - Assert.Throws( + Assert.Throws( () => serializer.ParseResult(type.Object, "")); }