| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 | |
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 | |
TML-3382: db.enums members equal the values queries return, and Postgres contracts store values as Postgres prints them (#30628) ## Linked issue Refs [TML-3382](https://linear.app/prisma-company/issue/TML-3382) and [TML-3383](https://linear.app/prisma-company/issue/TML-3383), both found while fixing #30512. Deferred: [TML-3479](https://linear.app/prisma-company/issue/TML-3479) (numeric scale), [TML-3480](https://linear.app/prisma-company/issue/TML-3480) (BC years), and the review follow-ups [TML-3500](https://linear.app/prisma-company/issue/TML-3500) to [TML-3507](https://linear.app/prisma-company/issue/TML-3507). ## Skill update `skills/prisma-8/references/contract.md` gains two paragraphs: what `db.enums` members hold at runtime, and which codecs an enum can use. ## At a glance A Prisma 8 enum can be typed by any codec, and the client exposes its members at runtime as `db.enums`. Abridged from `test/integration/test/enum-members/_fixture-postgres/contract.prisma`, an enum over `int8` and one over `inet`: ```prisma enum Int8Level { @@type("pg/int8@1") Low = "1" High = "10" } enum Host { @@type("pg/inet@1") Loopback = "127.0.0.1" Private = "10.0.0.0/8" } model Reading { id Int @id int8 Int8Level } model Network { id Int @id hosts Host[] } ``` Reading rows back and checking them against the enums, as `enum-members.postgres.test.ts` does on PGlite: ```ts const { Int8Level, Host } = client.enums.public; const [reading] = await db.public.Reading.all(); const [network] = await db.public.Network.all(); Int8Level.members.Low === 1n; // before: members.Low was the text "1" Int8Level.has(reading.int8); // before: false for every row read back network.hosts.map((host) => Host.has(host)); // before: the column refused 127.0.0.1 at insert ``` Before this PR, `members.Low` held the text `"1"` that `contract.json` stores, while a query returned the bigint `1n`, so no value read from the database was ever a member. And a `Host[]` column could not hold `127.0.0.1` at all. ## Decision This PR makes one rule hold end to end: **the value a codec reads from a contract's stored form equals the value a query returns for it, and `db.enums` compares with that value.** Three pieces deliver it: 1. **`db.enums` decodes its members.** The accessor reads each member through the enum's codec, so `members.Low` is `1n`, a timestamp member is a Temporal value. `has()`, `nameOf()` and `ordinalOf()` find a value equal to a member. `contract.d.ts` types the members the same way. Members are decoded once, when the enum is first read, so a contract with a Temporal enum still builds a client on a runtime without `Temporal`. Postgres, SQLite and Mongo, TypeScript and PSL contracts. 2. **Postgres stores values as it would return them.** An inet member or default written `10.0.0.1/32` is stored as `10.0.0.1`; a numeric written `01.5` as `1.5`; integer text written `007` is refused on every target and the message names `7`. An enum can only use a codec that declares the `equality` trait and whose members can equal a value read back. One function, `enumRefusalOf`, decides that for all four authoring surfaces, and refuses the string-timestamp codecs, `pg/json@1`, `pg/bytea@1` and `pg/tsquery@1` with the reason and what to use instead. 3. **An enum list column's CHECK compares in the column's type.** The list constraint used to cast the column to `text[]`; Postgres prints an inet as `127.0.0.1/32` in that cast, which is why the host address above was refused. The constraint now hands Postgres an untyped array literal and lets it compare in the element type, as the scalar `IN` form always did. A float enum may now mix `1.5` and `NaN`. ## Reviewer notes - **Every Postgres list enum changes its storage hash.** Piece 3 rewrites the membership CHECK for every list column typed by an enum, so re-emitting such a contract plans a migration that drops the old constraint and adds the new one. The upgrade entry `enum-list-check-compares-in-column-type` walks users through it, including the order of steps for a project coming from rc.14 through the rc.15 data-type script. The rc.14 and rc.15 upgrade paths were replayed on PGlite for both a migrations project and a `db update` project. Three ports fixtures with list enums were re-emitted for this reason. - **A numeric enum column accepts a value of another scale.** Both CHECK forms now compare as numbers, so a `numeric` enum column takes `0.50` against the member `0.5`, reads it back as `"0.50"`, and `has()` returns false for it. Documented under TML-3479; see the alternatives at the end for why not fixed here. - **bytea and tsquery enums are now refused, where before they silently never worked.** A bytea enum's CHECK compared the bytes of the base64 text, so every insert of a member failed; a tsquery enum stored the query as written where Postgres prints it normalised. Rendering CHECK members through the column's data type would allow both and is TML-3500. - **inet uses main's canonical-form mechanism; numeric does not.** ADR 254 lets a data type declare a canonical form. inet declares one. numeric keeps its rule in the codec, because default verification compares numerics using the column's scale and a canonical-form function cannot see parameters. The ADR 254 amendment in this PR records the rule, the eligibility rule, and this exception. - **Mongo API change.** `mongoOrm({ contract, executor, enums })` checks at construction that every enum of the contract has an accessor, and and `createMongoCollection(contract, model, executor, enums, mutationDefaults?)` take the enum accessors `db.enums` holds, built once by `buildMongoEnums(contract, codecs)`, so the ORM checks a written enum value against the same objects the client exposes. Clients built with `mongo()` need no change. The upgrade entry `mongo-orm-takes-enum-accessors` has the before and after. - **Largest diff:** the re-emitted enum-members fixtures (three targets), `canonical-inet.ts` with its two test files, and the test splits that keep files under 500 lines. ## How it fits together 1. **The accessor decodes.** `packages/1-framework/0-foundation/contract/src/enum-accessor.ts` resolves each enum's codec when the client is built, so a missing codec still fails then, and decodes the members on the first read of that enum. Immutable members are cached; a `Date` or `Uint8Array` is copied on each read. Lookups compare by the codec's canonical JSON, so a stored form that is not canonical still matches. 2. **The types agree.** The emitter writes an `enumMemberTypes` block into `contract.d.ts`, so `members.Low` is typed `bigint` where the codec reads one. A float enum column with a NaN or infinite member is typed `number`. 3. **Mongo stores what its validator can list.** A Mongo PSL enum stores members in the codec's stored form. An enum over a BSON type that JSON cannot hold (long, date, ObjectId, decimal, binary, vector) is refused at emit, instead of producing a collection validator no write satisfies. The Mongo ORM checks written enum values against the accessors. 4. **Postgres values are canonical, and eligibility is decided once.** `canonical-inet.ts`, a port of Postgres's `inet_net_pton` and `inet_net_ntop`, is the inet data type's canonical form and text cast. `pg/numeric@1` writes and reads the numeral Postgres prints. The default parser agrees with both. `enumRefusalOf` in framework-components reads the descriptor's `equality` trait and its `enumRefusal`, and the TypeScript and PSL enum factories of both families call it. 5. **The CHECK compares in the column type.** `packages/3-targets/3-targets/postgres/src/core/check-expressions.ts` renders `array_remove("col", NULL) <@ '{...}'` with array-literal quoting, so Postgres compares in the element type. 6. **Users are told.** Two pending upgrade fragments, `enum-members-hold-read-values` and `values-equal-what-queries-return`, carry one entry per observable change with detection patterns, for apps and for extension authors. The error reference, the codec authoring guide, ADR 244's description of the list check, and dated amendments to ADR 254 and ADR 157 are updated. ## Behavior changes and evidence - `db.enums` members equal values read back on all three targets, and are decoded lazily. Evidence: `test/integration/test/enum-members/`, one file per target plus a Mongo TypeScript-contract file; `packages/1-framework/0-foundation/contract/test/enum-accessor.lazy.test.ts`; `packages/3-targets/3-targets/postgres/test/enum-members.without-temporal.test.ts`. - `contract.d.ts` types members as read. Evidence: the re-emitted `_fixture-*/generated/contract.d.ts` files under `test/integration/test/enum-members/`. - inet defaults and members are stored as Postgres prints them; non-addresses are refused. Evidence: `packages/3-targets/3-targets/postgres/test/canonical-inet.integration.test.ts`, compared with PGlite's output, and `packages/3-extensions/postgres/test/contract-builder/values-as-postgres-prints.test.ts`. - numeric refuses non-printed numerals and names the text to write. Evidence: `test/canonical-numeric.integration.test.ts`, `test/codec-strictness.test.ts` in the Postgres target. - Integer-as-text codecs on Postgres, SQLite and Mongo refuse `"007"` and `"-0"`. Evidence: `test/canonical-integer-text.integration.test.ts` in the Postgres target, and the SQLite and Mongo codec tests. - Enums over codecs without equality, or over the string-timestamp, json, bytea and tsquery codecs, are refused on all four surfaces with the reason. Evidence: `packages/3-targets/3-targets/postgres/test/enum-eligibility.test.ts`, `test/integration/test/authoring/psl-defaults-read-by-codec.integration.test.ts`, the family `enum-refusal.test.ts` files. - An inet or numeric enum list column accepts members and refuses non-members in the element type; a float enum mixes finite and NaN members. Evidence: `test/check-expressions.integration.test.ts` in the Postgres target, `enum-members.postgres.test.ts`. - Mongo PSL enums over BSON-only types are refused; `mongoOrm()` takes the accessors. Evidence: `packages/2-mongo-family/9-family/test/enum-refusal.test.ts`, `test/integration/test/mongo/orm.test.ts`, `packages/2-mongo-family/7-runtime/test/mongo-enums.test.ts`. ## Testing performed On the final HEAD, after merging main at 8.0.0-rc.16: - `pnpm build`, `pnpm typecheck` (all packages), `pnpm lint:deps`, `pnpm lint:framework-vocabulary` (at the threshold, no new occurrences), `pnpm lint:casts` (no change), `pnpm fixtures:check` (clean), `pnpm check:upgrade-coverage --mode pr` against the merge base, `pnpm lint:examples`. - `pnpm lint` and `pnpm test` in every touched package. - Integration: `test/enum-members/` (all four files), `authoring/psl-defaults-apply-and-verify`, `authoring/psl-defaults-read-by-codec`, `value-objects`, `mongo/orm`, `mongo/no-emit`, the three ports fixtures with list enums, `upgrade-instructions/data-type-in-contract`, and the adapter's `check-lifecycle-e2e` and `check-introspection`. - A drive code review (architect and principal-engineer passes) plus two earlier ad-hoc rounds, all with probes against the real databases: `canonicalInet` against PGlite over 62,905 fuzzed and hostile inputs with zero differences; numeric and integer codecs against PGlite, `node:sqlite` and Mongo `Long` over the values each prints, the int8 limits included; array-literal quoting with 15 hostile members on PGlite; the rc.14 and rc.15 upgrade paths on PGlite. - CI runs the whole-suite coverage job. ## Follow-ups - TML-3479: on a `numeric(10,2)` column a default is stored as `"1.5"` where Postgres returns `"1.50"`, and a numeric enum column admits a value of another scale. - TML-3480: date-string members with BC years. - TML-3500: render enum CHECK members through the column's data type, which allows bytea enums again and gives bool enums a path. - TML-3501 to TML-3505: the emitter's duplicated literal typing, the two type carriers for `db.enums`, a test over every registered codec, integer spellings Postgres reads that the canonical form refuses, and backslash literals under `standard_conforming_strings = off`. - TML-3506: the published rc.14-to-rc.15 guide's `db sign <hash>` advice fails for projects without migrations. - TML-3507: `enumType` compares members by string conversion, so two object members always collide as duplicates. Predates this PR; blocks object and array enums on extension codecs. ## Alternatives considered - **Give numeric a canonical form like inet.** Rejected: default verification compares numerics using the column's scale, and a canonical-form function takes a value and nothing else. It would make `1.5` and `1.50` compare unequal on `numeric(10,2)` and break every Prisma 7 `Decimal @default(0)`. - **Compare numeric enum members by printed text in the CHECK, to refuse `0.50`.** Rejected for now: inet cannot be compared as text at all, so a text comparison for numeric alone means branching on the type inside the renderer. A per-data-type rendering hook is the right shape and is TML-3500 together with TML-3479. - **Keep the `text[]` cast for list enums and tell inet users to write `/32`.** Rejected: the rule of this PR is that a member is written as Postgres returns it, and Postgres returns a host address without `/32`. The cast also let `json` list enums accept writes that the scalar form never did; those enums are now refused up front. - **Decode every enum member when the client is built.** Rejected after review: it made a client with a Temporal enum fail at startup on a runtime without `Temporal`, against the error reference's promise that the check is lazy, and it decoded members on every read. Members decode on first access and are cached. - **Keep a per-codec `enumRefusal` only.** Rejected: `pg/json@1` was refused by a bespoke message while `pg/tsquery@1`, which also declares no equality, was not. Eligibility now comes from the `equality` trait, and `enumRefusal` adds a reason where the generic one is not enough. - **Let the Mongo ORM rebuild the enum accessors from codecs.** Rejected: `mongo()` already builds `db.enums`, so a second set meant two missing-codec errors with different wording and a shape unlike SQL's. The ORM takes the accessors the client built. - **Refuse `007` only on Postgres.** Rejected: SQLite and Mongo share the framework helper. One rule in the framework, worded without naming a target. - **List Mongo's BSON-only enum values in the collection validator.** Rejected: `$jsonSchema` cannot express a long, date or ObjectId literal, so such an enum is refused in PSL and allowed in TypeScript contracts, which carry no validator. ## 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. Agent: fibonacci-74 🤖 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** - Enum accessors now expose codec-decoded values, support accurate lookups across supported types, and return fresh copies of mutable values. - MongoDB writes validate enum values; SQLite contract definitions support authored enums. - Generated contract types include enum member value types for improved TypeScript inference. - PostgreSQL normalizes numeric and IP address values, and array membership checks compare values using the column’s type without explicit casts. - **Bug Fixes** - Enum authoring rejects codecs that cannot reliably represent enum values, with clearer diagnostics. - Integer and PostgreSQL numeric decoding rejects noncanonical text forms. - PostgreSQL enum and default handling now reflects values as returned by database queries. <!-- 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 Opus 5.5 <noreply@anthropic.com> | 12 小时前 | |
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 | |
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 | |
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 | |
TML-3382: db.enums members equal the values queries return, and Postgres contracts store values as Postgres prints them (#30628) ## Linked issue Refs [TML-3382](https://linear.app/prisma-company/issue/TML-3382) and [TML-3383](https://linear.app/prisma-company/issue/TML-3383), both found while fixing #30512. Deferred: [TML-3479](https://linear.app/prisma-company/issue/TML-3479) (numeric scale), [TML-3480](https://linear.app/prisma-company/issue/TML-3480) (BC years), and the review follow-ups [TML-3500](https://linear.app/prisma-company/issue/TML-3500) to [TML-3507](https://linear.app/prisma-company/issue/TML-3507). ## Skill update `skills/prisma-8/references/contract.md` gains two paragraphs: what `db.enums` members hold at runtime, and which codecs an enum can use. ## At a glance A Prisma 8 enum can be typed by any codec, and the client exposes its members at runtime as `db.enums`. Abridged from `test/integration/test/enum-members/_fixture-postgres/contract.prisma`, an enum over `int8` and one over `inet`: ```prisma enum Int8Level { @@type("pg/int8@1") Low = "1" High = "10" } enum Host { @@type("pg/inet@1") Loopback = "127.0.0.1" Private = "10.0.0.0/8" } model Reading { id Int @id int8 Int8Level } model Network { id Int @id hosts Host[] } ``` Reading rows back and checking them against the enums, as `enum-members.postgres.test.ts` does on PGlite: ```ts const { Int8Level, Host } = client.enums.public; const [reading] = await db.public.Reading.all(); const [network] = await db.public.Network.all(); Int8Level.members.Low === 1n; // before: members.Low was the text "1" Int8Level.has(reading.int8); // before: false for every row read back network.hosts.map((host) => Host.has(host)); // before: the column refused 127.0.0.1 at insert ``` Before this PR, `members.Low` held the text `"1"` that `contract.json` stores, while a query returned the bigint `1n`, so no value read from the database was ever a member. And a `Host[]` column could not hold `127.0.0.1` at all. ## Decision This PR makes one rule hold end to end: **the value a codec reads from a contract's stored form equals the value a query returns for it, and `db.enums` compares with that value.** Three pieces deliver it: 1. **`db.enums` decodes its members.** The accessor reads each member through the enum's codec, so `members.Low` is `1n`, a timestamp member is a Temporal value. `has()`, `nameOf()` and `ordinalOf()` find a value equal to a member. `contract.d.ts` types the members the same way. Members are decoded once, when the enum is first read, so a contract with a Temporal enum still builds a client on a runtime without `Temporal`. Postgres, SQLite and Mongo, TypeScript and PSL contracts. 2. **Postgres stores values as it would return them.** An inet member or default written `10.0.0.1/32` is stored as `10.0.0.1`; a numeric written `01.5` as `1.5`; integer text written `007` is refused on every target and the message names `7`. An enum can only use a codec that declares the `equality` trait and whose members can equal a value read back. One function, `enumRefusalOf`, decides that for all four authoring surfaces, and refuses the string-timestamp codecs, `pg/json@1`, `pg/bytea@1` and `pg/tsquery@1` with the reason and what to use instead. 3. **An enum list column's CHECK compares in the column's type.** The list constraint used to cast the column to `text[]`; Postgres prints an inet as `127.0.0.1/32` in that cast, which is why the host address above was refused. The constraint now hands Postgres an untyped array literal and lets it compare in the element type, as the scalar `IN` form always did. A float enum may now mix `1.5` and `NaN`. ## Reviewer notes - **Every Postgres list enum changes its storage hash.** Piece 3 rewrites the membership CHECK for every list column typed by an enum, so re-emitting such a contract plans a migration that drops the old constraint and adds the new one. The upgrade entry `enum-list-check-compares-in-column-type` walks users through it, including the order of steps for a project coming from rc.14 through the rc.15 data-type script. The rc.14 and rc.15 upgrade paths were replayed on PGlite for both a migrations project and a `db update` project. Three ports fixtures with list enums were re-emitted for this reason. - **A numeric enum column accepts a value of another scale.** Both CHECK forms now compare as numbers, so a `numeric` enum column takes `0.50` against the member `0.5`, reads it back as `"0.50"`, and `has()` returns false for it. Documented under TML-3479; see the alternatives at the end for why not fixed here. - **bytea and tsquery enums are now refused, where before they silently never worked.** A bytea enum's CHECK compared the bytes of the base64 text, so every insert of a member failed; a tsquery enum stored the query as written where Postgres prints it normalised. Rendering CHECK members through the column's data type would allow both and is TML-3500. - **inet uses main's canonical-form mechanism; numeric does not.** ADR 254 lets a data type declare a canonical form. inet declares one. numeric keeps its rule in the codec, because default verification compares numerics using the column's scale and a canonical-form function cannot see parameters. The ADR 254 amendment in this PR records the rule, the eligibility rule, and this exception. - **Mongo API change.** `mongoOrm({ contract, executor, enums })` checks at construction that every enum of the contract has an accessor, and and `createMongoCollection(contract, model, executor, enums, mutationDefaults?)` take the enum accessors `db.enums` holds, built once by `buildMongoEnums(contract, codecs)`, so the ORM checks a written enum value against the same objects the client exposes. Clients built with `mongo()` need no change. The upgrade entry `mongo-orm-takes-enum-accessors` has the before and after. - **Largest diff:** the re-emitted enum-members fixtures (three targets), `canonical-inet.ts` with its two test files, and the test splits that keep files under 500 lines. ## How it fits together 1. **The accessor decodes.** `packages/1-framework/0-foundation/contract/src/enum-accessor.ts` resolves each enum's codec when the client is built, so a missing codec still fails then, and decodes the members on the first read of that enum. Immutable members are cached; a `Date` or `Uint8Array` is copied on each read. Lookups compare by the codec's canonical JSON, so a stored form that is not canonical still matches. 2. **The types agree.** The emitter writes an `enumMemberTypes` block into `contract.d.ts`, so `members.Low` is typed `bigint` where the codec reads one. A float enum column with a NaN or infinite member is typed `number`. 3. **Mongo stores what its validator can list.** A Mongo PSL enum stores members in the codec's stored form. An enum over a BSON type that JSON cannot hold (long, date, ObjectId, decimal, binary, vector) is refused at emit, instead of producing a collection validator no write satisfies. The Mongo ORM checks written enum values against the accessors. 4. **Postgres values are canonical, and eligibility is decided once.** `canonical-inet.ts`, a port of Postgres's `inet_net_pton` and `inet_net_ntop`, is the inet data type's canonical form and text cast. `pg/numeric@1` writes and reads the numeral Postgres prints. The default parser agrees with both. `enumRefusalOf` in framework-components reads the descriptor's `equality` trait and its `enumRefusal`, and the TypeScript and PSL enum factories of both families call it. 5. **The CHECK compares in the column type.** `packages/3-targets/3-targets/postgres/src/core/check-expressions.ts` renders `array_remove("col", NULL) <@ '{...}'` with array-literal quoting, so Postgres compares in the element type. 6. **Users are told.** Two pending upgrade fragments, `enum-members-hold-read-values` and `values-equal-what-queries-return`, carry one entry per observable change with detection patterns, for apps and for extension authors. The error reference, the codec authoring guide, ADR 244's description of the list check, and dated amendments to ADR 254 and ADR 157 are updated. ## Behavior changes and evidence - `db.enums` members equal values read back on all three targets, and are decoded lazily. Evidence: `test/integration/test/enum-members/`, one file per target plus a Mongo TypeScript-contract file; `packages/1-framework/0-foundation/contract/test/enum-accessor.lazy.test.ts`; `packages/3-targets/3-targets/postgres/test/enum-members.without-temporal.test.ts`. - `contract.d.ts` types members as read. Evidence: the re-emitted `_fixture-*/generated/contract.d.ts` files under `test/integration/test/enum-members/`. - inet defaults and members are stored as Postgres prints them; non-addresses are refused. Evidence: `packages/3-targets/3-targets/postgres/test/canonical-inet.integration.test.ts`, compared with PGlite's output, and `packages/3-extensions/postgres/test/contract-builder/values-as-postgres-prints.test.ts`. - numeric refuses non-printed numerals and names the text to write. Evidence: `test/canonical-numeric.integration.test.ts`, `test/codec-strictness.test.ts` in the Postgres target. - Integer-as-text codecs on Postgres, SQLite and Mongo refuse `"007"` and `"-0"`. Evidence: `test/canonical-integer-text.integration.test.ts` in the Postgres target, and the SQLite and Mongo codec tests. - Enums over codecs without equality, or over the string-timestamp, json, bytea and tsquery codecs, are refused on all four surfaces with the reason. Evidence: `packages/3-targets/3-targets/postgres/test/enum-eligibility.test.ts`, `test/integration/test/authoring/psl-defaults-read-by-codec.integration.test.ts`, the family `enum-refusal.test.ts` files. - An inet or numeric enum list column accepts members and refuses non-members in the element type; a float enum mixes finite and NaN members. Evidence: `test/check-expressions.integration.test.ts` in the Postgres target, `enum-members.postgres.test.ts`. - Mongo PSL enums over BSON-only types are refused; `mongoOrm()` takes the accessors. Evidence: `packages/2-mongo-family/9-family/test/enum-refusal.test.ts`, `test/integration/test/mongo/orm.test.ts`, `packages/2-mongo-family/7-runtime/test/mongo-enums.test.ts`. ## Testing performed On the final HEAD, after merging main at 8.0.0-rc.16: - `pnpm build`, `pnpm typecheck` (all packages), `pnpm lint:deps`, `pnpm lint:framework-vocabulary` (at the threshold, no new occurrences), `pnpm lint:casts` (no change), `pnpm fixtures:check` (clean), `pnpm check:upgrade-coverage --mode pr` against the merge base, `pnpm lint:examples`. - `pnpm lint` and `pnpm test` in every touched package. - Integration: `test/enum-members/` (all four files), `authoring/psl-defaults-apply-and-verify`, `authoring/psl-defaults-read-by-codec`, `value-objects`, `mongo/orm`, `mongo/no-emit`, the three ports fixtures with list enums, `upgrade-instructions/data-type-in-contract`, and the adapter's `check-lifecycle-e2e` and `check-introspection`. - A drive code review (architect and principal-engineer passes) plus two earlier ad-hoc rounds, all with probes against the real databases: `canonicalInet` against PGlite over 62,905 fuzzed and hostile inputs with zero differences; numeric and integer codecs against PGlite, `node:sqlite` and Mongo `Long` over the values each prints, the int8 limits included; array-literal quoting with 15 hostile members on PGlite; the rc.14 and rc.15 upgrade paths on PGlite. - CI runs the whole-suite coverage job. ## Follow-ups - TML-3479: on a `numeric(10,2)` column a default is stored as `"1.5"` where Postgres returns `"1.50"`, and a numeric enum column admits a value of another scale. - TML-3480: date-string members with BC years. - TML-3500: render enum CHECK members through the column's data type, which allows bytea enums again and gives bool enums a path. - TML-3501 to TML-3505: the emitter's duplicated literal typing, the two type carriers for `db.enums`, a test over every registered codec, integer spellings Postgres reads that the canonical form refuses, and backslash literals under `standard_conforming_strings = off`. - TML-3506: the published rc.14-to-rc.15 guide's `db sign <hash>` advice fails for projects without migrations. - TML-3507: `enumType` compares members by string conversion, so two object members always collide as duplicates. Predates this PR; blocks object and array enums on extension codecs. ## Alternatives considered - **Give numeric a canonical form like inet.** Rejected: default verification compares numerics using the column's scale, and a canonical-form function takes a value and nothing else. It would make `1.5` and `1.50` compare unequal on `numeric(10,2)` and break every Prisma 7 `Decimal @default(0)`. - **Compare numeric enum members by printed text in the CHECK, to refuse `0.50`.** Rejected for now: inet cannot be compared as text at all, so a text comparison for numeric alone means branching on the type inside the renderer. A per-data-type rendering hook is the right shape and is TML-3500 together with TML-3479. - **Keep the `text[]` cast for list enums and tell inet users to write `/32`.** Rejected: the rule of this PR is that a member is written as Postgres returns it, and Postgres returns a host address without `/32`. The cast also let `json` list enums accept writes that the scalar form never did; those enums are now refused up front. - **Decode every enum member when the client is built.** Rejected after review: it made a client with a Temporal enum fail at startup on a runtime without `Temporal`, against the error reference's promise that the check is lazy, and it decoded members on every read. Members decode on first access and are cached. - **Keep a per-codec `enumRefusal` only.** Rejected: `pg/json@1` was refused by a bespoke message while `pg/tsquery@1`, which also declares no equality, was not. Eligibility now comes from the `equality` trait, and `enumRefusal` adds a reason where the generic one is not enough. - **Let the Mongo ORM rebuild the enum accessors from codecs.** Rejected: `mongo()` already builds `db.enums`, so a second set meant two missing-codec errors with different wording and a shape unlike SQL's. The ORM takes the accessors the client built. - **Refuse `007` only on Postgres.** Rejected: SQLite and Mongo share the framework helper. One rule in the framework, worded without naming a target. - **List Mongo's BSON-only enum values in the collection validator.** Rejected: `$jsonSchema` cannot express a long, date or ObjectId literal, so such an enum is refused in PSL and allowed in TypeScript contracts, which carry no validator. ## 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. Agent: fibonacci-74 🤖 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** - Enum accessors now expose codec-decoded values, support accurate lookups across supported types, and return fresh copies of mutable values. - MongoDB writes validate enum values; SQLite contract definitions support authored enums. - Generated contract types include enum member value types for improved TypeScript inference. - PostgreSQL normalizes numeric and IP address values, and array membership checks compare values using the column’s type without explicit casts. - **Bug Fixes** - Enum authoring rejects codecs that cannot reliably represent enum values, with clearer diagnostics. - Integer and PostgreSQL numeric decoding rejects noncanonical text forms. - PostgreSQL enum and default handling now reflects values as returned by database queries. <!-- 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 Opus 5.5 <noreply@anthropic.com> | 12 小时前 | |
TML-3415: The ORM client locks the rows a collection reads with forUpdate, forNoKeyUpdate, forShare and forKeyShare (#30555) An ORM collection can now lock the rows it reads, until the transaction ends: ```ts await db.transaction(async (tx) => { const product = await tx.orm.public.Product.where({ id: productId }).forUpdate().first(); if (product !== null && product.stock > 0) { await tx.orm.public.Product.where({ id: productId }).update({ stock: product.stock - 1 }); } }); ``` ```sql SELECT ... FROM "public"."product" WHERE "product"."id" = $1 LIMIT 1 FOR UPDATE OF "product" ``` Without the lock, two requests for the last unit can both read `stock = 1` and both write `stock = 0`. With it, the second request's read waits until the first transaction commits, then sees `stock = 0`. This PR builds on #30549, which is merged. #30549 gave the typed SQL builder the same four methods, and added the lock to the shared select tree, the seven capabilities and the Postgres rendering. The design is recorded in ADR 261, in #30542. Closes #30531. ## The decision **The same four methods as the typed SQL builder.** A collection gains `forUpdate()`, `forNoKeyUpdate()`, `forShare()` and `forKeyShare()`. Each takes an optional `nowait` or `skipLocked`, which exclude each other. **The ORM locks only the model's own rows.** There is no `of` option. Every clause renders `OF` the model's table, under the name the ORM's lowering writes in `FROM`. (The lowering is the step that turns a collection into a select tree.) This matters because the lowering adds joins the caller never wrote. A polymorphic model, for example, outer-joins its variant tables. Without `OF`, Postgres would try to lock those tables too, and it refuses to lock the nullable side of an outer join. The tests check this on a polymorphic model with and without `variant()`. **The methods need `sql.lockOf` as well as their strength's capability.** Because the ORM always renders `OF`, a target that cannot render `OF` cannot run its locks either. Without its capabilities, a method's parameter list is `never`, so even `forUpdate()` with no arguments is a type error. At run time the method checks again and throws `ORM.CAPABILITY_MISSING`. This is the pattern `distinctOn` uses. **A lock is refused together with anything that would drop it or that Postgres refuses.** Each refusal is `ORM.LOCK_INCOMPATIBLE`, and its `meta.conflict` says why: | What the caller wrote | `meta.conflict` | When it is refused | |---|---|---| | a locked collection read with `include()` | `include` | when the read is compiled | | a locked collection read with `distinct()` or `distinctOn()` | `distinct`, `distinctOn` | when the read is compiled | | a lock inside an `include()` refinement | `includeRefinement` | at the call, and again when the parent read is compiled | | `groupBy()` or `aggregate()` on a locked collection | `groupBy`, `aggregate` | at the call | | any mutation method on a locked collection | `mutation` | before the first statement | The `include()` row and the refinement row are different mistakes. An `include()` refinement is a callback that receives the related collection and narrows it. It can return that collection, a scalar such as a count, or a `combine` of several of those. A lock method called on the related collection inside the callback is refused at once, because the lock is on a related collection, not on the collection being read. A callback can also return a collection that was locked outside it. The ORM catches that when it compiles the parent read, by checking every included collection, scalar and `combine` branch for a lock. A mutation is refused because it already locks the rows it changes, and silently dropping the lock written before it would hide a mistake. A lock outside a transaction is not refused. Postgres then releases it when the statement ends, which is legal, and `nowait` there asks whether a row is free right now. **The locking rules now live in one module.** `packages/2-sql/4-lanes/relational-core/src/ast/locking.ts` holds three things: - which capabilities each strength and option needs; - the `nowait`/`skipLocked` option type and its run-time check; - the `LockConflict` union of `meta.conflict` values. The typed SQL builder, the ORM client and the Postgres renderer all read it, so they cannot disagree. That is why this PR touches the builder and the renderer as well as the ORM. Their behaviour and error messages do not change. ## How to review this PR 28 files change. The substance: | Where | What | |---|---| | `packages/2-sql/4-lanes/relational-core/src/ast/locking.ts` | the locking rules shared by the three consumers | | `packages/3-extensions/sql-orm-client/src/collection.ts` | the four methods, and the refusal calls in `groupBy()`, `aggregate()` and the mutation methods | | `packages/3-extensions/sql-orm-client/src/collection-contract.ts` | `assertLockCapability`, the run-time capability check | | `packages/3-extensions/sql-orm-client/src/types.ts` | `CollectionState.locking`, set to `undefined` by `emptyState()` | | `packages/3-extensions/sql-orm-client/src/lock-guards.ts` | `assertLockCompatible`, which refuses the shapes in the table and finds a lock inside an included collection, scalar or `combine` branch | | `packages/3-extensions/sql-orm-client/src/query-plan-select.ts` | runs `assertLockCompatible` when a read is compiled, and puts the lock on the outermost select | | `packages/2-sql/4-lanes/sql-builder/src/...`, `packages/3-targets/6-adapters/postgres/src/core/sql-renderer.ts` | switched to the shared module | Smaller changes: - `orm-errors.ts` registers `LOCK_INCOMPATIBLE`, and `relational-core`'s `exports/ast.ts` exports the new module. - The docs: `docs/reference/error-reference.md`, `docs/reference/query-patterns.md` and `skills/prisma-8/references/queries-postgres.md` now show the ORM methods beside the builder's, and say that a lock lasts until the transaction ends. - `projects/select-row-locking/` gains this slice's plan, and its `design.md` now points to ADR 261. The new tests are `lock-capability.test.ts`, `lock-capability.test-d.ts` and `select-locking-plan.test.ts` in the ORM, `locking.test.ts` and `locking.types.test-d.ts` in `relational-core`, a `bindSelectAst` case in `where-binding.test.ts`, and `test/integration/test/sql-orm-client/lock.test.ts`. ## What changes for people outside this repo - **Application authors** use the same contract as for the builder methods. A contract emitted again for #30549 already records every capability the ORM methods need. - **Extension authors** who build a `CollectionState` must pass the new required `locking` key. Start from `emptyState()`, or carry `locking` over from the state being derived from. Setting it to `undefined` while deriving from a locked state removes the lock without an error. The pending upgrade notes in `upgrade-instructions/pending/orm-row-locking/` say the same. ## What the tests prove The unit and type tests cover: - that each method and option exists only with its capabilities; - the rendered SQL for every method, option and polymorphic shape; - every refusal in the table above. The integration tests run each form inside a transaction against PGlite. They assert the exact SQL the runtime sent and the whole row returned. They read `xmax` to show the transaction holds the lock where a plain read does not. They include `FOR UPDATE OF "tasks"` next to two `LEFT JOIN`s on the polymorphism fixture, which Postgres accepts. PGlite serves one connection, so no test here shows a second transaction waiting, skipping a row or failing under `nowait`. ## Alternatives considered ADR 261 argues each of these in full: - **An `of` option on the ORM, or no `OF` at all.** Either way, the caller would need to know which tables the lowering joins. - **Rendering without `OF` on a target that lacks `sql.lockOf`.** That would lock every joined table, which is what `OF` prevents. - **Supporting a lock together with `include()`.** The lock would have to sit on an inner select of the include lowering, with the `OF` name chosen there. The read-then-write and work-queue patterns do not need it. - **Refusing a lock outside a transaction.** It is legal Postgres and has a real use. Agent: machiavelli-37 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added row-locking methods to ORM collections, with `nowait` and `skipLocked` options where supported. Locks target the collection’s model table. * Added PostgreSQL support for rendering available lock modes and options. * **Bug Fixes** * Incompatible combinations—such as locks with includes, grouping, aggregates, distinct operations, or mutation terminals—are rejected with a clear error. * Unsupported locking capabilities and conflicting wait options are reported as errors. * **Documentation** * Added guidance and examples for row locking, transaction behavior, work queues, and lock compatibility. <!-- 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 Opus 5.5 <noreply@anthropic.com> | 16 小时前 | |
TML-3382: db.enums members equal the values queries return, and Postgres contracts store values as Postgres prints them (#30628) ## Linked issue Refs [TML-3382](https://linear.app/prisma-company/issue/TML-3382) and [TML-3383](https://linear.app/prisma-company/issue/TML-3383), both found while fixing #30512. Deferred: [TML-3479](https://linear.app/prisma-company/issue/TML-3479) (numeric scale), [TML-3480](https://linear.app/prisma-company/issue/TML-3480) (BC years), and the review follow-ups [TML-3500](https://linear.app/prisma-company/issue/TML-3500) to [TML-3507](https://linear.app/prisma-company/issue/TML-3507). ## Skill update `skills/prisma-8/references/contract.md` gains two paragraphs: what `db.enums` members hold at runtime, and which codecs an enum can use. ## At a glance A Prisma 8 enum can be typed by any codec, and the client exposes its members at runtime as `db.enums`. Abridged from `test/integration/test/enum-members/_fixture-postgres/contract.prisma`, an enum over `int8` and one over `inet`: ```prisma enum Int8Level { @@type("pg/int8@1") Low = "1" High = "10" } enum Host { @@type("pg/inet@1") Loopback = "127.0.0.1" Private = "10.0.0.0/8" } model Reading { id Int @id int8 Int8Level } model Network { id Int @id hosts Host[] } ``` Reading rows back and checking them against the enums, as `enum-members.postgres.test.ts` does on PGlite: ```ts const { Int8Level, Host } = client.enums.public; const [reading] = await db.public.Reading.all(); const [network] = await db.public.Network.all(); Int8Level.members.Low === 1n; // before: members.Low was the text "1" Int8Level.has(reading.int8); // before: false for every row read back network.hosts.map((host) => Host.has(host)); // before: the column refused 127.0.0.1 at insert ``` Before this PR, `members.Low` held the text `"1"` that `contract.json` stores, while a query returned the bigint `1n`, so no value read from the database was ever a member. And a `Host[]` column could not hold `127.0.0.1` at all. ## Decision This PR makes one rule hold end to end: **the value a codec reads from a contract's stored form equals the value a query returns for it, and `db.enums` compares with that value.** Three pieces deliver it: 1. **`db.enums` decodes its members.** The accessor reads each member through the enum's codec, so `members.Low` is `1n`, a timestamp member is a Temporal value. `has()`, `nameOf()` and `ordinalOf()` find a value equal to a member. `contract.d.ts` types the members the same way. Members are decoded once, when the enum is first read, so a contract with a Temporal enum still builds a client on a runtime without `Temporal`. Postgres, SQLite and Mongo, TypeScript and PSL contracts. 2. **Postgres stores values as it would return them.** An inet member or default written `10.0.0.1/32` is stored as `10.0.0.1`; a numeric written `01.5` as `1.5`; integer text written `007` is refused on every target and the message names `7`. An enum can only use a codec that declares the `equality` trait and whose members can equal a value read back. One function, `enumRefusalOf`, decides that for all four authoring surfaces, and refuses the string-timestamp codecs, `pg/json@1`, `pg/bytea@1` and `pg/tsquery@1` with the reason and what to use instead. 3. **An enum list column's CHECK compares in the column's type.** The list constraint used to cast the column to `text[]`; Postgres prints an inet as `127.0.0.1/32` in that cast, which is why the host address above was refused. The constraint now hands Postgres an untyped array literal and lets it compare in the element type, as the scalar `IN` form always did. A float enum may now mix `1.5` and `NaN`. ## Reviewer notes - **Every Postgres list enum changes its storage hash.** Piece 3 rewrites the membership CHECK for every list column typed by an enum, so re-emitting such a contract plans a migration that drops the old constraint and adds the new one. The upgrade entry `enum-list-check-compares-in-column-type` walks users through it, including the order of steps for a project coming from rc.14 through the rc.15 data-type script. The rc.14 and rc.15 upgrade paths were replayed on PGlite for both a migrations project and a `db update` project. Three ports fixtures with list enums were re-emitted for this reason. - **A numeric enum column accepts a value of another scale.** Both CHECK forms now compare as numbers, so a `numeric` enum column takes `0.50` against the member `0.5`, reads it back as `"0.50"`, and `has()` returns false for it. Documented under TML-3479; see the alternatives at the end for why not fixed here. - **bytea and tsquery enums are now refused, where before they silently never worked.** A bytea enum's CHECK compared the bytes of the base64 text, so every insert of a member failed; a tsquery enum stored the query as written where Postgres prints it normalised. Rendering CHECK members through the column's data type would allow both and is TML-3500. - **inet uses main's canonical-form mechanism; numeric does not.** ADR 254 lets a data type declare a canonical form. inet declares one. numeric keeps its rule in the codec, because default verification compares numerics using the column's scale and a canonical-form function cannot see parameters. The ADR 254 amendment in this PR records the rule, the eligibility rule, and this exception. - **Mongo API change.** `mongoOrm({ contract, executor, enums })` checks at construction that every enum of the contract has an accessor, and and `createMongoCollection(contract, model, executor, enums, mutationDefaults?)` take the enum accessors `db.enums` holds, built once by `buildMongoEnums(contract, codecs)`, so the ORM checks a written enum value against the same objects the client exposes. Clients built with `mongo()` need no change. The upgrade entry `mongo-orm-takes-enum-accessors` has the before and after. - **Largest diff:** the re-emitted enum-members fixtures (three targets), `canonical-inet.ts` with its two test files, and the test splits that keep files under 500 lines. ## How it fits together 1. **The accessor decodes.** `packages/1-framework/0-foundation/contract/src/enum-accessor.ts` resolves each enum's codec when the client is built, so a missing codec still fails then, and decodes the members on the first read of that enum. Immutable members are cached; a `Date` or `Uint8Array` is copied on each read. Lookups compare by the codec's canonical JSON, so a stored form that is not canonical still matches. 2. **The types agree.** The emitter writes an `enumMemberTypes` block into `contract.d.ts`, so `members.Low` is typed `bigint` where the codec reads one. A float enum column with a NaN or infinite member is typed `number`. 3. **Mongo stores what its validator can list.** A Mongo PSL enum stores members in the codec's stored form. An enum over a BSON type that JSON cannot hold (long, date, ObjectId, decimal, binary, vector) is refused at emit, instead of producing a collection validator no write satisfies. The Mongo ORM checks written enum values against the accessors. 4. **Postgres values are canonical, and eligibility is decided once.** `canonical-inet.ts`, a port of Postgres's `inet_net_pton` and `inet_net_ntop`, is the inet data type's canonical form and text cast. `pg/numeric@1` writes and reads the numeral Postgres prints. The default parser agrees with both. `enumRefusalOf` in framework-components reads the descriptor's `equality` trait and its `enumRefusal`, and the TypeScript and PSL enum factories of both families call it. 5. **The CHECK compares in the column type.** `packages/3-targets/3-targets/postgres/src/core/check-expressions.ts` renders `array_remove("col", NULL) <@ '{...}'` with array-literal quoting, so Postgres compares in the element type. 6. **Users are told.** Two pending upgrade fragments, `enum-members-hold-read-values` and `values-equal-what-queries-return`, carry one entry per observable change with detection patterns, for apps and for extension authors. The error reference, the codec authoring guide, ADR 244's description of the list check, and dated amendments to ADR 254 and ADR 157 are updated. ## Behavior changes and evidence - `db.enums` members equal values read back on all three targets, and are decoded lazily. Evidence: `test/integration/test/enum-members/`, one file per target plus a Mongo TypeScript-contract file; `packages/1-framework/0-foundation/contract/test/enum-accessor.lazy.test.ts`; `packages/3-targets/3-targets/postgres/test/enum-members.without-temporal.test.ts`. - `contract.d.ts` types members as read. Evidence: the re-emitted `_fixture-*/generated/contract.d.ts` files under `test/integration/test/enum-members/`. - inet defaults and members are stored as Postgres prints them; non-addresses are refused. Evidence: `packages/3-targets/3-targets/postgres/test/canonical-inet.integration.test.ts`, compared with PGlite's output, and `packages/3-extensions/postgres/test/contract-builder/values-as-postgres-prints.test.ts`. - numeric refuses non-printed numerals and names the text to write. Evidence: `test/canonical-numeric.integration.test.ts`, `test/codec-strictness.test.ts` in the Postgres target. - Integer-as-text codecs on Postgres, SQLite and Mongo refuse `"007"` and `"-0"`. Evidence: `test/canonical-integer-text.integration.test.ts` in the Postgres target, and the SQLite and Mongo codec tests. - Enums over codecs without equality, or over the string-timestamp, json, bytea and tsquery codecs, are refused on all four surfaces with the reason. Evidence: `packages/3-targets/3-targets/postgres/test/enum-eligibility.test.ts`, `test/integration/test/authoring/psl-defaults-read-by-codec.integration.test.ts`, the family `enum-refusal.test.ts` files. - An inet or numeric enum list column accepts members and refuses non-members in the element type; a float enum mixes finite and NaN members. Evidence: `test/check-expressions.integration.test.ts` in the Postgres target, `enum-members.postgres.test.ts`. - Mongo PSL enums over BSON-only types are refused; `mongoOrm()` takes the accessors. Evidence: `packages/2-mongo-family/9-family/test/enum-refusal.test.ts`, `test/integration/test/mongo/orm.test.ts`, `packages/2-mongo-family/7-runtime/test/mongo-enums.test.ts`. ## Testing performed On the final HEAD, after merging main at 8.0.0-rc.16: - `pnpm build`, `pnpm typecheck` (all packages), `pnpm lint:deps`, `pnpm lint:framework-vocabulary` (at the threshold, no new occurrences), `pnpm lint:casts` (no change), `pnpm fixtures:check` (clean), `pnpm check:upgrade-coverage --mode pr` against the merge base, `pnpm lint:examples`. - `pnpm lint` and `pnpm test` in every touched package. - Integration: `test/enum-members/` (all four files), `authoring/psl-defaults-apply-and-verify`, `authoring/psl-defaults-read-by-codec`, `value-objects`, `mongo/orm`, `mongo/no-emit`, the three ports fixtures with list enums, `upgrade-instructions/data-type-in-contract`, and the adapter's `check-lifecycle-e2e` and `check-introspection`. - A drive code review (architect and principal-engineer passes) plus two earlier ad-hoc rounds, all with probes against the real databases: `canonicalInet` against PGlite over 62,905 fuzzed and hostile inputs with zero differences; numeric and integer codecs against PGlite, `node:sqlite` and Mongo `Long` over the values each prints, the int8 limits included; array-literal quoting with 15 hostile members on PGlite; the rc.14 and rc.15 upgrade paths on PGlite. - CI runs the whole-suite coverage job. ## Follow-ups - TML-3479: on a `numeric(10,2)` column a default is stored as `"1.5"` where Postgres returns `"1.50"`, and a numeric enum column admits a value of another scale. - TML-3480: date-string members with BC years. - TML-3500: render enum CHECK members through the column's data type, which allows bytea enums again and gives bool enums a path. - TML-3501 to TML-3505: the emitter's duplicated literal typing, the two type carriers for `db.enums`, a test over every registered codec, integer spellings Postgres reads that the canonical form refuses, and backslash literals under `standard_conforming_strings = off`. - TML-3506: the published rc.14-to-rc.15 guide's `db sign <hash>` advice fails for projects without migrations. - TML-3507: `enumType` compares members by string conversion, so two object members always collide as duplicates. Predates this PR; blocks object and array enums on extension codecs. ## Alternatives considered - **Give numeric a canonical form like inet.** Rejected: default verification compares numerics using the column's scale, and a canonical-form function takes a value and nothing else. It would make `1.5` and `1.50` compare unequal on `numeric(10,2)` and break every Prisma 7 `Decimal @default(0)`. - **Compare numeric enum members by printed text in the CHECK, to refuse `0.50`.** Rejected for now: inet cannot be compared as text at all, so a text comparison for numeric alone means branching on the type inside the renderer. A per-data-type rendering hook is the right shape and is TML-3500 together with TML-3479. - **Keep the `text[]` cast for list enums and tell inet users to write `/32`.** Rejected: the rule of this PR is that a member is written as Postgres returns it, and Postgres returns a host address without `/32`. The cast also let `json` list enums accept writes that the scalar form never did; those enums are now refused up front. - **Decode every enum member when the client is built.** Rejected after review: it made a client with a Temporal enum fail at startup on a runtime without `Temporal`, against the error reference's promise that the check is lazy, and it decoded members on every read. Members decode on first access and are cached. - **Keep a per-codec `enumRefusal` only.** Rejected: `pg/json@1` was refused by a bespoke message while `pg/tsquery@1`, which also declares no equality, was not. Eligibility now comes from the `equality` trait, and `enumRefusal` adds a reason where the generic one is not enough. - **Let the Mongo ORM rebuild the enum accessors from codecs.** Rejected: `mongo()` already builds `db.enums`, so a second set meant two missing-codec errors with different wording and a shape unlike SQL's. The ORM takes the accessors the client built. - **Refuse `007` only on Postgres.** Rejected: SQLite and Mongo share the framework helper. One rule in the framework, worded without naming a target. - **List Mongo's BSON-only enum values in the collection validator.** Rejected: `$jsonSchema` cannot express a long, date or ObjectId literal, so such an enum is refused in PSL and allowed in TypeScript contracts, which carry no validator. ## 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. Agent: fibonacci-74 🤖 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** - Enum accessors now expose codec-decoded values, support accurate lookups across supported types, and return fresh copies of mutable values. - MongoDB writes validate enum values; SQLite contract definitions support authored enums. - Generated contract types include enum member value types for improved TypeScript inference. - PostgreSQL normalizes numeric and IP address values, and array membership checks compare values using the column’s type without explicit casts. - **Bug Fixes** - Enum authoring rejects codecs that cannot reliably represent enum values, with clearer diagnostics. - Integer and PostgreSQL numeric decoding rejects noncanonical text forms. - PostgreSQL enum and default handling now reflects values as returned by database queries. <!-- 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 Opus 5.5 <noreply@anthropic.com> | 12 小时前 | |
chore(release): bump to 8.0.0-rc.16 (#30632) `8.0.0-rc.15` → `8.0.0-rc.16` The peer dependency of `@prisma/orm-toolchain`, in `packages/9-public/@prisma/orm-toolchain/package.json`: ```diff - "@prisma/cli-engine": "0.6.2", + "@prisma/cli-engine": "0.6.3", ``` ## Why this release Engine 0.6.3 fixes `prisma orm init` and `prisma contract emit` failing on a valid contract with Bun. Engine 0.6.2 required ArkType `2.2.3` exactly while the ORM packages accept `^2.2.2`, so an install could hold two ArkType copies. Engine 0.6.3 accepts `^2.2.7` ([prisma/prisma-cli#332](https://github.com/prisma/prisma-cli/pull/332)). The Prisma CLI can only ship engine 0.6.3 once every product it mounts peers exactly 0.6.3: its conformance check refuses a mismatch. Composer 0.27.0 already peers 0.6.3. ORM rc.15 still peers 0.6.2, so the next Composer and CLI releases wait on this one. ## What this PR holds - Every `@prisma/cli-engine` pin in the repository moves from `0.6.2` to `0.6.3`. - The lockfile is deduplicated so the workspace resolves one ArkType copy, `2.2.7`. With two copies, the config-loader declaration build fails with `TS2742`. The dedupe also drops seven duplicate copies of build tools whose other versions were already in the lockfile; it adds no new package version. The size-limit report shows bundles about 0.2% larger, from ArkType 2.2.7. - [prisma/orm#30539](https://github.com/prisma/orm/pull/30539), merged to `main` after this branch was cut, is merged in and released here: its `@default` diagnostics change and its extension API renames. - Upgrade guides for this hop, assembled from two fragments, `engine-pin-moves-to-0-6-3` and `arguments-typed-by-data-type`: [app](skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md) and [extension](skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.15-to-8.0.0-rc.16/instructions.md). - The version bump, and the release notes in [`docs/releases/v8.0.0-rc.16.md`](docs/releases/v8.0.0-rc.16.md). ## Checks run locally - `pnpm build`, and the package tests of the CLI and the config loader. - `pnpm test:packages`: one test timed out under machine load and passes alone. Three tarball tests could not install on this machine because its package manager refuses `@vercel/detect-agent@1.2.5`, which this PR does not change; CI runs them. - One CLI integration test, and `check:upgrade-coverage --mode publish` against `v8.0.0-rc.15`. Merging this PR ships the release: the push to `main` carries the bumped root `version`, the `Publish to npm` workflow publishes `8.0.0-rc.16` under `latest`, and a GitHub Release marked pre-release is created from the notes file. See [`docs/oss/versioning.md`](docs/oss/versioning.md). After it publishes, Composer and then the Prisma CLI release against it. Agent: grendel-61 🤖 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** * Prisma 8.0.0-rc.16 updates extension APIs for working with data types and tagged-literal text. Extension authors should review the migration guidance for compatibility changes. * **Bug Fixes** * Bun commands that validate contracts now avoid failures caused by multiple ArkType copies. * **Improvements** * `@default` diagnostics have updated locations and messages, including more relevant suggestions for list elements. * Prisma 8.0.0-rc.16 requires CLI engine 0.6.3; projects with a direct engine pin should update it. <!-- 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> | 21 小时前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 21 小时前 | ||
| 21 小时前 | ||
| 12 小时前 | ||
| 21 小时前 | ||
| 21 小时前 | ||
| 21 小时前 | ||
| 12 小时前 | ||
| 16 小时前 | ||
| 12 小时前 | ||
| 21 小时前 |