Skip to content

Persistence story: relational mapping guidance and a migration hook #37

Description

@btravers

Problem

Entities live or die by round-tripping through storage, and today that story is entirely manual. The toJSON() / make() contract is sound, and examples/billing-persistence shows a persuasive repository for a document-shaped store — but a relational database raises questions the package and docs never answer:

  • FK-vs-embedded nesting. A nested entity field (issuedTo: Organization) serialises embedded in toJSON(). Relational persistence wants a foreign key on write and a join + make on read; that mapper is hand-written today, and branded field types make it cast-heavy. There is no documented pattern, let alone a helper.
  • ORM guidance. No documented, tested integration story for Drizzle / Prisma / Kysely — even just type-level helpers or a recipe mapping SomeEntity.output to a table shape would carry most of the value.
  • Rows that predate the current model. make validating against input (and re-deriving computed) already heals some drift, and the new evolve an entity how-to documents read-both-write-new mappers — but a first-class migrate-on-make hook (a versioned chain of row transforms applied before validation) would close the gap properly.

Why it matters

This is the highest-leverage gap in the library's usefulness: the sweet-spot adopter (zod-v4 hexagonal backend, DDD-flavoured) meets it on day one, and today the answer is "write it yourself".

Possible shape (to be designed)

  • A documented pattern (docs first): reference-vs-embed decision guide, worked Drizzle/Kysely repository example with branded-type-safe mappers.
  • Optionally, type-level helpers: e.g. a Entity.Row<typeof X, { issuedTo: "id" }>-style mapped type replacing nested entity fields with their id type.
  • Optionally, make-side migration: SomeEntity.make(row, { migrate }) or a declaration option carrying versioned row transforms.

No runtime I/O enters the package in any variant — mapping and migration stay pure, per the no-I/O rule.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions