fix(fk): compound-FK violation message names every column pair
ADR-0043 residual: a compound-FK violation's friendly error named only the
first child->parent column pair (the ADR-0019 facts model is single-column).
enrich_fk_violation now gathers all pairs of the matched relationship and
carries them comma-joined in the existing single-column facts slots, so the
headline reads e.g. "no parent row in `Region` has `country, code` = `7, 8`."
instead of naming just `country`.
Single-column behaviour is unchanged (a one-element join is the element
itself). No facts-model or catalog change -- the joined strings flow through
the existing `{parent_column}` / `{value}` placeholders.
Tests: enrichment facts (compound names every pair, single-column
regression) + translate rendering (headline names both columns). 2211 pass
/ 0 fail / 1 ignored. Clippy clean.
This commit is contained in:
@@ -464,6 +464,81 @@ fn enrich_fk_insert_resolves_parent_table_column_and_value() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enrich_fk_insert_compound_names_every_column_pair() {
|
||||
// ADR-0043 residual: a compound-FK violation must name *every*
|
||||
// child->parent column pair, not just the first. The single-column
|
||||
// facts slots carry the comma-joined lists.
|
||||
let db = db();
|
||||
rt().block_on(async {
|
||||
db.create_table(
|
||||
"Region".to_string(),
|
||||
vec![
|
||||
ColumnSpec::new("country".to_string(), Type::Int),
|
||||
ColumnSpec::new("code".to_string(), Type::Int),
|
||||
],
|
||||
vec!["country".to_string(), "code".to_string()],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
db.create_table(
|
||||
"City".to_string(),
|
||||
vec![
|
||||
ColumnSpec::new("country".to_string(), Type::Int),
|
||||
ColumnSpec::new("region_code".to_string(), Type::Int),
|
||||
],
|
||||
vec![],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
db.add_relationship(
|
||||
None,
|
||||
"Region".to_string(),
|
||||
vec!["country".to_string(), "code".to_string()],
|
||||
"City".to_string(),
|
||||
vec!["country".to_string(), "region_code".to_string()],
|
||||
ReferentialAction::NoAction,
|
||||
ReferentialAction::NoAction,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Insert a City whose (country, region_code) has no parent Region.
|
||||
let cmd = Command::Insert {
|
||||
table: "City".to_string(),
|
||||
columns: Some(vec!["country".to_string(), "region_code".to_string()]),
|
||||
values: vec![
|
||||
Value::Number("7".to_string()),
|
||||
Value::Number("8".to_string()),
|
||||
],
|
||||
};
|
||||
let err = db
|
||||
.insert(
|
||||
"City".to_string(),
|
||||
Some(vec!["country".to_string(), "region_code".to_string()]),
|
||||
vec![
|
||||
Value::Number("7".to_string()),
|
||||
Value::Number("8".to_string()),
|
||||
],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
let facts = enrich_dsl_failure(&db, &cmd, &err).await;
|
||||
assert_eq!(facts.table.as_deref(), Some("City"));
|
||||
assert_eq!(facts.parent_table.as_deref(), Some("Region"));
|
||||
// Both pairs named, not just the first.
|
||||
assert_eq!(facts.column.as_deref(), Some("country, region_code"));
|
||||
assert_eq!(facts.parent_column.as_deref(), Some("country, code"));
|
||||
assert_eq!(facts.value.as_deref(), Some("7, 8"));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enrich_fk_insert_natural_order_multi_value_resolves_via_schema() {
|
||||
// Regression: `insert into Orders values (4, 11.99)` —
|
||||
|
||||
Reference in New Issue
Block a user