Rebuild on Prisma Next - #3
Merged
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 extensionsbecome
SqlMiddlewarethat rewrite a query AST, and everything they used toread from the generated config maps (
SOFT_DELETE_MODELS,AUDIT_CONFIG,ACCESS_SCOPE_MODELS, …) is now derived from the emittedcontract.json.The Prisma 7 generator is gone with the client that hosted it.
emit/producesthe same decorated
@imqueue/rpcclasses from the contract, and carries thethree 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:
repositoriesForwrites the children itself, in a transaction, taking the foreign key from the row it just createdselecton a writesecretthe caller had not asked for. The façade projects it, reading the row back when the projection names a relationx + 1in the databasegroupBy,createMany,skipDuplicatescreateBulk,count, andconflictOnonupsert; the aggregate cases stay one statement rather than a loopThree decoding bugs this fixes, each of which was silent:
pghands the codec an already-parsed JSON value and the codec parses itagain. An object survived; a JSON string did not — and a column holding
"5"came back as the number5.no parser for it and returns the literal text
{EMAIL,SMS}. Every read ofsuch a column failed with
RUNTIME.DECODE_FAILED.dataPool, which gives the codec the text it expectsand looks the enum-array oids up once.
isoDatesstays, for a different reason than before. The columns aretimestamptznow, so the instant is no longer ambiguous — but Postgres printsit as
2026-08-14 09:30:00.123+00, and every boundary downstream refuses thatspelling: the GraphQL
DateTimescalar rejects it outright, and so doesz.iso.datetime().Also new:
sqlRunner(aqueryand atransactionthat agree on theconnection, carried in async context so a statement written inside one is in
it), composable
sql/raw/joinfragments to replacePrisma.sql, andRowOf<Model>with aRepository<Entity>that lets a call site read a rowwithout naming its type.
Validated by migrating seven services onto it, all green.
Type of change
@prisma/client >=7to@prisma/orm-postgres >=8.0.0-rc.8and the./codegenexport is removedChecklist
npm test) — 86 tests.Contribution terms (required)
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.