Commit Graph

7 Commits

Author SHA1 Message Date
claude@clouddev1 60111f69d5 feat: ADR-0035 4a.3 — table-level / multi-column CHECK
Add table-level CHECK (e.g. `CREATE TABLE t (a int, b int, CHECK (a < b))`)
to advanced-mode SQL CREATE TABLE. Since SQLite exposes no PRAGMA for CHECK
constraints, a table-level CHECK cannot be read back from the engine and
becomes the source of truth in a new internal metadata table
`__rdbms_playground_table_checks (table_name, seq, check_expr)`.

- Grammar: new TABLE_CHECK element in ELEMENT_CHOICES.
- Builder: distinguishes a table-level CHECK from a column-level one by
  element position (no column-def open in the element), using depth-aware
  boundary tracking so a length-arg comma (`numeric(10,2)`) or a
  table-PRIMARY KEY's inner comma is not mistaken for an element separator.
- Worker: do_create_table emits the CHECK clauses and writes the metadata
  rows in its transaction; schema_to_ddl emits them identically on rebuild;
  read_schema / read_schema_snapshot read them from the metadata table;
  do_drop_table clears them.
- Persistence: TableSchema.check_constraints round-trips through project.yaml
  (#[serde(default)], optional on read), mirroring unique_constraints.
- Composite UNIQUE deliberately stays PRAGMA-detected (engine-reportable,
  unlike CHECK) — user-confirmed.

DA/runda round added cross-cutting tests and a forward-looking doc fix:
- table CHECK survives a rebuild triggered by `add column`, and a later
  rebuild_from_text (the ADR-0013 rebuild primitive uses a raw DROP, so the
  metadata rows keyed on the final name are preserved);
- dropping a column a table CHECK references fails cleanly (rollback, table
  intact); detection is 4e, friendly wording is H1;
- dropping a table clears its CHECK metadata (no orphan rows on re-create);
- amended ADR §6 so 4h's RENAME also updates the new metadata table.

20 Tier-3 + 9 grammar/builder + 2 YAML tests. Docs: ADR-0035 Status/§13/§6,
README index, requirements.md Q1. Help/usage skeleton + describe display of
table-level constraints deferred to 4i (symmetric with 4a.2).

Tests: 1769 passing, 0 failing, 1 ignored. Clippy clean.
2026-05-25 14:06:52 +00:00
claude@clouddev1 1c50133438 docs: ADR-0035 4a.2 plan + split table-level CHECK to 4a.3
Survey of the constraint persistence machinery revealed that
table-level/multi-column CHECK needs a NEW __rdbms_* metadata table
(SQLite exposes no PRAGMA for CHECK), unlike per-column CHECK/DEFAULT
(reuse __rdbms_playground_columns.check_expr + PRAGMA dflt_value) and
composite UNIQUE (PRAGMA index_list origin 'u' + a TableSchema field).

User-confirmed split: 4a.2 = per-column CHECK/DEFAULT (raw sql_expr
text) + composite UNIQUE(a,b), no new internal table; 4a.3 = table-level
CHECK + the new metadata table. ADR §13 and README updated in lockstep;
4a.2 plan doc added.
2026-05-25 10:34:04 +00:00
claude@clouddev1 631074ff9c feat: ADR-0035 4a — SQL CREATE TABLE command, worker, and exit gate
Command + builder + worker for advanced-mode SQL CREATE TABLE
(sub-phase 4a), executed structurally through do_create_table:

- Command::SqlCreateTable + build_sql_create_table (ddl.rs): aliases via
  from_sql_name (incl. double precision), column- and table-level
  PRIMARY KEY, redundant-flag de-dup off a sole PK, IF NOT EXISTS.
  Advanced REGISTRY entry on the shared `create` word (SQL-first, DSL
  fallback); no-PK tables allowed (user-confirmed).
- Worker (db.rs): Request::SqlCreateTable + CreateOutcome + snapshot_then
  (one undo step); IF NOT EXISTS no-op (no snapshot, but journalled, like
  read-only commands). do_create_table inline-PK rule aligned with the
  rebuild generator schema_to_ddl — no round-trip DDL drift; serial
  autoincrement is independent of inline-PK (verified by round-trip
  tests).
- Runtime/App: dispatch + CommandOutcome::SchemaSkipped +
  AppEvent::DslCreateSkipped (structure + "already exists — skipped"
  note). Friendly catalog keys added (engine-neutral).

DEFAULT/CHECK/table-level UNIQUE are absent from the 4a grammar (parse
error with usage skeleton; friendly message + support land in the 4a.2
constraint slice) — user-confirmed.

Tests: type resolver, grammar shape, builder (incl. the PK
detection bug they caught), and tests/sql_create_table.rs (worker
round-trip, serial autoincrement first/non-first across rebuild, IF NOT
EXISTS no-op + journalling, no-PK table, one undo step) + a replay-as-
write test. 1739 pass / 0 fail / 1 ignored; clippy clean.

Exit gate: ADR-0035 Proposed -> Accepted (validated end-to-end by 4a);
README + requirements.md Q1 updated.
2026-05-25 10:04:28 +00:00
claude@clouddev1 94ec87b2ff docs: ADR-0035 4a — refine scope (CHECK/DEFAULT to constraint slice; double-precision; serial-inline)
Three design questions settled during 4a implementation (plan + ADR §13
+ README in lockstep):
- CHECK/DEFAULT defer to the 4a.2 constraint slice: sql_expr is
  validate-only (no Expr AST), so they need raw-SQL-text storage on a
  separate path, not do_create_table's Expr->compile reuse. 4a.2 now
  also covers composite UNIQUE / multi-column table CHECK.
- double precision (the lone two-word alias) handled via a keyword-pair
  branch; single-word aliases + discarded (len) cover the rest.
- serial sole-PK in a multi-column table must inline PRIMARY KEY to keep
  autoincrement (worker-step do_create_table extension).
4a core narrows to columns + types + NOT NULL/UNIQUE/PRIMARY KEY +
IF NOT EXISTS; everything else errors "not yet supported".
2026-05-25 07:55:22 +00:00
claude@clouddev1 093496fe6b docs: ADR-0035 4a plan + 4a.2 split for composite UNIQUE / table CHECK
Add the sub-phase 4a implementation plan (docs/plans/), test-first,
mirroring the ADR-0033 DML sub-phase model: SqlCreateTable as its own
command executed structurally through the existing do_create_table
helper; shared-entry-word dispatch (SQL-first, simple fallback); the
type-alias resolver; IF NOT EXISTS no-op-with-note (CreateOutcome
enum); INTEGER PRIMARY KEY -> plain int; one-undo-step wiring.

Records the user-confirmed 4a/4a.2 split: composite UNIQUE(a,b) and
multi-column table CHECK move to a dedicated slice because they are the
first structures TableSchema cannot already represent, so they need a
persistence-model + round-trip extension rather than parse+execute
reuse. ADR-0035 §13 gains 4a.2; README sub-phase line updated in
lockstep.
2026-05-24 22:54:07 +00:00
claude@clouddev1 19d3cd3306 docs: ADR-0035 — record two /runda refinements (IF [NOT] EXISTS, INTEGER PRIMARY KEY)
Pre-implementation /runda round settled two open micro-calls before 4a,
both user-confirmed:

- IF [NOT] EXISTS admitted (no-op-that-succeeds-with-a-note), not
  refused — a near-universal cross-vendor idiom (PostgreSQL, MySQL,
  SQLite, Oracle 23ai), reclassified into scope rather than treated as
  an engine-specific spelling. Touches §3/§4/§12/§13 (4a, 4c).
- INTEGER PRIMARY KEY maps to a plain int PK, not auto-increment;
  serial stays the sole auto-increment type (§3).

README index updated in the same edit per the lockstep rule.
2026-05-24 22:31:44 +00:00
claude@clouddev1 a079200b17 docs: ADR-0035 — advanced-mode SQL DDL (Phase 4)
Phase 4 of the ADR-0030 roadmap; clarifies §4. Advanced-mode
CREATE/DROP/ALTER TABLE + CREATE/DROP INDEX get their own
per-statement Sql* commands, executed structurally (not verbatim)
so the playground's types, named relationships, and STRICT stay
intact. Full surface (no pre-emptive cuts): constraints, compound
PK, FK -> named relationships (one statement = one undo step),
ALTER incl. advanced-only table rename (C1), [UNIQUE] indexes.
Unified column-type-conversion: lossy refuses in simple mode but
proceeds-with-a-note in advanced, with undo as the safety net.
Integration (parser/hint/completion/diagnostics/history/replay/undo)
is structural via the unified grammar; replay treats DDL as a write.
Nine sub-phases (4a-4i). Updates the ADR README index.

Status: Proposed (design agreed; implementation pending).
2026-05-24 22:14:30 +00:00