Skip to content

fix(ts-sdk): Add primaryKey() and index() to SumBuilderImpl and SumColumnBuilder#4389

Open
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:fix/enum-primarykey-sum-builder
Open

fix(ts-sdk): Add primaryKey() and index() to SumBuilderImpl and SumColumnBuilder#4389
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:fix/enum-primarykey-sum-builder

Conversation

@Ludv1gL
Copy link
Copy Markdown
Contributor

@Ludv1gL Ludv1gL commented Feb 21, 2026

Summary

  • Codegen unconditionally emits .primaryKey() on all primary key columns, including enum types
  • SumBuilderImpl (used for all object-form enums via __t.enum("Name", { ... })) only implemented Defaultable and Nameable — not PrimaryKeyable or Indexable
  • This causes a runtime TypeError: SC.primaryKey is not a function whenever an enum type is used as a primary key column

Fix

Add Indexable and PrimaryKeyable interfaces and their methods to:

  • SumBuilderImpl (the base class for all enum type builders)
  • SumColumnBuilder (the column builder returned by SumBuilderImpl methods)

This matches the existing pattern already present in SimpleSumBuilderImpl and SimpleSumColumnBuilder.

Why SumBuilderImpl and not just SimpleSumBuilderImpl?

Codegen always generates object-form enums:

export const PlatformModuleType = __t.enum("PlatformModuleType", {
  Standard: __t.unit,
  Control: __t.unit,
});

The runtime dispatch in type_builders.ts (line ~3656) routes object-form enums to SumBuilder (backed by SumBuilderImpl), never to SimpleSumBuilder. So SimpleSumBuilderImpl's existing primaryKey()/index() methods are effectively dead code for codegen output.

Test plan

  • Verify enum types used as primary keys no longer throw TypeError: SC.primaryKey is not a function
  • Verify existing SimpleSumBuilderImpl/SimpleSumColumnBuilder behavior is unchanged (subclass overrides still work)

🤖 Generated with Claude Code

…lumnBuilder

Codegen unconditionally calls .primaryKey() on all primary key columns,
including enum types. But SumBuilderImpl (used for all object-form enums)
only implemented Defaultable and Nameable — not PrimaryKeyable or
Indexable. This caused a runtime TypeError when any enum type was used
as a primary key column.

Add Indexable and PrimaryKeyable interfaces and their methods to both
SumBuilderImpl and SumColumnBuilder, matching the existing pattern in
SimpleSumBuilderImpl and SimpleSumColumnBuilder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cloutiertyler
Copy link
Copy Markdown
Contributor

@gefjon correct me if I'm wrong, but I don't believe we support indexing and filtering on sum types, and to add support we'd have to add support in all languages. Definitely shouldn't have a runtime error, but I think the fix is to disallow primary keys on sum types, at least for now.

@gefjon
Copy link
Copy Markdown
Contributor

gefjon commented Apr 15, 2026

@gefjon correct me if I'm wrong, but I don't believe we support indexing and filtering on sum types, and to add support we'd have to add support in all languages. Definitely shouldn't have a runtime error, but I think the fix is to disallow primary keys on sum types, at least for now.

I believe we allow filtering and primary-key annotations on simple enums, i.e. those where all variants have the unit payload. It's possible I'm misremembering, thought.

@Ludv1gL
Copy link
Copy Markdown
Contributor Author

Ludv1gL commented Apr 15, 2026

Yeah and I definitely remember this was added to the C++ library back in the day since it was in sdk-test.
And we are using a simple enum pk in rust and now typescript (with this PR) successfully.
Not sure how it's implemented in Unreal and C#.
So question is also, why didn't the sdk-test catch this for Typescript?

@Ludv1gL
Copy link
Copy Markdown
Contributor Author

Ludv1gL commented Apr 15, 2026

I asked a friend and got this summary, which aligns with my intuition that the Typescript SDK is the odd one out:

Layer Component Enum PK Notes
Core: schema validation crates/schema Simple Direct index: unit-variant enums only
Core: BSATN eq/hash crates/sats, crates/table Full Sum types fully supported
Server bindings: Rust crates/bindings{,-macro} Works No type restriction (except scheduled=u64)
Server bindings: C# crates/bindings-csharp Works Enum byte-tag serialization
Server bindings: C++ crates/bindings-cpp Works FilterableValue concept includes enums
Codegen crates/codegen Works Emits .primaryKey() unconditionally
Client SDK: Rust sdks/rust Works Eq+Hash traits, tested
Client SDK: C# sdks/csharp Works* *TODO: exhaustive PK type testing needed
Client SDK: TypeScript sdks/typescript (=bindings-typescript) Fixed by PR SumBuilderImpl was missing PrimaryKeyable
Client SDK: Unreal sdks/unreal Works UENUM uint8, fully tested

Copy link
Copy Markdown
Contributor

@cloutiertyler cloutiertyler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I'm going to approve this one.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants