Skip to content

[Fusion] Collect nested Apollo entity targets from their parent target - #10627

Draft
tobias-tengler wants to merge 6 commits into
tte/fusion-nested-lookup-target-collectionfrom
tte/fusion-apollo-target-prefix-reuse
Draft

tobias-tengler wants to merge 6 commits into
tte/fusion-nested-lookup-target-collectionfrom
tte/fusion-apollo-target-prefix-reuse

Conversation

@tobias-tengler

@tobias-tengler tobias-tengler commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

An Apollo _entities lookup that serves several target paths (#10607) collects the entities for each target path by walking the result from the root. When one target path extends another, such as $.users.reviews.product and $.users.reviews.product.reviews.author.reviews.product, the longer path walks the shared prefix again, while the composite-schema multi-target path (#10615) already continues from the elements collected for the shorter path.

This PR moves the composite collection loop, including the collected prefix lookup, into a shared helper that both multi-target paths call, so an Apollo target path that extends another target path continues from the entities collected for it. Representations and results are unchanged, and a new test covers the Apollo path.

Stacked on #10615 (which is stacked on #10613 and #10612), with the two commits of #10607 applied on top, so the diff also shows #10607 until it is merged. Only the last commit belongs to this PR.

Each invocation runs one result store lifecycle with 16 representation creations, and per creation is (Mean − Lifecycle) / 16. Base and PR are adjacent runs of the same out-of-process BenchmarkDotNet session.

Method Version Mean Per creation Ratio Allocated Alloc Ratio
Lifecycle, no creations base 117.2 µs – – 258.44 KB 1.00
Lifecycle, no creations PR 118.8 µs – – 258.44 KB 1.00
Apollo products base 350.1 µs 14.6 µs 1.00 272.01 KB 1.00
Apollo products PR 328.0 µs 13.1 µs 0.90 272.00 KB 1.00
Apollo inventory base 465.6 µs 21.8 µs 1.00 274.03 KB 1.00
Apollo inventory PR 437.5 µs 19.9 µs 0.91 274.03 KB 1.00
Composite products base 278.7 µs 10.1 µs 1.00 268.99 KB 1.00
Composite products PR 295.3 µs 11.0 µs 1.09 269.00 KB 1.00

Apollo multi-target representation creation gets about 10% faster per creation, beyond the error interval, with allocations unchanged. The composite code only moved into the helper, and its difference is within the error interval (±13 µs per invocation). This is a small, reliable micro win; no end-to-end run was done.

When one lookup result is merged into a primary target and several additional
targets, the primary target is completed from the source data and, when every
completed value is a non-null, non-enum leaf of an object with the same
selection set, the completed rows are copied into each additional target
instead of completing the same source data again. Targets that do not qualify,
merges with errors and pocketed errors keep the existing completion.
Additional targets of a lookup variable set are kept as cursors into the
result document instead of building a path per target. The merge uses the
cursors directly while no value that references an object or a list was
replaced since the targets were collected, and resolves the target from the
root by its path otherwise. The paths of a CompactPathSegment are created on
first access, so error attribution, telemetry and custom clients keep working.
When a lookup has several target paths and one is a prefix of another, the
longer path continues from the elements collected for the shorter path instead
of walking the result from the root again.
…paths

Covers planning, JSON plan round-trip and subgraph requests for structurally
identical Apollo _entities lookups that target different paths. The snapshots
record the current behavior: one _entities operation per target path.
Structurally identical Apollo _entities lookups that target the same source
schema and sit at the same dependency depth now merge into one multi-target
lookup with one deduplicated representation list, like the composite-schema
merge. Bumps OperationPlanner.Version to 2.3.0 and the operation plan JSON
format to 1.2.0 (ApolloOperationBatch entries may carry targets).
When an Apollo multi-target lookup has a target path that extends another
target path, the longer path continues from the entities collected for the
shorter path instead of walking the result from the root again. The composite
and Apollo multi-target paths now share one combined collector.
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Patch coverage

85.3% of changed lines covered (631/740)

File Covered Changed Patch %
…/Execution/Nodes/ApolloOperationExecutionNode.cs 0 1 0.0% 🔴
…/Fusion/src/Fusion.Execution/Execution/ThrowHelper.cs 0 3 0.0% 🔴
…/src/Fusion.Execution/Execution/OperationPlanContext.cs 13 26 50.0% 🔴
…/Execution/Nodes/ApolloOperationBatchExecutionNode.cs 99 151 65.6% 🔴
…/Execution/Results/FetchResultStore.RepresentationValue.cs 22 26 84.6% 🟡
…/Fusion/src/Fusion.Execution/Text/Json/CompactPathSegment.cs 13 15 86.7% 🟡
…/src/Fusion.Execution/Execution/Results/FetchResultStore.cs 185 208 88.9% 🟡
…/Planning/OperationPlanner.BuildExecutionTree.cs 109 120 90.8% 🟡
…/Execution/Nodes/Serialization/JsonOperationPlanFormatter.cs 12 12 100.0% 🟢
…/Execution/Nodes/Serialization/JsonOperationPlanParser.cs 35 35 100.0% 🟢
…/Execution/Nodes/Serialization/YamlOperationPlanFormatter.cs 11 11 100.0% 🟢
…/Execution/Results/AdditionalPathAccumulator.cs 88 88 100.0% 🟢
…/src/Fusion.Execution/Execution/Results/TargetCursorPaths.cs 17 17 100.0% 🟢
…/Fusion/src/Fusion.Execution/Planning/OperationPlanner.cs 1 1 100.0% 🟢
…/src/Fusion.Execution/Text/Json/CompositeObjectContext.cs 1 1 100.0% 🟢
…/Fusion.Execution/Text/Json/CompositeResultDocument.MetaDb.cs 8 8 100.0% 🟢
…/src/Fusion.Execution/Text/Json/CompositeResultDocument.cs 17 17 100.0% 🟢
Uncovered changed lines (JSON)
{
  "sha": "e5c99fe294131ad9dba5a4f4f766a66c86303b61",
  "files": [
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationExecutionNode.cs", "ranges": [[243, 243]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/ThrowHelper.cs", "ranges": [[86, 86], [89, 89], [92, 92]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/OperationPlanContext.cs", "ranges": [[527, 533], [544, 545], [561, 562], [564, 564], [567, 567]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Nodes/ApolloOperationBatchExecutionNode.cs", "ranges": [[160, 162], [168, 170], [206, 208], [214, 216], [219, 222], [224, 229], [233, 238], [258, 263], [265, 265], [267, 272], [274, 276], [278, 280], [583, 584], [595, 595], [651, 651], [659, 659]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/FetchResultStore.RepresentationValue.cs", "ranges": [[170, 171], [179, 180]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Text/Json/CompactPathSegment.cs", "ranges": [[85, 85], [90, 90]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Execution/Results/FetchResultStore.cs", "ranges": [[729, 731], [733, 733], [751, 752], [759, 760], [773, 773], [789, 790], [805, 806], [835, 836], [845, 846], [888, 889], [924, 925], [1144, 1145]] },
    { "path": "src/HotChocolate/Fusion/src/Fusion.Execution/Planning/OperationPlanner.BuildExecutionTree.cs", "ranges": [[1614, 1614], [1645, 1646], [1674, 1679], [2067, 2068]] }
  ]
}

Project coverage: 59.0% (311993/528362 lines)

@tobias-tengler
tobias-tengler changed the base branch from main to tte/fusion-nested-lookup-target-collection October 19, 2026 06:44
michaelstaib added a commit that referenced this pull request Oct 22, 2026
The Apollo multi-target path shares the combined collector with the composite
path, so it continues from collected prefixes as well. The test is taken from
#10627.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant