feat: ADR-0035 4c — DROP TABLE [IF EXISTS]

Add advanced-mode SQL `DROP TABLE [IF EXISTS] <name>` -> SqlDropTable,
executing through the existing do_drop_table (cascade / inbound-
relationship refusal / metadata cleanup) — full parity with the simple
`drop table`. The only new behaviour is `IF EXISTS` as a
no-op-with-note: a new DropOutcome::Skipped mirroring
CreateOutcome::Skipped (journalled, no snapshot), rendered via a new
ddl.drop_skipped_absent note + DslDropSkipped event.

- Grammar: SQL_DROP_TABLE node (entry `drop`, shape `table [if exists]
  <name> [;]`), registered Advanced. SQL-first dispatch: `drop table T`
  -> SqlDropTable in advanced; `drop column`/`relationship`/`index`/
  `constraint` fall back to the simple `drop` node (and still execute).
- Worker: Request::SqlDropTable + db.sql_drop_table; the if-exists-and-
  absent arm journals + replies Skipped without a snapshot, else
  snapshot_then(do_drop_table) -> Dropped.
- Completion: advanced `drop ` now surfaces the SQL `table` (the
  shared-entry-word behaviour from `create`); test split into simple
  (full DSL list) + advanced (SQL surface).

Known shared-entry-word completion unevenness (advanced `drop ` offers
only `table`; partial `drop rel` returns an empty list) deferred to 4i
(merge candidate sets for shared entry words) along with a flagged user
request to visually distinguish simple- vs advanced-mode completions in
the hint UI — tracked in ADR §13 4i (d)/(e), the 4c plan, and the
completion test. The DSL drops still parse + execute via fallback.

10 new tests (parse/builder + Tier-3: drop existing + one-undo-step +
restore, IF EXISTS skip + journal, plain-absent error, inbound refusal).
Docs: ADR-0035 Status/§13, README, requirements.md Q1.

Tests: 1805 passing, 0 failing, 1 ignored. Clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-25 16:31:41 +00:00
parent 76d60591bf
commit e52e90c45b
16 changed files with 597 additions and 19 deletions
+33 -8
View File
@@ -3,13 +3,13 @@
## Status
Accepted. Design agreed with the user (2026-05-24); the approach is
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3 / 4b**
**validated end-to-end by sub-phases 4a / 4a.2 / 4a.3 / 4b / 4c**
(`CREATE TABLE` with column- and table-level constraints and foreign
keys, implemented 2026-05-25 — plans
keys, and `DROP TABLE [IF EXISTS]`, implemented 2026-05-25 — plans
`docs/plans/20260524-adr-0035-sql-ddl-4a.md`, `…-4a2.md`, `…-4a3.md`,
`docs/plans/20260525-adr-0035-sql-ddl-4b.md`), so the decision is
accepted while the remaining sub-phases (**4c4i**, §13) continue. This
is **Phase 4** of the ADR-0030 roadmap (the
`docs/plans/20260525-adr-0035-sql-ddl-4b.md`, `…-4c.md`), so the
decision is accepted while the remaining sub-phases (**4d4i**, §13)
continue. This is **Phase 4** of the ADR-0030 roadmap (the
advanced-mode SQL surface), the peer of ADR-0031 (expression grammar),
ADR-0032 (`SELECT`), and ADR-0033 (DML). It **clarifies ADR-0030 §4**
on how DDL is represented and executed.
@@ -367,8 +367,19 @@ ADR-0033's structure:
takes `CONSTRAINT <name>`. PK-target only (UNIQUE-target deferred with
`add relationship`); `Type::fk_target_type` (ADR-0011) governs type
compatibility.
- **4c — `DROP TABLE [IF EXISTS]`** → `SqlDropTable` (cascade parity;
`IF EXISTS` no-op-with-note, §4).
- **4c — `DROP TABLE [IF EXISTS]`** → `SqlDropTable`. *(Implemented
2026-05-25 — plan `docs/plans/20260525-adr-0035-sql-ddl-4c.md`.)*
Reuses `do_drop_table` (cascade parity + the inbound-relationship
refusal + metadata cleanup), so it matches the simple `drop table`;
`IF EXISTS` on an absent table is a no-op-with-note (a new
`DropOutcome::Skipped` mirroring `CreateOutcome::Skipped`; journalled,
no snapshot, §4). `drop` is a shared entry word: `drop table` parses
as `SqlDropTable` in advanced mode, `drop column`/`relationship`/
`index`/`constraint` fall back to the simple `drop` node. Advanced-
mode `drop ` completion now surfaces the SQL `table` (the
shared-entry-word behaviour from `create`, ADR-0033 Amendment 3); the
DSL drops still parse via fallback — 4i grows the surface as `DROP
INDEX` lands in 4d.
- **4d — `CREATE [UNIQUE] INDEX` / `DROP INDEX`** → `SqlCreateIndex`
/ `SqlDropIndex` (ADR-0025; the `UNIQUE` flag extension if needed).
- **4e — `ALTER TABLE` add/drop/rename column.** Drop/rename column
@@ -394,7 +405,21 @@ ADR-0033's structure:
schema-existence diagnostic falsely flags the not-yet-created self
table as unknown (the FK parent slot is `IdentSource::Tables`). Make
the diagnostic treat a FK parent equal to the `CREATE TABLE` target as
valid, so the indicator stops lying for self-references.
valid, so the indicator stops lying for self-references. (d) **4c
shared-entry-word completion merge** — in advanced mode a shared entry
word surfaces only the SQL node's continuations, so `drop ` offers
only `table` (not the DSL `column`/`relationship`/`index`/`constraint`)
and a partial keyword like `drop rel` returns an *empty* list (a
mid-word dead end), even though the DSL drops still parse + execute via
fallback. Merge the expected sets of all candidate nodes for a shared
entry word so advanced completion offers every valid continuation
(`drop ` → table + column + relationship + index + constraint; `drop
rel` → relationship); verify `create`/`insert`/`update`/`delete`
completion stays sensible. (e) **Discussion flag (user, 2026-05-25):**
before/with (d), discuss **visually distinguishing simple- vs
advanced-mode completions in the hint UI (likely by colour)** so a
learner can see which continuations are DSL and which are SQL — a UX
design conversation, not just the mechanical merge.
## Consequences
+1 -1
View File
File diff suppressed because one or more lines are too long