| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
docs: rewrite README for Prisma 8, fix orm init dist-tag, sweep "Prisma Next" prose (#30248) ## Linked issue n/a — no Linear ticket. Follow-up to the README banner swap in #30225. ## At a glance The README's getting-started commands, before and after, checked against [prisma.io/docs/getting-started](https://www.prisma.io/docs/getting-started): ```bash # before npm create prisma@next npx @prisma/cli@next orm init # after npm create prisma npx prisma orm init npx prisma skills sync ``` The `prisma` package has no `next` dist-tag any more (`latest` is `8.0.0-rc.13`, `prev` is `7.10.0`), so the old commands no longer resolve. ## Summary The README still introduced the product as "Prisma Next" in Early Access, pointed at the removed `next` dist-tag, listed extensions by their `@internal/*` workspace names, and linked to `prisma/prisma`. The rest of the repo had about a thousand prose mentions of the working name. This PR fixes all of it and one real bug the sweep turned up. ## Decision Five commits, each reviewable on its own (the fifth only records the sweep against the in-flight upgrade-instruction files for the coverage check): 1. **Rewrite the README against the live docs.** Every instruction in it now matches the getting-started, quickstart, `orm init`, `skills`, and extensions pages in prisma/web. 2. **Fix `orm init` to install `prisma@latest`.** The CLI added `prisma@next` as a dev dependency. That tag no longer exists on npm, so `orm init` fails at the install step for anyone running it today. The engine fallback moves from `@prisma/cli-engine@next` (0.2.3, stale) to `@latest` (0.3.0). 3. **Replace "Prisma Next" with "Prisma 8" in prose repo-wide.** Docs, doc comments, READMEs, package descriptions, skill references, and user-facing strings. 4. **Carry the pnpm trust-policy exemptions into the tarball smoke tests.** The scratch installs those tests run trip a trust-downgrade check on `undici-types@6.21.0` (no provenance, while 6.13.0 and 6.18.2 had it). The repo already exempts it for the workspace install; the test kit now restates `trustPolicy` and `trustPolicyExclude` in the scratch project the way it restates the release-age settings. Reproduced on main with a fresh metadata cache, so this is a pre-existing failure that any run without cached metadata hits. ## Reviewer notes - **Rebased on #30229.** That PR's release-candidate banner and its `scorecard.md` link replace the roadmap reference in the README, and `ROADMAP.md` stays deleted. The prose sweep re-applied cleanly on top of its CONTRIBUTING, SECURITY, and governance edits. - **Dated records keep the old name**, matching the allowances `scripts/lint-legacy-name.mjs` already defines for the `prisma-next` identifier: `CHANGELOG.md`, `docs/releases/`, the ADRs, `projects/`, and `drive/`. Rewriting those would misreport what was true at the time, and a mechanical pass produced sentences like "Prisma Next becomes Prisma 8" turning into "Prisma 8 becomes Prisma 8". - **Identifiers are untouched.** `prisma-next` package names, paths, env vars (`PRISMA_NEXT_*`), `PrismaNext*` types, the `images/prisma-next.png` file, and the `prisma-next.md` primer (the docs still call it that) are all unchanged. Renaming any of those is a behaviour change with an upgrade path, not a docs fix. - **The sweep is mechanical.** The third commit is a `sed` of `Prisma Next` and `Prisma-next` to `Prisma 8` over 345 files. Three sentences that became self-referential (`ROADMAP.md`, `ROADMAP.html`, `scorecard.md`) were rewritten by hand. - **`README.md` supported-databases section** now says PostgreSQL and MongoDB are first-class and SQLite is planned next, which is what [/docs/orm](https://www.prisma.io/docs/orm) says. The previous text referenced work "before the 8.0.0-rc.1 release". - **Discord channel name dropped.** The README linked to a `prisma-next` channel I could not verify; it now links to Discord generically. ## Behavior changes & evidence - **`orm init` installs `prisma@latest`** instead of `prisma@next`, and falls back to `@prisma/cli-engine@latest` when the manifest does not pin the engine. [packages/1-framework/3-tooling/cli/src/orm/init.ts](packages/1-framework/3-tooling/cli/src/orm/init.ts), [packages/1-framework/3-tooling/cli/src/orm/init-packages.ts](packages/1-framework/3-tooling/cli/src/orm/init-packages.ts). Evidence: [packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts](packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts), [test/integration/test/cli.init-skill-distribution.integration.test.ts](test/integration/test/cli.init-skill-distribution.integration.test.ts). - **Scaffolded quick-reference notes and the skill quickstart** tell users to run `prisma@latest orm init`. [packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md](packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md), [skills/prisma-8/references/quickstart.md](skills/prisma-8/references/quickstart.md). Evidence: [packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap](packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap). - **No other runtime change.** Every other edit is prose in docs, comments, `package.json` descriptions, and `//` comments in test fixture schemas, which the emitter drops. ## Testing performed - `pnpm test` in `packages/1-framework/3-tooling/cli`: 115 files, 1437 tests passed - `pnpm lint:legacy-name`, `pnpm lint:docs`, `pnpm lint:skills`, `pnpm lint:rules:footprint`, `pnpm lint:manifests`: all pass (the `errors` README warning is pre-existing) - `pnpm fixtures:check` could not run in this worktree because the examples' `prisma` binary is not installed. The only schema edits are `//` comments, which do not reach the emitted contract. ## Skill update `skills/prisma-8/references/quickstart.md` is updated in the second commit: its `orm init` commands moved from `@prisma/cli@next` to `prisma@latest`, the same change the README makes. ## Alternatives considered - **Rename the identifiers too** (`prisma-next.md`, `PRISMA_NEXT_*`, `PrismaNext*` types, the image file). Each is a user-visible surface with an upgrade path, and the docs still name `prisma-next.md`. Left for a deliberate rename with upgrade instructions. - **Sweep the ADRs, changelog, and project write-ups as well.** The repo's own legacy-name lint exempts them as dated records, and the mechanical pass mangled sentences that describe the rename itself. Following the existing policy keeps the diff honest. - **Keep `@latest` on the commands, as the docs pages write them.** The v8 line is `latest` now, so the tag adds nothing; the README uses the bare `npm create prisma` and `npx prisma …` forms. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated (the CLI install-command tests and snapshots). - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer The first two commits are small and worth reading line by line. The third is large but uniform; spot-check a few files rather than reading all 345. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
docs: rewrite README for Prisma 8, fix orm init dist-tag, sweep "Prisma Next" prose (#30248) ## Linked issue n/a — no Linear ticket. Follow-up to the README banner swap in #30225. ## At a glance The README's getting-started commands, before and after, checked against [prisma.io/docs/getting-started](https://www.prisma.io/docs/getting-started): ```bash # before npm create prisma@next npx @prisma/cli@next orm init # after npm create prisma npx prisma orm init npx prisma skills sync ``` The `prisma` package has no `next` dist-tag any more (`latest` is `8.0.0-rc.13`, `prev` is `7.10.0`), so the old commands no longer resolve. ## Summary The README still introduced the product as "Prisma Next" in Early Access, pointed at the removed `next` dist-tag, listed extensions by their `@internal/*` workspace names, and linked to `prisma/prisma`. The rest of the repo had about a thousand prose mentions of the working name. This PR fixes all of it and one real bug the sweep turned up. ## Decision Five commits, each reviewable on its own (the fifth only records the sweep against the in-flight upgrade-instruction files for the coverage check): 1. **Rewrite the README against the live docs.** Every instruction in it now matches the getting-started, quickstart, `orm init`, `skills`, and extensions pages in prisma/web. 2. **Fix `orm init` to install `prisma@latest`.** The CLI added `prisma@next` as a dev dependency. That tag no longer exists on npm, so `orm init` fails at the install step for anyone running it today. The engine fallback moves from `@prisma/cli-engine@next` (0.2.3, stale) to `@latest` (0.3.0). 3. **Replace "Prisma Next" with "Prisma 8" in prose repo-wide.** Docs, doc comments, READMEs, package descriptions, skill references, and user-facing strings. 4. **Carry the pnpm trust-policy exemptions into the tarball smoke tests.** The scratch installs those tests run trip a trust-downgrade check on `undici-types@6.21.0` (no provenance, while 6.13.0 and 6.18.2 had it). The repo already exempts it for the workspace install; the test kit now restates `trustPolicy` and `trustPolicyExclude` in the scratch project the way it restates the release-age settings. Reproduced on main with a fresh metadata cache, so this is a pre-existing failure that any run without cached metadata hits. ## Reviewer notes - **Rebased on #30229.** That PR's release-candidate banner and its `scorecard.md` link replace the roadmap reference in the README, and `ROADMAP.md` stays deleted. The prose sweep re-applied cleanly on top of its CONTRIBUTING, SECURITY, and governance edits. - **Dated records keep the old name**, matching the allowances `scripts/lint-legacy-name.mjs` already defines for the `prisma-next` identifier: `CHANGELOG.md`, `docs/releases/`, the ADRs, `projects/`, and `drive/`. Rewriting those would misreport what was true at the time, and a mechanical pass produced sentences like "Prisma Next becomes Prisma 8" turning into "Prisma 8 becomes Prisma 8". - **Identifiers are untouched.** `prisma-next` package names, paths, env vars (`PRISMA_NEXT_*`), `PrismaNext*` types, the `images/prisma-next.png` file, and the `prisma-next.md` primer (the docs still call it that) are all unchanged. Renaming any of those is a behaviour change with an upgrade path, not a docs fix. - **The sweep is mechanical.** The third commit is a `sed` of `Prisma Next` and `Prisma-next` to `Prisma 8` over 345 files. Three sentences that became self-referential (`ROADMAP.md`, `ROADMAP.html`, `scorecard.md`) were rewritten by hand. - **`README.md` supported-databases section** now says PostgreSQL and MongoDB are first-class and SQLite is planned next, which is what [/docs/orm](https://www.prisma.io/docs/orm) says. The previous text referenced work "before the 8.0.0-rc.1 release". - **Discord channel name dropped.** The README linked to a `prisma-next` channel I could not verify; it now links to Discord generically. ## Behavior changes & evidence - **`orm init` installs `prisma@latest`** instead of `prisma@next`, and falls back to `@prisma/cli-engine@latest` when the manifest does not pin the engine. [packages/1-framework/3-tooling/cli/src/orm/init.ts](packages/1-framework/3-tooling/cli/src/orm/init.ts), [packages/1-framework/3-tooling/cli/src/orm/init-packages.ts](packages/1-framework/3-tooling/cli/src/orm/init-packages.ts). Evidence: [packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts](packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts), [test/integration/test/cli.init-skill-distribution.integration.test.ts](test/integration/test/cli.init-skill-distribution.integration.test.ts). - **Scaffolded quick-reference notes and the skill quickstart** tell users to run `prisma@latest orm init`. [packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md](packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md), [skills/prisma-8/references/quickstart.md](skills/prisma-8/references/quickstart.md). Evidence: [packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap](packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap). - **No other runtime change.** Every other edit is prose in docs, comments, `package.json` descriptions, and `//` comments in test fixture schemas, which the emitter drops. ## Testing performed - `pnpm test` in `packages/1-framework/3-tooling/cli`: 115 files, 1437 tests passed - `pnpm lint:legacy-name`, `pnpm lint:docs`, `pnpm lint:skills`, `pnpm lint:rules:footprint`, `pnpm lint:manifests`: all pass (the `errors` README warning is pre-existing) - `pnpm fixtures:check` could not run in this worktree because the examples' `prisma` binary is not installed. The only schema edits are `//` comments, which do not reach the emitted contract. ## Skill update `skills/prisma-8/references/quickstart.md` is updated in the second commit: its `orm init` commands moved from `@prisma/cli@next` to `prisma@latest`, the same change the README makes. ## Alternatives considered - **Rename the identifiers too** (`prisma-next.md`, `PRISMA_NEXT_*`, `PrismaNext*` types, the image file). Each is a user-visible surface with an upgrade path, and the docs still name `prisma-next.md`. Left for a deliberate rename with upgrade instructions. - **Sweep the ADRs, changelog, and project write-ups as well.** The repo's own legacy-name lint exempts them as dated records, and the mechanical pass mangled sentences that describe the rename itself. Following the existing policy keeps the diff honest. - **Keep `@latest` on the commands, as the docs pages write them.** The v8 line is `latest` now, so the tag adds nothing; the README uses the bare `npm create prisma` and `npx prisma …` forms. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated (the CLI install-command tests and snapshots). - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer The first two commits are small and worth reading line by line. The third is large but uniform; spot-check a few files rather than reading all 345. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
refactor: rename every user-facing prisma-next identifier to Prisma 8 (#30262) ## Linked issue n/a — no Linear ticket. Completes the rename that #30248 started for prose; builds on #30261. ## At a glance Every `prisma-next` identifier a user can see is renamed. Before and after, for a scaffolded project: ```text // use prisma-next → // use prisma-8 (schema header) prisma-next.md → prisma-8.md (primer at the project root) PRISMA_NEXT_DISABLE_TELEMETRY → PRISMA_DISABLE_TELEMETRY (and every other PRISMA_NEXT_* variable) ~/.config/prisma-next/ → ~/.config/prisma-8/ (per-user telemetry config) prisma-next contract emit → prisma contract emit (CLI invocations in docs, fixtures, recordings) ``` ## Summary After #30248 the product was called Prisma 8 in prose, but the working name was still written into user projects and printed by the CLI: the schema header, the primer file, the environment variables, the per-user config directory, the language-server diagnostic source, the Standard Schema vendor string, the contract brand symbol, the advisory-lock domain, and about 650 fixture and doc files that spelled out `prisma-next …` commands. This PR renames all of it in one pass and tightens the legacy-name lint so the only occurrences left are the ones with a reason. ## Decision One commit. The mapping: | Surface | Before | After | |---|---|---| | Schema header | `// use prisma-next` | `// use prisma-8` | | Primer file `init` writes | `prisma-next.md` | `prisma-8.md` | | CLI environment variables | `PRISMA_NEXT_*` | `PRISMA_*` | | Per-user config directory | `prisma-next/` | `prisma-8/` | | Language-server diagnostic source | `prisma-next` | `prisma` | | Standard Schema vendor, VS Code publisher | `prisma-next` | `prisma` | | Contract brand symbol | `__prisma_next_brand__` | `__prisma_8_brand__` | | Postgres advisory-lock domain | `prisma_next.contract.marker` | `prisma_8.contract.marker` | | Example database names | `prisma_next_*` | `prisma_8_*` | | README banner image | `images/prisma-next.png` | `images/prisma-8.png` | | Telemetry docs URL | `prisma-next.dev/docs/…` | `www.prisma.io/docs/…` | | New-issue links | `github.com/prisma/prisma-next/issues/new` | `github.com/prisma/orm/issues/new` | | CLI invocations in prose, fixtures, and recordings | `prisma-next db verify` | `prisma db verify` | `prisma-8` is the slug the repo already uses for the skill, the examples, and the upgrade directories, so it is the slug for everything that needs one. Environment variables drop the infix entirely because `PRISMA_*` is what users expect and nothing else in the repo claims those names. What keeps the old name, each with a lint allowance that says why: - **Dated records**: changelog, release notes, ADRs, shipped upgrade instructions, gotcha logs, the framework-gaps review, and the `projects/` and `drive/` write-ups. - **Pinned links** into the old repository by number, Linear slugs, and links to ADRs whose filenames carry the name. - **`@cipherstash/prisma-next`**, a third party's published package name. - **Retirement proofs**: the list of old skill directories `init` deletes, and the tests asserting that no `prisma-next` bin or skill directory is installed any more. ## Behavior changes & evidence - **Schema header.** The inferred-schema printer and the `init` templates write `// use prisma-8`. The language server accepts both headers, so existing schemas keep their diagnostics and completion, and its Format action rewrites the old header to the new one. [packages/1-framework/3-tooling/language-server/src/schema-directive.ts](packages/1-framework/3-tooling/language-server/src/schema-directive.ts), [packages/1-framework/2-authoring/psl-printer/src/ast-to-print-document.ts](packages/1-framework/2-authoring/psl-printer/src/ast-to-print-document.ts). Evidence: the `renameLegacyDirective` tests, the server test that formats a legacy-headed schema, and the psl-printer tests. - **Environment variables.** Telemetry gating, the endpoint override, and the debug switch read the new names. `PRISMA_NEXT_DISABLE_TELEMETRY` is still honoured as an opt-out so nobody is silently opted back in; the endpoint and debug spellings are not. [packages/1-framework/3-tooling/cli-telemetry/src/gating.ts](packages/1-framework/3-tooling/cli-telemetry/src/gating.ts). Evidence: cli-telemetry gating tests. - **Per-user config directory.** [packages/1-framework/3-tooling/cli-telemetry/src/user-config.ts](packages/1-framework/3-tooling/cli-telemetry/src/user-config.ts). Existing users see the telemetry consent prompt once more; nothing else is lost. - **Primer file.** [packages/1-framework/3-tooling/cli/src/orm/init-scaffold.ts](packages/1-framework/3-tooling/cli/src/orm/init-scaffold.ts). Evidence: init-scaffold tests and template snapshots. - **Advisory-lock domain.** A CLI on this version and one on the previous version take different locks for the same marker. Both versions running migrations against one database at the same moment is already unsupported. - **Upgrade instructions.** Entries for the header, the environment variables, and the primer file are recorded in the rc.9 → rc.10 app and extension instructions with detection patterns, so the published upgrade skill applies the rename. ## Testing performed - `pnpm test` in cli (1437), cli-telemetry (112), language-server (312), psl-printer (63), framework-components (672), target-postgres (1607), vite-plugin-contract-emit (31), emitter (231), and `pnpm test:scripts` (507): all pass after `pnpm build`. The language-server tests hard-coded the old header's length in semantic-token arrays and span offsets; those expectations are updated. - Committed migration steps and their content-addressed contract snapshots are left untouched, since rewriting them would break their hashes; the lint treats them as dated records. - `pnpm lint:legacy-name` passes with the tightened allowances; `node --test scripts/lint-legacy-name.test.mjs` passes (14 tests, including new negative cases for the header, primer, and skill names). - `pnpm check:upgrade-coverage --mode pr --prev origin/main` passes. ## Skill update `skills/prisma-8` references and the two rc.9 → rc.10 upgrade instruction files are updated in this PR. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated. - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
TML-3233: emit Models namespace + models const; Scalars, Shape, and ResultType on ORM queries (#30231) ## Linked issue Refs [TML-3233](https://linear.app/prisma-company/issue/TML-3233) · Linear project [Model and result types](https://linear.app/prisma-company/project/model-and-result-types-080d7caa544f). Design: [ADR 250](docs/architecture%20docs/adrs/ADR%20250%20-%20Models%20and%20views%20are%20emitted%20from%20the%20contract.md). ## At a glance ```ts import type { models, Models } from '../prisma/contract'; import type { Scalars, Shape } from '@prisma/orm-postgres/family-contract/types'; import type { ResultType } from '@prisma/orm-postgres/components/runtime'; // Models types are directly available in two forms. This one is a bit nicer to type: type User = typeof models.public.User; // And the raw model type which doesn't require `typeof`: type User2 = Models.public_User; // A plain query returns the scalar form of the model, ie. all its properties without relations type UserRow = Scalars<User>; // But you often need a selection of your model properties and its relations. In Prisma 7 and below // you'd use GetPayload<> for this. In Prisma 8, it looks like the following. Mark fields or // relations for inclusion with `'+'`, or exclusion with `'-'`. Naming only relations in `'+'` keeps every scalar. type UserResponse = Shape<User, { '-': 'passwordHash'; posts: { '+': 'id' | 'title' | 'comments' }; }>; // { id; name; email; ...; posts: { id; title; comments: Scalars<Comment>[] }[] } // This is useful in situations where you need to declare a type derived from your models, eg an // API response type (real code: examples/prisma-8-demo/src/orm-client/get-user-profile.ts). TypeScript will then enforce that the result of your function, which will // involve Prisma queries, matches the expected output shape. If you change the contract, the // resulting shape will update. export async function getUserWithPosts(id: string): Promise<UserResponse | null> { const user = await db.orm.public.User.where({ id }).include('posts', (p) => p.include('comments')).first(); if (user === null) return null; const { passwordHash, ...rest } = user; return { ...rest, posts: user.posts.map(({ id, title, comments }) => ({ id, title, comments })) }; } // And if you just want the exact type of a query you already wrote: const usersWithPosts = db.orm.public.User.include('posts'); type UserWithPosts = ResultType<typeof usersWithPosts>; ``` Before this PR, `contract.d.ts` exported no model type, and `ResultType` returned `never` on ORM queries. ## Summary Two Prisma 7 users asked where `Prisma.User` and `Prisma.BookGetPayload<{ include: { author: true } }>` went. Prisma 8 had no answer: models were reachable only as `FieldOutputTypes['public']['User']`, and naming a query result meant `NonNullable<Awaited<ReturnType<typeof q.first>>>`. This PR gives users the model type, the scalar row a default fetch returns, a data structure derived from the model with picked or dropped scalars and nested relations, and the result type of any ORM query. ## Skill update `skills/prisma-8/references/queries.md` gains a "Naming model and result types" section and the routing table in `skills/prisma-8/SKILL.md` routes "type of my model", `GetPayload`, `ResultType`, `Scalars`, `Shape`, and `Models` prompts to it. ## Decision The model is the whole row plus its relations, as written in PSL. A query result is a view on it. Selection belongs to the query, not the model. [ADR 250](docs/architecture%20docs/adrs/ADR%20250%20-%20Models%20and%20views%20are%20emitted%20from%20the%20contract.md) records this. Concretely, this PR ships: 1. `contract.d.ts` emits `export namespace Models` with one member per model, the namespace folded into the member name (`public_User`, `unbound_Audit`; bare names on targets without namespaces), an `Any<Base>` union per polymorphic base, and `export declare const models` for dotted type-only access. 2. `RelationKeys`, `Scalars<M>`, and `Shape<M, Spec>` in `framework-components`, re-exported by both family contract packages. `Shape` takes an object spec: `'+'` keeps named scalars and relations, `'-'` drops scalars, any other key is a relation with a nested spec, and wrong names or `'+'` beside `'-'` are compile errors on the offending key (`projects/model-and-result-types/shape-design-brief.md`). 3. A `_row` phantom on both ORM collections so the existing `ResultType` works on ORM queries. 4. Type tests proving the ORM's rows equal `Scalars` and `Shape` of the emitted models (plain includes, projections, select plus include, nested includes, polymorphism) for SQL and for Mongo, and a demo test that declares an endpoint response with `Shape` and returns a transformed query result from a function with that return type. 5. Relation nullability is recorded on the contract. Every one-to-one and many-to-one relation carries `nullable`, set from the `?` on the relation field in PSL or from the TypeScript builder, and read by the emitter and both ORMs. A contract written before this change loads unchanged: a missing flag is derived at hydration from the foreign-key columns' storage nullability, and a present flag is checked against storage on load. The emitter requires the flag on the contracts it consumes. The storage-plane reconstruction in the ORM types and the emitter hook that mirrored it are gone. 6. Every emitted fixture regenerated, a reference page, and the user skill update. ## Reviewer notes - The largest diff is fixture regeneration: every emitted `contract.d.ts` in the repo gains the `Models` block, including the 204 port fixtures and the migration snapshot stores that `pnpm fixtures:check` did not cover before. The check now covers them through `test/integration/scripts/emit-fixture-configs.mjs` and `scripts/refresh-contract-snapshot.mjs`. 143 `contract.json` files change, and every changed line is the `_generated` banner, which those stale fixtures had never picked up. Spot-check `packages/3-extensions/sql-orm-client/test/fixtures/generated/contract.d.ts` and the polymorphism fixture under `test/integration/test/sql-orm-client/fixtures/polymorphism/`. - A default fetch returns `Scalars<Model>`, not the model. This is the opposite of Prisma 7, where the generated `User` is scalars-only, and the reference page says so in its first paragraph. - The namespace is in the member name wherever a collision is possible: on Postgres a default-schema model is `Models.unbound_User`, because `public.User` can sit beside it, matching `db.enums` and the contract views. A target whose descriptor declares `namespaceSupport: 'none'` (SQLite) emits bare names, `Models.User` and `models.User`. The choice is a declared target capability, never a count of the namespaces in a particular contract. - A relation whose target is a polymorphic base is emitted as the `Any<Base>` union, because that is what the ORM returns for such includes. - Relation nullability comes from the schema, not storage. `author User?` gives `nullable: true`, `author User` gives `false`; authoring rejects a required relation field over a nullable foreign key and the reverse. The side of a one-to-one that does not own the foreign key is always nullable, in PSL and in the builder, because nothing guarantees the related row exists. A refined to-one include is `| null` regardless, because the refinement can exclude the row. - Mongo follows the schema too. Its ORM used to type every to-one include as `| null`; now it reads the flag. A required reference whose document is missing comes back with the key absent at runtime, which the type no longer admits. That is a general read-time concern on Mongo, recorded in `projects/model-and-result-types/deferred.md`, not changed here. - `contract.json` gains one boolean per to-one relation. The domain section is canonicalized as empty for the storage hash, so no contract hash changes, and migration snapshots written before this change still load because a missing flag is derived at hydration. Seven ported `.prisma` schemas had an optional relation field over a required foreign key, which authoring now rejects; the `?` was removed and no emitted type changed. - The to-one nullability rule lives once, in `@internal/contract-authoring`, and the two PSL interpreters and two TypeScript builders call it. `Scalars` and `RelationNamesOf` infer the relation keys without a constraint fallback so they work in projects without `exactOptionalPropertyTypes`; a test compiles the fixture with that flag off. - Mongo embedded models carry no `RelationKeys` phantom, so `Scalars` of an owner's embed field equals the ORM's embed row. - `Shape` flattens each level so `toEqualTypeOf` can compare it with ORM rows and hover text shows one object. - Adjacent fixes in the second commit: `examples/prisma-8-demo` now passes `pnpm lint` (every bare throw uses a named `Error` subclass from `src/errors.ts` or `TypeError`), and the `no-bare-cast`, `no-bare-throw`, and `no-family-vocabulary` plugins exclude `.test.tsx`, `.test.mts`, and `.test.cts` the same way they exclude `.test.ts`. Forty orphan `contract.*` copies under `relation-mode-gh-*` fixtures, produced by an older emit and referenced by nothing, are deleted. - Left as they are, with reasons in the commit: two hand-authored minimal `contract.d.ts` test inputs, two telemetry-backend snapshots whose PSL no longer exists, 44 snapshots under `examples/prisma-8-demo/fixtures/*/migrations` that no script produces, and two vendored extension snapshots whose refresh belongs to the extension install flow. - Pre-existing flakes, not caused here: `@prisma/orm-framework test/module-identity.test.ts` races on `pnpm pack`'s skill sync and passes on rerun; `driver-adapters-error-forwarding › correctly forwards error for queryRaw` is a `test.fails` port that now passes, identically with the old fixture restored. - This PR is also the project's close-out: the transient artifacts under `projects/model-and-result-types/` are deleted in the last commit, ADR 250 and the reference page are the durable record, the final retro is in `drive/retro/findings.md`, and every deferred item has a Linear issue (TML-3235, 3236, 3237, 3242 to 3246). ## How it fits together 1. **Framework types.** `packages/1-framework/1-core/framework-components/src/execution/model-types.ts` declares the `RelationKeys` unique symbol and the two utilities. Both are distributive, so they work on `Any<Base>` unions. `Shape` validates the spec through a mapped constraint over the spec's own keys and reads each relation's wrapper from the model's own field type. 2. **Emission.** `packages/1-framework/3-tooling/emitter/src/model-types-emission.ts` renders the block from `contract.domain`, sharing the field-type resolver with `FieldOutputTypes` via `resolveModelFieldType`, and reads each to-one relation's `nullable` for the `| null` wrapper. Name collisions, non-identifier names, and unresolvable same-space relation targets throw structured errors before anything is written. 3. **ORM phantoms.** One `declare readonly _row?: Row` line on `CollectionImpl` and one `readonly _row?: SimplifyDeep<IncludedRow<...>>` member on `MongoCollection`. 4. **Proof.** Type tests in both ORM packages and the demo assert equality between the ORM's rows and the emitted types for every fixture model, every cardinality, polymorphic roots and variants, projections, nested and refined includes, and every `Shape` refusal as a `@ts-expect-error`. 5. **Docs.** `docs/reference/model-and-result-types.md`, with every snippet copied from a passing type test; ADR 250; the subsystem doc paragraph; README links; the user skill. ## Behavior changes & evidence - **`contract.d.ts` exports `Models` and `models`.** `packages/1-framework/3-tooling/emitter/src/model-types-emission.ts`, `packages/1-framework/3-tooling/emitter/src/generate-contract-dts.ts`. Evidence: `packages/1-framework/3-tooling/emitter/test/model-types-emission.test.ts`, `packages/3-extensions/sql-orm-client/test/fixtures/generated/contract.d.ts`. - **`Scalars` and `Shape` are exported from both families' contract types.** `packages/1-framework/1-core/framework-components/src/execution/model-types.ts`, `packages/2-sql/1-core/contract/src/exports/types.ts`, `packages/2-mongo-family/1-foundation/mongo-contract/src/exports/index.ts`. Evidence: `packages/1-framework/1-core/framework-components/test/model-types.test-d.ts`. - **`ResultType` works on ORM collections.** `packages/3-extensions/sql-orm-client/src/collection.ts`, `packages/2-mongo-family/5-query-builders/orm/src/collection.ts`. Evidence: `packages/3-extensions/sql-orm-client/test/model-types.test-d.ts`, `packages/2-mongo-family/5-query-builders/orm/test/model-types.test-d.ts`. - **Relation nullability is a contract fact.** `packages/1-framework/0-foundation/contract/src/domain-types.ts`, `packages/1-framework/0-foundation/contract/src/validate-domain.ts`, `packages/2-sql/2-authoring/contract-psl/src/psl-relation-resolution.ts`. Evidence: the validator tests beside `validate-domain.ts`, the PSL interpreter tests in both families, and `packages/3-extensions/sql-orm-client/test/include-cardinality.test-d.ts`. ## Project close-out Project definition of done, from the spec: | Item | Evidence | | --- | --- | | Repo checks, `pnpm fixtures:check`, Linear close-out | CI green on the previous head; `fixtures:check` stable across two runs; TML-3233 In Review, TML-3234 Done | | Every test in the spec's test list exists and passes | `packages/1-framework/1-core/framework-components/test/shape.test-d.ts`, `packages/3-extensions/sql-orm-client/test/model-types.test-d.ts`, `packages/2-mongo-family/5-query-builders/orm/test/model-types.test-d.ts`, `packages/1-framework/3-tooling/emitter/test/model-types-emission.test.ts`, `examples/prisma-8-demo/test/demo-dx.types.test.ts` | | All fixtures regenerated; `contract.json` changes limited to the new field | `pnpm fixtures:check` covers the port fixtures and snapshot stores; JSON diffs are `nullable` flags and the `_generated` banner only | | Docs page, index and README links, subsystem paragraph, ADR | `docs/reference/model-and-result-types.md`, `docs/README.md`, both ORM READMEs, subsystem doc 2, ADR 250 | | One PR over 1,000 lines on this branch | This PR | Migration: nothing to migrate; ADR 250 and the reference page were written in place during the project. Reference strip: no file outside the project folder referenced it. Deleted: `projects/model-and-result-types/` (spec, plan, design notes, design brief, Shape brief, slice 2 brief, deferred). Retro: `drive/retro/findings.md` 2026-09-10, with F20 in `drive/calibration/failure-modes.md` and a new project-DoD item in `drive/calibration/dod.md`. ## Testing performed - `pnpm build` (root) - `pnpm test:packages` (1186 files; one pre-existing race in `module-identity.test.ts`, passes on rerun) - `pnpm test` in framework-components (635), emitter (222), SQL emitter (184), Mongo emitter (64), sql-orm-client (787), Mongo ORM (235), prisma-8-demo (74) - `pnpm typecheck` and `pnpm lint` in every touched package (demo lint failure pre-existing, see reviewer notes) - `pnpm lint:deps`, `pnpm lint:skills` - `pnpm fixtures:check` (stable across two runs; `contract.json` diffs are the `_generated` banner only) - `pnpm test:integration` (372/373 files; the one failure is the pre-existing `test.fails` port noted above) - `pnpm lint:casts`, `pnpm lint:throws`, `pnpm lint:framework-vocabulary` ## Follow-ups - Rename `ResultType` to `Result` (open question in the brief; not done here). - `Scalars` versus `Row` naming, and the `_` separator, are open in the brief and can be changed before release. ## Alternatives considered - **Emit `GetPayload`-style types per query.** Ties the contract to one lane's vocabulary and grows `contract.d.ts` without bound. - **`With<M, 'rel'>`, a model plus a union of relation names.** The first draft. Replaced by `Shape` before merge: it could not drop or narrow scalars or nest, so an endpoint response still needed hand-written types. `With<User, 'posts'>` is `Shape<User, { posts: {} }>`. - **Prisma 7's boolean form, `{ id: true; posts: { title: true } }`.** Verbose: every scalar must be listed for the wide case. `'+'`/`'-'` sigils were chosen over words because words collide with field names. - **A relation-selection parameter on the contract, `Model<Contract, 'User', { posts: { comments: true } }>`.** Takes the contract rather than the model and reads as a query. `Shape` is a pure utility over the model type and describes end states, not queries. - **A parameter mapping relation name to the model type that sits there.** Makes the user import and restate what the contract already knows. - **`Models.public.User` as nested TypeScript namespaces.** `namespace public` does not compile; `public` is reserved in strict mode and is the default Postgres schema. Folding the schema into the member name gives the importable form; the declared constant gives the dotted form. - **Flat `export type User` at the top level.** Adding a second `User` in another schema would silently remove the alias and break every import of it. - **A runtime `db.models` accessor.** Either an object pretending to be a row or a definition object whose `typeof` is not the model. Dotted access already exists with no runtime. - **A separate `RowOf` helper for ORM queries.** `ResultType` exists and is documented; the collections now carry the marker it reads. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated. - [x] The PR title is in `TML-NNNN: <sentence-case title>` form. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer See Reviewer notes above. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 10 天前 | |
docs: rewrite README for Prisma 8, fix orm init dist-tag, sweep "Prisma Next" prose (#30248) ## Linked issue n/a — no Linear ticket. Follow-up to the README banner swap in #30225. ## At a glance The README's getting-started commands, before and after, checked against [prisma.io/docs/getting-started](https://www.prisma.io/docs/getting-started): ```bash # before npm create prisma@next npx @prisma/cli@next orm init # after npm create prisma npx prisma orm init npx prisma skills sync ``` The `prisma` package has no `next` dist-tag any more (`latest` is `8.0.0-rc.13`, `prev` is `7.10.0`), so the old commands no longer resolve. ## Summary The README still introduced the product as "Prisma Next" in Early Access, pointed at the removed `next` dist-tag, listed extensions by their `@internal/*` workspace names, and linked to `prisma/prisma`. The rest of the repo had about a thousand prose mentions of the working name. This PR fixes all of it and one real bug the sweep turned up. ## Decision Five commits, each reviewable on its own (the fifth only records the sweep against the in-flight upgrade-instruction files for the coverage check): 1. **Rewrite the README against the live docs.** Every instruction in it now matches the getting-started, quickstart, `orm init`, `skills`, and extensions pages in prisma/web. 2. **Fix `orm init` to install `prisma@latest`.** The CLI added `prisma@next` as a dev dependency. That tag no longer exists on npm, so `orm init` fails at the install step for anyone running it today. The engine fallback moves from `@prisma/cli-engine@next` (0.2.3, stale) to `@latest` (0.3.0). 3. **Replace "Prisma Next" with "Prisma 8" in prose repo-wide.** Docs, doc comments, READMEs, package descriptions, skill references, and user-facing strings. 4. **Carry the pnpm trust-policy exemptions into the tarball smoke tests.** The scratch installs those tests run trip a trust-downgrade check on `undici-types@6.21.0` (no provenance, while 6.13.0 and 6.18.2 had it). The repo already exempts it for the workspace install; the test kit now restates `trustPolicy` and `trustPolicyExclude` in the scratch project the way it restates the release-age settings. Reproduced on main with a fresh metadata cache, so this is a pre-existing failure that any run without cached metadata hits. ## Reviewer notes - **Rebased on #30229.** That PR's release-candidate banner and its `scorecard.md` link replace the roadmap reference in the README, and `ROADMAP.md` stays deleted. The prose sweep re-applied cleanly on top of its CONTRIBUTING, SECURITY, and governance edits. - **Dated records keep the old name**, matching the allowances `scripts/lint-legacy-name.mjs` already defines for the `prisma-next` identifier: `CHANGELOG.md`, `docs/releases/`, the ADRs, `projects/`, and `drive/`. Rewriting those would misreport what was true at the time, and a mechanical pass produced sentences like "Prisma Next becomes Prisma 8" turning into "Prisma 8 becomes Prisma 8". - **Identifiers are untouched.** `prisma-next` package names, paths, env vars (`PRISMA_NEXT_*`), `PrismaNext*` types, the `images/prisma-next.png` file, and the `prisma-next.md` primer (the docs still call it that) are all unchanged. Renaming any of those is a behaviour change with an upgrade path, not a docs fix. - **The sweep is mechanical.** The third commit is a `sed` of `Prisma Next` and `Prisma-next` to `Prisma 8` over 345 files. Three sentences that became self-referential (`ROADMAP.md`, `ROADMAP.html`, `scorecard.md`) were rewritten by hand. - **`README.md` supported-databases section** now says PostgreSQL and MongoDB are first-class and SQLite is planned next, which is what [/docs/orm](https://www.prisma.io/docs/orm) says. The previous text referenced work "before the 8.0.0-rc.1 release". - **Discord channel name dropped.** The README linked to a `prisma-next` channel I could not verify; it now links to Discord generically. ## Behavior changes & evidence - **`orm init` installs `prisma@latest`** instead of `prisma@next`, and falls back to `@prisma/cli-engine@latest` when the manifest does not pin the engine. [packages/1-framework/3-tooling/cli/src/orm/init.ts](packages/1-framework/3-tooling/cli/src/orm/init.ts), [packages/1-framework/3-tooling/cli/src/orm/init-packages.ts](packages/1-framework/3-tooling/cli/src/orm/init-packages.ts). Evidence: [packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts](packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts), [test/integration/test/cli.init-skill-distribution.integration.test.ts](test/integration/test/cli.init-skill-distribution.integration.test.ts). - **Scaffolded quick-reference notes and the skill quickstart** tell users to run `prisma@latest orm init`. [packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md](packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md), [skills/prisma-8/references/quickstart.md](skills/prisma-8/references/quickstart.md). Evidence: [packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap](packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap). - **No other runtime change.** Every other edit is prose in docs, comments, `package.json` descriptions, and `//` comments in test fixture schemas, which the emitter drops. ## Testing performed - `pnpm test` in `packages/1-framework/3-tooling/cli`: 115 files, 1437 tests passed - `pnpm lint:legacy-name`, `pnpm lint:docs`, `pnpm lint:skills`, `pnpm lint:rules:footprint`, `pnpm lint:manifests`: all pass (the `errors` README warning is pre-existing) - `pnpm fixtures:check` could not run in this worktree because the examples' `prisma` binary is not installed. The only schema edits are `//` comments, which do not reach the emitted contract. ## Skill update `skills/prisma-8/references/quickstart.md` is updated in the second commit: its `orm init` commands moved from `@prisma/cli@next` to `prisma@latest`, the same change the README makes. ## Alternatives considered - **Rename the identifiers too** (`prisma-next.md`, `PRISMA_NEXT_*`, `PrismaNext*` types, the image file). Each is a user-visible surface with an upgrade path, and the docs still name `prisma-next.md`. Left for a deliberate rename with upgrade instructions. - **Sweep the ADRs, changelog, and project write-ups as well.** The repo's own legacy-name lint exempts them as dated records, and the mechanical pass mangled sentences that describe the rename itself. Following the existing policy keeps the diff honest. - **Keep `@latest` on the commands, as the docs pages write them.** The v8 line is `latest` now, so the tag adds nothing; the README uses the bare `npm create prisma` and `npx prisma …` forms. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated (the CLI install-command tests and snapshots). - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer The first two commits are small and worth reading line by line. The third is large but uniform; spot-check a few files rather than reading all 345. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
docs: rewrite README for Prisma 8, fix orm init dist-tag, sweep "Prisma Next" prose (#30248) ## Linked issue n/a — no Linear ticket. Follow-up to the README banner swap in #30225. ## At a glance The README's getting-started commands, before and after, checked against [prisma.io/docs/getting-started](https://www.prisma.io/docs/getting-started): ```bash # before npm create prisma@next npx @prisma/cli@next orm init # after npm create prisma npx prisma orm init npx prisma skills sync ``` The `prisma` package has no `next` dist-tag any more (`latest` is `8.0.0-rc.13`, `prev` is `7.10.0`), so the old commands no longer resolve. ## Summary The README still introduced the product as "Prisma Next" in Early Access, pointed at the removed `next` dist-tag, listed extensions by their `@internal/*` workspace names, and linked to `prisma/prisma`. The rest of the repo had about a thousand prose mentions of the working name. This PR fixes all of it and one real bug the sweep turned up. ## Decision Five commits, each reviewable on its own (the fifth only records the sweep against the in-flight upgrade-instruction files for the coverage check): 1. **Rewrite the README against the live docs.** Every instruction in it now matches the getting-started, quickstart, `orm init`, `skills`, and extensions pages in prisma/web. 2. **Fix `orm init` to install `prisma@latest`.** The CLI added `prisma@next` as a dev dependency. That tag no longer exists on npm, so `orm init` fails at the install step for anyone running it today. The engine fallback moves from `@prisma/cli-engine@next` (0.2.3, stale) to `@latest` (0.3.0). 3. **Replace "Prisma Next" with "Prisma 8" in prose repo-wide.** Docs, doc comments, READMEs, package descriptions, skill references, and user-facing strings. 4. **Carry the pnpm trust-policy exemptions into the tarball smoke tests.** The scratch installs those tests run trip a trust-downgrade check on `undici-types@6.21.0` (no provenance, while 6.13.0 and 6.18.2 had it). The repo already exempts it for the workspace install; the test kit now restates `trustPolicy` and `trustPolicyExclude` in the scratch project the way it restates the release-age settings. Reproduced on main with a fresh metadata cache, so this is a pre-existing failure that any run without cached metadata hits. ## Reviewer notes - **Rebased on #30229.** That PR's release-candidate banner and its `scorecard.md` link replace the roadmap reference in the README, and `ROADMAP.md` stays deleted. The prose sweep re-applied cleanly on top of its CONTRIBUTING, SECURITY, and governance edits. - **Dated records keep the old name**, matching the allowances `scripts/lint-legacy-name.mjs` already defines for the `prisma-next` identifier: `CHANGELOG.md`, `docs/releases/`, the ADRs, `projects/`, and `drive/`. Rewriting those would misreport what was true at the time, and a mechanical pass produced sentences like "Prisma Next becomes Prisma 8" turning into "Prisma 8 becomes Prisma 8". - **Identifiers are untouched.** `prisma-next` package names, paths, env vars (`PRISMA_NEXT_*`), `PrismaNext*` types, the `images/prisma-next.png` file, and the `prisma-next.md` primer (the docs still call it that) are all unchanged. Renaming any of those is a behaviour change with an upgrade path, not a docs fix. - **The sweep is mechanical.** The third commit is a `sed` of `Prisma Next` and `Prisma-next` to `Prisma 8` over 345 files. Three sentences that became self-referential (`ROADMAP.md`, `ROADMAP.html`, `scorecard.md`) were rewritten by hand. - **`README.md` supported-databases section** now says PostgreSQL and MongoDB are first-class and SQLite is planned next, which is what [/docs/orm](https://www.prisma.io/docs/orm) says. The previous text referenced work "before the 8.0.0-rc.1 release". - **Discord channel name dropped.** The README linked to a `prisma-next` channel I could not verify; it now links to Discord generically. ## Behavior changes & evidence - **`orm init` installs `prisma@latest`** instead of `prisma@next`, and falls back to `@prisma/cli-engine@latest` when the manifest does not pin the engine. [packages/1-framework/3-tooling/cli/src/orm/init.ts](packages/1-framework/3-tooling/cli/src/orm/init.ts), [packages/1-framework/3-tooling/cli/src/orm/init-packages.ts](packages/1-framework/3-tooling/cli/src/orm/init-packages.ts). Evidence: [packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts](packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts), [test/integration/test/cli.init-skill-distribution.integration.test.ts](test/integration/test/cli.init-skill-distribution.integration.test.ts). - **Scaffolded quick-reference notes and the skill quickstart** tell users to run `prisma@latest orm init`. [packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md](packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md), [skills/prisma-8/references/quickstart.md](skills/prisma-8/references/quickstart.md). Evidence: [packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap](packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap). - **No other runtime change.** Every other edit is prose in docs, comments, `package.json` descriptions, and `//` comments in test fixture schemas, which the emitter drops. ## Testing performed - `pnpm test` in `packages/1-framework/3-tooling/cli`: 115 files, 1437 tests passed - `pnpm lint:legacy-name`, `pnpm lint:docs`, `pnpm lint:skills`, `pnpm lint:rules:footprint`, `pnpm lint:manifests`: all pass (the `errors` README warning is pre-existing) - `pnpm fixtures:check` could not run in this worktree because the examples' `prisma` binary is not installed. The only schema edits are `//` comments, which do not reach the emitted contract. ## Skill update `skills/prisma-8/references/quickstart.md` is updated in the second commit: its `orm init` commands moved from `@prisma/cli@next` to `prisma@latest`, the same change the README makes. ## Alternatives considered - **Rename the identifiers too** (`prisma-next.md`, `PRISMA_NEXT_*`, `PrismaNext*` types, the image file). Each is a user-visible surface with an upgrade path, and the docs still name `prisma-next.md`. Left for a deliberate rename with upgrade instructions. - **Sweep the ADRs, changelog, and project write-ups as well.** The repo's own legacy-name lint exempts them as dated records, and the mechanical pass mangled sentences that describe the rename itself. Following the existing policy keeps the diff honest. - **Keep `@latest` on the commands, as the docs pages write them.** The v8 line is `latest` now, so the tag adds nothing; the README uses the bare `npm create prisma` and `npx prisma …` forms. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated (the CLI install-command tests and snapshots). - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer The first two commits are small and worth reading line by line. The third is large but uniform; spot-check a few files rather than reading all 345. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
feat(sql): @noCheck opts a column out of generated CHECK constraints (#29928) ## Linked issue No Linear ticket — the operator waived tracker integration for this project. Slice 3 of [sql-check-constraint-unification](projects/sql-check-constraint-unification/spec.md) ([slice spec](projects/sql-check-constraint-unification/slices/check-enforcement-opt-out/spec.md)); follows #29892 (slice 1) and #29894 (slice 2). ## At a glance ```prisma model User { id Int @id role Role // enforced: membership check derived kind Role @noCheck // no checks derived for this column roles Role[] @noCheck(membership) // elementNotNull still derived; membership not tags String[] @noCheck(elementNotNull) } ``` TS equivalent: `f.enum(Role).noCheck()`, `f.text().many().noCheck('elementNotNull')`. And `contract infer` now emits the attribute itself: pulling a database whose list column has no element-non-null check produces `tags String[] @noCheck(elementNotNull)` — so a pulled schema passes `db verify --schema-only` immediately, instead of needing one migration first. ## Decision This PR ships three things: 1. **A per-column, per-kind opt-out for generated CHECK constraints** — PSL field attribute `@noCheck`, TS builder method `.noCheck(...)`, persisted on the column as `noCheck: ['membership' | 'elementNotNull']`. Opting out does not change declared types: the enum union and the non-null element type stand, and the divergence risk is stated in the user docs ([ADR 244](docs/architecture%20docs/adrs/ADR%20244%20-%20Check%20constraints%20are%20opaque%20wire-named%20expressions.md) § "Follow-up: a per-column opt-out", now marked delivered). 2. **Conservative infer emission of that opt-out.** `contract infer` computes the derived wire name for each list column and emits `@noCheck(elementNotNull)` exactly when no live check carries that name. Comparison is by full physical name only — never by predicate body (introspection is opaque). Hand-written live checks are untouched: still `--strict`-only extras. 3. **`composeCheckWirePrefix` lifted into `@internal/sql-schema-ir/naming`** (with a single `CheckKind` alias), replacing the file-private composition in build-contract and two hand-rolled test duplications. The whole effect is spent at contract-build time: an opted-out check is simply never declared, so the differ, verifier, planner, ops, and DDL are untouched by construction — there is no verify-side suppression mechanism, deliberately. ## Reviewer notes - **The largest commits are tests.** The feature surface is small; most of the diff is the lifecycle/e2e coverage. Spot-check `infer-roundtrip-fidelity.e2e.test.ts` — the interim `expectConvergesOnDerivedChecks` helper is deleted and all three call sites now assert immediate cleanliness. - **PSL tolerates `@noCheck` on a source-declared non-managed table** (drops the flag, no diagnostic), matching the TS build. This came out of the independent review pass: the first implementation rejected it on the PSL path only, which made a pulled-then-marked-`external` schema fail to load while the identical TS contract built. Both surfaces now drop-not-persist; a byte-for-byte parity test pins it. - **"membership" is unreachable at infer time** and pinned as intended: infer never emits domain enums (pre-existing gap, project non-goal), so no pulled column has member values and no membership check is ever derived from a pull. The emission site carries the comment. - **The e2e derives the expected constraint through the toolchain itself** (pull → remove `@noCheck` → migrate → assert catalog name shape → re-pull) rather than importing naming helpers — the cli-journeys test package consumes the published `@prisma/orm-*` root and the single-import-root rule (ADR 242) forbids mixing in `@internal/*`. - The independent review also cleared, with evidence: bare-form resolution parity across surfaces (down to `storageHash`), the wire-schema narrow (rejects empty/duplicate/unsorted), specifier-stamping order soundness, stale kinds impossible after a column shape change (`CONTRACT.CHECK_OPTOUT_INVALID` on rebuild), and mixed live-check inference. ## How it fits together 1. **Naming substrate** — `composeCheckWirePrefix(table, column, kind)` and the `CheckKind` alias move into `packages/2-sql/1-core/schema-ir/src/naming.ts`, the module that already owns the content hash and byte-cap truncation. 2. **Contract shape** — `StorageColumn` gains optional `noCheck` (presence means opted out, never empty, canonical ascending order), enforced by a `.narrow` on `StorageColumnSchema`. Contracts that don't use the flag are byte-identical, so no existing fixture regenerates. 3. **Authoring** — both surfaces converge on the definition tree's `FieldNode.noCheck`; `build-contract` resolves the bare form to the kinds derivable for the column shape, validates inapplicable kinds (`CONTRACT.CHECK_OPTOUT_INVALID`), filters the render hook's candidates, and persists the flag. The `managed`-table gate and the specifier strip funnel are unchanged — slice 3 adds no producer of checks, so "wire-named == derived" stays exact. 4. **Infer** — `buildScalarField` renders the expected expression with the in-package hook, composes the wire name with the shared helpers, and emits `@noCheck(elementNotNull)` when the live table lacks it. 5. **Proof** — unit tests for every validation row and both emission branches; real-database lifecycle tests (opt-out added later → one destructive drop; removed → one additive add; fresh create → enforcement genuinely absent, NULL-element insert succeeds); e2e journeys for the three pull scenarios (no live check, wire-named live check, hand-written live check). ## Behavior changes & evidence - **A pulled schema verifies clean immediately.** Implementation: `packages/3-targets/3-targets/postgres/src/core/psl-infer/infer-model-blocks.ts`. Evidence: `test/integration/test/cli-journeys/infer-roundtrip-fidelity.e2e.test.ts` (19 tests, three flipped call sites + two new journeys). - **`@noCheck` / `.noCheck()` suppress derivation per column and kind.** Implementation: `packages/2-sql/2-authoring/contract-ts/src/build-contract.ts`, `packages/2-sql/2-authoring/contract-psl/src/psl-field-resolution.ts`. Evidence: `packages/2-sql/2-authoring/contract-ts/test/check-constraint.authoring.test.ts`, `packages/2-sql/2-authoring/contract-psl/test/interpreter.no-check.test.ts` (incl. PSL↔TS parity with storageHash equality). - **Waived enforcement is real at the database.** Implementation: none beyond non-emission. Evidence: `packages/3-targets/6-adapters/postgres/test/migrations/check-lifecycle-e2e.integration.test.ts` (NULL-element insert succeeds on an opted-out column; add/remove lifecycle plans exactly one destructive/additive call). - **Declared types are unchanged by an opt-out.** Evidence: `packages/2-sql/2-authoring/contract-ts/test/no-check-declared-types.test-d.ts` (pins the union and `ReadonlyArray` non-null element types). - **Docs**: ADR 244 §§129/131/174 amended; user-facing risk statement in `skills/prisma-8/references/contract.md`; brownfield quickstart updated; two stale subsystem-doc lines from the pre-slice-1 model fixed in passing. ## Compatibility / migration / risk Purely additive: no existing schema, contract, or fixture changes meaning or bytes (`fixtures:check` clean). The new wire-schema key is optional and presence-only. No schema-IR, differ, verifier, planner, op, or DDL file is touched — the DoD's grep-clean requirement holds on the diff. The accepted risk is the documented one: an opted-out column's types still claim what enforcement no longer guarantees. ## Testing performed - `pnpm -w build` — 86/86; `pnpm typecheck` — 165/165 - `@internal/sql-schema-ir` 184 · `@internal/sql-contract` 322 · `@internal/sql-contract-ts` 458 · `@internal/sql-contract-psl` 424 · `@internal/target-postgres` 1387 — all pass - `check-lifecycle-e2e.integration.test.ts` 14/14 (real database); `infer-roundtrip-fidelity.e2e.test.ts` 19/19; `brownfield-adoption.e2e.test.ts` 2/2 - `pnpm lint` on all touched packages, `pnpm lint:deps`, `pnpm fixtures:check`, `pnpm check:upgrade-coverage --mode pr` — all clean ## Follow-ups - `packages/2-sql/2-authoring/contract-ts/schemas/data-contract-sql-v1.json` is long-stale (already omitted `many`/`control`/`valueSet`; now also `noCheck`) — tracked separately, not worsened here. - Project close-out (after this slice merges): Migration System subsystem doc section + `projects/sql-check-constraint-unification/` deletion, per the project plan. ## Alternatives considered - **Column `control` as the opt-out surface** — rejected: enforcement waiver is a statement about one derived constraint on an otherwise fully managed column; column control is a policy axis with verify/plan semantics far beyond checks, and conflating them would make "don't derive a check" imply "don't manage this column". - **Verify-/plan-time suppression of a declared-but-missing check** — rejected: `declaredMissing` has no suppression path even under `external`, and adding one would break "authoring declares, the planner reconciles". Not declaring the check is the invariant-preserving mechanism. - **A model-level attribute** — rejected: kinds attach to columns, blanket waivers invite accidents, and infer decides per column. - **Strict PSL validation on non-managed tables** — rejected during review for TS parity and order-independence (neither surface can see specifier-stamped policy at validation time). - **Computing the expected wire name in the e2e via naming imports or a hardcoded hash** — rejected: the former violates the single-import-root rule, the latter drifts silently; the journey derives the name through the toolchain instead. ## Checklist - [x] All commits carry DCO sign-off - [x] I have read CONTRIBUTING.md - [x] Tests added/updated for every behavior change - [x] Title follows the prevailing convention 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added `noCheck` support for opting out of generated membership and list-element checks. * Added selective opt-out forms in TypeScript and PSL, with validation for invalid or duplicate options. * Preserved declared field types when checks are disabled. * Added automatic inference of missing check waivers from existing PostgreSQL databases. * **Bug Fixes** * Improved schema verification and migration behavior for enforced and unenforced list checks. * **Documentation** * Documented check opt-outs, inference behavior, validation errors, and brownfield database workflows. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> | 1 个月前 | |
One config and one command language for the ORM: prisma.config.ts, driven by the unified CLI (#30058) Every surface in this repo now agrees on one config file and one command language. A freshly scaffolded project looks like this: ```ts // prisma.config.ts — the only config file the ORM reads, shared with the unified Prisma CLI import 'dotenv/config'; import { defineConfig } from '@prisma/cli-engine'; import { defineConfig as ormConfig } from '@prisma/orm-postgres/config'; export default defineConfig({ orm: ormConfig({ contract: './src/prisma/contract.prisma', db: { connection: process.env['DATABASE_URL']! }, }), }); ``` and is driven like this: ``` prisma-cli orm init # scaffold (init sits under `orm`; compute owns top-level init) prisma-cli contract emit # every other ORM command is top-level prisma-cli db init prisma-cli migration plan --name first prisma-cli migrate prisma-cli db verify ``` **The decision: the transition period is over.** Until now the loaders still accepted the retired `prisma-next.config.ts` filename and the old un-nested config shape (with deprecation warnings), and this repo still built its own `prisma-next` binary whose command tree didn't match the CLI users actually install. This PR deletes all of it. A config in the old spelling now fails loudly, and the workspace binary is a faithful stand-in for the real host — same command paths, same loader semantics. ## Why now, and what it flushed out The soft fallbacks weren't just clutter — they were hiding bugs. Because the workspace bin loaded config its own way and mounted commands at its own paths, the 22 ORM commands had never once run the way `@prisma/cli` actually runs them. Making the workspace bin mount the family exactly like the shipped host immediately surfaced three real defects, all fixed here: 1. **Mounted commands couldn't construct.** The family's retired-invocation redirects pointed at command paths that only existed in the old standalone tree, so the engine rejected the whole CLI at build time. 2. **Relative config paths crashed every path-consuming command.** The engine's loader hands commands the config exactly as authored, so under the real host `contract.output` arrived as `./src/prisma/contract.json` and `contract emit` died inside `createRequire`. This is the failure Shane hit with `bunx prisma@next orm init` — init succeeds, then the very next command falls over. The ORM command boundary (`defineOrmCommand`) now finalizes contract and migration paths idempotently, so both hosts hand handlers the same absolute paths. 3. **`init` installed a broken toolchain.** It added `@prisma/cli-engine` untagged, which resolves npm's lagging `latest` (0.0.9) instead of the version `@prisma/cli` actually runs against. It now reads the exact engine version from the installed CLI's own manifest. An end-to-end QA run (empty directory → init → emit → `db init` → typed queries → schema change → plan → migrate → verify, against the *published* `@prisma/cli@8.0.0-rc.5` with this branch's toolchain) is green top to bottom. That run also caught a fourth defect: the TypeScript starter contract triggered `PN_CONTRACT_TYPED_FALLBACK_AVAILABLE` warnings on its own first emit; it now uses the typed model-token form the warning recommends. ## What changed, piece by piece - **Loaders**: `@internal/config-loader` and the bin's loader read only `prisma.config.ts` with the `$prismaConfig` envelope. The deprecated-filename discovery, the flat-shape acceptance, the `CONFIG.DEPRECATED_*` codes, and the old Symbol-based format marker are deleted. The telemetry enricher's matching fallbacks too. - **Binary**: the workspace bin is named `prisma` and mounts the family the way the host does — commands top-level, `init` under `orm`. Examples, e2e journeys, and harnesses drive it through those paths, which is what finally puts the mounted tree under test. - **Strings**: every user-facing command string (errors, docs, READMEs, scaffolded scripts, next-step hints) reads `prisma <command>` / `prisma orm init`. - **Ratchet**: `scripts/lint-legacy-name.mjs` now *forbids* `prisma-next.config.ts` repo-wide, so the retired spelling can't creep back. Deliberate residuals stay allowed: `prisma-next.md`, `// use prisma-next` schema headers, `prisma-next-*` skill names, the per-user telemetry dir. - **Upgrade path**: `upgrades/8.0.0-rc.3-to-8.0.0-rc.4/` entries in both skill clusters walk consumers through the rename, the envelope rewrite, the dependency change, and the command grammar. Verified: 15,296 package tests, 2,075 integration tests, fixtures regenerated and stable, all repo lints green. One honest gap: the upgrade-instruction entries were authored from the applied diff, not validated by the full revert-and-replay flow. ## Alternatives considered - **Keep the deprecation fallbacks another release.** Rejected: every surface that still worked under the old spelling postponed exactly the couplings this change needed to surface, and the fallback paths themselves had no coverage in the real host. - **Mount the workspace commands under `prisma orm <command>`.** This PR briefly did that — the config *section* is named `orm`, so it looked right. The published rc.5 host proved otherwise: its tree is top-level with only `init` nested. The workspace bin now copies the host instead of guessing. - **Fix path finalization in the engine instead.** The cleaner home would be the engine handing validators the config file's path, but that's a prisma-cli-repo API change. The command-boundary fix works with today's engine, is idempotent, and stays correct if the engine later finalizes upstream. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> | 1 个月前 | |
migration plan and migration new no longer need contract.d.ts on disk; vitest configs cannot budget with timeouts.default (#30298) ## Linked issue n/a — the two follow-ups deferred from #30293 (db init, db update and migrate no longer strand the database when contract.d.ts is missing). ## Skill update n/a — no user-facing surface changes; `migration plan` and `migration new` stop needing a `contract.d.ts` next to `contract.json`, which no skill ever told users to keep. ## At a glance Before, `migration plan` copied whatever `contract.d.ts` sat next to `contract.json` into the snapshot store, after the package was already written: ```ts const [contractJsonRaw, contractDts] = await Promise.all([ readFile(destinationArtifacts.jsonPath, 'utf-8'), readFile(destinationArtifacts.dtsPath, 'utf-8'), ]); await writeContractSnapshot(migrationsDir, destHash, { contractJson: JSON.parse(contractJsonRaw), contractDts }); ``` Now it renders the declarations from the emitted JSON it already parsed, before anything is written, through the same client method the db commands use: ```ts // packages/1-framework/3-tooling/cli/src/control-api/operations/migration-plan.ts const rendered = await renderSnapshotDeclarations({ client: options.client, contractJson: emittedContractJson, contractJsonPath: contractPathAbsolute, resolveImportSpecifier, }); ``` And a vitest config can no longer do this: ```text $ pnpm lint:vitest-timeouts lint-vitest-timeouts: timeouts.default is 100ms (200ms on CI) and fails healthy tests; use timeouts.vitestPackageDefault, or timeouts.databaseOperation for a package that talks to a database: packages/a/vitest.config.ts:6 testTimeout: timeouts.default ``` ## Decision This PR ships three things: 1. **Every snapshot writer renders its declarations from the JSON it stores.** `migration plan` and `migration new` were the last two writers that copied the sibling `contract.d.ts` from disk. They now render through `renderContractDts` on the control client, before any package or store entry is written. With no reader left, `readContractSnapshotDts` and the `contractDts` field on `contractAt` are gone from `@internal/migration-tools`. 2. **`contract.d.ts` is generated from the canonical contract.** `emit()` canonicalised the contract for `contract.json` but generated the declarations from the contract as authored, so a snapshot rendered from the JSON could differ from the emitted file in the order of models, fields, relations, and the keys of literal types. The mongo e2e journey compares the two byte for byte and caught it. `emit()` now generates from the canonical JSON round-trip and the literal-type serializer sorts keys, so a render from `contract.json` reproduces the emitted file exactly. Every committed `contract.d.ts` fixture is re-emitted in that order; the diff is reordering only. 3. **A lint keeps `timeouts.default` out of vitest test and hook budgets.** #30293 swept 31 configs off the 100ms value that CI doubles into a false failure. `timeouts.default` stays, because tests use it for short waits, so the guard is a lint over tracked `vitest.config.ts` files, wired into `pnpm lint:vitest-timeouts`, `test:scripts`, and CI. ## Reviewer notes - **The fixture re-emit is large but mechanical.** 227 `contract.d.ts` files change, all of them collections reordered into canonical order. Nothing in `contract.json` changes. The in-flight upgrade entry for rc.11 to rc.12 declares `changes: []`, since a consumer who re-emits sees the same reordering and has nothing to do. - **The from-side snapshot writes are gone, not moved.** `migration plan` used to write the from contract's store entry when the origin was a ref or an auto-baseline. In both cases that contract came out of the store through `contractAt`, so the entry already existed and the write-if-absent store made the write a no-op. The same holds for a `--to` destination. Only the emitted contract can be new, so only it is rendered and written. - **The plan and new commands now take the client factory** like the db commands, with `migrationPlanCommand` and `migrationNewCommand` kept as the constants the family tree mounts. The command tests mount a fake client from [offline-project.ts](packages/1-framework/3-tooling/cli/test/orm/fixtures/offline-project.ts), whose fake family cannot drive the real emitter. - **`timeouts.default` is not retired.** Ten tests use it as a short wait: a connection timeout, a polling budget. The lint rejects it only as `testTimeout` or `hookTimeout` in a vitest config, and its doc comment now says so. ## How it fits together 1. **One helper renders for every writer.** [snapshot-declarations.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/snapshot-declarations.ts) takes a client, the JSON, its path and the project's import resolver, and returns the declarations or the same structured errors the ref preflight already produced. `preflightRefAdvancement` in [ref-advancement.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/ref-advancement.ts) now calls it. 2. **The scaffolding operations render before they write.** [migration-plan.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/migration-plan.ts) renders right after the import resolver is built, ahead of the seed phase, and writes the destination entry with the planned package. [migration-new.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/migration-new.ts) renders before `writeMigrationPackage`. 3. **The store stops serving declarations.** [aggregate.ts](packages/1-framework/3-tooling/migration/src/aggregate/aggregate.ts) reads only `contract.json` for `contractAt`; [plan-resolution.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/plan-resolution.ts) drops the fields nobody consumes. 4. **The lint.** [lint-vitest-timeouts.mjs](scripts/lint-vitest-timeouts.mjs) walks `git ls-files` for vitest configs and names each `testTimeout` or `hookTimeout` set to `timeouts.default`. ## Behavior changes & evidence - **`migration plan` and `migration new` refuse before writing anything when the destination's declarations cannot be rendered**, and write a snapshot whose `contract.d.ts` is rendered from the emitted JSON. Implementation: [migration-plan.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/migration-plan.ts), [migration-new.ts](packages/1-framework/3-tooling/cli/src/control-api/operations/migration-new.ts). Evidence: [migration-plan.test.ts](packages/1-framework/3-tooling/cli/test/orm/migration-plan.test.ts), [migration-new.test.ts](packages/1-framework/3-tooling/cli/test/orm/migration-new.test.ts). - **Neither command needs `contract.d.ts` on disk any more.** The offline fixture stopped writing one, and every existing plan, new, and tamper test still passes. Evidence: [offline-project.ts](packages/1-framework/3-tooling/cli/test/orm/fixtures/offline-project.ts). - **`contractAt` no longer carries `contractDts`, and `readContractSnapshotDts` is gone.** Implementation: [contract-snapshot-store.ts](packages/1-framework/3-tooling/migration/src/contract-snapshot-store.ts), [types.ts](packages/1-framework/3-tooling/migration/src/aggregate/types.ts). Evidence: [contract-at.test.ts](packages/1-framework/3-tooling/migration/test/aggregate/contract-at.test.ts). - **A vitest config budgeting with `timeouts.default` fails CI.** Implementation: [lint-vitest-timeouts.mjs](scripts/lint-vitest-timeouts.mjs), [ci.yml](.github/workflows/ci.yml). Evidence: [lint-vitest-timeouts.test.mjs](scripts/lint-vitest-timeouts.test.mjs). - **Docs.** The migration-system subsystem doc describes the scaffolding snapshot write and states that nothing reads a `.d.ts` out of the store. ## Testing performed - `pnpm typecheck` and `pnpm test` in `@internal/migration-tools` (43 files, 601 tests), then `pnpm build` - `pnpm typecheck` and `pnpm test` in `@internal/cli` (116 files, 1476 tests) against the rebuilt migration-tools, then `pnpm build` - `pnpm typecheck` in `@internal/extension-sqlite` against the rebuilt CLI - `node --test scripts/lint-vitest-timeouts.test.mjs` (9 tests) and `pnpm lint:vitest-timeouts` on the repo - `pnpm test` in `@internal/emitter` (234 tests) and in the sql and mongo family emitters, then a full `pnpm build` - `pnpm fixtures:check` against the full build, and `pnpm check:upgrade-coverage --mode pr --prev origin/main` - `test/cli-journeys/mongo-migration.e2e.test.ts` in the integration suite, which compares a snapshot's `contract.d.ts` with the emitted one byte for byte ## Alternatives considered - **Render the from-side snapshots too.** Rendering an old snapshot's JSON under the current install could refuse a plan for a contract that already has a valid entry, for no gain: the write was a no-op. Dropping the write is both simpler and safer. - **Retire `timeouts.default`.** Its ten remaining uses are real short waits inside tests. A lint on the two config settings catches the class without taking a value away. - **Make the fake families in the offline fixtures render for real.** That would mean shipping a real target's serializer and emission hook into structural stand-ins. The client is the seam the db command tests already use, so the plan and new commands take the same factory. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated. - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form — no Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer See the reviewer notes above. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Migration creation and planning now generate contract declarations for destination snapshots. - Contract rendering errors prevent incomplete migration outputs from being written. - **Bug Fixes** - Improved migration snapshot consistency by deriving declarations from contract definitions. - Standardized generated contract declaration ordering for consistent output. - **Chores** - Added automated checks for inappropriate default timeout budgets in Vitest configurations. - **Documentation** - Clarified recommended timeout settings and migration contract snapshot behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 5 天前 | |
docs: rewrite README for Prisma 8, fix orm init dist-tag, sweep "Prisma Next" prose (#30248) ## Linked issue n/a — no Linear ticket. Follow-up to the README banner swap in #30225. ## At a glance The README's getting-started commands, before and after, checked against [prisma.io/docs/getting-started](https://www.prisma.io/docs/getting-started): ```bash # before npm create prisma@next npx @prisma/cli@next orm init # after npm create prisma npx prisma orm init npx prisma skills sync ``` The `prisma` package has no `next` dist-tag any more (`latest` is `8.0.0-rc.13`, `prev` is `7.10.0`), so the old commands no longer resolve. ## Summary The README still introduced the product as "Prisma Next" in Early Access, pointed at the removed `next` dist-tag, listed extensions by their `@internal/*` workspace names, and linked to `prisma/prisma`. The rest of the repo had about a thousand prose mentions of the working name. This PR fixes all of it and one real bug the sweep turned up. ## Decision Five commits, each reviewable on its own (the fifth only records the sweep against the in-flight upgrade-instruction files for the coverage check): 1. **Rewrite the README against the live docs.** Every instruction in it now matches the getting-started, quickstart, `orm init`, `skills`, and extensions pages in prisma/web. 2. **Fix `orm init` to install `prisma@latest`.** The CLI added `prisma@next` as a dev dependency. That tag no longer exists on npm, so `orm init` fails at the install step for anyone running it today. The engine fallback moves from `@prisma/cli-engine@next` (0.2.3, stale) to `@latest` (0.3.0). 3. **Replace "Prisma Next" with "Prisma 8" in prose repo-wide.** Docs, doc comments, READMEs, package descriptions, skill references, and user-facing strings. 4. **Carry the pnpm trust-policy exemptions into the tarball smoke tests.** The scratch installs those tests run trip a trust-downgrade check on `undici-types@6.21.0` (no provenance, while 6.13.0 and 6.18.2 had it). The repo already exempts it for the workspace install; the test kit now restates `trustPolicy` and `trustPolicyExclude` in the scratch project the way it restates the release-age settings. Reproduced on main with a fresh metadata cache, so this is a pre-existing failure that any run without cached metadata hits. ## Reviewer notes - **Rebased on #30229.** That PR's release-candidate banner and its `scorecard.md` link replace the roadmap reference in the README, and `ROADMAP.md` stays deleted. The prose sweep re-applied cleanly on top of its CONTRIBUTING, SECURITY, and governance edits. - **Dated records keep the old name**, matching the allowances `scripts/lint-legacy-name.mjs` already defines for the `prisma-next` identifier: `CHANGELOG.md`, `docs/releases/`, the ADRs, `projects/`, and `drive/`. Rewriting those would misreport what was true at the time, and a mechanical pass produced sentences like "Prisma Next becomes Prisma 8" turning into "Prisma 8 becomes Prisma 8". - **Identifiers are untouched.** `prisma-next` package names, paths, env vars (`PRISMA_NEXT_*`), `PrismaNext*` types, the `images/prisma-next.png` file, and the `prisma-next.md` primer (the docs still call it that) are all unchanged. Renaming any of those is a behaviour change with an upgrade path, not a docs fix. - **The sweep is mechanical.** The third commit is a `sed` of `Prisma Next` and `Prisma-next` to `Prisma 8` over 345 files. Three sentences that became self-referential (`ROADMAP.md`, `ROADMAP.html`, `scorecard.md`) were rewritten by hand. - **`README.md` supported-databases section** now says PostgreSQL and MongoDB are first-class and SQLite is planned next, which is what [/docs/orm](https://www.prisma.io/docs/orm) says. The previous text referenced work "before the 8.0.0-rc.1 release". - **Discord channel name dropped.** The README linked to a `prisma-next` channel I could not verify; it now links to Discord generically. ## Behavior changes & evidence - **`orm init` installs `prisma@latest`** instead of `prisma@next`, and falls back to `@prisma/cli-engine@latest` when the manifest does not pin the engine. [packages/1-framework/3-tooling/cli/src/orm/init.ts](packages/1-framework/3-tooling/cli/src/orm/init.ts), [packages/1-framework/3-tooling/cli/src/orm/init-packages.ts](packages/1-framework/3-tooling/cli/src/orm/init-packages.ts). Evidence: [packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts](packages/1-framework/3-tooling/cli/test/orm/init-install.test.ts), [test/integration/test/cli.init-skill-distribution.integration.test.ts](test/integration/test/cli.init-skill-distribution.integration.test.ts). - **Scaffolded quick-reference notes and the skill quickstart** tell users to run `prisma@latest orm init`. [packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md](packages/1-framework/3-tooling/cli/src/commands/init/templates/quick-reference-postgres.md), [skills/prisma-8/references/quickstart.md](skills/prisma-8/references/quickstart.md). Evidence: [packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap](packages/1-framework/3-tooling/cli/test/commands/init/__snapshots__/templates.test.ts.snap). - **No other runtime change.** Every other edit is prose in docs, comments, `package.json` descriptions, and `//` comments in test fixture schemas, which the emitter drops. ## Testing performed - `pnpm test` in `packages/1-framework/3-tooling/cli`: 115 files, 1437 tests passed - `pnpm lint:legacy-name`, `pnpm lint:docs`, `pnpm lint:skills`, `pnpm lint:rules:footprint`, `pnpm lint:manifests`: all pass (the `errors` README warning is pre-existing) - `pnpm fixtures:check` could not run in this worktree because the examples' `prisma` binary is not installed. The only schema edits are `//` comments, which do not reach the emitted contract. ## Skill update `skills/prisma-8/references/quickstart.md` is updated in the second commit: its `orm init` commands moved from `@prisma/cli@next` to `prisma@latest`, the same change the README makes. ## Alternatives considered - **Rename the identifiers too** (`prisma-next.md`, `PRISMA_NEXT_*`, `PrismaNext*` types, the image file). Each is a user-visible surface with an upgrade path, and the docs still name `prisma-next.md`. Left for a deliberate rename with upgrade instructions. - **Sweep the ADRs, changelog, and project write-ups as well.** The repo's own legacy-name lint exempts them as dated records, and the mechanical pass mangled sentences that describe the rename itself. Following the existing policy keeps the diff honest. - **Keep `@latest` on the commands, as the docs pages write them.** The v8 line is `latest` now, so the tag adds nothing; the README uses the bare `npm create prisma` and `npx prisma …` forms. ## Checklist - [x] All commits are signed off (`git commit -s`) per the [DCO](../CONTRIBUTING.md#developer-certificate-of-origin-dco). - [x] I read [CONTRIBUTING.md](../CONTRIBUTING.md) and the change is scoped to one logical concern. - [x] Tests are updated (the CLI install-command tests and snapshots). - [ ] The PR title is in `TML-NNNN: <sentence-case title>` form. No Linear ticket exists for this change. - [x] The **Skill update** section above is filled in. ## Notes for the reviewer The first two commits are small and worth reading line by line. The third is large but uniform; spot-check a few files rather than reading all 345. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 9 天前 | |
feat(psl): write raw SQL column defaults as sql`...` tagged literals (#30325) A raw SQL column default is now written as a tagged literal. Before and after, in PSL: ```prisma // before id String @id @default(dbgenerated("gen_random_uuid()")) expiresAt DateTime @default(dbgenerated("(now() + '00:03:00'::interval)")) // after id String @id @default(sql`gen_random_uuid()`) expiresAt DateTime @default(sql`(now() + '00:03:00'::interval)`) ``` And in TypeScript: ```ts // before id: field.column(uuidColumn).defaultSql('gen_random_uuid()').id(), createdAt: field.column(timestamptzColumn).defaultSql('now()'), // after id: field.column(uuidColumn).default(sql`gen_random_uuid()`).id(), createdAt: field.column(timestamptzColumn).default(now()), expiresAt: field.column(timestamptzColumn).default(sql`(now() + '00:03:00'::interval)`), ``` Both forms emit exactly the contract the old ones did. `contract.json` does not change shape, every existing fixture emits byte-identical output, and `dbgenerated` still works after this PR. The Postgres demo app now has a column with a `sql` default, so its migration replay test proves the form end to end against a real database. ## The decision `dbgenerated("...")` puts arbitrary SQL into a schema as an unnamed string. It was accepted in ADR 167 as a stopgap until typed defaults existed, and it was never meant to ship. It is being retired in three PRs: this one adds the replacement, a parallel PR adds codec-owned PSL literals so JSON and other typed defaults no longer need raw SQL (ADR 184), and a final PR deletes `dbgenerated`, regenerates the Supabase contract, and ships the upgrade instruction. The replacement is the tagged literal ADR 129 designed. ADR 129 is rewritten in this PR to describe the mechanism as built; it is the reference for everything below. ## How it works, from the schema down **Syntax.** A tag followed by a string literal: `` sql`...` ``, `sql"..."`, or `sql'...'`. The tag is an ordinary qualified name and the string is an ordinary string literal, which now also accepts backticks; whitespace between them is allowed and the formatter removes it. A backtick string may span lines and has only two escapes, `` \` `` and `\\`, so everything else reaches the database as written. A backtick string is valid only after a tag. An unterminated backtick string stops before the next line that starts with `}`, so the rest of the file still parses. **One canonical body.** After escapes, the framework normalises line endings, trims a blank first and last line, removes common indentation, refuses NUL, and caps the body at 64 KiB. PSL and the TypeScript `sql` tag call the same function on the same raw text, so the two languages cannot disagree about a default. **Who registers tags.** Any pack may; only the target may register an unprefixed one. Postgres registers `sql` and `pg.sql`, SQLite registers `sql` and `sqlite.sql`, both through one implementation the SQL family exports. The registry sits beside the existing default-function registry on `ControlMutationDefaults`. Attribute parsing only checks that an argument is a tagged literal; lowering checks the tag is registered (the diagnostic lists the registered tags) and that the body canonicalizes. The language server completes the registered tags inside `@default(`. **Lowering.** The `sql` tag lowers to the function-kind column default the contract already has. The body is used verbatim: nothing rewrites it at authoring, in the contract, or in DDL. One body check, `checkSqlDefaultBody` in the SQL contract package, refuses `;`, comment markers, `$$`, and `SELECT`; authoring runs it with a source span and both planners run it before rendering. SQLite's planner previously had a weaker copy of that check. A body that is exactly `now()` or `autoincrement()` is refused, in PSL and TypeScript alike, with a hint to write the named function: those two texts are Prisma markers the planners render specially, so the SQL would not be used as written. Every other body, including `NOW()` and `gen_random_uuid()`, passes unchanged. **TypeScript.** The SQL contract builder exports `sql` (interpolation is a compile error and a runtime error), `now()`, and `autoincrement()`. `.defaultSql()` stays, marked deprecated with the replacement named, and is removed at 8.0.0 GA. Every call in this repository is rewritten. ## Behaviour changes to check - **List columns take storage defaults.** `` tags String[] @default(sql`'{}'::text[]`) `` and `tags String[] @default(now())` both lower. The interpreter cannot know any function's return type, so it no longer refuses functions on lists; the database reports a wrong type. Two things are still refused on a list: single-value client generators such as `uuid()`, and `autoincrement()`, which is a Prisma marker for a sequence-backed scalar column rather than SQL (`PSL_LIST_AUTOINCREMENT_UNSUPPORTED`). - **Both planners render the authored default.** Postgres previously rendered its normalised form, so `` sql`nextval('orders_seq'::regclass)` `` would have become a `SERIAL` column and `CURRENT_TIMESTAMP` would have become `now()`. Plan and verify on both targets compare through each target's introspection parser, so `` sql`CURRENT_TIMESTAMP` `` verifies clean and a second `db update` plans nothing. - **`ControlMutationDefaults.defaultLiteralTagRegistry` is required.** A pack that contributes default functions must now contribute a tag registry too, empty or not. The extension upgrade note shows the one-line fix. ## Where to start reviewing 1. `packages/1-framework/2-authoring/psl-parser/src/tokenizer.ts`, `parse.ts`, and `syntax/ast/expressions.ts`: backtick strings, their escapes, and the tagged-literal node built from a qualified name and a string literal. 2. `packages/1-framework/1-core/framework-components/src/shared/tagged-literal.ts`: the canonical body, with a table test per step. 3. `packages/2-sql/9-family/src/core/sql-default-literal-tag.ts` and both adapters' `control-mutation-defaults.ts`: registration and lowering. 4. `packages/2-sql/2-authoring/contract-ts/src/sql-default-literal.ts`: the TypeScript tag. 5. `test/integration/test/authoring/parity/default-sql-literal/`: PSL and TypeScript emitting the same contract. 6. `examples/prisma-8-demo/migrations/app/20260917T0818_add_post_expires_at/`: the DDL the planner renders for a `sql` default. ## Alternatives considered - **Named functions plus typed literals only, with anything else reported as a gap.** Rejected: a real default such as `(now() + '00:03:00'::interval)` would have no way to be written. - **Keep `dbgenerated` and document it.** Rejected: it was never accepted as a feature, and it keeps raw text in the language with no owner. - **Store raw defaults as a hashed payload, like index expressions and check constraints.** Not adopted here. A column default has no catalog name to carry a hash, so verify would still compare the database's reprint, and the contract shape would change for every consumer. Recorded in ADR 129's alternatives. - **A separate token and node for tagged literals.** Replaced during review: the node now reuses the qualified-name and string-literal parsing, so escaping and unterminated-string recovery live in one place. - **A named `gen_random_uuid()` default on Postgres.** Tried and removed during review. It read like Prisma's own `uuid()`, which generates the value in the client, while `gen_random_uuid()` makes the database generate it, and the names do not show that. Named defaults stay limited to `now()` and `autoincrement()`; database functions are written as `sql`. - **Rewrite known expressions at authoring time**, as the SQLite adapter did for `CURRENT_TIMESTAMP`. Rejected: a person who writes SQL expects that SQL to run. Refs: ADR 129, ADR 167, ADR 184. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added SQL tagged literals for column defaults in PSL and TypeScript, including `sql`, `pg.sql`, and `sqlite.sql`. - Added `now()` and `autoincrement()` helpers for common defaults. - Added editor completions and formatting support for tagged literals. - SQL defaults now support multiline content with normalization and safety validation. - **Bug Fixes** - Migrations preserve authored SQL default expressions across PostgreSQL and SQLite. - **Documentation** - Added upgrade guidance and updated architecture, error-reference, and usage documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 9 天前 | ||
| 9 天前 | ||
| 9 天前 | ||
| 10 天前 | ||
| 9 天前 | ||
| 9 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 5 天前 | ||
| 9 天前 | ||
| 3 天前 |