@prisma/orm-mongo 8.0.0-rc.14-dev.43 → 8.0.0-rc.14-dev.44
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.14-dev.
|
|
3
|
+
"version": "8.0.0-rc.14-dev.44",
|
|
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.14-dev.
|
|
14
|
-
"@prisma/orm-framework": "8.0.0-rc.14-dev.
|
|
15
|
-
"@prisma/orm-target-mongo": "8.0.0-rc.14-dev.
|
|
16
|
-
"@prisma/orm-toolchain": "8.0.0-rc.14-dev.
|
|
13
|
+
"@prisma/orm-family-mongo": "8.0.0-rc.14-dev.44",
|
|
14
|
+
"@prisma/orm-framework": "8.0.0-rc.14-dev.44",
|
|
15
|
+
"@prisma/orm-target-mongo": "8.0.0-rc.14-dev.44",
|
|
16
|
+
"@prisma/orm-toolchain": "8.0.0-rc.14-dev.44",
|
|
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.14-dev.
|
|
23
|
-
"@repo/tsconfig": "8.0.0-rc.14-dev.
|
|
24
|
-
"@repo/tsdown": "8.0.0-rc.14-dev.
|
|
22
|
+
"@internal/mongo": "8.0.0-rc.14-dev.44",
|
|
23
|
+
"@repo/tsconfig": "8.0.0-rc.14-dev.44",
|
|
24
|
+
"@repo/tsdown": "8.0.0-rc.14-dev.44",
|
|
25
25
|
"tsdown": "0.22.14",
|
|
26
26
|
"typescript": "5.9.3"
|
|
27
27
|
},
|
package/skills/prisma-8/SKILL.md
CHANGED
|
@@ -15,7 +15,7 @@ description: >-
|
|
|
15
15
|
ORM 7 or earlier (schema.prisma + @prisma/client).
|
|
16
16
|
metadata:
|
|
17
17
|
library: '@prisma/orm-mongo'
|
|
18
|
-
library_version: '8.0.0-rc.14-dev.
|
|
18
|
+
library_version: '8.0.0-rc.14-dev.44'
|
|
19
19
|
version: '2026-09-12'
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -62,7 +62,7 @@ Open the reference whose triggers match the task. If more than one matches, open
|
|
|
62
62
|
| Author migrations | [`references/migrations.md`](references/migrations.md) | `db update` vs `migration plan`, `db migrate`, `migration new`, `migration show`, `db update --dry-run`, `db verify`, `db sign`, data migration, `dataTransform`, placeholder sentinels in framework-rendered `migration.ts`, `MIGRATION.HASH_MISMATCH`, `MIGRATION.UNFILLED_PLACEHOLDER`, `MIGRATION.DESTRUCTIVE_CHANGES` / `--confirm <database>`, schema drift |
|
|
63
63
|
| Migration graph, refs, plan origin | [`references/migration-model.md`](references/migration-model.md) | migration graph, refs, `migration ref set` / `list` / `delete`, the `db` ref, `--advance-ref`, `--no-advance-ref`, `migration plan --from`, `from: (baseline)` in plan output, greenfield / from-scratch plan, baseline, first migration before deploy (Composer / CD-managed databases), chaining migrations, retrofitting migrations onto an existing database, `MIGRATION.HASH_NOT_IN_GRAPH`, `MIGRATION.PATH_UNREACHABLE` at plan/chain time |
|
|
64
64
|
| Review migrations on deploy | [`references/migration-review.md`](references/migration-review.md) | "what migrations are going to run", "what runs on deploy / merge", merge conflict, diamond convergence, concurrent migrations, migration status, ref management for CI, staging / production environment refs, `MIGRATION.MARKER_NOT_IN_HISTORY`, `MIGRATION.MISSING_INVARIANTS`, `db migrate --show` |
|
|
65
|
-
| Write queries | [`references/queries.md`](references/queries.md) | query, where, select, project, orderBy, limit, offset, take, skip, include, lookup, first, all, count, aggregate, groupBy, create, update, delete, upsert, returning, transaction, `db.orm`, `db.sql`, `runtime.query(plan)` vs `runtime.execute(plan)`, `db.prepare` / prepared statements, streaming / `for await`, many-to-many `include` and nested `connect`, `and` / `or` / `not` from `@prisma/orm-postgres/orm-client`, `db.query.from(...)` (Mongo pipeline), namespace-aware accessors, `.all()` Thenable, single-use iterators (`RUNTIME.ITERATOR_CONSUMED`), target-declared aggregate types (`count`, integer `sum`, and integer `avg` are `number`; `count` and integer `sum` throw outside ±(2^53 − 1) rather than round, while `avg` is a fraction already and carries no guard; `countBigInt` / `sumBigInt` / `avgDecimal` are the lossless forms, `avgDecimal` on PostgreSQL only), custom collection class (`extends Collection`), `apply` and scopes (`Scope`, `Filtered`, `Ordered`), drizzle-style, kysely-style. Naming types (§ *Naming model and result types*): "type of my model", "return type of a query", `ResultType`, `Scalars`, `Shape`, `models` / `Models` namespace in `contract.d.ts`, `Models.public_User`, Prisma 7 `Prisma.User` / `GetPayload` / `UserGetPayload` equivalents. Postgres/SQLite specifics: [`references/queries-postgres.md`](references/queries-postgres.md); Mongo specifics: [`references/queries-mongo.md`](references/queries-mongo.md) |
|
|
65
|
+
| Write queries | [`references/queries.md`](references/queries.md) | query, where, select, project, orderBy, limit, offset, take, skip, include, lookup, first, all, count, aggregate, groupBy, create, update, delete, upsert, returning, transaction, `db.orm`, `db.sql`, `runtime.query(plan)` vs `runtime.execute(plan)`, `db.prepare` / prepared statements, streaming / `for await`, many-to-many `include` and nested `connect`, `and` / `or` / `not` from `@prisma/orm-postgres/orm-client`, `db.query.from(...)` (Mongo pipeline), namespace-aware accessors, `.all()` Thenable, single-use iterators (`RUNTIME.ITERATOR_CONSUMED`), target-declared aggregate types (`count`, integer `sum`, and integer `avg` are `number`; `count` and integer `sum` throw outside ±(2^53 − 1) rather than round, while `avg` is a fraction already and carries no guard; `countBigInt` / `sumBigInt` / `avgDecimal` are the lossless forms, `avgDecimal` on PostgreSQL only), custom collection class (`extends Collection`), `apply` and scopes (`Scope`, `Filtered`, `Ordered`), shared query fragments (`db.orm.scope(fields, body)` for a filter on every model with given fields, `CodecField`, `db.orm.public.Post.scope(...)` for a shared `select` / `include`, `orderByField` for an order or sort parameter from a request), drizzle-style, kysely-style. Naming types (§ *Naming model and result types*): "type of my model", "return type of a query", `ResultType`, `Scalars`, `Shape`, `models` / `Models` namespace in `contract.d.ts`, `Models.public_User`, Prisma 7 `Prisma.User` / `GetPayload` / `UserGetPayload` equivalents. Postgres/SQLite specifics: [`references/queries-postgres.md`](references/queries-postgres.md); Mongo specifics: [`references/queries-mongo.md`](references/queries-mongo.md) |
|
|
66
66
|
| Wire the runtime | [`references/runtime.md`](references/runtime.md) | `db.ts`, `postgres<Contract>(...)` / `sqlite<Contract>(...)` / `mongo<Contract>(...)` façades, middleware composition (lints, budgets, cache via `@prisma/orm-extension-middleware-cache`, custom `afterQuery` middleware, `@prisma/orm-postgres/family-runtime`), `DATABASE_URL`, `.env`, connection pool / `poolOptions`, dev vs prod config, transactions, read replicas, multi-database, script won't exit / hangs, `db.close` / `pool.end`, `await using` / `[Symbol.asyncDispose]` |
|
|
67
67
|
| Build-tool integration | [`references/build.md`](references/build.md) | Vite plugin (`@internal/vite-plugin-contract-emit`, Vite 7/8), `vite.config.ts`, contract emit on save, HMR / dev server, Next.js / Webpack / esbuild / Rollup / Turbopack (named gaps, not fabricated) |
|
|
68
68
|
| Supabase | [`references/supabase.md`](references/supabase.md) | `@internal/extension-supabase`, RLS, row level security, policies (`policy_select` / `policy_update` / `@@rls`, `auth.uid()`), role binding (`asUser(jwt)` / `asAnon()` / `asServiceRole()`), `auth.users`, cross-space FKs to `supabase:auth.AuthUser`, JWT / JWKS (`SUPABASE_JWKS_URL`, `SUPABASE_JWT_SECRET`), `SUPABASE.JWT_INVALID`, `SUPABASE.CONFIG_INVALID`, `RoleBoundDb`, session pooler |
|
|
@@ -180,7 +180,7 @@ export const contract = defineContract(
|
|
|
180
180
|
);
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
Then `pnpm prisma contract emit`.
|
|
183
|
+
Then `pnpm prisma contract emit`. On Postgres, the `field` that `@prisma/orm-postgres/contract-builder` exports has the same `field.<scalar>()` helpers as the callback's, without the helpers an extension adds (such as pgvector's); for those, use the callback's `field`. On other targets the `field.<scalar>()` helpers are only available inside the callback overload; outside the callback only `field.column(...)`, `field.generated(...)`, `field.namedType(...)` exist.
|
|
184
184
|
|
|
185
185
|
For Mongo, swap every `@internal/postgres/*` import for `@internal/mongo/*`. The Mongo builder also exposes `index` and `valueObject`.
|
|
186
186
|
|
|
@@ -423,7 +423,7 @@ Infer captures indexes at full fidelity — expression, partial (`where:`), uniq
|
|
|
423
423
|
|
|
424
424
|
1. **Forgetting to re-emit after an edit.** `contract.json` and `contract.d.ts` go stale; downstream typecheck and `migration plan` see the old shape. Re-emit, or install the Vite plugin (`references/build.md`).
|
|
425
425
|
2. **Editing the emitted artefacts.** `contract.json` and `contract.d.ts` are emitted; edits there round-trip away on the next emit. Edit the source.
|
|
426
|
-
3. **Wrong factory/import path for the TS builder.** `defineContract`, `field`, `model`, `rel` come from `@internal/postgres/contract-builder` (or `@internal/mongo/contract-builder`).
|
|
426
|
+
3. **Wrong factory/import path for the TS builder.** `defineContract`, `field`, `model`, `rel` come from `@internal/postgres/contract-builder` (or `@internal/mongo/contract-builder`). On Postgres the imported `field` has the target's presets (`field.text()`, `field.temporal.timestamptz()`, `field.uuidString()`, …) but not an extension's; elsewhere, outside the callback overload, the available field constructors are `field.column(...)`, `field.generated(...)`, `field.namedType(...)`.
|
|
427
427
|
4. **Reaching into internal packages from user code.** User-authored files (`prisma.config.ts`, `contract.ts`, `db.ts`, control clients) import only from `@internal/<target>/<subpath>` and `@internal/extension-<name>/<subpath>`. Imports from `@internal/cli/*`, `@internal/family-*`, `@internal/target-*`, `@internal/adapter-*`, `@internal/driver-*`, or `@internal/sql-contract-*` are framework-internal — the façade composes them for you. If a façade subpath you need is missing for your target, see *What Prisma 8 doesn't do yet* and route to `references/feedback.md`. The canonical worked examples are `examples/multi-extension-monorepo/app/prisma.config.ts` and `examples/prisma-8-postgis-demo/prisma.config.ts`.
|
|
428
428
|
5. **Confusing the config `extensions` with the TS builder's `extensions`.** Same packs, two surfaces, one field name but two shapes: `ormConfig({ extensions: [pgvector] })` (array of *control* descriptors from `@internal/extension-<name>/control`) versus `defineContract({ extensions: { pgvector } })` (record of *pack* descriptors from `@internal/extension-<name>/pack`).
|
|
429
429
|
6. **Writing a flat `prisma.config.ts`.** `export default defineConfig({ contract, extensions })` from the target config alone is the pre-rc.4 shape and fails with `CONFIG.VERSION_MARKER_MISSING`. Wrap it: `definePrismaConfig({ orm: ormConfig({...}) })`.
|
|
@@ -302,6 +302,8 @@ if (search) {
|
|
|
302
302
|
|
|
303
303
|
The same holds for an `if` with an early return, a `switch`, a loop and a reassigned `let`.
|
|
304
304
|
|
|
305
|
+
**A write refuses what it would ignore.** `updateAll`, `updateAndCount`, `deleteAll` and `deleteAndCount` change every row that matches the filter, and throw `ORM.ARGUMENT_INVALID` on a collection with a `limit`, an `offset`, a `cursor`, `distinct` or `distinctOn`; an `orderBy` is accepted. To change a page of rows, read their ids first and filter on them. `update` and `delete` change the one row `first()` returns, so the order, offset, cursor, `distinct` and `distinctOn` choose it; after `limit(0)` they change nothing and return `null`. `update` with a relation callback finds its row by the filter alone and throws on any of these and on an order.
|
|
306
|
+
|
|
305
307
|
## Workflow — Custom collection classes
|
|
306
308
|
|
|
307
309
|
A custom collection class gives a model its own named queries. Extend `Collection`, register the class with `orm({ collections })`, and build that client inside the request from `db.runtime()` and `db.context`:
|
|
@@ -356,6 +358,68 @@ function deleteMatching(posts: Filtered<PostCollection>) {
|
|
|
356
358
|
await deleteMatching(Post.byAuthor(userId)).toArray();
|
|
357
359
|
```
|
|
358
360
|
|
|
361
|
+
## Workflow — Scopes
|
|
362
|
+
|
|
363
|
+
A piece of a query used in several places is a function. Do not build a filter object and spread it into each query; write a function and pass it to `.where(...)`, `.orderBy(...)` or `.apply(...)`. A function from a collection to a collection is a **scope**, and `.apply(...)` runs it.
|
|
364
|
+
|
|
365
|
+
**The same filter on several models.** Define a scope with `db.orm.scope(fields, body)`. Declare each field the scope needs with the same builder the schema uses, from the `field` that `@prisma/orm-postgres/contract-builder` exports, adding `.optional()` for a field that may be null. The body sees only those fields:
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import { field } from '@prisma/orm-postgres/contract-builder';
|
|
369
|
+
|
|
370
|
+
const createdSince = (since: Temporal.Instant) =>
|
|
371
|
+
db.orm.scope({ createdAt: field.temporal.timestamptz() }, (rows) =>
|
|
372
|
+
rows.where((r) => r.createdAt.gte(since)),
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
await db.orm.public.User.apply(createdSince(since)).all();
|
|
376
|
+
await db.orm.public.Post.apply(createdSince(since)).deleteAll();
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Pick the builder whose codec matches the field's codec in `contract.d.ts`: a PSL `DateTime` is `field.temporal.timestamptz()` (`pg/timestamptz-temporal@1`), a `String` is `field.text()` (`pg/text@1`), a `Uuid` is `field.uuidNative()` (`pg/uuid@1`). `field.column(columnType)` is the explicit form. A package that offers a scope and does not import the facade writes `{ codecId: 'pg/text@1', nullable: false }`, with a codec of the contract. For a list field such as `String[]`, add `.many()` to the builder or `many: { elementNullable: false }` to the object; for a `String?[]`, whose elements may be null, add `.many({ elementsNullable: true })` or `many: { elementNullable: true }`. Without it the declaration does not match a list field, and with it the element nullability must match too. A list of value objects such as `Address[]` is stored as one `jsonb` value and is still a list: `field.column(jsonbColumn).many()`. The body may call `where`, `orderBy`, `limit` and `offset`. The result keeps the collection's class and records the filter, so `update` and `delete` are allowed after a scope that filters. `updateAll`, `deleteAll` and their `AndCount` forms change every matching row and throw `ORM.ARGUMENT_INVALID` when the chain has a `limit`, `offset`, `cursor`, `distinct` or `distinctOn`, so do not put a limit in a scope that will be followed by one of them. `update` and `delete` change the one row `first()` returns, so the order, offset, cursor, `distinct` and `distinctOn` choose it, and after `limit(0)` they change nothing and return `null`; `update` with a relation callback throws on an order, a limit, an offset, a cursor, `distinct` or `distinctOn`, because it finds its row by the filter alone. A model without the field, or with the field under another codec or nullability, is a compile error, and a run-time `ORM.FIELD_UNKNOWN`. A custom collection class carries no namespace in its type, so at compile time it matches only a field that every model of that name has, with the same codec and nullability, and its real namespace is checked at run time. The codec, the nullability, whether the field is a list and the nullability of its elements are compared; the column type's parameters are not, so `field.uuidString()` (`char(36)`) also matches a `char(10)` field.
|
|
380
|
+
|
|
381
|
+
For a filter used inside a larger `where`, a plain function of the row works too. Type the field with `CodecField<Contract, CodecId, Nullable>`, the type of any field with that codec:
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
import { and, type CodecField } from '@prisma/orm-postgres/orm-client';
|
|
385
|
+
|
|
386
|
+
type CreatedAt = CodecField<Contract, 'pg/timestamptz-temporal@1'>;
|
|
387
|
+
const created = (since: Temporal.Instant) => (row: { createdAt: CreatedAt }) => row.createdAt.gte(since);
|
|
388
|
+
|
|
389
|
+
await db.orm.public.Post.where((p) => and(created(since)(p), p.title.ilike('%orm%'))).all();
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
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.
|
|
393
|
+
|
|
394
|
+
**The same `select` and `include` in several queries.** Define it once with `.scope(...)` on a collection of the model, run it with `.apply(...)`, and name its row with `CollectionRowOf`:
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import type { CollectionRowOf } from '@prisma/orm-postgres/orm-client';
|
|
398
|
+
|
|
399
|
+
const postSummary = db.orm.public.Post.scope((posts) =>
|
|
400
|
+
posts.select('id', 'title', 'createdAt').include('tags'),
|
|
401
|
+
);
|
|
402
|
+
type PostSummary = CollectionRowOf<ReturnType<typeof postSummary>>;
|
|
403
|
+
|
|
404
|
+
await db.orm.public.Post.where({ userId }).apply(postSummary).limit(20).all();
|
|
405
|
+
await db.orm.public.User.include('posts', (posts) => posts.apply(postSummary)).all();
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
The body receives the plain collection of the model, without a custom class's methods. Apply the scope 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 `update`, `delete` and `cursor` are refused, although an earlier `.where(...)` still runs; it is for reads. For a filter on one model, use a class method or `db.orm.scope`. A scope for one model refuses a collection of another model or namespace at run time with `ORM.ARGUMENT_INVALID`.
|
|
409
|
+
|
|
410
|
+
**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:
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
413
|
+
import { orderByField } from '@prisma/orm-postgres/orm-client';
|
|
414
|
+
|
|
415
|
+
await db.orm.public.Post
|
|
416
|
+
.orderBy(orderByField(db.orm.public.Post, input.orderBy, input.direction, ['title', 'createdAt']))
|
|
417
|
+
.limit(20)
|
|
418
|
+
.all();
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Pass the request's direction string as it is; `undefined` means `'asc'`. The allowed list is required: without it a request could order by a secret field and learn its values from the order of the results. A name outside the list, a relation, a field that cannot be ordered, or a direction other than `'asc'` or `'desc'` throws `ORM.ARGUMENT_INVALID` before the query runs; answer it as a bad request. Only the model's own fields can be named, not the fields of one variant.
|
|
422
|
+
|
|
359
423
|
## Workflow — Aggregates
|
|
360
424
|
|
|
361
425
|
```typescript
|
|
@@ -560,6 +624,7 @@ Cross-namespace relations (e.g. `public.Profile` → `auth.User`) follow the sam
|
|
|
560
624
|
- [ ] Expressed ranges as chained `.where(...)` clauses or a single `and(...)` clause — did NOT reach for a non-existent `.between(...)` operator.
|
|
561
625
|
- [ ] For cursor pagination, used `.orderBy(...).cursor({ field: lastValue }).limit(n).all()` — did NOT hand-write a `.where(p => p.field.lt(cursor))` workaround when the `.cursor()` API serves the same purpose.
|
|
562
626
|
- [ ] For ORM combinators, imported `and` / `or` / `not` from `@prisma/orm-postgres/orm-client`.
|
|
627
|
+
- [ ] Wrote a query piece shared between places as a function: a scope from `db.orm.scope(fields, body)` or `collection.scope(body)` run with `.apply(...)`, a `where` callback typed with `CodecField`, or `orderByField` for an order parameter from a request.
|
|
563
628
|
- [ ] Ran SQL-builder plans via `db.runtime().query(plan)` when they return rows and `db.runtime().execute(plan)` only for non-returning writes (`tx.query` / `tx.execute` inside a transaction). Passed `insert()` an array of rows.
|
|
564
629
|
- [ ] Wrapped multi-statement work in `db.transaction(async (tx) => { ... })` where atomicity matters.
|
|
565
630
|
- [ ] For top-N grouped aggregates at meaningful scale, dropped to `db.sql.<ns>.<table>` rather than JS-side sort + slice over `groupBy(...).aggregate(...)`.
|