@prisma/orm-mongo 8.0.0-rc.17-dev.12 → 8.0.0-rc.17-dev.14
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/orm-mongo",
|
|
3
|
-
"version": "8.0.0-rc.17-dev.
|
|
3
|
+
"version": "8.0.0-rc.17-dev.14",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
"skills"
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@prisma/orm-family-mongo": "8.0.0-rc.17-dev.
|
|
14
|
-
"@prisma/orm-framework": "8.0.0-rc.17-dev.
|
|
15
|
-
"@prisma/orm-target-mongo": "8.0.0-rc.17-dev.
|
|
16
|
-
"@prisma/orm-toolchain": "8.0.0-rc.17-dev.
|
|
13
|
+
"@prisma/orm-family-mongo": "8.0.0-rc.17-dev.14",
|
|
14
|
+
"@prisma/orm-framework": "8.0.0-rc.17-dev.14",
|
|
15
|
+
"@prisma/orm-target-mongo": "8.0.0-rc.17-dev.14",
|
|
16
|
+
"@prisma/orm-toolchain": "8.0.0-rc.17-dev.14",
|
|
17
17
|
"mongodb-connection-string-url": "^7.0.1",
|
|
18
18
|
"pathe": "^2.0.3",
|
|
19
19
|
"tinyglobby": "^0.2.17"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@internal/mongo": "8.0.0-rc.17-dev.
|
|
23
|
-
"@repo/tsconfig": "8.0.0-rc.17-dev.
|
|
24
|
-
"@repo/tsdown": "8.0.0-rc.17-dev.
|
|
22
|
+
"@internal/mongo": "8.0.0-rc.17-dev.14",
|
|
23
|
+
"@repo/tsconfig": "8.0.0-rc.17-dev.14",
|
|
24
|
+
"@repo/tsdown": "8.0.0-rc.17-dev.14",
|
|
25
25
|
"tsdown": "0.22.14",
|
|
26
26
|
"typescript": "5.9.3"
|
|
27
27
|
},
|
package/skills/prisma-8/SKILL.md
CHANGED
|
@@ -125,7 +125,7 @@ Then run `pnpm prisma contract emit` (or rely on the Vite plugin — see `refere
|
|
|
125
125
|
@@index([authorId], where: sql`(archived_at IS NULL)`, name: "posts_author_active")
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
`name:` declares a wire-named index (physical name `<name>_<8-hex hash>`, renames plan as `ALTER INDEX … RENAME`); `map:` adopts an exact physical name verbatim (for infer-captured objects — combining it with a SQL body warns, because drift detection byte-compares the authored text against Postgres's reprint). An `expression:` requires `name:` or `map:`. The TS builder mirrors this via `constraints.index([cols.x], {...})` / `constraints.index({ expression, ... })` — see `packages/2-sql/2-authoring/contract-ts/README.md`.
|
|
128
|
+
`name:` declares a wire-named index (physical name `<name>_<8-hex hash>`, renames plan as `ALTER INDEX … RENAME`); `map:` adopts an exact physical name verbatim (for infer-captured objects — combining it with a SQL body warns, because drift detection byte-compares the authored text against Postgres's reprint). An `expression:` requires `name:` or `map:`. The TS builder mirrors this via `constraints.index([cols.x], {...})` / `constraints.index({ expression, ... })`, where `expression` and `where` are `sql` values such as ``sql`lower(email)` `` (a string does not compile) — see `packages/2-sql/2-authoring/contract-ts/README.md`.
|
|
129
129
|
|
|
130
130
|
**Full-text search indexes (PostgreSQL).** Do not hand-write the `to_tsvector` expression — Postgres only uses the index when the query carries the same search document: the same columns, configuration and weights. Declare `@@fullTextIndex`, and the index and the queries `fullTextMatches` / `fullTextRank` / `fullTextHeadline` build are rendered from the same definition (see `references/queries-postgres.md`):
|
|
131
131
|
|
|
@@ -138,7 +138,7 @@ Then run `pnpm prisma contract emit` (or rely on the Vite plugin — see `refere
|
|
|
138
138
|
|
|
139
139
|
The fields are one field, or a list whose items are fields or lists of fields. Each top-level item is a weight group, strongest first (`A` to `D`, so at most four groups); fields in a nested list share a weight. `[title, body]` is two groups, `[[title, body]]` one. A single field has no weight. Diagnostics refuse more than four groups, an empty group, a field named twice, an unknown field and a field that is not text.
|
|
140
140
|
|
|
141
|
-
The TS builder has the same helper: `fullTextIndex(cols.text, { name: 'message_text_search' })` or `fullTextIndex([[cols.title, cols.subtitle], cols.body], { name: 'post_search' })`, from `@prisma/orm-postgres/contract-builder`, inside the model's `sql({ indexes: [...] })`. Both take an optional `language` (default `english`, from the same allowlist the operations accept), an optional `where:` for a partial index, and `name:` xor `map:`. Both are repeatable. In the SQL builder, pass the index itself, `table.indexes.<name>`, to `fullTextMatches` and `fullTextRank`, which then search its document with its groups and language. A column or a `fullTextDocument` given other groups or another `language` than the index is silent, costing the index and falling back to a sequential scan. The parser that builds the query (`websearchToTsquery` and the others) takes its own `language` for the query side; it does not affect index use. With `map:` the index keeps the exact database name you give it, and `db verify` compares the rendered search document with the text Postgres prints back for the index exactly, character for character. Postgres prints it in its own form (`to_tsvector('english'::regconfig, title)`), so a `map:` full-text index reports drift; `@@fullTextIndex` and `fullTextIndex` warn about this with `PN_EXACT_NAME_BODY_COMPARISON`. Use `name:` unless the database already has the index under that name.
|
|
141
|
+
The TS builder has the same helper: `fullTextIndex(cols.text, { name: 'message_text_search' })` or `fullTextIndex([[cols.title, cols.subtitle], cols.body], { name: 'post_search' })`, from `@prisma/orm-postgres/contract-builder`, inside the model's `sql({ indexes: [...] })`. Both take an optional `language` (default `english`, from the same allowlist the operations accept), an optional `where:` for a partial index (a `sql` value, ``where: sql`archived_at IS NULL` ``), and `name:` xor `map:`. Both are repeatable. In the SQL builder, pass the index itself, `table.indexes.<name>`, to `fullTextMatches` and `fullTextRank`, which then search its document with its groups and language. A column or a `fullTextDocument` given other groups or another `language` than the index is silent, costing the index and falling back to a sequential scan. The parser that builds the query (`websearchToTsquery` and the others) takes its own `language` for the query side; it does not affect index use. With `map:` the index keeps the exact database name you give it, and `db verify` compares the rendered search document with the text Postgres prints back for the index exactly, character for character. Postgres prints it in its own form (`to_tsvector('english'::regconfig, title)`), so a `map:` full-text index reports drift; `@@fullTextIndex` and `fullTextIndex` warn about this with `PN_EXACT_NAME_BODY_COMPARISON`. Use `name:` unless the database already has the index under that name.
|
|
142
142
|
|
|
143
143
|
The contract stores the index as data, not SQL: an index of type `fullText` whose `columns` are the covered storage columns and whose `options` are `{ weightGroups, language }`, the weight groups as storage column names. The DDL is a GIN index over the rendered document, `to_tsvector('<language>', "<column>")` for one field, and `setweight(...) || ...` with every column wrapped in `coalesce` for several. `@@index(expression: …)` remains only for expressions this attribute does not cover.
|
|
144
144
|
|
|
@@ -335,7 +335,7 @@ model Order {
|
|
|
335
335
|
- **`name:`** — declaring a new rule. Prisma 8 picks the physical constraint name and future plans compare by that name, so Postgres's own reprint of your predicate (which rarely matches what you typed byte-for-byte) never causes false drift.
|
|
336
336
|
- **`map:`** — adopting a rule that already exists. Give the constraint's exact physical name and Prisma 8 compares the predicate byte-for-byte against what's live. This is the form `contract infer` writes for you (see *Workflow — Brownfield introspection* below) when it finds a hand-written check in the database. Every `map:` body warns at emit time (`PN_EXACT_NAME_BODY_COMPARISON`) — the warning fires on the text, not on who wrote it, so the check `contract infer` just wrote warns again on your next `contract emit` too. That is expected, not a defect: the comparison is still sound because both sides are Postgres's own reprint. Prefer `name:` for anything you're authoring fresh: your text and Postgres's reprint of it rarely match character-for-character, and a byte comparison reports that as drift even when both mean exactly the same thing. Reserve `map:` for adopting what's already there, where both sides are the database's own reprint and so do match.
|
|
337
337
|
|
|
338
|
-
A model can carry any number of `@@check` attributes. The TS builder mirrors this with `check({ expression, name })` / `check({ expression, map })` on a model's `.sql({ checks: [...] })`, next to `index()
|
|
338
|
+
A model can carry any number of `@@check` attributes. The TS builder mirrors this with `check({ expression, name })` / `check({ expression, map })` on a model's `.sql({ checks: [...] })`, next to `index()`; `expression` is a `sql` value, as in ``check({ expression: sql`total > 0`, name: 'order_total_positive' })``. The `sql` tag, from the same contract-builder module, may interpolate other `sql` values: ``sql`${owner} AND deleted_at IS NULL` ``.
|
|
339
339
|
|
|
340
340
|
Check constraints need the target's `checkConstraint` capability. Postgres has it; SQLite does not. `@@check` on a SQLite contract is rejected at authoring time; `check()` on a SQLite contract isn't caught until migration DDL is rendered, but either way you get a refusal, never a silently-dropped constraint.
|
|
341
341
|
|
|
@@ -413,7 +413,7 @@ await db.orm.public.Post.where((p) => and(created(since)(p), p.title.ilike('%orm
|
|
|
413
413
|
|
|
414
414
|
Both forms check values against the codec's type, not the field's. For a field that narrows its codec's values, such as an enum stored as `pg/text@1`, they accept values the field would refuse: `row.kind.eq('superuser')` compiles even when `kind` has no such member. Write a filter on such a field inline, on the model, where the field's own type checks the value.
|
|
415
415
|
|
|
416
|
-
**The same `select` and `include` in several queries.** Define it once with `.fragment(...)` on
|
|
416
|
+
**The same `select` and `include` in several queries.** Define it once with `.fragment(...)` on the model's root collection, such as `db.orm.public.Post`, run it with `.with(...)`, and name its row with `CollectionRowOf`:
|
|
417
417
|
|
|
418
418
|
```typescript
|
|
419
419
|
import type { CollectionRowOf } from '@prisma/orm-postgres/orm-client';
|
|
@@ -427,7 +427,7 @@ await db.orm.public.Post.where({ userId }).with(postSummary).limit(20).all();
|
|
|
427
427
|
await db.orm.public.User.include('posts', (posts) => posts.with(postSummary)).all();
|
|
428
428
|
```
|
|
429
429
|
|
|
430
|
-
The body receives the plain collection of the model, without a custom class's methods. Apply the fragment before `.select(...)` or `.variant(...)`: it is refused on a collection they narrowed. Its result is always typed as the plain collection, even when the body keeps the row, so a custom class's methods are gone after it, and
|
|
430
|
+
The body receives the plain collection of the model, without a custom class's methods. Apply the fragment before `.select(...)` or `.variant(...)`: it is refused on a collection they narrowed. Its result is always typed as the plain collection, even when the body keeps the row, so a custom class's methods are gone after it, and a filter or order applied before it is not recorded, although an earlier `.where(...)` still runs. `update` and `delete` are refused after it unless the body itself calls `where`, and `cursor` unless the body calls `orderBy`. For a filter on one model, use a class method or `db.orm.fragment`. A fragment for one model refuses a collection of another model or namespace at run time with `ORM.ARGUMENT_INVALID`. Calling `.fragment(...)` on a collection with chained calls throws `ORM.ARGUMENT_INVALID`, because the fragment is built from the model alone; a filter, an order or an include before it, or a receiver typed by a type parameter such as `this` in a class method, is a compile error. Inside a class method, chain on `this` directly instead.
|
|
431
431
|
|
|
432
432
|
**A field to order by, from a request.** Pass the request's string to `orderByField` with the fields the endpoint allows. Do not index the field proxy with the raw string:
|
|
433
433
|
|
|
@@ -442,7 +442,10 @@ node <skill>/upgrading/app/upgrades/8.0.0-rc.14-to-8.0.0-rc.15/scripts/data-type
|
|
|
442
442
|
|
|
443
443
|
`<skill>` is the directory of the synced `prisma-8` skill. Node 24 or later runs the TypeScript script directly; it needs no `tsx`. It reads and writes files only and needs no database. It rewrites every `*.json` file under the root that parses as a SQL contract in the old format (a column or `storage.types` entry that stores `nativeType`), skipping `node_modules`, `.git`, `dist` and `build`. That includes a test fixture of an old-format contract: if you keep such a fixture on purpose, restore it with git afterwards (`git restore <file>`), or keep it outside the project root. In each contract it rewrites, it also writes lists in this release's new form (`reemit-explicit-list-cardinality`): a list column or field stored as `many: true` becomes `many: { elementNullable: false }`, and `contract.d.ts` declares `many` on every column. This is the SQL part of `refresh-historical-list-contracts`.
|
|
444
444
|
|
|
445
|
-
On PostgreSQL, a list column of an enum keeps the membership check its database has, because the database still holds that check. Run `prisma db sign` before you emit the contract again. The next `prisma contract emit` writes the check as `array_remove(…) <@ ARRAY[…]` under a new name; `prisma migration plan` then writes a migration that drops the old check and adds the new one, and `prisma db migrate` applies it. The plan warns that dropping the old check may lose data; it does not, because only the check changes, not the column. If you already emitted before signing, `db sign` reports the new check as missing:
|
|
445
|
+
On PostgreSQL, a list column of an enum keeps the membership check its database has, because the database still holds that check. Run `prisma db sign` before you emit the contract again. The next `prisma contract emit` writes the check as `array_remove(…) <@ ARRAY[…]` under a new name; `prisma migration plan` then writes a migration that drops the old check and adds the new one, and `prisma db migrate` applies it. The plan warns that dropping the old check may lose data; it does not, because only the check changes, not the column. If you already emitted before signing, `db sign` reports the new check as missing:
|
|
446
|
+
|
|
447
|
+
- In a project with migrations, sign each database with the storage hash the script printed (`prisma db sign <new hash>`), then plan and migrate as above.
|
|
448
|
+
- In a project without migrations, kept with `db init` or `db update`, run `prisma db update` and type the database name when it asks; where nobody can answer, run `prisma db update --no-interactive --confirm <database>`. It drops the old check and adds the new one, and `prisma db verify` then passes. `prisma db sign <new hash>` fails there with `MIGRATION.REF_NOT_FOUND`, because no migration holds that hash.
|
|
446
449
|
|
|
447
450
|
If the script stops on an error, for example on a full disk, it prints the error and `the upgrade stopped partway, run the script again to finish it`, and exits 1. After an error, Ctrl-C or a crash, run it again: it finishes the upgrade. A file the script was writing at that moment is either unchanged or complete, and it removes its own temporary files (ending in `.data-type-in-contract-tmp`) on the next run.
|
|
448
451
|
|