@prisma/orm-mongo 8.0.0-rc.5 → 8.0.0-rc.5-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/package.json +11 -10
  2. package/skills/prisma-8/SKILL.md +84 -0
  3. package/skills/prisma-8/references/build.md +142 -0
  4. package/skills/prisma-8/references/contract.md +417 -0
  5. package/skills/prisma-8/references/debug.md +141 -0
  6. package/skills/prisma-8/references/feedback.md +251 -0
  7. package/skills/prisma-8/references/migration-review.md +224 -0
  8. package/skills/prisma-8/references/migrations.md +519 -0
  9. package/skills/prisma-8/references/queries-mongo.md +236 -0
  10. package/skills/prisma-8/references/queries-postgres.md +415 -0
  11. package/skills/prisma-8/references/queries.md +168 -0
  12. package/skills/prisma-8/references/quickstart.md +326 -0
  13. package/skills/prisma-8/references/runtime.md +344 -0
  14. package/skills/prisma-8/references/supabase.md +244 -0
  15. package/skills/prisma-8/references/upgrade-app.md +101 -0
  16. package/skills/prisma-8/references/upgrade-extension.md +105 -0
  17. package/skills/prisma-8/upgrading/app/upgrades/0.10-to-0.11/instructions.md +56 -0
  18. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/instructions.md +381 -0
  19. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-closed-mongo-contracts.ts +202 -0
  20. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-domain-namespaced-contracts.ts +201 -0
  21. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/re-emit-postgres-public-default.ts +198 -0
  22. package/skills/prisma-8/upgrading/app/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  23. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/instructions.md +339 -0
  24. package/skills/prisma-8/upgrading/app/upgrades/0.12-to-0.13/re-emit-mti-variant-link-columns.ts +229 -0
  25. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/instructions.md +543 -0
  26. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  27. package/skills/prisma-8/upgrading/app/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  28. package/skills/prisma-8/upgrading/app/upgrades/0.14-to-0.15/instructions.md +359 -0
  29. package/skills/prisma-8/upgrading/app/upgrades/0.15-to-0.16/instructions.md +173 -0
  30. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/instructions.md +805 -0
  31. package/skills/prisma-8/upgrading/app/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  32. package/skills/prisma-8/upgrading/app/upgrades/0.17-to-8.0.0-rc.1/instructions.md +72 -0
  33. package/skills/prisma-8/upgrading/app/upgrades/0.7-to-0.8/instructions.md +8 -0
  34. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/instructions.md +36 -0
  35. package/skills/prisma-8/upgrading/app/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  36. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/instructions.md +86 -0
  37. package/skills/prisma-8/upgrading/app/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  38. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +588 -0
  39. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  40. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +158 -0
  41. package/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +42 -0
  42. package/skills/prisma-8/upgrading/extension/upgrades/0.10-to-0.11/instructions.md +276 -0
  43. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/instructions.md +738 -0
  44. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/migrate-contract-testing-imports.ts +97 -0
  45. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/regenerate-extension-public-baseline.ts +223 -0
  46. package/skills/prisma-8/upgrading/extension/upgrades/0.11-to-0.12/strip-migration-labels-hints.ts +340 -0
  47. package/skills/prisma-8/upgrading/extension/upgrades/0.12-to-0.13/instructions.md +266 -0
  48. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/instructions.md +522 -0
  49. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/migration-op-factories-to-methods.ts +290 -0
  50. package/skills/prisma-8/upgrading/extension/upgrades/0.13-to-0.14/uuid-preset-rename.ts +43 -0
  51. package/skills/prisma-8/upgrading/extension/upgrades/0.14-to-0.15/instructions.md +803 -0
  52. package/skills/prisma-8/upgrading/extension/upgrades/0.15-to-0.16/instructions.md +219 -0
  53. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/instructions.md +731 -0
  54. package/skills/prisma-8/upgrading/extension/upgrades/0.16-to-0.17/strip-sha256-hash-prefixes.ts +382 -0
  55. package/skills/prisma-8/upgrading/extension/upgrades/0.17-to-8.0.0-rc.1/instructions.md +194 -0
  56. package/skills/prisma-8/upgrading/extension/upgrades/0.7-to-0.8/instructions.md +8 -0
  57. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/instructions.md +57 -0
  58. package/skills/prisma-8/upgrading/extension/upgrades/0.8-to-0.9/strip-inline-contracts.ts +226 -0
  59. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/instructions.md +150 -0
  60. package/skills/prisma-8/upgrading/extension/upgrades/0.9-to-0.10/stamp-storage-types-kind.ts +360 -0
  61. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.1-to-8.0.0-rc.2/instructions.md +746 -0
  62. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.2-to-8.0.0-rc.3/instructions.md +5 -0
  63. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.3-to-8.0.0-rc.4/instructions.md +137 -0
  64. package/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.4-to-8.0.0-rc.5/instructions.md +129 -0
@@ -0,0 +1,588 @@
1
+ ---
2
+ from: "8.0.0-rc.1"
3
+ to: "8.0.0-rc.2"
4
+ changes:
5
+ - id: check-constraints-are-opaque-expressions
6
+ summary: |
7
+ CHECK constraints in `contract.json` changed shape: `{ name, column, valueSet }` became
8
+ `{ name, prefix, expression }`, where `expression` is the raw SQL predicate and `name`
9
+ is a content-addressed wire name (`<prefix>_<8hex>`, the same convention indexes and RLS
10
+ policies already use). Run `prisma-next contract emit` to regenerate `contract.json` and
11
+ `contract.d.ts` — an old-shape contract is rejected on read, so this is not optional.
12
+ Regeneration also changes the physical names of your enum CHECK constraints, because the
13
+ hash suffix is new: `prisma-next migration plan` will show a DROP of the old unsuffixed
14
+ constraint plus an ADD of the wire-named one. That plan needs `destructive` to drop the
15
+ stale constraint; under an additive-only policy the new constraint installs and the old
16
+ one survives, and `prisma-next db verify --strict` reports it as an undeclared extra
17
+ until you allow the drop. Every list (`many`) column now also carries a declared
18
+ element-non-null CHECK that the planner previously invented behind your back; it appears
19
+ in the contract and in the plan for the first time.
20
+ Introspection also stopped parsing predicates, so every CHECK constraint on a managed
21
+ table is now visible — including hand-written ones (`price > 0`, a composite `AND`, a
22
+ `NOT VALID` constraint) that earlier versions could not see at all. An undeclared check
23
+ is an extra: `prisma-next db verify --strict` reports it, and a plan run under a policy
24
+ that allows `destructive` emits a `dropCheckConstraint` operation for it. Read the first
25
+ plan for `dropCheckConstraint` operations naming constraints you wrote by hand. There is
26
+ To keep one, declare it: `@@check(expression: "…", map: "<its physical name>")` adopts the
27
+ constraint under the name it already has, after which `db verify` is clean and no plan drops
28
+ it. `contract infer` writes that form for you, so re-running a pull is the quickest route.
29
+ Let a drop through only when the constraint is deliberately retired. Running the table under
30
+ an additive-only policy also keeps it, but leaves it reported by `--strict` as undeclared.
31
+ detection:
32
+ glob: "**/contract.json"
33
+ contains:
34
+ - '"valueSet"'
35
+ - '"checks"'
36
+ anyMatch: true
37
+ - id: add-check-constraint-takes-an-expression
38
+ summary: |
39
+ In committed migration files, `this.addCheckConstraint({ schema, table, constraint,
40
+ column, values })` is now `this.addCheckConstraint({ schema, table, constraint,
41
+ expression })`. Replace the `column` and `values` pair with the predicate they used to
42
+ describe — `column: 'kind', values: ['admin', 'user']` becomes
43
+ `` expression: `"kind" IN ('admin', 'user')` `` — and use the wire name from your
44
+ regenerated contract as `constraint`. If the constraint was created by the same
45
+ migration's `createTable`, prefer moving it inline: add
46
+ `checkExpression(<name>, <expression>)` to that table's `constraints` array and delete
47
+ the follow-up `addCheckConstraint` call, which is what a freshly planned migration now
48
+ produces. Import `checkExpression` from the same migration entrypoint as `col` and
49
+ `primaryKey`.
50
+ detection:
51
+ glob: "**/migrations/**/*.ts"
52
+ contains:
53
+ - 'addCheckConstraint'
54
+ anyMatch: true
55
+ - id: specifier-default-control-policy-requires-create-namespace
56
+ summary: |
57
+ If your `prisma.config.ts` passes `defaultControlPolicy` in the options bag of
58
+ `typescriptContract` or `typescriptContractFromPath`, that bag now also requires
59
+ `createNamespace`. Stamping a default policy strips derived CHECK constraints from
60
+ tables the policy leaves non-managed, and the strip rebuilds storage namespaces through
61
+ the target's factory, so the two options travel together.
62
+ `typescriptContract(contract, output, { defaultControlPolicy: 'external' })` becomes
63
+ `typescriptContract(contract, output, { defaultControlPolicy: 'external',
64
+ createNamespace: postgresCreateNamespace })`, with `postgresCreateNamespace` imported
65
+ from the Postgres target's types entrypoint (`@internal/target-postgres/types`) — the
66
+ same factory the PSL specifier already takes. Calls without an options bag are
67
+ unchanged, and `emptyContract` already took `createNamespace`.
68
+ detection:
69
+ glob: "**/*.{ts,mts,cts}"
70
+ contains:
71
+ - 'typescriptContract'
72
+ - 'defaultControlPolicy'
73
+ anyMatch: false
74
+ - id: int-backed-enums-fail-at-authoring
75
+ summary: |
76
+ An `enumType()` whose codec is numeric (e.g. `pg/int4@1`) used to build fine and fail
77
+ later, at migrate time. It now throws `CONTRACT.ENUM_INVALID` while the contract is being
78
+ built, because a numeric member set cannot be rendered as a CHECK predicate. If
79
+ `prisma-next contract emit` fails with "numeric-enum CHECK constraints are not yet
80
+ supported", change that enum's codec to a text one (`pg/text@1`) and give each member a
81
+ string value, or replace it with a Postgres native enum (`pg.enum`), which enforces
82
+ membership through the column type and needs no CHECK at all.
83
+ detection:
84
+ glob: "**/*.{ts,mts,cts,prisma}"
85
+ contains:
86
+ - 'enumType'
87
+ anyMatch: true
88
+ - id: aggregate-methods-come-from-the-emitted-contract
89
+ summary: |
90
+ The aggregate methods — `count`, `sum`, `avg`, `min`, `max` — are no longer declared on the
91
+ ORM and SQL-builder surfaces outright. Each surface is derived from the operation names in
92
+ the emitted `contract.d.ts`'s `AggregateTypes` block, so a target or extension can contribute
93
+ an operation and it appears under its own name with no client change. Deriving the surface
94
+ neither adds nor removes a method by itself, but the block a re-emit produces is not the
95
+ list it was: PostgreSQL now contributes eight operations and SQLite seven, and every bare
96
+ result type moved — `count-over-a-field-counts-that-field` and
97
+ `aggregate-defaults-are-js-native-numbers` cover that, so work them too. If it is not — you author it
98
+ in code with `defineContract(...)` and hand that value straight to the client (the no-emit
99
+ flow), or you have not re-emitted since before 8.0.0-rc.1 — every aggregate surface resolves
100
+ to `AggregateOperationsUnavailable`, an empty type, and each call becomes
101
+ `Property 'count' does not exist on type 'AggregateOperationsUnavailable'`. That covers
102
+ `aggregate()`, `groupBy().aggregate()`, `groupBy().having()`, the `include(...)` reducers,
103
+ and `sql()`'s `fns.count` / `fns.sum` / … Runtime behaviour is unchanged; this is a
104
+ compile-time change. Re-emit the contract, or cast the builder to a dynamic record.
105
+ detection:
106
+ glob: "**/*.{ts,tsx,mts,cts}"
107
+ contains:
108
+ - "defineContract"
109
+ - ".aggregate("
110
+ - ".having("
111
+ - "fns.count"
112
+ anyMatch: true
113
+ - id: count-over-a-field-counts-that-field
114
+ summary: |
115
+ `aggregate.count(field)` renders `COUNT(<column>)`. It used to accept the argument, discard
116
+ it, and render `COUNT(*)`. PostgreSQL declares `count` over any input, so the derived method
117
+ carries both arities honestly: `count()` counts rows, `count(field)` counts that field's
118
+ non-null values. No previously type-safe call changes meaning — `count` took no argument
119
+ before, so the field-taking form never typechecked. What changes is a call that got past
120
+ the types: a `@ts-expect-error` above a `count(...)`, a `count(x as never)`, or dynamic
121
+ dispatch. Those now count a column instead of rows, which differs whenever the column holds
122
+ NULLs. Sweep them and drop the argument wherever `COUNT(*)` was what you meant.
123
+ detection:
124
+ glob: "**/*.{ts,tsx,mts,cts}"
125
+ contains:
126
+ - "count("
127
+ - ".aggregate("
128
+ anyMatch: true
129
+ - id: aggregate-defaults-are-js-native-numbers
130
+ summary: |
131
+ `count()`, `sum()` over an integer column, and `avg()` over an integer column all return
132
+ `number`. On PostgreSQL they returned, respectively, a `bigint`; a `bigint` or a decimal
133
+ string depending on the column's width; and a decimal string. On SQLite the first two
134
+ returned a `bigint` and `avg()` was already a `number`. The lossless results moved to three new
135
+ operations beside them — `countBigInt()` → `bigint`, `sumBigInt()` → `bigint` (on
136
+ PostgreSQL exact past 2^63 over a `BigInt` / `BigIntNumber` / `UnboundedInt` column, whose
137
+ total the database computes as `numeric`; over the narrower integers the total is an `int8`
138
+ and PostgreSQL raises `bigint out of range` past 2^63), `avgDecimal()` → decimal string
139
+ (PostgreSQL only; SQLite has no
140
+ decimal type and contributes none). An empty input set answers `count()` with `0`, not `0n`.
141
+ A `count()`, or a `sum()` over an integer column, whose value passes ±(2^53 − 1) raises
142
+ `RUNTIME.DECODE_FAILED` instead of returning a rounded number — on the `.include()` path as
143
+ well as the top level — so switch that call to `countBigInt()` / `sumBigInt()` wherever the
144
+ magnitude is real. No other result is guarded: a `sum` outside the integer columns keeps its
145
+ own family, and `avg` is a fraction that rounds as any double does.
146
+ Unchanged: `min` / `max`, `sum` / `avg` over a float column, `sum` over `numeric` (still a
147
+ decimal string), `sum` over `UnboundedInt` (still a `bigint`), and the ORM's `having(...)`
148
+ operands, which the ORM types as `number` whatever the aggregate's result type is. The SQL
149
+ builder's comparison operands are the other case, and they do move: `fns.gt(a, b)` types
150
+ both sides from one codec, so `fns.gt(fns.count(), 1n)` becomes `fns.gt(fns.count(), 1)`.
151
+ Sweep aggregate results for
152
+ `2n`-style literals, `String(count)` serialisation, `Number(...)` unwrapping, and `?? '0'`
153
+ coalescing, and write each as the plain number it now is. Then re-emit with
154
+ `prisma-next contract emit`: `contract.d.ts`'s `AggregateTypes` block carries the new
155
+ result codecs and the three new operations, and until you re-emit, the types describe the
156
+ old results and the new methods do not exist.
157
+ detection:
158
+ glob: "**/*.{ts,tsx,mts,cts}"
159
+ contains:
160
+ - ".aggregate("
161
+ - ".count()"
162
+ - ".groupBy("
163
+ - ".include("
164
+ anyMatch: true
165
+ - id: integer-columns-refuse-the-wrong-js-type
166
+ summary: |
167
+ A `BigInt` or `UnboundedInt` column refuses a JS `number`, and a `BigIntNumber` column
168
+ refuses a `bigint`, with `RUNTIME.ENCODE_FAILED` and a message naming the type that
169
+ arrived: `pg/int8@1 value must be a bigint, got number 9`. The wide-integer codecs used to
170
+ accept a number and stringify it, which let a fractional value such as `1.5` reach an
171
+ integer column unremarked. No typed call site changes — a `BigInt` column's application
172
+ type has always been `bigint` — so sweep the ones that bypassed the types: a
173
+ `// @ts-expect-error` over a create/update value, an `as never` / `as any` argument, a
174
+ value that came out of `JSON.parse` (which yields numbers, never bigints), and dynamic
175
+ dispatch. Convert each to the column's own type, `BigInt(value)` for a `bigint` column.
176
+ Schema-written literal defaults are unaffected: `BigInt @default(0)` still emits, because
177
+ the JSON side of these codecs accepts a safe-integer number and only the wire side does not.
178
+ detection:
179
+ glob: "**/*.{ts,tsx,mts,cts}"
180
+ contains:
181
+ - "bigint"
182
+ - "BigInt"
183
+ anyMatch: true
184
+ - id: authored-check-constraints
185
+ summary: |
186
+ A CHECK constraint can now be declared in the contract: `@@check(expression: "…", name: "…")`
187
+ in PSL, `check({ expression, name })` in the TypeScript builder. `name:` is a wire-name
188
+ prefix — the physical constraint becomes `name_<8hex>`, hashed over the predicate, and
189
+ compared by name, so Postgres reprinting the expression never causes drift. Use `map:`
190
+ instead to adopt a constraint that already exists under its own physical name; that form
191
+ compares the predicate byte-for-byte, and warns whenever the body was not captured from the
192
+ database — including on contracts `contract infer` wrote, which warn on the next
193
+ `contract emit`. `contract infer` now writes the `map:` form for you: pulling a database
194
+ emits `@@check` for every live check Prisma Next did not derive, so a hand-written constraint
195
+ is declared from the first pull instead of reading as an undeclared extra that a plan allowing
196
+ destructive changes would drop. Nothing is required of an existing contract — the surface is
197
+ additive.
198
+ detection:
199
+ glob: "**/*.{prisma,ts}"
200
+ contains:
201
+ - '@@check'
202
+ anyMatch: true
203
+ - id: runtime-query-execute-hard-cut
204
+ summary: |
205
+ Runtime row execution uses `query()`, while rc.1 prepared rows use `target.queryPrepared(prepared, params, options?)` and rc.2 uses `prepared.query(target, params, options?)`. Classify each call by its consumed result rather than replacing every `execute`: move row plans to `query`, prepared rows to `prepared.query(target, params, options?)`, and keep non-returning writes on `execute` while reading `affectedRows` when needed. Middleware uses operation-specific `beforeQuery` / `interceptQuery` / `afterQuery` and `beforeExecute` / `interceptExecute` / `afterExecute` hooks, with shared `beforeCompile`; interception returns `{ rows }` for queries and `{ stats }` for execution. There is no operation discriminator, compatibility alias, or generic fallback hook. The Mongo facade keeps static `db.query` and removes row `db.execute`; execute a built row plan through `(await db.runtime()).query(plan)`.
206
+ detection:
207
+ glob: "**/*.{ts,tsx,mts,cts}"
208
+ contains:
209
+ - ".execute("
210
+ - ".queryPrepared("
211
+ - "beforeQuery"
212
+ - "interceptExecute"
213
+ anyMatch: true
214
+ - id: config-file-is-prisma-config-with-an-orm-section
215
+ summary: |
216
+ The CLI config file is `prisma.config.ts` — the `prisma-next.config.ts` name is
217
+ deprecated — and the config value is engine-shaped: `defineConfig` from
218
+ `@prisma/cli-engine` wraps the whole ORM config as its `orm` section. Rename the file,
219
+ then wrap the existing export: alias the current `defineConfig` import (from the target
220
+ facade or CLI config-types) as `ormConfig` and write
221
+ `export default defineConfig({ orm: ormConfig({ ...existing config... }) })`, adding
222
+ `@prisma/cli-engine` to devDependencies. Both the deprecated filename and the flat shape
223
+ still load, each printing a deprecation warning on stderr, so the two steps can land
224
+ separately; anything asserting clean stderr around CLI invocations sees the warning
225
+ until both are done.
226
+ detection:
227
+ glob: "**/prisma*.config.*"
228
+ contains:
229
+ - "defineConfig"
230
+ anyMatch: true
231
+ - id: published-prisma-next-bin-retired
232
+ summary: |
233
+ Nothing published ships a `prisma-next` bin anymore: `@prisma/orm-toolchain` publishes
234
+ the `orm` command family at `@prisma/orm-toolchain/cli` and no bin, and the database
235
+ facades forward no launcher. The only user-facing binary is the unified `prisma` CLI
236
+ (the prisma-cli distribution), which mounts the same commands. Replace
237
+ `prisma-next <command>` invocations in package scripts and CI with the unified CLI's
238
+ equivalent, and drop any dependency that was taken only to put the bin on PATH.
239
+ detection:
240
+ glob: "**/package.json"
241
+ contains:
242
+ - "prisma-next"
243
+ anyMatch: true
244
+ - id: raw-is-a-reserved-storage-namespace
245
+ summary: |
246
+ A storage namespace named `raw` is refused: the SQL surface exposes the whole-query raw
247
+ statement tag as `db.sql.raw`, so a namespace of that name would be unreachable through
248
+ the builder while the emitted types still promised its tables. Building the client raises
249
+ `ORM.NAMESPACE_RESERVED` naming the namespace. Rename the namespace in your schema —
250
+ `@@schema("raw")` becomes any other name — re-emit the contract, and plan the rename
251
+ against the database as you would any other namespace rename. Only `raw` is reserved; every other namespace name is unaffected.
252
+ detection:
253
+ glob: "**/*.{prisma,json}"
254
+ contains:
255
+ - '@@schema("raw")'
256
+ - '"raw": {'
257
+ anyMatch: true
258
+ - id: codec-ids-are-checked-where-they-are-authored
259
+ summary: |
260
+ A codec id you write in a prepared declaration or in a contract-bound raw fragment is
261
+ now checked against your contract's codec map, so an id the contract does not carry is
262
+ a compile error where before it compiled and failed at execution with
263
+ `RUNTIME.PARAM_REF_MISSING_CODEC`. The usual cause is an unversioned id:
264
+ `db.prepare({ id: 'pg/int4' }, ...)` becomes `db.prepare({ id: 'pg/int4@1' }, ...)`, and
265
+ `fns.raw\`...\`.returns('pg/text')` becomes `.returns('pg/text@1')`. Take the id from your
266
+ emitted `contract.d.ts` — every id it carries now completes at both positions, so the
267
+ editor offers the correct spelling rather than accepting a wrong one. Raw fragments
268
+ built through a contract-free lane are unaffected; they have no map to check against.
269
+ detection:
270
+ glob: "**/*.{ts,tsx,mts,cts}"
271
+ contains:
272
+ - "prepare({"
273
+ - ".returns('pg/"
274
+ - ".returns(\"pg/"
275
+ anyMatch: true
276
+ ---
277
+
278
+ # 8.0.0-rc.1 → 8.0.0-rc.2 — User upgrade instructions
279
+
280
+ ## `aggregate-methods-come-from-the-emitted-contract`
281
+
282
+ Which aggregate methods exist is now the contract's answer rather than a fixed list in the client. The emitted `contract.d.ts` carries an `AggregateTypes` block naming every operation your target and extensions declare, and each surface below is derived from it:
283
+
284
+ | Surface | What it offers |
285
+ | --- | --- |
286
+ | `db.orm.User.aggregate((a) => …)` | one selector method per declared operation |
287
+ | `db.orm.User.groupBy('kind').aggregate((a) => …)` | the same |
288
+ | `db.orm.User.groupBy('kind').having((h) => …)` | the same, restricted to `count` / `sum` / `avg` / `min` / `max` |
289
+ | `db.orm.User.include('posts', (posts) => posts.count())` | one reducer per declared operation |
290
+ | `db.sql.public.user.select('n', (f, fns) => fns.count())` | one function per declared operation |
291
+
292
+ **If your contract is emitted, re-emit it — and keep reading.** Deriving the surface takes nothing away on its own: whatever the composed targets and extensions declare is what the block names. But the built-in targets changed what they declare in this same release. PostgreSQL now contributes eight operations and SQLite seven, and the bare results over integer columns moved — `count`, `sum`, and `avg`. `min` / `max` did not, nor did `sum` and `avg` over a float, `numeric`, or temporal column, nor `sum` over an `UnboundedInt` column. Two entries below carry those changes, and a re-emitted contract lands you in both: [`count-over-a-field-counts-that-field`](#count-over-a-field-counts-that-field) and [`aggregate-defaults-are-js-native-numbers`](#aggregate-defaults-are-js-native-numbers).
293
+
294
+ **If your contract's block is unknown, the surfaces are empty.** Two situations reach that state:
295
+
296
+ - You author the contract in TypeScript with `defineContract(...)` and pass the value straight to the client, never running `prisma-next contract emit`. A contract value built in code carries no emitted type maps.
297
+ - You are still using a `contract.d.ts` emitted before 8.0.0-rc.1, when the `AggregateTypes` block did not exist yet.
298
+
299
+ Either way the call is a compile error:
300
+
301
+ ```text
302
+ Property 'count' does not exist on type 'AggregateOperationsUnavailable'.
303
+ ```
304
+
305
+ The type is an empty interface whose name is the diagnosis; hovering it shows the reason. Nothing changes at runtime — the client installs its aggregate methods from the composed target and extensions, exactly as it always has.
306
+
307
+ **Preferred fix: emit the contract.** Run
308
+
309
+ ```bash
310
+ prisma-next contract emit
311
+ ```
312
+
313
+ and type the client from the emitted `Contract`. That gives you the whole aggregate surface back, plus the per-operation result types and the field names each operation admits.
314
+
315
+ **Alternative, where the contract is deliberately un-emitted:** cast the builder and dispatch by name.
316
+
317
+ ```ts
318
+ import type { AggregateSpec } from '@prisma/orm-postgres/orm-client';
319
+
320
+ type DynamicAggregates = Record<string, (field?: string) => AggregateSpec[string]>;
321
+
322
+ const stats = await db.User.aggregate((aggregate) => {
323
+ const dynamic = aggregate as DynamicAggregates;
324
+ return { total: dynamic['sum']!('views'), peak: dynamic['max']!('views') };
325
+ });
326
+ ```
327
+
328
+ If you previously widened the *argument* instead — `aggregate.sum('views' as never)`, which compiled because the admitted field names were already `never` for such a contract — move the cast from the argument to the builder and pass the field name as a plain string.
329
+
330
+ ## `count-over-a-field-counts-that-field`
331
+
332
+ ```ts
333
+ await db.User.aggregate((aggregate) => ({ all: aggregate.count() }));
334
+ // SELECT COUNT(*) …
335
+
336
+ await db.User.aggregate((aggregate) => ({ withEmail: aggregate.count('email') }));
337
+ // SELECT COUNT("email") … — rows whose email is NULL are not counted
338
+ ```
339
+
340
+ The second form used to render `COUNT(*)`: the argument was accepted and thrown away. Both arities are now read off what the target declares for `count` — PostgreSQL declares it over any input, which means both a call with a value and a call without one — so the argument is honoured.
341
+
342
+ No previously type-safe call changes meaning, because `count` took no argument and the field-taking form did not typecheck. Sweep instead for calls that bypassed the types:
343
+
344
+ - a `// @ts-expect-error` directly above a `count(...)` call — where the argument is a field your contract admits, that suppression is now unused and TypeScript flags the unused directive;
345
+ - `count(field as never)` or `count(field as any)`;
346
+ - dynamic dispatch through a `Record<string, …>` cast.
347
+
348
+ For each, decide which count you meant: `count()` for rows, `count(field)` for that field's non-null values.
349
+
350
+ ## `aggregate-defaults-are-js-native-numbers`
351
+
352
+ The aggregate vocabulary is split in two. The bare operations answer in the type a JS developer expects; three new suffixed operations answer losslessly.
353
+
354
+ | Call | Reads as | Empty input set |
355
+ | --- | --- | --- |
356
+ | `count()` | `number` | `0` |
357
+ | `countBigInt()` | `bigint` | `0n` |
358
+ | `sum(field)` over `Int` / `BigInt` / `BigIntNumber` | `number \| null` | `null` |
359
+ | `sumBigInt(field)` over any integer column | `bigint \| null` | `null` |
360
+ | `avg(field)` over any integer column | `number \| null` | `null` |
361
+ | `avgDecimal(field)` over any integer or `Decimal` column | decimal `string \| null` | `null` |
362
+
363
+ These do not move: `min` / `max` keep the column's own type; `sum` and `avg` over a float column stay `number`; `sum` over `Decimal` stays a decimal string; `sum` over `UnboundedInt` stays a `bigint`; and the ORM's `having(...)` operands stay plain numbers, because the ORM types a HAVING comparand as `number` whatever result type the aggregate carries.
364
+
365
+ The SQL builder's comparison operands are the other case, and they do move. `fns.gt(a, b)` types both sides from one codec, so a literal compared against an aggregate follows that aggregate's result codec:
366
+
367
+ ```ts
368
+ // before
369
+ .having((_f, fns) => fns.gt(fns.count(), 1n))
370
+ // after
371
+ .having((_f, fns) => fns.gt(fns.count(), 1))
372
+ ```
373
+
374
+ Make the same one-token change wherever a `fns.count()` or an integer `fns.sum(...)` meets a literal — in `having(...)`, in `where(...)`, and inside a larger expression.
375
+
376
+ SQLite states the same policy in its own terms — `count`, integer `sum`, and `avg` are all `number`, with `countBigInt` and `sumBigInt` beside them. **SQLite has no `avgDecimal`**: an exact mean needs a decimal type the database does not have, so the method is absent from a SQLite contract and calling it is a type error.
377
+
378
+ ### What to change
379
+
380
+ 1. **Re-emit first.** `prisma-next contract emit` rewrites the `AggregateTypes` block. Until you do, the types describe the old results and the three new methods do not exist.
381
+ 2. **Unwrap the bigint handling around bare aggregates.** Each of these is now noise or a type error:
382
+
383
+ ```ts
384
+ const { total } = await db.User.aggregate((a) => ({ total: a.count() }));
385
+
386
+ total === 2n // ← was needed; now `total === 2`
387
+ Number(total) // ← was needed; `total` is already a number
388
+ String(total) // ← was needed for JSON; JSON.stringify handles it now
389
+ JSON.stringify(rows, (_k, v) => typeof v === 'bigint' ? String(v) : v)
390
+ // ↑ the replacer can go
391
+ ```
392
+
393
+ 3. **Change the method, not the value, where you need exactness.** A decimal-string average was doing real work in a money or reporting path; `avgDecimal(field)` returns exactly what `avg(field)` used to, and `countBigInt()` exactly what `count()` used to.
394
+
395
+ `sumBigInt(field)` matches the old `sum(field)` everywhere but one column class. On PostgreSQL, a `BigInt` or `BigIntNumber` column's `sum` used to be a decimal `string`, because the database totals a 64-bit column as `numeric`; `sumBigInt` reads that same total as a `bigint`. So a money path summing a `BigInt` column gets a `bigint` where it had a string — exact either way, but a different type. Convert at the consumption site (`String(total)`) if a decimal library or a string comparison is downstream. Over every other integer column, and on SQLite, `sumBigInt` is the old `sum` unchanged.
396
+
397
+ ### The bare operations throw rather than round
398
+
399
+ A `count()`, or a `sum()` over an integer column, whose value passes ±(2^53 − 1) raises a structured error instead of answering with a rounded one:
400
+
401
+ ```text
402
+ RUNTIME.DECODE_FAILED: pg/int8number@1 value must be an integer within
403
+ the safe integer range, got 9007199254740992
404
+ ```
405
+
406
+ That is the trade these defaults make: a value you can compare, serialise, and do arithmetic with, and a loud failure rather than a quietly wrong total. It fires on the `.include()` path too — the reducer's value travels as a JSON number, but the guard runs after the parse, and rounding is monotone, so a value that was outside the range is still outside it after parsing.
407
+
408
+ Those two are the results a guarded integer codec produces. A `sum` over a `Decimal`, `UnboundedInt`, or float column stays in that column's own family and has no such guard, and neither does `avg`, which is a fraction already and rounds as any double does — reach for `avgDecimal` where the exact mean matters.
409
+
410
+ Totals cross the boundary in practice where counts do not: summing 64-bit IDs, or cent amounts across a large table. If a `sum` in your code can plausibly get there, move it to `sumBigInt` now rather than waiting for the error in production.
411
+
412
+ ### If you are upgrading from before 8.0.0-rc.1
413
+
414
+ You cross two hops, and the aggregate result types move in both. The `0.17 → 8.0.0-rc.1` step changes `count()` to `bigint` and integer averages to decimal strings; this step changes those same calls to `number` and adds the suffixed variants. Apply the steps in order — that is what the upgrade skill does — but do the sweeping once, at the end: for `count()` and integer `sum()` / `avg()`, the destination is `number`, which is where a pre-8.0.0-rc.1 codebase already was. What genuinely changed for you across both hops is the throw outside ±(2^53 − 1) on `count()` and integer `sum()`, and the three new operations; the empty-relation `count` ends where it started, at `0`.
415
+
416
+ ## `integer-columns-refuse-the-wrong-js-type`
417
+
418
+ Writing a JS `number` to a `BigInt` or `UnboundedInt` column now fails before any SQL runs:
419
+
420
+ ```text
421
+ RUNTIME.ENCODE_FAILED: pg/int8@1 value must be a bigint, got number 9
422
+ ```
423
+
424
+ The codec used to accept the number and stringify it, so `9` wrote `9` and `1.5` wrote `1.5` — a fractional value in an integer column, unremarked. The mirror case reports as clearly: passing `9n` to a `BigIntNumber` column names the type that arrived rather than complaining about a range the value is plainly inside.
425
+
426
+ No typed call site changes, because a `BigInt` column's application type has always been `bigint`. Sweep the ones that got past the types:
427
+
428
+ - a `// @ts-expect-error` over a `create(...)` / `update(...)` value;
429
+ - `value as never` or `value as any` in a write;
430
+ - a value that came out of `JSON.parse`, which yields numbers and never bigints;
431
+ - dynamic dispatch through a `Record<string, unknown>`.
432
+
433
+ Convert each to the column's own type — `BigInt(value)` for a `bigint` column, and a plain number for a `BigIntNumber` one.
434
+
435
+ Schema-written defaults need nothing. `BigInt @default(0)` still emits and still migrates: the JSON side of these codecs accepts a safe-integer number, because a schema language writes no `bigint` literal, and only the query-parameter side requires the exact type.
436
+
437
+
438
+ ## `config-file-is-prisma-config-with-an-orm-section`
439
+
440
+ Two mechanical steps, in either order:
441
+
442
+ 1. `git mv prisma-next.config.ts prisma.config.ts` (same for `.mts` / `.mjs` variants).
443
+ 2. Wrap the flat export in the engine shape:
444
+
445
+ ```ts
446
+ // before
447
+ import { defineConfig } from '@prisma/orm-postgres/config';
448
+ export default defineConfig({ ... });
449
+
450
+ // after
451
+ import { defineConfig } from '@prisma/cli-engine';
452
+ import { defineConfig as ormConfig } from '@prisma/orm-postgres/config';
453
+ export default defineConfig({ orm: ormConfig({ ... }) });
454
+ ```
455
+
456
+ Add `@prisma/cli-engine` to `devDependencies`. The inner config is unchanged — only the file
457
+ name and the outer wrapper move. The loader still discovers the deprecated filename and still
458
+ accepts the flat shape, each with a stderr deprecation warning, so nothing breaks mid-rename;
459
+ finish both steps to silence the warnings.
460
+
461
+ ## `published-prisma-next-bin-retired`
462
+
463
+ `prisma-next ...` in a package script resolved through a bin the database facades forwarded
464
+ from the toolchain. That chain is gone: the published toolchain is bin-less and exports the
465
+ `orm` command family at `@prisma/orm-toolchain/cli` for the unified `prisma` CLI (the
466
+ prisma-cli distribution) to mount. Point scripts and CI at the unified CLI, which serves the
467
+ same command paths.
468
+
469
+ <!--
470
+ PR #30049: `changes: []`. The 8.0.0-rc.2 release cut. The example diff is the lockstep version bump, the `@prisma/cli-engine` peer moving to 0.1.1, and the supabase contract fixtures re-emitted so their embedded extension version matches. No user API, contract, configuration, generated-artifact, or source translation follows from it — the consumer-facing changes this release ships are the entries above, recorded by the PRs that made them.
471
+ PR #29910: `changes: []`. The example changes repair test instrumentation and fixture/runtime isolation after the driver SPI split; they require no user API, contract, configuration, generated-artifact, or source translation.
472
+ PR #29902: `changes: []`. Generated contracts gain additive aggregate rows for new opt-in integer representation codecs, but existing schemas and source require no migration; users re-emit only when adopting the new target-scoped types.
473
+ PR #29950: `changes: []`. The demo applications adopt the integer representation types and the precision-preserving aggregates on their own models, and the reference docs gain the matching examples; the diff is confined to example apps and documentation and requires no user API, contract, configuration, generated-artifact, or source translation.
474
+ PR #29939: `changes: []`. Dependabot's weekly runtime-dependency bumps (`ws`, `lucide-react`, `postcss`, `uniku`, `@vercel/detect-agent`, and the `@types/node` / `@types/pg` / `tsx` catalog entries). The example diff is dependency version strings, and requires no user API, contract, configuration, generated-artifact, or source translation.
475
+ PR #29940: `changes: []`. Dependabot's weekly dev-dependency bumps (type packages, wrangler, biome, test tooling) plus the matching `biome.jsonc` `$schema` realignment; the example diffs are devDependency version strings and a schema URL, and require no user API, contract, configuration, generated-artifact, or source translation.
476
+ PR #29965: `changes: []`. Dependabot's dev-dependency bumps (`wrangler`, `@cloudflare/vitest-pool-workers`, `@biomejs/biome`) plus the matching `biome.jsonc` `$schema` realignment to 2.5.7; the example diffs are devDependency version strings and a schema URL, and require no user API, contract, configuration, generated-artifact, or source translation.
477
+ PR #30031: `changes: []`. Dependabot's weekly runtime-dependency bumps (`esbuild`, `evlog`, `next`). The example diff is dependency version strings, and requires no user API, contract, configuration, generated-artifact, or source translation.
478
+ -->
479
+
480
+ ## Regenerating is the first step
481
+
482
+ `prisma-next contract emit` rewrites `contract.json` / `contract.d.ts` into the new check shape
483
+ and mints the wire names every later step refers to. Do it before editing migration files, so
484
+ the constraint names you paste into `addCheckConstraint` / `checkExpression` are the ones the
485
+ contract actually declares.
486
+ ## What the first plan after upgrading looks like
487
+
488
+ For each enum-restricted column: a DROP of the old unsuffixed constraint and an ADD of the
489
+ wire-named one. For each list column: an ADD of an element-non-null constraint that was
490
+ previously created without ever being declared. Neither is a data change — but the DROP is
491
+ classified `destructive`, so a plan run under an additive-only policy converges only partway
492
+ and `db verify --strict` will report the leftovers until you allow it.
493
+
494
+ There may also be a third kind of operation, and it is the one to read carefully. Introspection
495
+ no longer parses predicates: it captures every CHECK constraint on a managed table verbatim,
496
+ including the hand-written and platform-installed ones that earlier versions were structurally
497
+ unable to see. A check the contract does not declare is an undeclared extra, so
498
+ `db verify --strict` reports it and a plan run under a policy that allows `destructive` emits a
499
+ `dropCheckConstraint` for it — a constraint you wrote by hand and that has been enforcing your
500
+ data all along. Grep the first plan for `dropCheckConstraint` and check every constraint named:
501
+
502
+ - to keep it, run plans for that table under an additive-only policy. The constraint stays in
503
+ place and keeps enforcing; plain `db verify` tolerates it, and only `--strict` reports it as
504
+ an undeclared extra. Better: declare it with `@@check(expression: "…", map: "<physical name>")`,
505
+ or re-run `contract infer`, which now emits exactly that for every live check Prisma Next did
506
+ not derive — the constraint becomes declared and stops being an extra at all;
507
+ - if it was already dead, let the drop through under the destructive plan.
508
+
509
+ Nothing drops silently — an additive-only policy never emits the operation at all — but the
510
+ first plan after upgrading is the moment to look, because it is the first plan that can see
511
+ these constraints.
512
+
513
+ ## `runtime-query-execute-hard-cut`
514
+
515
+ Runtime operations state whether the caller expects rows or statement statistics. Do not apply a global `execute` → `query` replacement: an insert, update, or delete that does not return rows belongs on `execute`, while a select, a returning write, a Mongo command-result plan, or any plan whose result is iterated, awaited as an array, indexed, decoded, or otherwise read belongs on `query`.
516
+
517
+ | 8.0.0-rc.1 | 8.0.0-rc.2 |
518
+ | --- | --- |
519
+ | `await runtime.execute(rowPlan)` | `await runtime.query(rowPlan)` |
520
+ | `runtime.execute(rowPlan).toArray()` | `runtime.query(rowPlan).toArray()` |
521
+ | `await target.queryPrepared(prepared, params, options?)` | `await prepared.query(target, params, options?)` |
522
+ | `await runtime.execute(nonReturningWrite)` with ignored rows | `await runtime.execute(nonReturningWrite)` and ignore the returned statistics |
523
+ | A count or status derived from rows returned by a non-returning write | `const stats = await runtime.execute(writePlan)` and use `stats.affectedRows` |
524
+
525
+ Apply the same classification to connection and transaction scopes. `query()` and `prepared.query(target, params, options?)` remain lazy row results, so consume them inside the scope when their connection or transaction must remain valid. `execute()` is eager and resolves to `{ affectedRows: number }`; it does not return an iterable, and `affectedRows` must not be synthesized from a row array's length.
526
+
527
+ If the application defines runtime middleware, use the operation-specific hooks: query interception returns `{ rows }`, execute interception returns `{ stats }`, and completion handlers use their matching `afterQuery` or `afterExecute` result. `beforeQuery` / `interceptQuery` / `onRow` / `afterQuery` and `beforeExecute` / `interceptExecute` / `afterExecute` are distinct capabilities, while `beforeCompile` remains shared. Hook selection carries the operation distinction; contexts and results have no operation discriminator. Row-oriented middleware must not derive statistics from rows, and no compatibility aliases or generic fallback hooks are provided.
528
+
529
+ Tests that observe row queries should spy on `driver.query`, not `driver.execute`; statistics tests should observe `driver.execute`. Keep separate row-result and statistics queues so a wrong route fails loudly. Behavior intended for both operations assigns one private implementation to both corresponding hook names. Mongo keeps `db.query` as the static builder and has no row-execution `db.execute` facade method: build with `db.query`, obtain the connected runtime, then query through `(await db.runtime()).query(plan)`.
530
+
531
+ Search broadly for `.execute(` and retired prepared execution, then inspect each candidate's plan and downstream use. Rows being iterated, indexed, decoded, compared as arrays, or passed to a row mapper identify `query`; reads of `affectedRows` or ignored results from non-returning DML identify `execute`. Leave unrelated APIs such as migration runners alone.
532
+
533
+ ## `raw-is-a-reserved-storage-namespace`
534
+
535
+ The SQL surface answers `db.sql.raw` with the whole-query raw statement tag, so `raw` is no
536
+ longer available as a storage namespace name. A contract that declares one is refused where the
537
+ client is built, before any query runs:
538
+
539
+ ```text
540
+ ORM.NAMESPACE_RESERVED: The SQL surface exposes the raw statement tag as "db.raw", so a storage
541
+ namespace named "raw" cannot be reached through it. Rename the namespace in the schema.
542
+ ```
543
+
544
+ Rename the namespace and re-emit:
545
+
546
+ ```prisma
547
+ // Before: unreachable through the builder
548
+ model Event {
549
+ id String @id
550
+ @@schema("raw")
551
+ }
552
+
553
+ // After: any other name
554
+ model Event {
555
+ id String @id
556
+ @@schema("ingest")
557
+ }
558
+ ```
559
+
560
+ Then re-emit the contract, and plan the rename against the database as you would any
561
+ other namespace rename — the physical schema still carries the old name until a plan moves it.
562
+ Only `raw` is reserved; no other namespace name is affected.
563
+
564
+ ## `codec-ids-are-checked-where-they-are-authored`
565
+
566
+ Two places where you write a codec id by hand now check it against the codec map your
567
+ contract emitted: the declaration passed to `db.prepare(...)`, and `.returns(...)` on a raw
568
+ fragment built from a contract-bound tag.
569
+
570
+ ```ts
571
+ // Before: compiled, then failed at execution with RUNTIME.PARAM_REF_MISSING_CODEC
572
+ await db.prepare({ id: 'pg/int4' }, (sql, params) => ...);
573
+ const upper = fns.raw`UPPER(${f.email})`.returns('pg/text');
574
+
575
+ // After: the id is the one your contract carries
576
+ await db.prepare({ id: 'pg/int4@1' }, (sql, params) => ...);
577
+ const upper = fns.raw`UPPER(${f.email})`.returns('pg/text@1');
578
+ ```
579
+
580
+ The compile error is the messenger, not the injury: an id no codec registry carries could
581
+ never have executed. If a declaration or fragment of yours stops compiling, the id in it was
582
+ already wrong at runtime.
583
+
584
+ Read the correct spelling off your emitted `contract.d.ts`, or let the editor offer it — the
585
+ ids now complete at both positions, which is the other half of this change.
586
+
587
+ A raw fragment built through a contract-free lane keeps accepting any string: that lane has
588
+ no contract map to check an id against.
@@ -0,0 +1,5 @@
1
+ ---
2
+ from: "8.0.0-rc.2"
3
+ to: "8.0.0-rc.3"
4
+ changes: []
5
+ ---