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.
This commit is contained in:
@@ -15,6 +15,33 @@ use crate::dsl::action::ReferentialAction;
|
||||
use crate::dsl::types::Type;
|
||||
use crate::dsl::value::Value;
|
||||
|
||||
/// A foreign key declared in an advanced-mode SQL `CREATE TABLE`.
|
||||
///
|
||||
/// The SQL spelling of an ADR-0013 named relationship (ADR-0035 §5,
|
||||
/// sub-phase 4b). Produced by both the inline
|
||||
/// `<col> … REFERENCES <parent>[(<pcol>)] …` form (always auto-named)
|
||||
/// and the table-level `[CONSTRAINT <name>] FOREIGN KEY (<ccol>)
|
||||
/// REFERENCES <parent>[(<pcol>)] …` form. The relationship is created
|
||||
/// together with the table, in one transaction = one undo step.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SqlForeignKey {
|
||||
/// `CONSTRAINT <name>` on a table-level FK; `None` for an inline
|
||||
/// FK or an unnamed table FK (auto-named at execution per
|
||||
/// ADR-0013).
|
||||
pub name: Option<String>,
|
||||
/// The column in the table being created that holds the FK.
|
||||
pub child_column: String,
|
||||
/// The referenced (parent) table — may be the table being created
|
||||
/// (a self-referencing FK).
|
||||
pub parent_table: String,
|
||||
/// The referenced parent column. `None` for the bare
|
||||
/// `REFERENCES <parent>` form, resolved at execution to the
|
||||
/// parent's single-column primary key (ADR-0035 §4b, user-confirmed).
|
||||
pub parent_column: Option<String>,
|
||||
pub on_delete: ReferentialAction,
|
||||
pub on_update: ReferentialAction,
|
||||
}
|
||||
|
||||
/// A column at table-creation time: a name, a user-facing
|
||||
/// type, and its column-level constraints (ADR-0029).
|
||||
///
|
||||
@@ -153,6 +180,11 @@ pub enum Command {
|
||||
/// CHECK has no column to hang on and the engine reports no
|
||||
/// CHECKs, so it round-trips via a dedicated metadata table.
|
||||
check_constraints: Vec<String>,
|
||||
/// Foreign keys (ADR-0035 §5, sub-phase 4b) — inline
|
||||
/// `REFERENCES` and table-level `FOREIGN KEY`, each created as
|
||||
/// an ADR-0013 named relationship in the same transaction as
|
||||
/// the table (one undo step).
|
||||
foreign_keys: Vec<SqlForeignKey>,
|
||||
if_not_exists: bool,
|
||||
},
|
||||
/// Add a column to an existing table. The column carries
|
||||
|
||||
Reference in New Issue
Block a user