Fix batch resolver in paging context#9660
Open
michaelstaib wants to merge 5 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes batch resolver behavior when paging and node/lookup resolvers are involved, ensuring batched execution remains correct when selections use different paging arguments (and supporting batch pipelines for node resolvers). It also extends the execution scheduler to reliably dispatch root-level batch entries and updates the source generator/analyzers to correctly recognize batch connection resolvers and batch lookup patterns.
Changes:
- Add batch-pipeline support to node resolvers and extend type interception to capture batch resolver pipelines.
- Introduce batch middleware + partitioning for paging to correctly handle per-selection paging arguments in batched resolvers.
- Ensure root batch entries are dispatched even when there are no non-batch root resolver tasks, and update analyzers/source generation to support new batch/connection/lookup combinations.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/HotChocolate/Data/test/Data.Tests/Pagination/PagingArgumentsParameterExpressionBuilderTests.cs | Adds coverage for paging argument mapping/partitioning in batch resolvers (including PageConnection). |
| src/HotChocolate/Core/test/Types.Tests/Types/Relay/NodeResolverTests.cs | Adds tests for node resolver behavior when the query field uses a batch resolver. |
| src/HotChocolate/Core/test/Types.Tests/Types/Relay/snapshots/NodeResolverTests.NodeResolver_On_Query_Field_With_BatchResolver_Schema.snap | New snapshot for schema output of the new node/batch resolver test. |
| src/HotChocolate/Core/test/Types.Tests/Types/Relay/snapshots/NodeResolverTests.NodeResolver_On_Query_Field_With_BatchResolver_Fetch_Through_Node_Field.snap | New snapshot for execution output of node field resolving through a batch resolver. |
| src/HotChocolate/Core/test/Types.Tests/Types/Composite/LookupTests.cs | Adds schema + execution coverage for [Lookup] combined with [BatchResolver]. |
| src/HotChocolate/Core/test/Types.Tests/Execution/BatchResolverTests.cs | Adds regression test ensuring aliased field arguments are properly batched. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/PagingTests.cs | Adds generator snapshot coverage for batch resolver returning PageConnection<T> with PagingArguments. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/ObjectTypeTests.cs | Adds generator snapshot coverage for [Lookup] + [BatchResolver]. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/LookupReturnsNonNullableTypeAnalyzerTests.cs | Adds analyzer snapshot coverage: batch lookup returning nullable list should not warn. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/LookupReturnsListTypeAnalyzerTests.cs | Adds analyzer snapshot coverage: batch lookup list return should not error. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/PagingTests.GenerateSource_BatchResolver_PageConnection_MatchesSnapshot.md | New generated-source snapshot for batch paging + connection generation. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/ObjectTypeTests.BatchResolver_With_Lookup_MatchesSnapshot.md | New generated-source snapshot for batch lookup generation. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/LookupReturnsNonNullableTypeAnalyzerTests.Method_BatchResolverNullableListReturn_NoWarning.md | New snapshot asserting no warning for batch lookup nullable list return. |
| src/HotChocolate/Core/test/Types.Analyzers.Tests/snapshots/LookupReturnsListTypeAnalyzerTests.Method_BatchResolverListReturn_NoError.md | New snapshot asserting no error for batch lookup list return. |
| src/HotChocolate/Core/src/Types/Types/Relay/NodeResolverTypeInterceptor.cs | Captures batch resolver pipeline when a query field doubles as a node resolver. |
| src/HotChocolate/Core/src/Types/Types/Relay/NodeResolverInfo.cs | Extends node resolver metadata to include an optional batch pipeline. |
| src/HotChocolate/Core/src/Types/Types/Relay/NodeFieldResolvers.cs | Executes batch pipeline when available for node resolution (single + nodes field). |
| src/HotChocolate/Core/src/Types/Types/Pagination/PagingHelper.cs | Adds batch paging middleware and introduces paging-based batch partitioning key. |
| src/HotChocolate/Core/src/Types/Types/ObjectType.Initialization.cs | Ensures batch partition key resolver is propagated from interface fields. |
| src/HotChocolate/Core/src/Types/Types/ObjectField.cs | Carries batch partition key resolver into the executable ObjectField instance. |
| src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/ObjectFieldConfiguration.cs | Stores/merges/copies the batch partition key resolver in field configuration. |
| src/HotChocolate/Core/src/Types/Types/Descriptors/Configurations/InterfaceFieldConfiguration.cs | Stores/merges/copies the batch partition key resolver for interface fields. |
| src/HotChocolate/Core/src/Types/Resolvers/BatchPartitionKeyResolver.cs | Introduces internal delegate type for batch partition key resolution. |
| src/HotChocolate/Core/src/Types/Execution/Processing/WorkScheduler.Execute.cs | Flushes pending root batch entries before entering the scheduler work loop. |
| src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/ResolverTaskFactory.cs | Avoids dummy root task scheduling when only batch entries exist; avoids registering empty spans. |
| src/HotChocolate/Core/src/Types/Execution/Processing/Tasks/BatchResolverTask.cs | Executes batch pipelines partitioned by a per-context partition key when configured. |
| src/HotChocolate/Core/src/Types/Execution/Processing/QueryExecutor.cs | Updates scheduler entry point name (ExecuteAsync1 → ExecuteAsync). |
| src/HotChocolate/Core/src/Types.CursorPagination/Extensions/UseConnectionAttribute.cs | Adds batch paging validation middleware and sets paging batch partition key resolver. |
| src/HotChocolate/Core/src/Types.Analyzers/Models/Resolver.cs | Tracks whether a resolver is a connection resolver independent of resolver kind (incl. batch). |
| src/HotChocolate/Core/src/Types.Analyzers/LookupReturnsNonNullableTypeAnalyzer.cs | Skips non-nullability lookup checks for batch lookup resolvers. |
| src/HotChocolate/Core/src/Types.Analyzers/LookupReturnsListTypeAnalyzer.cs | Skips list-type lookup checks for batch lookup resolvers. |
| src/HotChocolate/Core/src/Types.Analyzers/Inspectors/ObjectTypeInspector.cs | Detects batch connection resolvers and marks them for connection generation/flags. |
| src/HotChocolate/Core/src/Types.Analyzers/Inspectors/ConnectionTypeTransformer.cs | Uses IsConnectionResolver and supports batch resolver return shapes for connection type inference. |
| src/HotChocolate/Core/src/Types.Analyzers/FileBuilders/TypeFileBuilderBase.cs | Updates generator output for connection resolvers and improves batch parameter binding (incl. paging args/flags). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+170
to
+193
| internal static ulong GetPagingBatchPartitionKey(IMiddlewareContext context) | ||
| { | ||
| var options = GetPagingOptions(context.Schema, context.Selection.Field); | ||
| var first = context.ArgumentValue<int?>(FirstArgumentName); | ||
| var after = context.ArgumentValue<string?>(AfterArgumentName); | ||
| int? last = null; | ||
| string? before = null; | ||
|
|
||
| if (options.AllowBackwardPagination ?? PagingDefaults.AllowBackwardPagination) | ||
| { | ||
| last = context.ArgumentValue<int?>(LastArgumentName); | ||
| before = context.ArgumentValue<string?>(BeforeArgumentName); | ||
| } | ||
|
|
||
| var flags = ConnectionFlagsHelper.GetConnectionFlags(context); | ||
|
|
||
| if (first is null | ||
| && after is null | ||
| && last is null | ||
| && before is null | ||
| && flags is ConnectionFlags.None) | ||
| { | ||
| return 0; | ||
| } |
Generalize the engine's batch partitioner from a single delegate to an ImmutableArray<BatchPartitionKeyResolver> and recurse through the levels in BatchResolverTask. Each leaf partition is dispatched to the user's batch pipeline once, preserving the all-same-key fast path at every level. Carry the inner partition key on NodeResolverInfo so the upcoming node-level batch resolver can honor a node-resolver source field's partitioner.
- node field uses BatchResolver + chained partitioners (typeName outer, user partitioner inner) so sibling node calls coalesce per node type and per inner partition. - nodes field uses BatchResolver without partitioners; the resolver expands ids into per-id child contexts, groups by type, and sub-partitions by the type's inner BatchPartitionKey before invoking BatchPipeline. - ResolveNodeBatchAsync / ResolveNodesBatchAsync replace the per-context middleware shims.
# Conflicts: # .gitignore # src/HotChocolate/Core/src/Types.Analyzers/Inspectors/ObjectTypeInspector.cs # src/HotChocolate/Core/src/Types.Analyzers/Models/Resolver.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.