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
+15 -5
View File
@@ -80,14 +80,24 @@ A column spec gains an optional, repeatable constraint suffix
**after** the `(type)` group:
```
create table Users with pk
id(serial),
email(text) not null unique,
age(int) default 18 check (age >= 0)
create table Books with pk isbn(text) check (length(isbn) = 13)
add column to Orders: note (text) default ''
add column to Books: title (text) not null
add column to Books: stock (int) default 0 check (stock >= 0)
```
**Where each constraint is useful.** The simple-mode `create
table … with pk …` declares *only* primary-key columns —
every column in the `with pk` list is part of the primary key
(non-PK columns are added afterward with `add column`; see
`docs/simple-mode-limitations.md`). Since a PK column is
already `NOT NULL` and `UNIQUE`, §9 rejects those two as
redundant there — so on a `create table` column the suffix is
useful for `default` / `check`. `not null` / `unique` come
into their own on `add column` (non-PK columns) and on `add
constraint`. The suffix grammar is nonetheless shared
verbatim across all three surfaces; §9 does the rejecting.
- Standard SQL writes constraints after the data type
(`email TEXT NOT NULL UNIQUE`). The playground brackets the
type as `email(text)` — a pre-existing convention this ADR
+10
View File
@@ -38,3 +38,13 @@ entry names the ADR that drew the boundary.
yet available.
- **No `LIMIT … OFFSET`** — `limit` takes a row count
only.
## Table creation (ADR-0029)
- **`create table` declares only primary-key columns.**
`create table T with pk …` makes every listed column part
of the primary key; there is no simple-mode syntax for a
non-PK column in the same statement. Non-PK columns are
added afterward with `add column`. Creating a table with a
mix of PK and non-PK columns in one statement needs
advanced-mode `CREATE TABLE` syntax.