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
+27 -6
View File
@@ -1458,12 +1458,14 @@ mod tests {
}
#[test]
fn drop_offers_all_five_subcommands() {
// `drop` branches: column / relationship / table / index
// (ADR-0025) / constraint (ADR-0029 §2.2). Candidates
// follow grammar declaration order, so `constraint` —
// added last — appears last.
let cs = cands("drop ", 5);
fn drop_offers_all_five_subcommands_in_simple_mode() {
// The DSL `drop` branches: column / relationship / table / index
// (ADR-0025) / constraint (ADR-0029 §2.2). Candidates follow
// grammar declaration order, so `constraint` — added last —
// appears last. Simple mode, because `drop` is a shared entry
// word: advanced mode surfaces the SQL `DROP TABLE` completion
// instead (ADR-0033 Amendment 3 / ADR-0035 §4c — see below).
let cs = cands_simple("drop ", 5);
assert_eq!(
cs,
vec![
@@ -1476,6 +1478,23 @@ mod tests {
);
}
#[test]
fn drop_in_advanced_mode_surfaces_the_sql_drop_table_completion() {
// ADR-0035 §4c: `drop` gained an advanced SQL node
// (`DROP TABLE [IF EXISTS]`). As with the `create`/`insert`/
// `update`/`delete` shared entry words (ADR-0033 Amendment 3),
// advanced mode surfaces the SQL grammar's completion — here
// just `table` — rather than the DSL subcommands. The DSL drops
// (`drop column` etc.) still parse via fallback; only the
// completion hint differs (and a partial DSL keyword like
// `drop rel` returns an empty list — a mid-word dead end).
// ADR-0035 §13 4i (d)/(e) tracks merging the candidate sets for
// shared entry words, and the user's request to visually
// distinguish simple- vs advanced-mode completions in the hint
// UI (likely by colour); this expectation grows when 4i lands.
assert_eq!(cands("drop ", 5), vec!["table".to_string()]);
}
#[test]
fn complete_command_offers_no_candidates() {
// `create table T with pk` is a complete command —
@@ -2444,3 +2463,5 @@ mod tests {
assert!(candidates_at_cursor_with("create ", 7, &cache, empty_ranker).is_none());
}
}