Skip to content

Rebuild on Prisma Next - #3

Merged
SerhiyGreench merged 1 commit into
masterfrom
prisma-8
Aug 28, 2026
Merged

Rebuild on Prisma Next#3
SerhiyGreench merged 1 commit into
masterfrom
prisma-8

Conversation

@SerhiyGreench

@SerhiyGreench SerhiyGreench commented Aug 28, 2026

Copy link
Copy Markdown
Member

What does this PR do?

Rebuilds this package on Prisma Next (8.x). Prisma 8 replaces the generated
client with a contract and drops $extends, so the four query extensions
become SqlMiddleware that rewrite a query AST, and everything they used to
read from the generated config maps (SOFT_DELETE_MODELS, AUDIT_CONFIG,
ACCESS_SCOPE_MODELS, …) is now derived from the emitted contract.json.

The Prisma 7 generator is gone with the client that hosted it. emit/ produces
the same decorated @imqueue/rpc classes from the contract, and carries the
three things a contract cannot: validation rules, fields kept off the wire, and
the names of enum members whose database label is not the name (STRING @map("string") had no equivalent, and losing it renamed a published field).

What the ORM cannot do, and what stands in for it:

Gone Replacement
Nested writes repositoriesFor writes the children itself, in a transaction, taking the foreign key from the row it just created
select on a write A write returned every column — including a credential secret the caller had not asked for. The façade projects it, reading the row back when the projection names a relation
Atomic update values A function passed as one is silently stringified, so a counter has to be x + 1 in the database
groupBy, createMany, skipDuplicates createBulk, count, and conflictOn on upsert; the aggregate cases stay one statement rather than a loop

Three decoding bugs this fixes, each of which was silent:

  • pg hands the codec an already-parsed JSON value and the codec parses it
    again. An object survived; a JSON string did not — and a column holding
    "5" came back as the number 5.
  • An enum's array type is numbered when the enum is created, so the driver has
    no parser for it and returns the literal text {EMAIL,SMS}. Every read of
    such a column failed with RUNTIME.DECODE_FAILED.
  • Both are corrected by dataPool, which gives the codec the text it expects
    and looks the enum-array oids up once.

isoDates stays, for a different reason than before. The columns are
timestamptz now, so the instant is no longer ambiguous — but Postgres prints
it as 2026-08-14 09:30:00.123+00, and every boundary downstream refuses that
spelling: the GraphQL DateTime scalar rejects it outright, and so does
z.iso.datetime().

Also new: sqlRunner (a query and a transaction that agree on the
connection, carried in async context so a statement written inside one is in
it), composable sql/raw/join fragments to replace Prisma.sql, and
RowOf<Model> with a Repository<Entity> that lets a call site read a row
without naming its type.

Validated by migrating seven services onto it, all green.

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Refactor / internal
  • Other: breaking — rebuilt for Prisma Next; the peer moves from
    @prisma/client >=7 to @prisma/orm-postgres >=8.0.0-rc.8 and the
    ./codegen export is removed

Checklist

  • I have read the Contributing guide.
  • Tests added or updated, and the full suite passes locally (npm test) — 86 tests.
  • Docs / doc-blocks updated where relevant.
  • The PR is focused on a single logical change.

Contribution terms (required)

  • I have read and agree to the @imqueue Contribution Terms.
    I grant the project owner the right to license my contribution
    commercially, royalty-free, my contribution stays available under
    GPL-3.0, I keep my copyright, and I understand I will receive no fee for
    it. If I did not agree, I would not be submitting this contribution.

Prisma 8 replaces the generated client with a contract and drops `$extends`,
so the four query extensions become `SqlMiddleware` that rewrite a query AST,
and everything they used to read from the generated config maps is now derived
from the emitted `contract.json` instead.

What the ORM cannot do, and what stands in for it:

  * No nested writes. `repositoriesFor` writes the children itself, in a
    transaction, taking the foreign key from the row it just created.
  * No `select` on a write. A write returned every column, which handed a
    caller the credential secret it had not asked for; the façade projects it,
    reading the row back when the projection names a relation.
  * No atomic update values. A function passed as one is stringified, so a
    counter has to be `x + 1` in the database.
  * `pg` hands the codec a parsed JSON value and the codec parses it again — a
    column holding `"5"` came back as the number 5. `dataPool` gives the codec
    the text it expects, and registers the enum-array oids the driver cannot
    know, without which every such column fails to decode.

`isoDates` stays, for a different reason than before: the columns are
`timestamptz` now, so the instant is no longer ambiguous, but Postgres prints
it as `2026-08-14 09:30:00.123+00` and every boundary downstream — the GraphQL
DateTime scalar, `z.iso.datetime()` — refuses that spelling.

The Prisma 7 generator is gone. `emit/` produces the same decorated RPC classes
from the contract, and carries what the contract cannot: validation rules,
fields kept off the wire, and the names of enum members whose database label is
not the name.

Migrated seven services against this. 86 tests.
@SerhiyGreench
SerhiyGreench merged commit dc746c4 into master Aug 28, 2026
14 of 15 checks passed
@SerhiyGreench
SerhiyGreench deleted the prisma-8 branch August 28, 2026 08:39
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant