Support for Partial Indexes (Filtered Indexes) (#5749)
## Summary
This PR implements support for **partial indexes** (also known as
filtered indexes) in Prisma Schema Language. Partial indexes allow
creating indexes that only include rows matching a specific condition,
reducing index size and improving query performance.
There was an [issue](https://github.com/prisma/prisma/issues/6974)
related to this PR that was 5 years old. 😱
## New Syntax
### Raw SQL Syntax (all supported databases)
```prisma
model User {
id Int @id
email String
status String
@@unique([email], where: raw("status = 'active'"))
@@index([email], where: raw("deletedAt IS NULL"))
}
```
### Object Literal Syntax (type-safe alternative)
```prisma
model Post {
id Int @id
title String
published Boolean
@@index([title], where: { published: true })
@@unique([title], where: { published: { not: false } })
}
```
## Preview Feature
This feature is gated behind the `partialIndexes` preview feature:
```prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["partialIndexes"]
}
```
## Supported Databases
| Database | Support | Migrations | Introspection | Notes |
|-------------|---------|------------|---------------|-------|
| PostgreSQL | ✅ Full | ✅ | ✅ | Full predicate support |
| SQLite | ✅ Full | ✅ | ✅ | Full predicate support |
| SQL Server | ✅ Full | ✅ | ✅ | Filtered indexes via `CREATE INDEX` |
| CockroachDB | ⚠️ Partial | ✅ Create only | ❌ | Cannot introspect
predicate text |
| MySQL | ❌ | - | - | Not supported by the database |
### CockroachDB Limitation
CockroachDB supports creating partial indexes but cannot introspect
predicate text. This means:
- ✅ Initial index creation works
- ❌ Predicate modifications are not detected
- ❌ `add`/`modify`/`remove` predicate migrations don't work
The differ skips predicate comparison for CockroachDB to prevent
false-positive migrations.
## Changes
### PSL Parser (`psl/`)
- **Grammar**: Extended Pest grammar with `object_expression` and
`object_member` rules
- **AST**: Added `Expression::Object` variant and `ObjectMember` struct
- **Types**: Added `WhereClause`, `WhereCondition`,
`WhereFieldCondition`, `WhereValue` enums
- **Validation**: Added `partial_index_is_supported` validation
requiring preview feature
- **Capabilities**: Added `PartialIndex` connector capability for
PostgreSQL, SQLite, CockroachDB, SQL Server
### Schema Engine (`schema-engine/`)
- **DDL Generation**: Implemented `CREATE INDEX ... WHERE` for all
supported databases
- **Migrations**:
- Added `predicates_match()` trait method to `SqlSchemaDifferFlavour`
- Delegate predicate comparison to flavour-specific implementations
- CockroachDB skips predicate comparison (DB limitation)
- **Introspection**:
- Modified PostgreSQL/SQLite/MSSQL describers to fetch index predicates
- Auto-injects `partialIndexes` preview feature when partial indexes
detected
- **Normalization**:
- PostgreSQL predicates wrapped in parentheses to match DB format
- SQL Server predicates wrapped in parentheses for consistency
### SQL Server Specifics
- Filtered unique indexes must be created via `CREATE INDEX` (not as
table constraints)
- Modified `render_create_table_as` to exclude filtered unique indexes
from constraints
- Added `filter_definition` column to index introspection query
### SQL DDL (`libs/sql-ddl/`)
- Added `WhereClause` support to `CreateIndex` for PostgreSQL
- Implemented `CreatePartialIndex` for SQLite
## Test Coverage
### PSL Unit Tests (`psl/psl/tests/attributes/partial_index.rs`)
- 33 test cases covering:
- Raw SQL syntax for `@@unique` and `@@index`
- Object literal syntax (boolean, string, number, null conditions)
- Multiple field conditions
- `{ not: true/false/null }` syntax
- Error cases (unsupported databases, invalid syntax)
- CockroachDB support
### Migration Tests (`schema-engine/sql-migration-tests/`)
| Database | unique | normal | compound | add | modify | remove | Total
|
|-------------|--------|--------|----------|-----|--------|--------|-------|
| PostgreSQL | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | **6** |
| SQLite | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | **6** |
| SQL Server | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | **6** |
| CockroachDB | ✅ | ✅ | ✅ | - | - | - | **3** |
**Total: 21 migration tests**
### Introspection Tests (`schema-engine/sql-introspection-tests/`)
- PostgreSQL partial unique index introspection
- SQLite partial unique index introspection
- SQL Server partial unique index introspection
- Automatic preview feature injection
- Field-level `@unique` with `where` clause
## Generated SQL Examples
### PostgreSQL
```sql
CREATE UNIQUE INDEX "User_email_key" ON "User" ("email") WHERE (status = 'active'::text);
```
### SQLite
```sql
CREATE UNIQUE INDEX "User_email_key" ON "User" ("email") WHERE status = 'active';
```
### SQL Server
```sql
CREATE UNIQUE NONCLUSTERED INDEX [User_email_key] ON [dbo].[User]([email]) WHERE ([status]='active');
```
### CockroachDB
```sql
CREATE UNIQUE INDEX "User_email_key" ON "User" ("email") WHERE (status = 'active');
```
### Key Files
| File | Changes |
|------|---------|
| `psl/schema-ast/src/parser/datamodel.pest` | Grammar rules for object
expressions |
| `psl/schema-ast/src/ast/expression.rs` | `Expression::Object` AST type
|
| `psl/parser-database/src/attributes.rs` | `where` clause parsing logic
|
| `psl/parser-database/src/walkers/index.rs` | SQL predicate generation
|
| `psl/psl-core/src/common/preview_features.rs` | `PartialIndexes`
feature flag |
| `psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs` |
MSSQL `PartialIndex` capability |
| `schema-engine/.../sql_schema_calculator.rs` | DDL generation with
predicates |
| `schema-engine/.../sql_schema_differ/table.rs` | Predicate comparison
for migrations |
| `schema-engine/.../sql_schema_differ_flavour.rs` |
`predicates_match()` trait method |
| `schema-engine/.../flavour/postgres/schema_differ.rs` | CockroachDB
predicate handling |
| `schema-engine/.../flavour/mssql/renderer.rs` | SQL Server filtered
index rendering |
| `schema-engine/.../flavour/mssql/schema_differ.rs` | SQL Server index
matching |
| `schema-engine/sql-schema-describer/src/mssql.rs` | SQL Server
predicate introspection |
| `schema-engine/.../introspection/` | Partial index introspection |
## Related
- Related to [ISSUE 6974](https://github.com/prisma/prisma/issues/6974)
## Checklist
- [x] PSL parser changes
- [x] Schema engine DDL generation
- [x] Migration diff logic
- [x] Introspection support
- [x] Preview feature gate
- [x] Unit tests
- [x] Migration tests (21 tests across 4 databases)
- [x] Introspection tests
- [x] SQL Server support
- [x] CockroachDB limitation handling
- [ ] Documentation update (separate PR)
---------
Co-authored-by: jacek-prisma <malec@prisma.io>