Skip to content

fix(codegen-ts): emit self-referential FKs without a self-import#53

Merged
dmealing merged 1 commit into
mainfrom
fix/codegen-self-referential-fk
Jun 21, 2026
Merged

fix(codegen-ts): emit self-referential FKs without a self-import#53
dmealing merged 1 commit into
mainfrom
fix/codegen-self-referential-fk

Conversation

@dmealing

Copy link
Copy Markdown
Member

A foreign key whose target is the same entity (createdBy → this table, parentId, managerId, …) was emitted as .references(() => <self>.id) with an imp() of the entity's own module — a circular self-import that fails to typecheck (TS2440/TS7022).

renderColumn now detects fkInfo.targetEntityName === currentEntityName and emits Drizzle's self-ref form:

createdBy: uuid("created_by").references((): AnyPgColumn => userProfiles.id),

— the local table const referenced directly (no import), with the explicit Any*Column return type that breaks the circular inference. Dialect-aware (AnyPgColumn / AnySQLiteColumn).

Tests: postgres + sqlite self-FK cases (assert the annotation, the local-const reference, and no self-import). codegen-ts 801/0.

🤖 Generated with Claude Code

@dmealing
dmealing force-pushed the fix/codegen-self-referential-fk branch from 47031d2 to d46cbbd Compare June 21, 2026 13:49
A foreign key whose target is the SAME entity (createdBy → this table, parentId,
managerId, …) was emitted as `.references(() => <self>.id)` with an `imp()` of the
entity's own module — a circular self-import that fails to typecheck
(TS2440/TS7022: import conflicts with local declaration, implicit any from
self-reference).

renderColumn now detects `fkInfo.targetEntityName === currentEntityName` and emits
Drizzle's self-ref form: `.references((): AnyPgColumn => <self>.id)` — referencing
the local table const directly (no import) with the explicit `Any*Column` return
type that breaks the circular inference. Dialect-aware: `AnyPgColumn` (postgres) /
`AnySQLiteColumn` (sqlite). The current entity name is threaded into renderColumn.

Tests: postgres + sqlite self-FK cases (asserts the Any*Column annotation, the
local-const reference, and NO self-import). codegen-ts 801/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dmealing
dmealing force-pushed the fix/codegen-self-referential-fk branch from d46cbbd to 98f2693 Compare June 21, 2026 14:12
@dmealing
dmealing merged commit 1ca86e4 into main Jun 21, 2026
29 checks passed
@dmealing
dmealing deleted the fix/codegen-self-referential-fk branch June 21, 2026 14:24
dmealing added a commit that referenced this pull request Jun 21, 2026
…ss all ports (#54)

Closes a real cross-port coverage gap: the only self-references in the shared corpus
were M:N junction self-joins (FR-018) — a plain 1:N self-FK (parentId → same entity)
was unexercised in every port. A 1:N self-FK is a scalar column (field.long) whose
FK-ness is declared by identity.reference; TS/Drizzle alone emits a column-level
.references() (the self-import bug fixed in #53), so the others are safe by construction
but were untested end-to-end.

Adds a `Node` entity (id PK + nullable parentId + identity.reference fkParent → Node) to
the persistence-conformance canonical metadata, regenerates the TS-owned schema SQL (now
emits the self-referencing FK constraint), and a `roundtrip-self-fk` scenario: a root
node (NULL parent) and a seeded-parent child, each written through the runtime/ORM write
codec and read back by PK. Per-port wiring: C# committed Node.g.cs + AppDbContext; Kotlin
hand-written NodeTable (PK-first so the self-reference resolves) + runner registration;
TS/Java/Python are metadata-driven (zero wiring). Updated the migration bootstrap's
expected table list to include `nodes`.

Verified: TS full integration (incl. the self-FK roundtrip) 111/0 against Testcontainers
PG; Kotlin + C# integration wiring compiles. Java/Python pick it up from the metadata.
Note: the codegen self-FK surface is already covered (TS via #53, Kotlin via an existing
pk-first codegen test, Java/C#/Python safe-by-construction) — this gates the runtime path.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant