fix(core): emit @@index for isIndexed: true, not an invalid inline @index - #859
Merged
Merged
Conversation
…ndex
Prisma has no field-level `@index` attribute — `@id`, `@unique`, `@default`,
`@map`, `@relation`, `@updatedAt` and `@ignore` are the whole field-level set,
and a non-unique index exists only as the model-level `@@index([...])`. The
text(), decimal() and calendarDay() builders appended ` @index` to their field
modifiers, so any config using `isIndexed: true` on a scalar generated a schema
Prisma refuses to parse:
error: Attribute not known: "@index".
--> prisma/schema.prisma:567
|
567 | twilioSid String @index
`isIndexed: 'unique'` was unaffected, since inline `@unique` is valid.
A field's index request now travels out-of-line: getPrismaType() gains an
optional `index`, sitting beside the existing `enumValues` — already the channel
by which a field asks for emission outside its own line. The generator collects
these per list and emits them through the same pass that has always handled
relationship foreign keys, so `@@index([...])` for scalars and FKs is one code
path. Keeping the field the authority (rather than having the generator sniff
`isIndexed` itself) preserves field self-containment and lets a multi-column
field, which has no single column matching its field name, decline.
`isIndexed: 'unique'` still emits the inline `@unique` modifier — it has a valid
field-level form, and every schema generated to date contains it — so this
channel carries only what cannot be written inline.
The existing unit test asserted our own return value against our own convention
and so went green on output Prisma rejects; it now asserts the index request and
the absence of an inline attribute. Post.title in examples/blog gains
`isIndexed: true`, which makes the already-existing nightly generate → db:push
gate exercise a real scalar index for the first time — that gate never fired
because no config in the repo used the option.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q142a6D7WsLJ39noXqrkN6
🦋 Changeset detectedLatest commit: b13ea79 The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Coverage Report for Core Package Coverage (./packages/core)
File CoverageNo changed files found. |
Contributor
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Contributor
Coverage Report for CLI Package Coverage (./packages/cli)
File Coverage
|
||||||||||||||||||||||||||||||||||||||
Contributor
Coverage Report for Auth Package Coverage (./packages/auth)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Contributor
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Contributor
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Prisma has no field-level
@indexattribute.@id,@unique,@default,@map,@relation,@updatedAtand@ignoreare the entire field-level set — a non-unique index exists only as the model-level@@index([...]).The
text(),decimal()andcalendarDay()builders appended@indexto their field modifiers, so any config usingisIndexed: trueon a scalar produced a schema Prisma refuses to parse:isIndexed: 'unique'was unaffected — inline@uniqueis valid.relationship()has always got this right, emitting@@index([authorId])viagetPrismaRelation(). Only the scalar path was broken.The fix
A field's index request now travels out-of-line.
getPrismaType()gains an optionalindex?: boolean | 'unique', sitting beside the existingenumValues— already the channel by which a field asks for emission outside its own line. The generator collects these per list and emits them through the same pass that has always handled relationship foreign keys, so@@index([...])for scalars and FKs is one code path.Keeping the field the authority — rather than having the generator sniff
isIndexeditself — preserves field self-containment, and lets a multi-column field (getPrismaColumns, ADR-0006), which has no single column matching its field name, decline rather than emit a fresh broken index.isIndexed: 'unique'keeps emitting the inline@uniquemodifier. It has a valid field-level form and every schema generated to date contains it, so this channel carries only what cannot be written inline. Output for existing configs is byte-identical.Why the tests didn't catch it
packages/core/tests/field-types.test.ts:106asserted our own return value against our own convention, so it went green on output Prisma rejects — and a replacement assertingindex: truewould have the identical blind spot.CI already has real Prisma gates (the scaffold
generate→db:pushguard, and the nightly per-example run). They never fired because no config in the repo usedisIndexed: trueon a scalar — the gate existed, the fixture didn't.Post.titleinexamples/blognow carries the option, so the nightly gate exercises a real scalar index, and the regenerated schema is committed as a visible artifact.Verified end-to-end locally:
pnpm generate(which runsprisma formatandprisma generate, both of which parse the schema) →pnpm db:push→Post_title_idxpresent in the SQLite database.Scope
Fixes the three builders that emit the broken attribute.
integer,timestampandselectdon't acceptisIndexedat all — that's a compile error rather than a broken schema, and closing that gap is additive with its own design questions, so it's tracked separately rather than riding along in a fix.No doc changes: the prose at
docs/content/reference/fields-api.md:59/:623already described@@indexsemantics correctly — the docs were ahead of the code, and the copy-pasteable examples atdocs/content/concepts/field-types.md:100/:221become valid as of this change.Testing
field-types.test.tsto assert the index request and the absence of an inline attribute@@indexfor a scalar, for all three affected types,'unique'still inline, and no index without the optionpnpm lint0 errorsGenerated by Claude Code