Skip to content

fix(bindings-csharp): allow [SpacetimeDB.Type] newtype structs as primary keys#5463

Open
ritankarsaha wants to merge 1 commit into
clockworklabs:masterfrom
ritankarsaha:fix/csharp-newtype-struct-primary-key
Open

fix(bindings-csharp): allow [SpacetimeDB.Type] newtype structs as primary keys#5463
ritankarsaha wants to merge 1 commit into
clockworklabs:masterfrom
ritankarsaha:fix/csharp-newtype-struct-primary-key

Conversation

@ritankarsaha

Copy link
Copy Markdown

Description of Changes

Fixes #5425
Allows [SpacetimeDB.Type] structs that wrap exactly one SpacetimeDB-supported primary-key type to be used as [PrimaryKey], [Unique], or single-column index columns without the STDB0003 diagnostic.

Example that now works:

[SpacetimeDB.Type]
public partial struct ItemKey
{
    public ulong Value;
    public static implicit operator ulong(ItemKey key) => key.Value;
    public static implicit operator ItemKey(ulong value) => new() { Value = value };
}

[SpacetimeDB.Table(Name = "item", Public = true)]
public partial struct Item
{
    [SpacetimeDB.PrimaryKey]
    public ItemKey Key;
    public string Name;
}

How it works:
BSATN encodes a single-field product struct as pure field bytes with no framing — identical bytes to the underlying scalar. A newtype of ulong therefore serializes identically to a bare ulong. The fix teaches ColumnTypeValidation.IsEquatable() to recognize these newtype wrappers, using SpacetimeDbFieldDiscovery to inspect only the fields declared in
the [SpacetimeDB.Type]-annotated partial (the same set the BSATN codegen serializes). Multi-field structs and nullable wrappers continue to be rejected with STDB0003.

The change also updates the scheduled table PK check to accept a newtype of ulong in addition to a bare ulong.

API and ABI breaking changes

None. This is a purely additive change. All previously valid code in unaffected.

Expected complexity level and risk

2/5.
The diff is small and self-contained to Codegen/Module.cs. It reuses the existing SpacetimeDbFieldDiscovery helper (already used by BSATN.Codegen) to enumerate BSATN fields, keeping the detection logic consistent with what the serializer actually emits. The main risk area is the IsEquatable extension — any type that now passes this check but shouldn't would silently generate incorrect index code, but the two-guard check (struct + [SpacetimeDB.Type] + exactly one field + that field passes IsEquatable) is conservative.

Testing

  • All 6 codegen snapshot tests pass (dotnet test Codegen.Tests/Codegen.Tests.csproj)
  • New snapshot Type#ItemKey.verified.cs confirms correct BSATN serialization for the newtype struct
  • New snapshot Module#FFI.verified.cs confirms KeyUniqueIndex uses ItemKey/ItemKey.BSATN as type params and the table accessor is correctly generated
  • Existing STDB0003 diagnostic test updated — NonEquatableViewPrimaryKey given a second field to remain genuinely non-equatable; STDB0038 is still emitted for it.
@CLAassistant

CLAassistant commented Jun 30, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@ritankarsaha

Copy link
Copy Markdown
Author

@Shubham8287
Hey a new contributor to SpaceTimeDB, can you review the changes? Signed the CLI

@ritankarsaha ritankarsaha changed the title fix(bindings-csharp): allow [SpacetimeDB.Type] newtype structs as primary keya Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants