Skip to content

fix(strawberry-shake): populate union member classes for fragment selections#8

Open
cliedeman wants to merge 1 commit into
fork-ci-basefrom
fix/ss-union-fragments-empty-classes
Open

fix(strawberry-shake): populate union member classes for fragment selections#8
cliedeman wants to merge 1 commit into
fork-ci-basefrom
fix/ss-union-fragments-empty-classes

Conversation

@cliedeman

@cliedeman cliedeman commented Jun 27, 2026

Copy link
Copy Markdown

Fixes ChilliCream#5992

Problem

When a query selects fields on union members through a named fragment whose type condition is the union itself (or another abstract type), Strawberry Shake generated member model classes that are empty: the requested fields are dropped and only __typename survives. The code still compiles, so the standard compile-check does not catch it.

This is the exact shape from the linked repro (svelue/StrawberryShakeUnionTypeBug):

query ExampleQuery {
  exampleQuery { ... ExampleUnion }
}

fragment ExampleUnion on ExampleUnion {   # type condition is the union
  ... on TypeA { fieldA }
  ... on TypeB { fieldB }
}

Selecting the same members via inline fragments directly on the union field, or via named fragments on the concrete members, already worked. Only the named-fragment-on-the-abstract-type path was broken.

Root cause

FragmentHelper.CollectFields (src/StrawberryShake/CodeGeneration/src/CodeGeneration/Analyzers/FragmentHelper.cs:311) builds the field set for a concrete union member. It descended into inline fragment nodes but not into named fragment nodes whose type condition is an abstract type.

A named fragment on the union does not get its own interface for a concrete member (RewriteForConcreteType only rewrites interface conditions, and a union is neither object nor interface), so the member inline fragments nested inside it were never visited. The member interface ended up with no fields, and CreateClass then filters the (correctly collected) selectionSet.Fields down to the interface field names, producing an empty class.

Fix

In CollectFields, additionally descend into named fragment nodes whose abstract type condition applies to the concrete member type, so the nested member selections are reached. Inline-fragment and concrete-named-fragment paths are unchanged.

Evidence of no regression: every existing integration *.Client.cs snapshot (including StarWarsUnionListTest, StarWarsTypeNameOnUnionsTest, StarWarsTypeNameOnInterfacesTest, fragment + include/skip, hero traits) is byte-identical after the change. The fix only adds the previously-missing fields.

Tests

New UnionTypeGeneratorTests drives CSharpGenerator.Generate directly and asserts the generated member classes contain the requested properties (the previous empty output still compiled, so source-level assertions are required). It covers three selection shapes:

  • inline fragments on the union field (was passing) — regression guard
  • a named fragment on the union (was failing) — the bug
  • named fragments on the members (was passing) — regression guard

Verified red before the fix (only the named-fragment-on-union case failed) and green after. Ran the surrounding generator and integration test classes (140+ tests) with no regressions.

— Claude
🤖 Generated with Claude Code

…ections

When union members were selected through a named fragment whose type
condition is the union itself (or another abstract type), the generated
member classes came out empty: the requested fields were dropped and only
__typename remained.

The cause is in FragmentHelper.CollectFields, which builds the field set
for a concrete union member. It descended into inline fragment nodes but
not into named fragment nodes on an abstract type. A named fragment on the
union does not become its own interface for a concrete member, so the
member inline fragments nested inside it were never reached and no fields
were collected. This left the member interface (and therefore the member
class) empty while the code still compiled.

The fix descends into named fragment nodes whose abstract type condition
applies to the concrete member type, so the nested member selections are
collected. Inline-fragment and concrete named-fragment selections are
unaffected, and existing generated client snapshots are byte-identical.

Adds UnionTypeGeneratorTests covering union members selected via inline
fragments, via a named fragment on the union, and via named fragments on
the members. The test drives the generator directly and asserts the
member classes contain the requested properties, because the previous
empty output still compiled.

Fixes ChilliCream#5992
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.

Generated union type classes are empty with SS13.0.5 and .NET7 when using fragments

2 participants