create table: column constraints — NOT NULL / UNIQUE / DEFAULT grammar (ADR-0029)

`create table … with pk` now parses the column-constraint
suffix; combined with the commit-1 db layer, a constrained
table works end to end.

- A shared constraint-suffix grammar fragment — `not null`,
  `unique`, `default <literal>` — sits after each column's
  `(type)` group; `build_create_table` walks the matched path
  per column and folds the constraints into `ColumnSpec`.
- §9 redundancy check: every `with pk` column is a primary-key
  column, so `not null` (any) and `unique` (single-column PK)
  are rejected with a friendly error
  (`parse.custom.constraint_redundant_on_pk`).
- `project.yaml` round-trip: `ColumnSchema` gains `not_null` /
  `default`; the YAML reader/writer and `build_read_schema`
  carry them, so `rebuild` / `export` / `import` preserve
  constraints.
- ADR-0029 §2.1's example corrected — `create table` columns
  are all PK columns, so its suffix is for `default` / `check`;
  `docs/simple-mode-limitations.md` records that non-PK
  columns at create time need advanced mode.

CHECK is deferred to the next commit. 1184 tests pass (+7);
clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-19 14:41:29 +00:00
parent a60e879f20
commit 12395a9a6c
11 changed files with 348 additions and 76 deletions
+4
View File
@@ -398,6 +398,10 @@ parse:
# classifies the input as mid-typing rather than
# dispatching a logically-empty Form C insert.
insert_form_a_missing_values: "`insert into ...({columns})` looks like Form A — add `values (...)` to supply the matching values."
# ADR-0029 §9: a primary-key column is already NOT NULL,
# and a single-column primary key is already UNIQUE —
# declaring either explicitly is redundant.
constraint_redundant_on_pk: "`{column}` is a primary-key column, so it is already {constraint} — drop the redundant constraint."
# Caret pointer showing where in the input the parser
# failed. `{padding}` is the leading whitespace; the
# template appends `^` so the rendered line places the