Repository navigation
[Fusion] Build the introspection schema programmatically - #10174
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces the Fusion introspection schema’s SDL-text parsing approach with a programmatic builder that constructs DocumentNode definitions from syntax nodes, caching immutable documents by an explicit “shape” key derived from IFusionSchemaOptions. It also folds the former semantic introspection SDL into the same builder and removes the redundant SemanticIntrospectionSchema class.
Changes:
- Build the introspection schema programmatically (one method per introspection type) and cache per option “shape”.
- Integrate semantic introspection type definitions into the same builder and remove
SemanticIntrospectionSchema. - Update
CompositeSchemaBuilderto consume the unifiedIntrospectionSchema.GetDocument(options)output.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/SemanticIntrospectionSchema.cs | Removed redundant SDL-based semantic introspection document source (now built by IntrospectionSchema). |
| src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/IntrospectionSchema.cs | Introduces the programmatic introspection schema builder with per-shape caching and conditional fields/args. |
| src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/CompositeSchemaBuilder.cs | Switches introspection definition sourcing to the new unified cached document. |
Suppressed comments (4)
src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/IntrospectionSchema.cs:166
When(optIn, Field(...))still constructs theField(...)node and allocates theparamsarray even whenoptInis false. Prefer a conditional collection expression so the field is only created for the opt-in shape.
.. When(optIn, Field("requiresOptIn", "[String!]"))
src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/IntrospectionSchema.cs:225
When(optIn, s_includeOptIn)allocates aparamsarray even whenoptInis false. A simple conditional avoids that extra allocation and keeps the opt-in argument out of the base shape path.
private static InputValueDefinitionNode[] FilterArguments(bool optIn)
=> [s_includeDeprecated, .. When(optIn, s_includeOptIn)];
src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/IntrospectionSchema.cs:141
When(optIn, Field(...))still constructs theField(...)node and allocates theparamsarray even whenoptInis false. Prefer a conditional collection expression so the field is only created for the opt-in shape.
.. When(optIn, Field("requiresOptIn", "[String!]"))
src/HotChocolate/Fusion/src/Fusion.Execution.Types/Completion/IntrospectionSchema.cs:152
When(optIn, Field(...))still constructs theField(...)node and allocates theparamsarray even whenoptInis false. Prefer a conditional collection expression so the field is only created for the opt-in shape.
.. When(optIn, Field("requiresOptIn", "[String!]"))
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Patch coverage100.0% of changed lines covered (201/201)
Project coverage: 54.2% (236232/435832 lines) |
Summary
The introspection schema was maintained as two near-identical SDL documents: a base copy, and a full copy with the opt-in feature fields and arguments interleaved. Adding one conditional field or argument meant editing every copy, and further options would multiply them, because SDL type extensions can add fields but cannot add arguments to an existing field.
IntrospectionSchemanow builds the document from syntax nodes, one method per introspection type, with each conditional field and argument declared once beside the definition it belongs to.SemanticIntrospectionSchemafolds into the same builder and is removed. Documents are cached and shared by shape, and the shape is a key type naming every option the document depends on, so the document cannot be built from an option that is not part of its cache key.One behavior change:
__Directive.requiresOptInis now the last field of__Directiveinstead of precedingisDeprecated, matching where the Core introspection types append it. All other output is unchanged.Performance
Measured against
mainin Release on .NET 10, 20k iterations per case.The first build of a given shape replaces lexing and parsing the SDL with direct node
construction, so it gets cheaper on both axes:
Every later build of that shape is served from the cache, as it was on
main:Those timings are at noise level and should be read as "free" on both sides rather than
compared to each other. The allocation difference is real: the call site no longer builds
a
Concatiterator to splice the semantic definitions on.For scale, a full
FusionSchemaDefinition.Createof thefusion1fixture is ~544 µs and~286 KB, so none of the above is on a hot path.
Test plan
main, parsed and re-printed on both sides: identical apart from the__Directive.requiresOptInposition noted above.Fusion.Execution.Testsand theFusion.AspNetCore.Testsintrospection tests pass.