refactor: relationship model to column lists for compound FK (ADR-0043)
Move the FK column fields String->Vec<String> through all six layers (AddRelationship/SqlForeignKey AST, RelationshipSchema, metadata, project.yaml, ReadForeignKey, RelationshipEnd). Metadata stores comma-joined lists in the existing TEXT cells; project.yaml endpoints now columns: [a, b] (house style). Executor logic is multi-column ready: resolve_fk_parent_columns (full-PK F-A + auto-expand F-D), per-pair type-compat, schema_to_ddl multi-column emission, pragma FK read grouped by id, auto-name + --create-fk per-column, multi-column teaching echo. Single-column behaviour preserved (one-element vecs); all 2181 tests green. The grammar to parse multi-column input lands next.
This commit is contained in:
+36
-11
@@ -29,15 +29,20 @@ pub struct SqlForeignKey {
|
||||
/// 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 column(s) in the table being created that hold the FK.
|
||||
/// One element for a single-column FK; ordered list for a
|
||||
/// compound FK (ADR-0043). Positionally paired with
|
||||
/// `parent_columns`.
|
||||
pub child_columns: Vec<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>,
|
||||
/// The referenced parent column(s), positionally paired with
|
||||
/// `child_columns`. `None` for the bare `REFERENCES <parent>`
|
||||
/// form, resolved at execution to the parent's primary key —
|
||||
/// the single-column PK, or (ADR-0043 F-D) the full compound PK
|
||||
/// when the child arity matches.
|
||||
pub parent_columns: Option<Vec<String>>,
|
||||
pub on_delete: ReferentialAction,
|
||||
pub on_update: ReferentialAction,
|
||||
}
|
||||
@@ -253,9 +258,14 @@ pub enum Command {
|
||||
AddRelationship {
|
||||
name: Option<String>,
|
||||
parent_table: String,
|
||||
parent_column: String,
|
||||
/// Parent (referenced) PK column(s); one element for a
|
||||
/// single-column FK, ordered list for a compound FK
|
||||
/// (ADR-0043). Positionally paired with `child_columns`.
|
||||
parent_columns: Vec<String>,
|
||||
child_table: String,
|
||||
child_column: String,
|
||||
/// Child (referencing) column(s), positionally paired with
|
||||
/// `parent_columns`; equal, non-zero length.
|
||||
child_columns: Vec<String>,
|
||||
on_delete: ReferentialAction,
|
||||
on_update: ReferentialAction,
|
||||
create_fk: bool,
|
||||
@@ -1032,11 +1042,26 @@ impl Command {
|
||||
match self {
|
||||
Self::AddRelationship {
|
||||
parent_table,
|
||||
parent_column,
|
||||
parent_columns,
|
||||
child_table,
|
||||
child_column,
|
||||
child_columns,
|
||||
..
|
||||
} => format!("from {parent_table}.{parent_column} to {child_table}.{child_column}"),
|
||||
} => {
|
||||
// `from P.col to C.col` (single) or `from P.(a, b) to
|
||||
// C.(x, y)` (compound — ADR-0043), mirroring the DSL.
|
||||
let fmt = |cols: &[String]| {
|
||||
if cols.len() == 1 {
|
||||
cols[0].clone()
|
||||
} else {
|
||||
format!("({})", cols.join(", "))
|
||||
}
|
||||
};
|
||||
format!(
|
||||
"from {parent_table}.{} to {child_table}.{}",
|
||||
fmt(parent_columns),
|
||||
fmt(child_columns),
|
||||
)
|
||||
}
|
||||
Self::DropRelationship { selector } => match selector {
|
||||
RelationshipSelector::Named { name } => name.clone(),
|
||||
RelationshipSelector::Endpoints {
|
||||
|
||||
Reference in New Issue
Block a user