Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
87219a4
Aligned to GraphQL Java Field Merging Rule
michaelstaib Apr 7, 2025
5b9e1c7
edits
michaelstaib Apr 7, 2025
b321d9a
edits
michaelstaib Apr 7, 2025
3d6b245
edits
michaelstaib Apr 8, 2025
0d2e783
edits
michaelstaib Apr 8, 2025
af64267
Merge remote-tracking branch 'origin/main' into mst/field-merging-v2
tobias-tengler Jan 14, 2026
b09ed93
Update snapshots
tobias-tengler Jan 15, 2026
dea41eb
Merge remote-tracking branch 'origin/main' into mst/field-merging-v2
tobias-tengler Jan 17, 2026
fd05ad6
Properly format error snapshots
tobias-tengler Jan 17, 2026
c1fff32
Fix LeafFieldSelectionRuleTests
tobias-tengler Jan 17, 2026
2e2cf86
Fix build
tobias-tengler Jan 17, 2026
0e45ac9
Fix more tests
tobias-tengler Jan 17, 2026
9598c06
Treat object fields as an unordered set
tobias-tengler Jan 17, 2026
18276d1
Update GetHashCode for ObjectValueNode
tobias-tengler Jan 17, 2026
a0a31bc
Fix more tests
tobias-tengler Jan 17, 2026
ad181bb
Fix more tests
tobias-tengler Jan 17, 2026
8d6d9af
Update specifiedBy to latest spec version
tobias-tengler Jan 17, 2026
3a61a57
Update more snapshots
tobias-tengler Jan 17, 2026
7ef4994
Fix most of the remaining errors
tobias-tengler Jan 18, 2026
c031c97
Fix more tests
tobias-tengler Jan 18, 2026
804480a
Limit number of locations per error
tobias-tengler Jan 18, 2026
31c53f8
Cleanup
tobias-tengler Jan 18, 2026
176fc32
Cleanup
tobias-tengler Jan 19, 2026
5c8401e
Merge remote-tracking branch 'origin/main' into mst/field-merging-v2
tobias-tengler Jan 19, 2026
52e2f76
Cleanup 2
tobias-tengler Jan 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ protected override IEnumerable<ISnapshotValueFormatter> CreateFormatters()
yield return SnapshotValueFormatters.OperationResult;
yield return SnapshotValueFormatters.Schema;
yield return SnapshotValueFormatters.SchemaError;
yield return SnapshotValueFormatters.Error;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Buffers;
using System.Text.Json;
using CookieCrumble.Formatters;
using HotChocolate;
using HotChocolate.Execution;

namespace CookieCrumble.HotChocolate.Formatters;

internal sealed class ErrorSnapshotValueFormatter()
: SnapshotValueFormatter<IError>("json")
{
protected override void Format(IBufferWriter<byte> snapshot, IError value)
{
var jsonWriter = new Utf8JsonWriter(snapshot, new JsonWriterOptions { Indented = true });
JsonValueFormatter.WriteError(jsonWriter, value, new JsonSerializerOptions { WriteIndented = true }, default);
jsonWriter.Flush();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ public static class SnapshotValueFormatters

public static ISnapshotValueFormatter SchemaError { get; } =
new SchemaErrorSnapshotValueFormatter();

public static ISnapshotValueFormatter Error { get; }
= new ErrorSnapshotValueFormatter();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
"column": 5
}
],
"path": [
"onReview"
],
"extensions": {
"type": "Review",
"field": "_stars",
"responseName": "_stars",
"specifiedBy": "https://spec.graphql.org/October2021/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-Field-Selections"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@
"column": 46
}
],
"path": [
"onReview"
],
"extensions": {
"type": "Review",
"field": "_stars",
"responseName": "_stars",
"specifiedBy": "https://spec.graphql.org/October2021/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-Field-Selections"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
],
"extensions": {
"specifiedBy": "https://spec.graphql.org/October2021/#sec-All-Variables-Used"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-All-Variables-Used"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
],
"extensions": {
"specifiedBy": "https://spec.graphql.org/October2021/#sec-All-Variable-Uses-Defined"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-All-Variable-Uses-Defined"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
],
"extensions": {
"specifiedBy": "https://spec.graphql.org/October2021/#sec-All-Variables-Used"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-All-Variables-Used"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}
],
"extensions": {
"specifiedBy": "https://spec.graphql.org/October2021/#sec-All-Variable-Uses-Defined"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-All-Variable-Uses-Defined"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,11 @@
"column": 46
}
],
"path": [
"onReview"
],
"extensions": {
"type": "Review",
"field": "____",
"responseName": "____",
"specifiedBy": "https://spec.graphql.org/October2021/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types"
"specifiedBy": "https://spec.graphql.org/September2025/#sec-Field-Selections"
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,14 @@ public static IRequestExecutorBuilder DisableIntrospection(
}

/// <summary>
/// Sets the max allowed document validation errors.
/// Sets the maximum allowed document validation errors.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="maxAllowedValidationErrors"></param>
/// <param name="maxAllowedValidationErrors">
/// The maximum number of validation errors.
/// </param>
/// <returns>
/// Returns an <see cref="IRequestExecutorBuilder"/> that can be used to chain
/// configuration.
Expand All @@ -228,6 +230,35 @@ public static IRequestExecutorBuilder SetMaxAllowedValidationErrors(
return builder;
}

/// <summary>
/// Sets the maximum allowed locations per validation error.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="maxAllowedLocationsPerError">
/// The maximum number of locations per validation error.
/// </param>
/// <returns>
/// Returns an <see cref="IRequestExecutorBuilder"/> that can be used to chain
/// configuration.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="builder"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder SetMaxLocationsPeralidationError(
this IRequestExecutorBuilder builder,
int maxAllowedLocationsPerError)
{
ArgumentNullException.ThrowIfNull(builder);

ConfigureValidation(
builder,
(_, b) => b.ModifyOptions(o => o.MaxLocationsPerError = maxAllowedLocationsPerError));

return builder;
}

/// <summary>
/// Sets the max allowed depth for introspection queries.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public async ValueTask InvokeAsync(IMiddlewareContext context)
{
errors[i] = ErrorBuilder
.FromError(ex.Errors[i])
.AddLocations(context.Selection.SyntaxNodes)
.SetPath(context.Path)
.Build();
}
Expand Down
2 changes: 0 additions & 2 deletions src/HotChocolate/Core/src/Types/Utilities/ErrorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ public static IError Relay_NoNodeResolver(string typeName, Path path, IReadOnlyL
=> ErrorBuilder.New()
.SetMessage(ErrorHelper_Relay_NoNodeResolver, typeName)
.SetPath(path)
.AddLocations(fieldNodes)
.Build();

public static ISchemaError NodeResolver_MustHaveExactlyOneIdArg(
Expand Down Expand Up @@ -503,7 +502,6 @@ public static IError FetchedToManyNodesAtOnce(
ErrorHelper_FetchedToManyNodesAtOnce,
maxAllowedNodes,
requestNodes)
.AddLocations(fieldNodes)
.SetPath(path)
.SetCode(ErrorCodes.Execution.FetchedToManyNodesAtOnce)
.Build();
Expand Down
10 changes: 8 additions & 2 deletions src/HotChocolate/Core/src/Validation/DocumentValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class DocumentValidator
private readonly IDocumentValidatorRule[] _allRules;
private readonly IDocumentValidatorRule[] _nonCacheableRules;
private readonly int _maxAllowedErrors;
private readonly int _maxLocationsPerError;

/// <summary>
/// Initializes a new instance of <see cref="DocumentValidator"/>.
Expand All @@ -30,10 +31,14 @@ public sealed class DocumentValidator
/// <param name="maxAllowedErrors">
/// The maximum number of errors that are allowed to be reported.
/// </param>
/// <param name="maxLocationsPerError">
/// The maximum number of locations that will be added to a validation error.
/// </param>
internal DocumentValidator(
ObjectPool<DocumentValidatorContext> contextPool,
IDocumentValidatorRule[] rules,
int maxAllowedErrors)
int maxAllowedErrors,
int maxLocationsPerError)
{
ArgumentNullException.ThrowIfNull(rules);
ArgumentNullException.ThrowIfNull(contextPool);
Expand All @@ -43,6 +48,7 @@ internal DocumentValidator(
_allRules = rules;
_nonCacheableRules = [.. rules.Where(rule => !rule.IsCacheable)];
_maxAllowedErrors = maxAllowedErrors > 0 ? maxAllowedErrors : 1;
_maxLocationsPerError = maxLocationsPerError > 0 ? maxLocationsPerError : 1;
}

/// <summary>
Expand Down Expand Up @@ -152,7 +158,7 @@ private DocumentValidatorContext RentContext(
IFeatureCollection? features)
{
var context = _contextPool.Get();
context.Initialize(schema, documentId, document, _maxAllowedErrors, features);
context.Initialize(schema, documentId, document, _maxAllowedErrors, _maxLocationsPerError, features);
return context;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ public DocumentValidator Build()

var contextPool = _services.GetService<ObjectPool<DocumentValidatorContext>>();
contextPool ??= new DocumentValidatorContextPool();
return new DocumentValidator(contextPool, [.. rules], _options.MaxAllowedErrors);
return new DocumentValidator(
contextPool,
[.. rules],
_options.MaxAllowedErrors,
_options.MaxLocationsPerError);
}

private static T CreateInstance<T>(
Expand Down
15 changes: 15 additions & 0 deletions src/HotChocolate/Core/src/Validation/DocumentValidatorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public sealed class DocumentValidatorContext : IFeatureProvider
private readonly PooledFeatureCollection _features;
private ISchemaDefinition? _schema;
private int _maxAllowedErrors;
private int _maxLocationsPerError;

/// <summary>
/// Initializes a new instance of <see cref="DocumentValidatorContext"/>.
Expand Down Expand Up @@ -109,6 +110,11 @@ public ISchemaDefinition Schema
/// </summary>
public Dictionary<string, object?> ContextData { get; } = [];

/// <summary>
/// A set that stores the visited fragments (type-name, spread-name).
/// </summary>
public HashSet<(string, string)> VisitedFragments { get; } = [];

/// <summary>
/// A list to track validation errors that occurred during the visitation.
/// </summary>
Expand All @@ -127,11 +133,17 @@ public ISchemaDefinition Schema
/// </summary>
public bool FatalErrorDetected { get; set; }

/// <summary>
/// The maximum number of locations per error.
/// </summary>
public int MaxLocationsPerError => _maxLocationsPerError;

public void Initialize(
ISchemaDefinition schema,
OperationDocumentId documentId,
DocumentNode document,
int maxAllowedErrors,
int maxLocationsPerError,
IFeatureCollection? features)
{
ArgumentNullException.ThrowIfNull(schema);
Expand All @@ -142,6 +154,7 @@ public void Initialize(
DocumentId = documentId;
Document = document;
_maxAllowedErrors = maxAllowedErrors;
_maxLocationsPerError = maxLocationsPerError;

_features.Initialize(features);

Expand Down Expand Up @@ -187,6 +200,7 @@ internal void Reset()
OutputFields.Clear();
Fields.Clear();
InputFields.Clear();
VisitedFragments.Clear();

// we just make sure that all features are reset but we do not want
// to fully reset the feature collection.
Expand Down Expand Up @@ -221,6 +235,7 @@ internal void Clear()
Fields.Clear();
InputFields.Clear();
ContextData.Clear();
VisitedFragments.Clear();
_errors.Clear();
}

Expand Down
Loading
Loading