Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ Run from `apps/docs`:
2. `pnpm audit:redirects:strict` after adding redirects.
3. `pnpm lint:agent-ready` after touching sections, llms surfaces, or the OpenAPI explorer.
4. `pnpm types:check` and `pnpm build` for code changes.
5. `pnpm lint:versions` after pinning a Prisma package version. Every pin in the current docs must be the package's `latest` on npm; write "since `8.0.0-rc.10`" or use an "Added in" column for history.
5. `pnpm lint:versions` after pinning a Prisma package version. Every pin in the current docs must be the package's `latest` on npm, except `@prisma/cli-engine`, which must be the version that `prisma@latest` depends on; write "since `8.0.0-rc.10`" or use an "Added in" column for history.
14 changes: 7 additions & 7 deletions apps/docs/content/docs/guides/database/schema-changes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ App space
└─ marker 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e

✔ Advanced ref "db" → 91e7f9f035806fa2789a4d726ef7724cad434fd6b00014d47ebf12d6e6bb784e
→ Check every space against the database: {bin} migration status
→ Check every space against the database: prisma migration status
```

The `{bin}` in the hint is the CLI's placeholder for however you invoked it. Read it as `npx prisma migration status`. Every developer clones this repository, points `DATABASE_URL` in their `.env` at their own database, and runs `npx prisma db migrate` once to bring it to the same state.
Every developer clones this repository, points `DATABASE_URL` in their `.env` at their own database, and runs `npx prisma db migrate` once to bring it to the same state.

## 2. Incorporate team changes

Expand Down Expand Up @@ -379,7 +379,7 @@ npx prisma migration status
│↑ 20260910T1543_init ∅ → 91e7f9f 6 ops ✓ applied
○ ∅

⚠ No migration path from the database state (91e7f9f03580) to the application's contract (1e5059c1976c). Run `{bin} migration plan --name <name>` to author one.
⚠ No migration path from the database state (91e7f9f03580) to the application's contract (1e5059c1976c). Run `prisma migration plan --name <name>` to author one.
```

Do not follow that hint literally. Without `--from`, the planner takes the `db` ref as its origin, and after `git checkout --ours` that ref is Ania's tip, so `migration plan --name merge_schema` writes only the half of the merge her branch is missing. Javier's database would still have no path to the top. Had the ref still pointed at `init`, the planner would have started a third branch from the divergence point instead, with a warning that it forks the graph. Neither is the merge. Do not delete either branch's migration directory to get out of this: Ania's and Javier's databases have already applied those migrations. Name the origin yourself, once per tip.
Expand Down Expand Up @@ -485,7 +485,7 @@ npx prisma migration status
│↑ 20260910T1543_init ∅ → 91e7f9f 6 ops ✓ applied
○ ∅

⚠ 1 pending: run `{bin} db migrate --to 1e5059c1976c`
⚠ 1 pending: run `prisma db migrate --to 1e5059c1976c`
```

```npm
Expand Down Expand Up @@ -613,9 +613,9 @@ const tag = await db.orm.public.Tag.create({ tagName: "arcade", tagCategory: "ga
```text no-copy
✘ [MIGRATION.PLAN_ORIGIN_UNKNOWN] Cannot determine the plan origin: migrations exist but no origin is named
why: Migrations exist on disk, but there is no `db` ref and no --from was given, so the plan origin would silently fall back to an empty database and the resulting migration would recreate everything the existing migrations already create.
→ Point the db ref at the origin contract: {bin} migration ref set db <contract>
→ Plan from an explicit origin: {bin} migration plan --from <contract>
→ Plan from an empty database deliberately: {bin} migration plan --from @empty
→ Point the db ref at the origin contract: prisma migration ref set db <contract>
→ Plan from an explicit origin: prisma migration plan --from <contract>
→ Plan from an empty database deliberately: prisma migration plan --from @empty
```

Pick the first or second. `--from @empty` over an existing history is only right for a deliberate rebuild.
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/docs/guides/frameworks/solid-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ check: enabled

Skill Package Version Installed into
prisma-8 @prisma/orm-postgres 8.0.0-rc.13 .claude/skills, .cursor/skills, .agents/skills, .devin/skills
prisma-composer-core-concepts @prisma/composer 0.23.0 .claude/skills, .cursor/skills, .agents/skills, .devin/skills
prisma-composer-core-concepts @prisma/composer 0.25.0 .claude/skills, .cursor/skills, .agents/skills, .devin/skills
prisma-platform-core-concepts prisma 8.0.0-rc.19 .claude/skills, .cursor/skills, .agents/skills, .devin/skills

⚠ [INIT.CONFIG_KEPT] prisma.config.ts already exists, so init left it alone instead of writing the skills section.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ npx prisma contract emit
✔ Emitted contract.json and contract.d.ts

storageHash: 0c3a18eb65d5a5027c444cf0626d843cdb41dfd5fe8e66d6fce8d2eab460c971
executionHash: 796fa270d853489edb1c3e0d332d596412292127a259b856b495a498c752882a
executionHash: 4e88564095b5e0ba7904ffdba3c563ef916d87688c8c483c67055f71a9194f0f
profileHash: 3916f444a8a17ad749191acf9e08dad97d1a327b88c2f1d45d12f240296aa8b2
```

Expand Down
24 changes: 16 additions & 8 deletions apps/docs/content/docs/orm/reference/sql-query-builder.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -385,15 +385,9 @@ Sort the result set by a column or a computed expression, in a direction you cho
|---|---|---|---|
| `key` | Column name (`string`) or `(f, fns) => Expression` | Yes | The column or computed value to sort by. |
| `options.direction` | `'asc' \| 'desc'` | No | Sort direction. |
| `options.nulls` | `'first' \| 'last'` | No | Where rows with a null sort value go. Adds `NULLS FIRST` or `NULLS LAST` to the sort key. |

TypeScript also accepts a `nulls` option, but it does nothing, and no `NULLS FIRST` or `NULLS LAST` reaches the SQL. To put nulls last, sort by a computed value first, then by the column:

```ts
db.sql.public.task
.select('id', 'description')
.orderBy((f, fns) => fns.raw`CASE WHEN ${f.description} IS NULL THEN 1 ELSE 0 END`.returns('pg/int4@1'))
.orderBy('description', { direction: 'asc' });
```
Without `options.nulls`, PostgreSQL puts nulls last for `'asc'` and first for `'desc'`. Any value other than `'first'` or `'last'` makes `orderBy()` throw an error whose `code` is `ORM.ARGUMENT_INVALID`.

#### Return type

Expand All @@ -410,6 +404,20 @@ const plan = db.sql.public.user.select('id', 'email').orderBy('email', { directi
const rows = await runtime.query(plan);
```

##### Put nulls last

```ts
const plan = db.sql.public.task
.select('id', 'description')
.orderBy('description', { direction: 'desc', nulls: 'last' })
.build();
const rows = await runtime.query(plan);
```

```sql no-copy
SELECT "id" AS "id", "description" AS "description" FROM "public"."task" ORDER BY "description" DESC NULLS LAST
```

##### Sort by a computed value

```ts
Expand Down
45 changes: 32 additions & 13 deletions apps/docs/scripts/lint-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

/**
* Every pinned Prisma ORM 8 version in the current docs must be the package's
* `latest` dist-tag on npm. A version mentioned as history ("since 8.0.0-rc.10",
* `latest` dist-tag on npm. `@prisma/cli-engine` is the exception: `prisma`
* installs the exact engine version it depends on, so the expected version is
* the one in the `dependencies` of `prisma@latest`. A version mentioned as history ("since 8.0.0-rc.10",
* an "Added in" column) is allowed to be older, and so is a pin to an older
* major line, such as a `prisma@6.x` install step for readers staying on 6.
*
Expand All @@ -16,13 +18,9 @@ import { fileURLToPath } from "node:url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DOCS_DIR = path.join(__dirname, "../content/docs");

const TRACKED_PACKAGES = [
"prisma",
"@prisma/orm-postgres",
"@prisma/orm-mongo",
"@prisma/cli-engine",
"@prisma/prisma7",
];
const TRACKED_PACKAGES = ["prisma", "@prisma/orm-postgres", "@prisma/orm-mongo", "@prisma/prisma7"];

const PACKAGES_PINNED_BY_PRISMA = ["@prisma/cli-engine"];

/** Older releases keep their own content trees and pin their own versions. */
const VERSIONED_TREES = ["(index)/v7", "cli/v7", "guides/v7", "orm/v6", "orm/v7"];
Expand Down Expand Up @@ -55,12 +53,23 @@ type Violation = {
expected: string;
};

async function fetchLatest(pkg: string): Promise<string> {
type Manifest = { version: string; dependencies?: Record<string, string> };

async function fetchLatestManifest(pkg: string): Promise<Manifest> {
const response = await fetch(`https://registry.npmjs.org/${pkg}/latest`);
if (!response.ok) {
throw new Error(`npm registry returned ${response.status} for ${pkg}`);
}
const { version } = (await response.json()) as { version: string };
return (await response.json()) as Manifest;
}

function versionPinnedByPrisma(prisma: Manifest, pkg: string): string {
const version = prisma.dependencies?.[pkg];
if (!version || !/^\d+\.\d+\.\d+(?:-[\w.]+)?$/.test(version)) {
throw new Error(
`prisma@${prisma.version} does not depend on an exact version of ${pkg} (found ${version})`,
);
}
return version;
}

Expand Down Expand Up @@ -151,11 +160,21 @@ function lintFile(file: string, latest: Map<string, string>): Violation[] {
}

async function main() {
const latest = new Map(
await Promise.all(TRACKED_PACKAGES.map(async (pkg) => [pkg, await fetchLatest(pkg)] as const)),
const manifests = new Map(
await Promise.all(
TRACKED_PACKAGES.map(async (pkg) => [pkg, await fetchLatestManifest(pkg)] as const),
),
);
const latest = new Map([...manifests].map(([pkg, { version }]) => [pkg, version]));
for (const [pkg, version] of latest) console.log(`${pkg}@${version}`);

const prisma = manifests.get("prisma")!;
for (const pkg of PACKAGES_PINNED_BY_PRISMA) {
const version = versionPinnedByPrisma(prisma, pkg);
latest.set(pkg, version);
console.log(`${pkg}@${version} (installed by prisma@${prisma.version})`);
}

const files = findMdxFiles(DOCS_DIR).filter((file) => !isVersionedTree(file));
const violations = files.flatMap((file) => lintFile(file, latest));

Expand All @@ -166,7 +185,7 @@ async function main() {

console.error(`\n❌ ${violations.length} stale version reference(s):\n`);
for (const { file, line, found, expected } of violations) {
console.error(`${file}:${line}: ${found} (latest is ${expected})`);
console.error(`${file}:${line}: ${found} (expected ${expected})`);
}
console.error(
'\nBump the version, or mark it as history with a phrase like "since" or "before" or an "Added in" column.',
Expand Down
Loading