feat: ADR-0035 4d — CREATE [UNIQUE] INDEX / DROP INDEX

Advanced-mode SQL CREATE [UNIQUE] INDEX [IF NOT EXISTS] [<name>] ON
<T> (cols) -> SqlCreateIndex and DROP INDEX [IF EXISTS] <name> ->
SqlDropIndex, both reusing the ADR-0025 executors (do_add_index /
do_drop_index), like 4c reused do_drop_table.

- CREATE UNIQUE INDEX admitted in advanced mode (ADR-0025 Amendment 1):
  ADR-0025 deferred UNIQUE indexes for the simple-mode DSL, but advanced
  mode trusts the user like SQL does. Adds an additive IndexSchema.unique
  flag (project.yaml, serde-default, version stays 1); rebuild re-emits
  CREATE UNIQUE INDEX; the redundant-set guard keys on (columns, unique).
  Simple-mode `add unique index` stays deferred.
- IF [NOT] EXISTS on both forms reuses the 4c no-op-with-note skip
  (journalled, not snapshotted) via CreateIndexOutcome / DropIndexOutcome.
- Unnamed CREATE INDEX auto-named (ADR-0025 convention); the [UNIQUE]
  prefix is a concrete-keyword Choice and the optional name an on-led-first
  selector (the drop-index selector precedent) — trap-safe.
- create/drop each gain a second advanced node; the existing all-candidates
  dispatch handles it (locked by parse tests).
- Unique indexes marked [unique] in the structure view and items panel.
- do_add_index refuses internal __rdbms_* tables as "no such table",
  closing a latent exposure on both the simple `add index` and the new
  SQL CREATE INDEX surfaces (ADR-0025 Amendment 1).

Docs: ADR-0035 status + §13 4d + 4i; ADR-0025 Amendment 1; ADR README;
requirements.md Q1/C3. Plan: docs/plans/20260525-adr-0035-sql-ddl-4d.md.

Tests: 1834 passing / 0 failing / 0 skipped / 1 ignored; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-25 18:41:02 +00:00
parent 44248fb8bb
commit 701217d29f
22 changed files with 1865 additions and 48 deletions
+41 -1
View File
@@ -2,7 +2,11 @@
## Status
Accepted
Accepted. **Amendment 1 (2026-05-25):** UNIQUE indexes are admitted on
the **advanced-mode** SQL surface (`CREATE UNIQUE INDEX`) — see
*Amendment 1* below and ADR-0035 §4d. The original *Out of scope*
exclusion stands for the **simple-mode DSL** (`add unique index` remains
deferred).
## Context
@@ -335,6 +339,42 @@ here so the decision text and the code agree:
list with each table's indexes indented beneath — the
`S2` nested view — reading the two together.
## Amendment 1 — UNIQUE indexes in advanced mode (2026-05-25)
This ADR's *Out of scope* excluded UNIQUE indexes (`add unique index`)
on the grounds that a unique index conflates two concepts the playground
teaches separately — an index (a performance structure) and a UNIQUE
*constraint* (an integrity rule, tracked as its own `C3` sub-item). That
reasoning was written on 2026-05-16, when the **simple-mode DSL was the
only input surface**, and it still holds there: simple mode teaches the
two concepts separately, so `add unique index` stays deferred.
ADR-0035 (advanced-mode SQL DDL) introduced a second surface whose
explicit posture is to "trust the user like SQL does" (ADR-0035 §7). On
that surface `CREATE UNIQUE INDEX` is standard SQL a learner types
verbatim, and the concept-separation argument does not transfer — so
ADR-0035 §4 lists `CREATE [UNIQUE] INDEX` and **§4d supersedes this
ADR's exclusion for the advanced surface**. The constraint track this
ADR deferred *to* (ADR-0018 → ADR-0029 → ADR-0035 §4a.2) has since
shipped, so there is no remaining dependency.
Mechanically, the index model gains an `IndexSchema.unique` flag — an
additive, `#[serde(default)]` `project.yaml` field (`version` stays
`1`); the engine already reports uniqueness via `pragma_index_list`
(origin `c`), so **no `__rdbms_*` metadata table is added** (the §Storage
decision is unchanged — the divergence from the relationship precedent
stands). The rebuild primitive re-emits `CREATE UNIQUE INDEX`; the
structure view and items panel mark a unique index `[unique]`
(ADR-0035 §4d). The redundant-column-set guard keys on `(columns,
unique)` so a plain and a unique index over the same columns are not
mutual duplicates.
The amendment also hardened the shared `do_add_index` executor to refuse
an internal `__rdbms_*` table as "no such table" (consistent with the
app-wide opacity of internal tables) — closing a latent exposure on
*both* the simple `add index` and the new SQL `CREATE INDEX` surfaces,
which both reach `do_add_index`.
## See also
- ADR-0004 / ADR-0015 (project file format and storage runtime)