prisma-engines
2997580c - Support for Partial Indexes (Filtered Indexes) (#5749)

Commit
75 days ago
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>
Author
Parents
Loading