Skip to content

A native enum column is not textual: text operations stop accepting it, and a conformance test enforces the trait - #30390

Merged
wmadden-electric merged 2 commits into
mainfrom
native-enum-not-textual
Sep 24, 2026
Merged

wmadden-electric merged 2 commits into
mainfrom
native-enum-not-textual

Conversation

@wmadden-electric

@wmadden-electric wmadden-electric commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Linked issue

n/a — no Linear ticket. Follow-up recorded in #30386.

Skill update

n/a — the skill reference never described native enums as text-searchable. The pending upgrade fragment native-enum-not-textual tells app and extension authors what changed.

At a glance

db.orm.public.Ticket.where((t) => t.status.ilike('open%'));
// before: compiles, then fails in Postgres: operator does not exist: ticket_status ~~* unknown
// after: type error — a native enum column has no text operations

Decision

The native Postgres enum codec pg/enum@1 no longer declares the textual trait. A codec's traits are its claim about what the database type supports, and Postgres has no LIKE, ILIKE, to_tsvector, or text-search parser for an enum type. So like, ilike, the three full-text operations, the tsquery parsers, and @@fullTextIndex stop accepting native enum columns, turning a runtime failure into a compile error. No operation special-cases enums; each one follows the corrected trait.

A new conformance test in the Postgres codec testkit enforces what textual means: for every built-in codec that declares it, Postgres must accept the column in ILIKE, to_tsvector, websearch_to_tsquery, and a to_tsvector GIN index. A future codec that misdeclares the trait fails that test.

Reviewer notes

  • Only native enums change. A PSL enum block with @@type("pg/text@1") is stored as text and keeps every text operation.
  • min/max over native enums still work. They used to come through the textual rule in the aggregate table; the enum codec now joins the existing per-codec min/max list beside the temporal types. Deriving min/max from order would claim codecs Postgres has no min/max for, as the list's own comment explains.
  • The conformance test was committed first and failed on pg/enum@1 in all four checks with SQLSTATE 42883, then passes with the fix. A negative control keeps it able to fail: it asserts an enum column is refused in all four places.
  • A cast would not have rescued full-text search on enums. to_tsvector(col::text) runs, but Postgres refuses to index it because the enum-to-text conversion is not immutable.
  • Extension-visible. An extension operation declared on textual no longer attaches to native enum columns; the extension fragment says so.

Behavior changes & evidence

Testing performed

  • Target package typecheck, lint, test; codec testkit (186 tests, including the new conformance test against a dev database).
  • test/integration sql-builder, sql-orm-client, enum-order-by: 1015 tests.
  • pnpm build, pnpm typecheck:packages --concurrency=1, examples typecheck, pnpm lint; lint:casts and lint:throws unchanged.
  • pnpm fixtures:check, pnpm check:error-reference, pnpm check:upgrade-coverage --mode pr --prev main --head HEAD.

Alternatives considered

  • A codec capability for rendering a column as text, with enums declaring a ::text cast that text operations lower through. Rejected: it needs a second capability for "indexable as text", since the cast cannot be indexed, and its only benefit is pattern or full-text search over a small fixed set of labels, where equality is the right tool.
  • Special-casing enums in the full-text operations. Rejected: the trait was wrong, so every textual operation was broken on enums, not just full-text search.

Checklist

  • All commits are signed off (git commit -s) per the DCO.
  • I read CONTRIBUTING.md and the change is scoped to one logical concern.
  • Tests are updated.
  • The PR title is in TML-NNNN: <sentence-case title> form — no ticket.
  • The Skill update section above is filled in.

Notes for the reviewer

See Reviewer notes above.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Native PostgreSQL enum columns are no longer treated as text. Pattern matching, full-text search, and full-text indexes now reject them before a database error occurs.
    • min and max continue to preserve native enum values and their type.
  • Documentation
    • Added upgrade guidance for changes to enum text operations, with alternatives for pattern matching and full-text search.
    • Clarified which database capabilities the textual trait represents.

wmadden-electric and others added 2 commits September 24, 2026 13:59
A codec that declares the textual trait gets like, ilike, the full-text operations, the tsquery parsers' text argument and @@fullTextIndex. All of them pass the column where Postgres expects text. The new testkit suite reads the textual codecs off the descriptors and checks that Postgres accepts each one's column in ILIKE, to_tsvector, websearch_to_tsquery and a to_tsvector GIN index.

It fails on pg/enum@1 at this commit: Postgres has no ILIKE or to_tsvector for an enum type. A second test runs the same checks on a native enum column and requires all four to be refused, so the checks can fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
pg/enum@1 declared the textual trait, so like, ilike, the full-text operations, the tsquery parsers and @@fullTextIndex all accepted a native enum column. Postgres has no LIKE, ILIKE or to_tsvector for an enum type, so every one of them typechecked and then failed in the database. The codec now declares equality and order only, and the textual conformance suite passes.

min and max over a native enum used to resolve through the textual fallback. The target now lists pg/enum@1 among the codecs whose min/max preserve the input, so they still resolve to the enum codec and the emitted aggregate types do not change.

Type tests cover the ORM field surface, the SQL builder fns and parsers, and min/max over the enum-order-by fixture's native enum column. @@fullTextIndex and fullTextIndex on a native enum column are refused. Upgrade fragments describe the change for apps and extensions, and ADR 203 says what textual promises.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: willbot <w.a.madden+machine@gmail.com>
Signed-off-by: Will Madden <madden@prisma.io>
@wmadden-electric
wmadden-electric requested a review from a team as a code owner September 24, 2026 12:16
@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: prisma/orm/.coderabbit.yml

Review profile: CHILL

Plan: Advanced

Run ID: 6945a3a3-7429-4187-b615-8cb8d44f11bb

📥 Commits

Reviewing files that changed from the base of the PR and between cdd49d3 and 1306819.

📒 Files selected for processing (15)
  • docs/architecture docs/adrs/ADR 203 - Trait-targeted operation arguments.md
  • packages/2-sql/4-lanes/sql-builder/test/native-enum-column.field-output.test-d.ts
  • packages/3-extensions/postgres/src/contract/full-text-index.ts
  • packages/3-extensions/postgres/test/contract-builder/full-text-index.test.ts
  • packages/3-extensions/sql-orm-client/test/native-enum.field-output.test-d.ts
  • packages/3-targets/3-targets/postgres/src/core/aggregates.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs.ts
  • packages/3-targets/3-targets/postgres/test/full-text.test-d.ts
  • packages/3-targets/3-targets/postgres/test/psl-full-text-index.test.ts
  • packages/3-targets/6-adapters/postgres-codec-testkit/test/aggregate-matrix.ts
  • packages/3-targets/6-adapters/postgres-codec-testkit/test/aggregate-resolution.test.ts
  • packages/3-targets/6-adapters/postgres-codec-testkit/test/textual-trait-conformance.integration.test.ts
  • test/integration/test/enum-order-by/native-enum-operations.test-d.ts
  • upgrade-instructions/pending/native-enum-not-textual/app/instructions.md
  • upgrade-instructions/pending/native-enum-not-textual/extension/instructions.md

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

PostgreSQL native enum codecs now advertise equality and order, but not textual. Text-dependent operations and full-text indexes reject native enums. Explicit min/max resolution preserves enum output. The changes also add PostgreSQL conformance tests and upgrade instructions.

Changes

Native enum text-operation support

Layer / File(s) Summary
Define and verify the textual trait
packages/3-targets/3-targets/postgres/src/core/codecs.ts, packages/2-sql/4-lanes/sql-builder/test/native-enum-column.field-output.test-d.ts, packages/3-extensions/sql-orm-client/test/native-enum.field-output.test-d.ts, packages/3-targets/6-adapters/postgres-codec-testkit/test/*, docs/architecture docs/adrs/ADR 203 - Trait-targeted operation arguments.md
Native enum codecs and their test fixtures no longer declare the textual trait. The codec testkit checks codecs declaring textual against PostgreSQL text operations. The ADR describes the trait contract.
Reject text operations on native enums
packages/3-extensions/postgres/src/contract/full-text-index.ts, packages/3-extensions/postgres/test/contract-builder/full-text-index.test.ts, packages/3-targets/3-targets/postgres/test/full-text.test-d.ts, packages/3-targets/3-targets/postgres/test/psl-full-text-index.test.ts, test/integration/test/enum-order-by/native-enum-operations.test-d.ts
Tests verify that native enums are rejected by text-dependent operations and full-text indexes. The TypeScript full-text index error guidance no longer lists enums as supported columns.
Preserve enum min and max results
packages/3-targets/3-targets/postgres/src/core/aggregates.ts, packages/3-targets/6-adapters/postgres-codec-testkit/test/aggregate-resolution.test.ts, test/integration/test/enum-order-by/native-enum-operations.test-d.ts, upgrade-instructions/pending/native-enum-not-textual/*/instructions.md
PostgreSQL explicitly resolves min and max for native enum codecs. Tests verify enum output types. Upgrade instructions describe the trait change, its effects, and migration options.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: tensordreams

Merge Risk: ⚪ Minimal · up to 13068

Native enums now reject unsupported text operations while retaining comparisons and min/max. No identified issue prevents merging after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 12 files. (3 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the primary change: native enum columns no longer support textual operations, and a conformance test enforces the trait behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 12 files. (3 skipped: 3 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Sep 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@prisma/orm-extension-arktype-json

npm i https://pkg.pr.new/@prisma/orm-extension-arktype-json@30390

@prisma/orm-extension-middleware-cache

npm i https://pkg.pr.new/@prisma/orm-extension-middleware-cache@30390

@prisma/orm-extension-paradedb

npm i https://pkg.pr.new/@prisma/orm-extension-paradedb@30390

@prisma/orm-extension-pgvector

npm i https://pkg.pr.new/@prisma/orm-extension-pgvector@30390

@prisma/orm-extension-postgis

npm i https://pkg.pr.new/@prisma/orm-extension-postgis@30390

@prisma/orm-extension-supabase

npm i https://pkg.pr.new/@prisma/orm-extension-supabase@30390

@prisma/orm-family-mongo

npm i https://pkg.pr.new/@prisma/orm-family-mongo@30390

@prisma/orm-family-sql

npm i https://pkg.pr.new/@prisma/orm-family-sql@30390

@prisma/orm-framework

npm i https://pkg.pr.new/@prisma/orm-framework@30390

@prisma/orm-mongo

npm i https://pkg.pr.new/@prisma/orm-mongo@30390

@prisma/orm-postgres

npm i https://pkg.pr.new/@prisma/orm-postgres@30390

@prisma/orm-sqlite

npm i https://pkg.pr.new/@prisma/orm-sqlite@30390

@prisma/orm-target-mongo

npm i https://pkg.pr.new/@prisma/orm-target-mongo@30390

@prisma/orm-target-postgres

npm i https://pkg.pr.new/@prisma/orm-target-postgres@30390

@prisma/orm-target-sqlite

npm i https://pkg.pr.new/@prisma/orm-target-sqlite@30390

@prisma/orm-toolchain

npm i https://pkg.pr.new/@prisma/orm-toolchain@30390

commit: 1306819

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
postgres / no-emit 194.94 KB (+0.01% 🔺)
postgres / emit 165.57 KB (+0.01% 🔺)
mongo / no-emit 110.57 KB (0%)
mongo / emit 92.12 KB (0%)
cf-worker / no-emit 218.07 KB (+0.01% 🔺)
cf-worker / emit 185.58 KB (-0.01% 🔽)

@wmadden-electric
wmadden-electric added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit fc35fca Sep 24, 2026
26 checks passed
@wmadden-electric
wmadden-electric deleted the native-enum-not-textual branch September 24, 2026 13:50
SevInf added a commit that referenced this pull request Sep 24, 2026
Brings in main through fc35fca: multi-file PSL emission (#30379), the
orm config section declared once as a schema (#30372), two migration-graph
fixes, and a native enum column no longer counting as textual (#30390).

Multi-file emission lands on our ground without touching it. Of the four
psl-parser files it changes, none is binder.ts, entity-reference.ts,
scope-chain.ts or symbol-table.ts: it adds a directive predicate, turns
the interpreters plural (documents for document), and gives PslSources a
merge that unions registries. A symbol table built from several documents
was already the binder contract - the multiple-documents and
namespace-reopened-across-documents pins covered it - so the two compose.

Conflicts resolved:

- psl-parser exports: both sides added an export beside the other, so
  both are kept, main schema-directive ahead of our scope-chain.
- sql interpreter: main restructured the opening, replacing the missing
  target and scalar-descriptor diagnostics with assertions and deriving
  source from an anchor document out of the plural input. Took that
  opening whole and re-seated our binder construction after the collector
  it needs, which also lets the uncomposed-namespace filter read the
  target directly now that a missing one throws.

Signed-off-by: Steven McClankerton <tatarintsev@prisma.io>
wmadden pushed a commit to veksa/prisma that referenced this pull request Sep 24, 2026
## Release: 8.0.0-rc.11 → 8.0.0-rc.12

This is the release PR described in
[docs/oss/versioning.md](https://github.com/prisma/orm/blob/main/docs/oss/versioning.md).
It bumps every workspace package to 8.0.0-rc.12 and moves the Prisma
dependencies to their latest versions.

**Merging this PR ships the release.** The push to `main` carries the
new root `version`. The `Publish to npm` workflow then publishes
8.0.0-rc.12 under `latest` and creates a pre-release GitHub Release from
the notes file.

## Review these first

-
[docs/releases/v8.0.0-rc.12.md](https://github.com/prisma/orm/blob/release/8.0.0-rc.12/docs/releases/v8.0.0-rc.12.md):
the release notes, which become the GitHub Release body. The same entry
is at the top of `CHANGELOG.md`.
- The upgrade guides for
[apps](https://github.com/prisma/orm/blob/release/8.0.0-rc.12/skills/prisma-8/upgrading/app/upgrades/8.0.0-rc.11-to-8.0.0-rc.12/instructions.md)
and
[extensions](https://github.com/prisma/orm/blob/release/8.0.0-rc.12/skills/prisma-8/upgrading/extension/upgrades/8.0.0-rc.11-to-8.0.0-rc.12/instructions.md).
They merge the 24 pending fragments. The original fragments are moved
unchanged to
`upgrade-instructions/releases/8.0.0-rc.11-to-8.0.0-rc.12/sources/`.
- Four guide entries have no fragment behind them. The `migration new`
default and its removed error codes (prisma#30389) had no guide entry. Neither
did the PSL parser API changes (prisma#30312, prisma#30344, prisma#30335, prisma#30379). I wrote
those entries while preparing the release.
- Where fragments contradicted later code, the guide follows the code.
Examples: the Supabase storage hash, `voidParamsSchema`, and quoted
defaults printed by `infer`.

## Dependency updates

| Package | From | To | Where |
| --- | --- | --- | --- |
| `@prisma/cli-engine` | 0.4.0 | 0.6.1 | examples, test fixtures, apps
(the toolchain packages were already on 0.6.1 from prisma#30372) |
| `@prisma/dev` | 0.25.1 | 0.25.2 | the workspace catalog |
| `@prisma/compute-sdk` | ^0.39.0 | ^0.43.0 | `apps/telemetry-backend` |
| `@prisma/management-api-sdk` | ^1.56.0 | ^1.76.0 |
`apps/telemetry-backend` |

compute-sdk 0.43 renames "service" to "app" and "version" to
"deployment". The telemetry deploy script now uses the new names. Both
SDK versions call `/v1/apps/{appId}`, so the ID stored in the existing
`TELEMETRY_DEPLOY_SERVICE_ID` secret is still correct. The app's
typecheck now includes `scripts/`, so it catches the next SDK rename.

The repo does not depend on `@prisma/composer`.

## Fixes needed to publish

- **The publish workflow has failed on `main` since prisma#30372.**
`check:conformance` called the `orm` config validator as
`validate(value)`. Engine 0.6 always calls `validate(value,
provenance)`, and the validator reads `provenance.files`, so it threw on
every input. The check now passes the same provenance the engine would.
The prisma-cli copy of this check already does this.
- `set-version` rewrote `workspace:@internal/cli@<version>` to
`workspace:<version>`, dropping the alias. The prisma7-adoption example
uses that alias. This is the first bump since the alias was added.
- `lint:legacy-name` and the `add-model-map` test pointed at the pending
fragment paths. They now point at the archived sources.

## Verification

Passed locally:

- `pnpm build`
- `pnpm typecheck`
- `pnpm lint`
- `pnpm test:scripts` (563 tests)
- `pnpm check:conformance`
- `pnpm check:publish-deps`
- `pnpm check:upgrade-coverage`, in both publish and PR mode
- `pnpm check:release-notes`, in both publish and PR mode
- `pnpm lint:legacy-name`
- `pnpm lint:skills`
- `pnpm test:packages`: all 18,196 tests passed

Not covered locally, left to CI:

- Three `test:packages` suites install packed tarballs from the
registry. This machine's pnpm refuses `@vercel/detect-agent@1.2.5`
because it has no provenance. CI passed the same suites on prisma#30390.
- `prisma-8-cloudflare-worker` needs a local Hyperdrive database.
- The telemetry backend tests need Node 24.16 with `Temporal`. This
machine has 24.13.
- `fixtures:check` needs Postgres.

🤖 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 PostgreSQL full-text search, multi-file schemas, prepared ORM
reads and aggregates, and conflict-skipping options for bulk creation.
* Added support for using a Prisma 7 schema as the contract source,
JavaScript `Date` timestamps on PostgreSQL, editor support for attribute
arguments, and per-finding diagnostics.

* **Breaking Changes**
* Prisma 8 schema files now require `// use prisma-8` on the first line;
unmapped models use their names verbatim for table names.
* Replace `dbgenerated(...)` with SQL tagged literals. Defaults must be
valid for their column types, creation timestamps use the application
clock, and native PostgreSQL enums no longer support text operations.
* Config naming and path resolution, migration starting points, and
extension contracts have changed.

* **Bug Fixes**
* Improved migration checks and branching warnings, contract generation
and inference, default verification, and type checking.
<!-- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants