Skip to content

Commit 2e77a1a

Browse files
docs: btree spelling change converges as a phase-2 rename, not create+drop
The DEFAULT_INDEX_TYPE comment claimed a btree-vs-untyped spelling change plans create + drop; normalization makes the two spellings content-equal, so phase-2 content pairing converges them with a rename (phase-1 never pairs them — the wire hashes differ). Also note the deliberate PSL/TS options asymmetry in both authoring READMEs: PSL accepts type: without options: (absent validates as {}), the TS pack-typed arm requires the options key at compile time, and both lower to the same IR. Signed-off-by: willbot <w.a.madden+machine@gmail.com> Signed-off-by: Will Madden <madden@prisma.io>
1 parent 5c12c97 commit 2e77a1a

3 files changed

Lines changed: 6 additions & 5 deletions

File tree

packages/2-sql/1-core/schema-ir/src/ir/sql-index-ir.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ import { assertNode, defineNonEnumerable, SqlSchemaIRNode } from './sql-schema-i
1313
* authored `type: "btree"` and a default-method introspected index compare
1414
* equal — both derivation paths construct through this class. The contract
1515
* JSON and the wire-name content hash keep the authored spelling, so
16-
* `@@index([a], type: "btree")` and `@@index([a])` are distinct wire names
17-
* (a spelling change between them is a content edit — create + drop, not a
18-
* rename).
16+
* `@@index([a], type: "btree")` and `@@index([a])` are distinct wire names —
17+
* but content-equal after normalization, so a spelling change between them
18+
* converges as a rename via the planner's phase-2 content pairing (the
19+
* hashes differ, so phase-1 never pairs them).
1920
*/
2021
const DEFAULT_INDEX_TYPE = 'btree';
2122

packages/2-sql/2-authoring/contract-psl/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Supported timestamp authoring surface:
8383
- Exactly one of a fields list or `expression:` (the whole CREATE INDEX element list as one opaque string); violating this raises `PSL_INDEX_FIELDS_XOR_EXPRESSION`.
8484
- `expression:` requires `name:` or `map:` (`PSL_INDEX_EXPRESSION_REQUIRES_NAME` — no default name can be derived from an expression); at most one of `name:`/`map:` (`PSL_INDEX_NAME_XOR_MAP`).
8585
- `name:` declares a managed index — the physical name is `<name>_<8-hex content hash>` and renames plan as `ALTER INDEX … RENAME`. `map:` adopts an exact physical name verbatim, intended for objects captured by `contract infer`.
86-
- `where:` is a partial-index predicate (WHERE body, without the keyword); `unique:` a boolean; `type:` plus `options:` select a target-registered index access method (e.g. `type: "hash"`).
86+
- `where:` is a partial-index predicate (WHERE body, without the keyword); `unique:` a boolean; `type:` plus `options:` select a target-registered index access method (e.g. `type: "hash"`). Unlike the TS builder (whose pack-typed arm requires the `options` key at compile time), PSL accepts `type:` without `options:` — absent options validate as `{}` and lower to the same IR.
8787
- `map:` combined with a SQL body (`expression:`/`where:`) emits the `PN_EXACT_NAME_BODY_COMPARISON` warning: drift detection byte-compares the authored text against Postgres's reprinted form, which is only reliable for infer-captured text — prefer `name:` for hand-authored bodies.
8888

8989
Model-level control policy:

packages/2-sql/2-authoring/contract-ts/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ constraints.index([cols.email], { unique: true, where: '(archived_at IS NULL)',
203203
constraints.index({ expression: 'eql_v3.eq_term(email)', name: 'users_email_eq' })
204204
```
205205

206-
- **Fields form**`constraints.index(cols | [cols...], options?)`. Options: `unique?`, `where?` (partial-index predicate, WHERE body without the keyword), `name?` xor `map?`, and — when the target pack registers index types — `type?` paired with its `options?` (e.g. `type: 'hash', options: {}`).
206+
- **Fields form**`constraints.index(cols | [cols...], options?)`. Options: `unique?`, `where?` (partial-index predicate, WHERE body without the keyword), `name?` xor `map?`, and — when the target pack registers index types — `type?` paired with its `options?` (e.g. `type: 'hash', options: {}`). The pack-typed arm requires the `options` key at compile time; PSL accepts `type:` without `options:` (absent validates as `{}`) — both lower to the same IR.
207207
- **Expression form**`constraints.index({ expression, ...options })`. The expression is the whole CREATE INDEX element list as one opaque string; `name` or `map` is required (no default name can be derived from an expression). Same remaining options as the fields form.
208208

209209
`name:` declares a **managed** index: the physical name is `<name>_<8-hex content hash>`, and renames plan as `ALTER INDEX … RENAME`. `map:` adopts an **exact** physical name verbatim (no hash) — intended for objects captured by `contract infer`. Combining `map:` with a SQL body (`expression`/`where`) emits the `PN_EXACT_NAME_BODY_COMPARISON` warning at build time: drift detection byte-compares the authored text against Postgres's reprinted form, which is only reliable for infer-captured text. Prefer `name:` for hand-authored bodies.

0 commit comments

Comments
 (0)