fix: ADR-0036 — name the offending value for natural-order SQL INSERTs

A no-column-list (natural-order / Form B) SQL INSERT that hit a UNIQUE/
CHECK violation degraded to the neutral "that value" because
user_value_for_column only resolved the offending value for the explicit-
column-list form. Extend user_value_for_column_with_schema to map each
VALUES position to the schema's columns in declaration order (ALL columns
— advanced-mode Form B auto-fills nothing, so every column has a value),
single-row only (multi-row stays ambiguous). Closes the Phase 1 carryover
gap so the error names the real value either way.

Tests: 1948 passing (+1), 0 failed, 0 skipped, 1 ignored; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-27 10:54:29 +00:00
parent 8906661f69
commit d98717156e
2 changed files with 99 additions and 3 deletions
+71
View File
@@ -146,6 +146,77 @@ fn enrich_unique_insert_natural_order_short_form_resolves_value_via_schema() {
});
}
#[test]
fn enrich_unique_sql_insert_natural_order_resolves_value_via_schema() {
// ADR-0036 Phase 1 follow-up: a no-column-list (natural-order) SQL
// INSERT also names the offending value in a constraint error. The
// schema maps each VALUES position to its column, in declaration
// order — ALL columns (advanced-mode Form B auto-fills nothing, so
// the user supplies a value for every column).
let db = db();
rt().block_on(async {
db.create_table(
"Customers".to_string(),
vec![
ColumnSpec::new("id".to_string(), Type::Int),
ColumnSpec::new("name".to_string(), Type::Text),
],
vec!["id".to_string()],
None,
)
.await
.unwrap();
db.insert(
"Customers".to_string(),
None,
vec![Value::Number("5".to_string()), Value::Text("Alice".to_string())],
None,
)
.await
.unwrap();
// Natural-order SQL insert (no column list) collides on id=5.
let input = "insert into Customers values (5, 'Bob')";
let cmd = parse_command(input).expect("parses as advanced-mode SQL insert");
let Command::SqlInsert {
sql,
target_table,
listed_columns,
row_source,
returning,
literal_rows,
} = cmd.clone()
else {
panic!("expected Command::SqlInsert, got {cmd:?}");
};
assert!(listed_columns.is_empty(), "natural-order form has no column list");
let err = db
.run_sql_insert_with_literals(
sql,
None,
target_table,
listed_columns,
row_source,
returning,
literal_rows,
)
.await
.unwrap_err();
assert!(matches!(
err,
DbError::Sqlite { kind: SqliteErrorKind::UniqueViolation, .. }
));
let facts = enrich_dsl_failure(&db, &cmd, &err).await;
assert_eq!(facts.column.as_deref(), Some("id"));
assert_eq!(
facts.value.as_deref(),
Some("5"),
"the offending value is named even without an explicit column list",
);
});
}
#[test]
fn enrich_unique_update_resolves_value_from_assignments() {
let db = db();