feat: ADR-0035 4g — ALTER TABLE add/drop constraint + add FK
ALTER TABLE <T> ADD [CONSTRAINT <name>] (CHECK | UNIQUE | FOREIGN KEY)
and DROP CONSTRAINT <name>. ADD = table-CHECK + composite UNIQUE + FK
(ADD PRIMARY KEY and a named UNIQUE refused — composite UNIQUE is
anonymous in our model). Each ADD reuses a low-level path with a dry-run
guard (table-CHECK/UNIQUE rebuild; FK -> add_relationship, bare
REFERENCES -> parent single PK). DROP CONSTRAINT resolves the name to a
named table-CHECK then a child-side FK, else refuses. One undo step each.
Named table-CHECKs round-trip: a nullable `name` column on
__rdbms_playground_table_checks (rebuild-only arrival; a named add on a
pre-4g project is refused with a "rebuild first" hint) plus a project.yaml
check_constraints {expr, name} extension (bare-string form still reads).
The internal-__rdbms_* guard was folded into do_add_constraint /
do_add_relationship, completing that guard class.
Grammar: the action Choice keeps one branch per verb (add/drop/rename/
alter) with an inner Choice fanning out on the distinct second keyword,
since the walker's Choice does not backtrack between same-led branches.
Tests: 7 Tier-1 parse + 2 yaml round-trip + 1 internal-guard + 9 Tier-3
e2e. Help/usage refreshed; ADR-0035 §13 4g + README + requirements.md in
lockstep.
This commit is contained in:
+31
-6
@@ -147,12 +147,37 @@ pub struct TableSchema {
|
||||
/// optional on read.
|
||||
pub unique_constraints: Vec<Vec<String>>,
|
||||
/// Table-level `CHECK (<expr>)` constraints, in declaration
|
||||
/// order, as raw SQL text (ADR-0035 §4a.3). The engine reports
|
||||
/// no CHECK constraints, so these are the source of truth (held
|
||||
/// in `__rdbms_playground_table_checks`) and echoed verbatim
|
||||
/// into the rebuilt DDL. Empty for project files written before
|
||||
/// table-level CHECK existed — the YAML field is optional on read.
|
||||
pub check_constraints: Vec<String>,
|
||||
/// order, as raw SQL text with an optional name (ADR-0035 §4a.3,
|
||||
/// named in §4g). The engine reports no CHECK constraints, so these
|
||||
/// are the source of truth (held in
|
||||
/// `__rdbms_playground_table_checks`) and echoed verbatim into the
|
||||
/// rebuilt DDL. Empty for project files written before table-level
|
||||
/// CHECK existed — the YAML field is optional on read.
|
||||
pub check_constraints: Vec<TableCheck>,
|
||||
}
|
||||
|
||||
/// A table-level `CHECK` constraint with an optional name (ADR-0035 §4g).
|
||||
///
|
||||
/// The name is `Some` only for a `CONSTRAINT <name> CHECK (…)` added via
|
||||
/// `ALTER TABLE` (the source of `DROP CONSTRAINT <name>`); a `CREATE
|
||||
/// TABLE` table-CHECK and any pre-4g project file are unnamed (`None`).
|
||||
/// The YAML carries a bare string for the unnamed form (back-compatible)
|
||||
/// and an `{expr, name}` mapping for the named form.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TableCheck {
|
||||
pub name: Option<String>,
|
||||
pub expr: String,
|
||||
}
|
||||
|
||||
impl TableCheck {
|
||||
/// An unnamed table-CHECK (the `CREATE TABLE` / pre-4g form).
|
||||
#[must_use]
|
||||
pub fn unnamed(expr: impl Into<String>) -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
expr: expr.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
||||
Reference in New Issue
Block a user