Skip to content

add support for partial indexes based on the Prisma syntax#2622

Open
lsmith77 wants to merge 1 commit intozenstackhq:devfrom
lsmith77:partial-indexes
Open

add support for partial indexes based on the Prisma syntax#2622
lsmith77 wants to merge 1 commit intozenstackhq:devfrom
lsmith77:partial-indexes

Conversation

@lsmith77
Copy link
Copy Markdown
Contributor

@lsmith77 lsmith77 commented Apr 27, 2026

https://www.prisma.io/docs/orm/prisma-schema/data-model/indexes#configuring-partial-indexes-with-where

fix #2621

I wasn't quite sure where to place the test.

Summary by CodeRabbit

  • New Features

    • Added support for partial (filtered) indexes and unique constraints
    • @@index and @@unique now accept an optional where parameter (Prisma filter object or raw SQL)
    • Prisma output will include a partialIndexes section automatically when partial constraints are present
  • Bug Fixes / Validation

    • where must be a filter object or raw SQL; plain string literals are rejected with a validation error
  • Tests

    • End-to-end and regression tests added to verify partial index/unique generation and schema output

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds support for partial indexes/uniques: language model accepts an optional where on @@index/@@unique, raw() is allowed in Unique/Index contexts, Prisma schema generator emits partialIndexes preview feature and handles object-shaped where expressions, builder/runtime support for raw attribute args, validators and tests updated.

Changes

Cohort / File(s) Summary
Language model
packages/language/res/stdlib.zmodel
Adds Unique to ExpressionContext, extends raw() contexts to include Unique, and adds optional where: Any? to @@index and @@unique signatures.
Prisma attribute builder
packages/sdk/src/prisma/prisma-builder.ts
Adds 'Raw' variant to AttributeArgValue construction and serialization so raw SQL argument values are emitted unchanged.
Prisma schema generation
packages/sdk/src/prisma/prisma-schema-generator.ts
Detects composite attributes with where and ensures partialIndexes is added to generator previewFeatures; emits object-shaped where expressions as Raw argument values instead of rejecting them.
Validators
packages/language/src/validators/attribute-application-validator.ts
Validates where argument on constraint attributes and errors when where resolves to a plain string literal (must be filter object or raw("SQL")).
TypeScript schema gen
packages/sdk/src/ts-schema-generator.ts
Adds support for ObjectExpr nodes by generating corresponding TS object literals recursively.
Tests
tests/e2e/orm/partial-index.e2e.test.ts, tests/regression/test/prisma-schema-generator.test.ts
Adds e2e and regression tests to verify partial @@index/@@unique preservation, partialIndexes preview feature enablement, and correct emission of where in raw and object forms.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I nibble code and twitch my nose,
Where-clauses bloom where the carrot grows.
Raw SQL hops in, no need to hide,
Indexes and uniques stride side-by-side.
A little hop, a little cheer — partials are here!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed All primary objectives from issue #2621 are met: partial index syntax support added to stdlib, Prisma schema generator updated to emit partial indexes with where clauses, and both raw() expressions and filter objects are supported.
Out of Scope Changes check ✅ Passed All changes directly support partial index implementation. Updates to ExpressionContext, AttributeArgValue, TsSchemaGenerator, and validators are all necessary for the feature and are within scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately summarizes the main feature being added—support for partial indexes using Prisma syntax—which is the primary focus of all changes across multiple files and test suites.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/sdk/src/prisma/prisma-schema-generator.ts (1)

351-380: ⚠️ Potential issue | 🟠 Major

String literals passed as where will produce invalid Prisma output.

A user writing @@index([id], where: "id > 0") reaches the isLiteralExpr branch (line 352) and is emitted as where: "id > 0". Prisma's where only accepts raw("…") or { field: value } object literals, so a bare quoted string is a syntax error in the generated Prisma schema — even though the regression test in tests/regression/test/prisma-schema-generator.test.ts (lines 6–22, 43–60) currently asserts this output is produced.

Two reasonable options:

  1. Reject String/non-object/non-raw() values on where at validation time, so the user is steered to raw("…").
  2. Auto-wrap a string literal where value with raw(...) in the generator (e.g. produce where: raw("id > 0")) so the emitted Prisma is valid.

If string-shaped where is intentional for ZModel ergonomics, option 2 is the least surprising; otherwise option 1 keeps things explicit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sdk/src/prisma/prisma-schema-generator.ts` around lines 351 - 380,
The generator currently emits raw string literals for attribute args (in
makeAttributeArgValue) which produces invalid Prisma for a `where` arg; change
makeAttributeArgValue to accept an optional argName (e.g. add parameter
argName?: string) and when isLiteralExpr(node) && node.$type === StringLiteral
&& argName === 'where' return a PrismaAttributeArgValue('Raw',
this.exprToText(node)) or construct a raw(...) FunctionCall equivalent instead
of emitting a plain String; update all callers that create attribute args (where
attribute parsing site(s)) to pass the arg name so the function can auto-wrap
`where` string literals into Raw (or alternatively throw a validation error
there if you prefer rejection).
🧹 Nitpick comments (1)
packages/language/res/stdlib.zmodel (1)

253-253: Document the new where parameter and broaden raw() expression context to include @@unique.

Two small follow-ups for the new where: Any? parameter on @@unique (line 253) and @@index (line 356):

  1. The JSDoc above each attribute (lines 244–252 and 345–355) doesn't describe the new where parameter. Adding a one-liner clarifying it's used for partial indexes (Prisma partialIndexes preview) and accepts either raw("SQL") or an object literal would help schema authors discover it.
  2. The raw() helper is declared with @@@expressionContext([Index]) (line 634). Now that where is also valid on @@unique, raw(...) used inside @@unique(..., where: raw("...")) is technically outside the declared expression context. Consider widening that context (e.g. introduce a new Unique context or reuse Index) so language-level validation stays consistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/language/res/stdlib.zmodel` at line 253, Update the JSDoc for the
@@unique and @@index attributes to document the new where: Any? parameter with a
one-line description stating it is for partial indexes (Prisma partialIndexes
preview) and accepts either raw("SQL") or an object literal; then broaden the
raw() expression context declaration (the raw symbol/@@@expressionContext) to
include Unique (or both Index and Unique) so raw(...) used inside @@unique(...,
where: raw("...")) is recognized by the language-level validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/sdk/src/prisma/prisma-schema-generator.ts`:
- Around line 372-373: The generator currently neither adds previewFeatures =
["partialIndexes"] when index/constraint args use a where predicate nor properly
emits string literal predicates, so update generateDefaultGenerator to scan
index/unique definitions (where the code constructs @@index/@@unique and `@unique`
attributes) and if any PrismaAttributeArg with name "where" is present mark the
generator previewFeatures to include "partialIndexes"; additionally, change the
handling in exprToText/isLiteralExpr (the branch that returns
PrismaAttributeArgValue('Raw', this.exprToText(node)) and the branch emitting
bare quoted strings for literals) so that string literal `where` values are
either rejected with a clear validation error or automatically wrapped as
raw("...") (prefer wrapping to preserve compatibility), ensuring object
expressions remain emitted as before; reference the affected symbols:
generateDefaultGenerator, PrismaAttributeArgValue('Raw'), isLiteralExpr,
isObjectExpr, and exprToText.

In `@tests/e2e/orm/partial-index.e2e.test.ts`:
- Around line 1-21: This e2e test is brittle and redundant; remove this test
file (tests/e2e/orm/partial-index.e2e.test.ts) or rewrite it to use the
programmatic API: replace the execSync-based runGenerate()/npx invocation with a
call to loadSchema from `@zenstackhq/testtools` and invoke PrismaSchemaGenerator
directly (or the existing regression helper used in
tests/regression/test/prisma-schema-generator.test.ts), assert on the generated
schema string instead of reading/writing SCHEMA_FILE/GENERATED_PRISMA, and if
you must write files use a tmpdir or add cleanup in afterAll to avoid polluting
the source tree.

In `@tests/e2e/orm/schemas/partial-index/schema.zmodel`:
- Around line 1-13: The fixture is missing the generator preview feature for
partial indexes, so update the schema to include an explicit generator block
that sets previewFeatures = ["partialIndexes"] (so Prisma accepts the
model-level @@index and @@unique with where clauses); add this generator (using
the same generator name pattern produced by
PrismaSchemaGenerator.generateDefaultGenerator if you want parity) near the top
of the schema (above or below the datasource block) so the Post model's
@@index([title], where: { published: true }) and @@unique([title], where: {
published: true }) validate correctly.

In `@tests/regression/test/prisma-schema-generator.test.ts`:
- Around line 6-22: Tests currently expect the generator to emit bare quoted
string values for index `where`, which is invalid Prisma syntax; update the
PrismaSchemaGenerator so that when it encounters a string literal for an index
`where` it emits it wrapped in raw(...), e.g. `where: raw("...")`, and then
update the failing tests in
tests/regression/test/prisma-schema-generator.test.ts to assert for
`@@index([id], where: raw("id > 0"))` and `@@index([email], where: raw("email IS
NOT NULL"))` instead of the bare quoted strings; locate logic inside
PrismaSchemaGenerator.generate() that serializes index attributes and alter the
serializer for Index/@@index where-value handling to detect string nodes and
emit raw("...") accordingly.

---

Outside diff comments:
In `@packages/sdk/src/prisma/prisma-schema-generator.ts`:
- Around line 351-380: The generator currently emits raw string literals for
attribute args (in makeAttributeArgValue) which produces invalid Prisma for a
`where` arg; change makeAttributeArgValue to accept an optional argName (e.g.
add parameter argName?: string) and when isLiteralExpr(node) && node.$type ===
StringLiteral && argName === 'where' return a PrismaAttributeArgValue('Raw',
this.exprToText(node)) or construct a raw(...) FunctionCall equivalent instead
of emitting a plain String; update all callers that create attribute args (where
attribute parsing site(s)) to pass the arg name so the function can auto-wrap
`where` string literals into Raw (or alternatively throw a validation error
there if you prefer rejection).

---

Nitpick comments:
In `@packages/language/res/stdlib.zmodel`:
- Line 253: Update the JSDoc for the @@unique and @@index attributes to document
the new where: Any? parameter with a one-line description stating it is for
partial indexes (Prisma partialIndexes preview) and accepts either raw("SQL") or
an object literal; then broaden the raw() expression context declaration (the
raw symbol/@@@expressionContext) to include Unique (or both Index and Unique) so
raw(...) used inside @@unique(..., where: raw("...")) is recognized by the
language-level validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 008b5d0b-0d7c-4e01-bf01-577bd8d2229a

📥 Commits

Reviewing files that changed from the base of the PR and between 8609d5b and b06e557.

📒 Files selected for processing (6)
  • packages/language/res/stdlib.zmodel
  • packages/sdk/src/prisma/prisma-builder.ts
  • packages/sdk/src/prisma/prisma-schema-generator.ts
  • tests/e2e/orm/partial-index.e2e.test.ts
  • tests/e2e/orm/schemas/partial-index/schema.zmodel
  • tests/regression/test/prisma-schema-generator.test.ts

Comment thread packages/sdk/src/prisma/prisma-schema-generator.ts
Comment thread tests/e2e/orm/partial-index.e2e.test.ts Outdated
Comment thread tests/e2e/orm/schemas/partial-index/schema.zmodel Outdated
Comment thread tests/regression/test/prisma-schema-generator.test.ts Outdated
@lsmith77 lsmith77 force-pushed the partial-indexes branch 2 times, most recently from c641029 to 57d82e2 Compare April 28, 2026 06:14
* @param where: Filters rows included in the partial unique constraint; accepts a Prisma filter object or raw("SQL").
*/
attribute @@unique(_ fields: FieldReference[], name: String?, map: String?, length: Int?, sort: SortOrder?, clustered: Boolean?) @@@prisma
attribute @@unique(_ fields: FieldReference[], name: String?, map: String?, length: Int?, sort: SortOrder?, clustered: Boolean?, where: Any?) @@@prisma
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess there is no support for union types to be able to be more strict here.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
packages/sdk/src/prisma/prisma-schema-generator.ts (1)

192-205: ⚠️ Potential issue | 🟠 Major

Apply partialIndexes to explicit generator blocks too.

This only updates the synthetic default client generator. Any schema that already declares generator client will still miss previewFeatures = ["partialIndexes"], so partial indexes remain broken there.

Please reuse the same detection when serializing declared generators as well.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sdk/src/prisma/prisma-schema-generator.ts` around lines 192 - 205,
The partial-index detection (using partialIndexAttrs, zmodel.declarations and
getAllAttributes) currently only pushes 'partialIndexes' into the synthetic
previewFeatures array; update the code that serializes declared generator blocks
(the generator serialization logic that writes each generator's previewFeatures)
to reuse the same detection and add 'partialIndexes' to that generator's
previewFeatures when applicable, merging/deduplicating with any existing
previewFeatures value rather than replacing it so existing generator client
blocks gain the flag as well.
packages/language/res/stdlib.zmodel (1)

255-257: ⚠️ Potential issue | 🟠 Major

Constrain the where parameter to valid Prisma forms and validate explicitly.

The where: Any? type annotation in @@unique (line 257) and @@index (line 361) admits expressions beyond what Prisma's partial index predicates accept. Current validation only rejects plain string literals, allowing expressions like arithmetic or boolean operations to pass validation and fail later during schema generation with a generic "Unsupported attribute argument expression type" error.

Valid forms are object predicates ({ published: true }) and raw SQL (raw("...")). Tighten the type annotation or add explicit validation to reject invalid expression types during schema analysis rather than codegen.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/language/res/stdlib.zmodel` around lines 255 - 257, The where
parameter for the attribute definitions @@unique and @@index is currently typed
as Any? (symbol: attribute @@unique(... where: Any?) and the @@index analog)
which permits invalid expressions; update the model and analyzer to restrict
accepted forms to either an object predicate or raw("SQL") by changing the
type/annotation from Any? to a union of the allowed expression types (e.g.,
ObjectExpression | RawCall) and add explicit validation in the attribute
parsing/analysis code (the @@unique/@@index attribute handler) to reject any
other expression kinds (arithmetic, boolean ops, string literal without raw,
etc.) with a clear error during schema analysis rather than deferring to
codegen.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/language/res/stdlib.zmodel`:
- Around line 255-257: The where parameter for the attribute definitions
@@unique and @@index is currently typed as Any? (symbol: attribute @@unique(...
where: Any?) and the @@index analog) which permits invalid expressions; update
the model and analyzer to restrict accepted forms to either an object predicate
or raw("SQL") by changing the type/annotation from Any? to a union of the
allowed expression types (e.g., ObjectExpression | RawCall) and add explicit
validation in the attribute parsing/analysis code (the @@unique/@@index
attribute handler) to reject any other expression kinds (arithmetic, boolean
ops, string literal without raw, etc.) with a clear error during schema analysis
rather than deferring to codegen.

In `@packages/sdk/src/prisma/prisma-schema-generator.ts`:
- Around line 192-205: The partial-index detection (using partialIndexAttrs,
zmodel.declarations and getAllAttributes) currently only pushes 'partialIndexes'
into the synthetic previewFeatures array; update the code that serializes
declared generator blocks (the generator serialization logic that writes each
generator's previewFeatures) to reuse the same detection and add
'partialIndexes' to that generator's previewFeatures when applicable,
merging/deduplicating with any existing previewFeatures value rather than
replacing it so existing generator client blocks gain the flag as well.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eaa2cb4e-8cbc-4e13-ace6-2fe2b793a648

📥 Commits

Reviewing files that changed from the base of the PR and between 57d82e2 and 87ea867.

📒 Files selected for processing (7)
  • packages/language/res/stdlib.zmodel
  • packages/language/src/validators/attribute-application-validator.ts
  • packages/sdk/src/prisma/prisma-builder.ts
  • packages/sdk/src/prisma/prisma-schema-generator.ts
  • packages/sdk/src/ts-schema-generator.ts
  • tests/e2e/orm/partial-index.e2e.test.ts
  • tests/regression/test/prisma-schema-generator.test.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/regression/test/prisma-schema-generator.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/language/src/validators/attribute-application-validator.ts
  • tests/e2e/orm/partial-index.e2e.test.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/sdk/src/prisma/prisma-schema-generator.ts (1)

169-207: Extract the partial-index preview-feature merge.

Both generator paths now duplicate the same partialIndexes detection/update logic. A small helper would keep the JSON parsing and append behavior in one place and reduce drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sdk/src/prisma/prisma-schema-generator.ts` around lines 169 - 207,
Extract the duplicated logic that ensures the 'partialIndexes' preview feature
is present into a single helper (e.g., addPartialIndexPreviewFeature) and call
it from both locations: the generator-creation block that builds gen via
prisma.addGenerator(...) and the generateDefaultGenerator method after building
the previewFeatures array; the helper should detect/merge into an existing
'previewFeatures' JSON field on a Generator (updating parsed array and
re-stringifying) or accept the previewFeatures array and push 'partialIndexes'
if missing, and reuse the existing hasPartialIndex() check to decide when to
invoke it.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/language/res/stdlib.zmodel`:
- Around line 638-639: The stdlib declares raw(...) supports ExpressionContext
Unique, but the language layer is missing it; add a Unique member to the
ExpressionContext enum in packages/language/src/constants.ts and update the
mapping in packages/language/src/validators/function-invocation-validator.ts to
map the @@unique directive to ExpressionContext.Unique (in the same style as the
existing @@index -> ExpressionContext.Index mapping) so functions used inside
@@unique constraints are accepted; ensure any related switch/validation logic
that inspects ExpressionContext also recognizes the new Unique value.

In `@packages/language/src/validators/attribute-application-validator.ts`:
- Around line 313-318: The validator currently only rejects string literals for
the `where` attribute but allows other invalid shapes (numbers, booleans, null,
etc.); update the check in the block that grabs whereArg (using
getAttributeArg(attr, 'where')) to only accept object literal filter shapes or a
raw(...) call: i.e., replace the isStringLiteral check with logic that verifies
whereArg is either an ObjectLiteralExpression (the filter object) or a
CallExpression whose callee is the identifier "raw" with a single string arg;
for any other node type call accept('error', "`where` expects a filter object or
raw(\"SQL\"), not a plain literal/expression", { node: whereArg }); keep
references to getAttributeArg, whereArg, isStringLiteral (remove/replace), and
accept to locate the code.

---

Nitpick comments:
In `@packages/sdk/src/prisma/prisma-schema-generator.ts`:
- Around line 169-207: Extract the duplicated logic that ensures the
'partialIndexes' preview feature is present into a single helper (e.g.,
addPartialIndexPreviewFeature) and call it from both locations: the
generator-creation block that builds gen via prisma.addGenerator(...) and the
generateDefaultGenerator method after building the previewFeatures array; the
helper should detect/merge into an existing 'previewFeatures' JSON field on a
Generator (updating parsed array and re-stringifying) or accept the
previewFeatures array and push 'partialIndexes' if missing, and reuse the
existing hasPartialIndex() check to decide when to invoke it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0f07d0c1-0ee8-4c43-8e20-a31865c9aac3

📥 Commits

Reviewing files that changed from the base of the PR and between 87ea867 and ef76539.

📒 Files selected for processing (7)
  • packages/language/res/stdlib.zmodel
  • packages/language/src/validators/attribute-application-validator.ts
  • packages/sdk/src/prisma/prisma-builder.ts
  • packages/sdk/src/prisma/prisma-schema-generator.ts
  • packages/sdk/src/ts-schema-generator.ts
  • tests/e2e/orm/partial-index.e2e.test.ts
  • tests/regression/test/prisma-schema-generator.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/e2e/orm/partial-index.e2e.test.ts
  • packages/sdk/src/ts-schema-generator.ts
  • tests/regression/test/prisma-schema-generator.test.ts
  • packages/sdk/src/prisma/prisma-builder.ts

Comment thread packages/language/res/stdlib.zmodel
Comment thread packages/language/src/validators/attribute-application-validator.ts
@lsmith77 lsmith77 changed the title WIP: add support for partial indexes based on the Prisma syntax add support for partial indexes based on the Prisma syntax Apr 28, 2026
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.

[Feature Request] Add support for partial indexes

1 participant