feat: ADR-0035 4i(a,b) — CREATE TABLE help/usage + describe table constraints; Phase 4 complete

(b) describe shows table-level constraints: TableDescription gains
unique_constraints + check_constraints (populated by do_describe_table
from read_schema), rendered in a new "Table constraints:" section —
composite UNIQUE and table-level CHECK (named + unnamed). The per-column
Constraints column already covered single-column NOT NULL/UNIQUE/PK/CHECK.

(a) CREATE TABLE help/usage skeleton refreshed for the column DEFAULT/
CHECK/REFERENCES, table-level composite UNIQUE, table CHECK, and
table-level FOREIGN KEY forms (4a.2/4a.3/4b) — engine-neutral,
vocab-audit clean.

With 4i's (c)/(d)/(e) already shipped, this completes sub-phase 4i — the
verification sweep — and therefore ADR-0035 Phase 4 (4a–4i). ADR-0035
Status, §13 4i, the ADR index, and requirements.md Q1 updated to
"Phase 4 complete".

Tests: render_structure table-level-constraints unit test +
e2e_describe_shows_table_level_constraints. Full suite 1917 passing /
0 failing / 1 ignored; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-26 14:38:28 +00:00
parent c2eb8cb982
commit 22e5bf5d6a
10 changed files with 176 additions and 46 deletions
+44
View File
@@ -653,6 +653,50 @@ fn e2e_named_check_metadata_survives_a_fresh_rebuild() {
.expect("DROP CONSTRAINT after a fresh rebuild — the CHECK metadata was reconstructed");
}
// --- 4i (b): describe shows table-level constraints ---------------------
#[test]
fn e2e_describe_shows_table_level_constraints() {
// ADR-0035 §4i (b): `describe` surfaces composite UNIQUE and
// table-level CHECK constraints (named + unnamed) — the executor
// populates them on TableDescription from the metadata.
let (project, db, _d) = open();
let r = rt();
std::fs::write(
project.path().join("d.commands"),
"create table T (a integer primary key, b integer, unique (a, b), check (a < b))\n\
alter table T add constraint a_ne_b check (a <> b)\n",
)
.expect("write script");
let events = r.block_on(run_replay(&db, project.path(), "d.commands"));
assert!(
matches!(events.last(), Some(AppEvent::ReplayCompleted { .. })),
"events: {events:?}"
);
let desc = r.block_on(db.describe_table("T".to_string(), None)).expect("describe");
assert_eq!(
desc.unique_constraints,
vec![vec!["a".to_string(), "b".to_string()]],
"composite UNIQUE surfaced"
);
let checks: Vec<(Option<String>, String)> = desc
.check_constraints
.iter()
.map(|c| (c.name.clone(), c.expr.clone()))
.collect();
assert!(
checks.iter().any(|(n, e)| n.is_none() && e.contains("a < b")),
"unnamed table CHECK surfaced: {checks:?}"
);
assert!(
checks
.iter()
.any(|(n, e)| n.as_deref() == Some("a_ne_b") && e.contains("a <> b")),
"named table CHECK surfaced with its name: {checks:?}"
);
}
// --- 4h: ALTER TABLE … RENAME TO (ADR-0035 §6) --------------------------
/// Path to a table's CSV in the project data dir.