Commit Graph

10 Commits

Author SHA1 Message Date
claude@clouddev1 701217d29f feat: ADR-0035 4d — CREATE [UNIQUE] INDEX / DROP INDEX
Advanced-mode SQL CREATE [UNIQUE] INDEX [IF NOT EXISTS] [<name>] ON
<T> (cols) -> SqlCreateIndex and DROP INDEX [IF EXISTS] <name> ->
SqlDropIndex, both reusing the ADR-0025 executors (do_add_index /
do_drop_index), like 4c reused do_drop_table.

- CREATE UNIQUE INDEX admitted in advanced mode (ADR-0025 Amendment 1):
  ADR-0025 deferred UNIQUE indexes for the simple-mode DSL, but advanced
  mode trusts the user like SQL does. Adds an additive IndexSchema.unique
  flag (project.yaml, serde-default, version stays 1); rebuild re-emits
  CREATE UNIQUE INDEX; the redundant-set guard keys on (columns, unique).
  Simple-mode `add unique index` stays deferred.
- IF [NOT] EXISTS on both forms reuses the 4c no-op-with-note skip
  (journalled, not snapshotted) via CreateIndexOutcome / DropIndexOutcome.
- Unnamed CREATE INDEX auto-named (ADR-0025 convention); the [UNIQUE]
  prefix is a concrete-keyword Choice and the optional name an on-led-first
  selector (the drop-index selector precedent) — trap-safe.
- create/drop each gain a second advanced node; the existing all-candidates
  dispatch handles it (locked by parse tests).
- Unique indexes marked [unique] in the structure view and items panel.
- do_add_index refuses internal __rdbms_* tables as "no such table",
  closing a latent exposure on both the simple `add index` and the new
  SQL CREATE INDEX surfaces (ADR-0025 Amendment 1).

Docs: ADR-0035 status + §13 4d + 4i; ADR-0025 Amendment 1; ADR README;
requirements.md Q1/C3. Plan: docs/plans/20260525-adr-0035-sql-ddl-4d.md.

Tests: 1834 passing / 0 failing / 0 skipped / 1 ignored; clippy clean.
2026-05-25 18:54:32 +00:00
claude@clouddev1 e52e90c45b 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.
2026-05-25 16:31:41 +00:00
claude@clouddev1 76d60591bf feat: ADR-0035 4b — foreign keys in CREATE TABLE
Add foreign keys to advanced-mode SQL CREATE TABLE — the SQL spelling of
an ADR-0013 named relationship, created in the same transaction as the
table (one undo step).

- Grammar: inline `<col> … REFERENCES <parent>[(<col>)] [ON DELETE/UPDATE
  …]` (a new column constraint) and table-level `[CONSTRAINT <name>]
  FOREIGN KEY (<col>) REFERENCES …` (two new element branches — both
  start on a concrete keyword, never a leading Optional, which would
  abort the element Choice). Referential clauses reuse
  shared::REFERENTIAL_CLAUSES.
- Builder: greedy FK-clause consumption (parens consumed internally so
  they don't perturb the 4a.3 element-boundary depth tracker); inline FK
  auto-named, table FK takes an optional CONSTRAINT name.
- Worker: do_create_table resolves + validates each FK before building
  the DDL (self-ref validates against the in-statement columns/PK; bare
  REFERENCES resolves to the parent's single-column PK, composite ->
  error; PK-target + Type::fk_target_type compatibility), emits the
  FOREIGN KEY clause identically to schema_to_ddl, and writes the
  relationship metadata in the create transaction.
- Reuse: name/uniqueness/metadata-insert/type-compat factored into shared
  helpers; do_add_relationship refactored to use them.
- FKs round-trip via the existing relationship plumbing (no new
  persistence structures); describe surfaces the relationship.

Self-references and bare `REFERENCES <parent>` supported (user-confirmed).
Self-ref pre-submit indicator wrinkle deferred to 4i (tracked in ADR §13,
a code comment, and the plan).

DA/runda round added cross-cutting probes (FK survives the add-column
rebuild + a later rebuild_from_text; referential actions survive rebuild;
drop-child clears the relationship; drop-parent refused; bare self-ref
resolves to own PK) — all green, no fixes needed.

27 new tests (grammar/builder + Tier-3). Docs: ADR-0035 Status/§13,
README, requirements.md Q1.

Tests: 1795 passing, 0 failing, 1 ignored. Clippy clean.
2026-05-25 15:35:48 +00:00
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