constraints: CHECK-violation friendly error + typing-surface matrix (ADR-0029 §10)
Completes ADR-0029's implementation: the friendly-error layer now names the rule a CHECK violation broke, and the typing-surface matrix covers the whole constraint grammar. CHECK-violation friendly error (ADR-0029 §10): - enrich_dsl_failure gains a CHECK branch — it reads the column from the engine's `CHECK constraint failed: <column>` message, then resolves the table, the offending value, and the column's compiled CHECK expression. - FailureContext / TranslateContext carry the resolved check_rule; translate_check renders "the value <v> breaks the rule `<rule>`" when it is known, falling back to the plain hint otherwise. Typing-surface matrix: a new `constraints` submodule, 14 cells covering the create-table / add-column constraint suffix and the add-constraint / drop-constraint commands (174 → 188). 16 tests added (1 translate unit, 1 enrichment integration, 14 matrix cells).
This commit is contained in:
@@ -1248,6 +1248,8 @@ pub async fn enrich_dsl_failure(
|
||||
enrich_unique_violation(database, command, message).await
|
||||
} else if lower.contains("not null constraint failed") {
|
||||
enrich_not_null_violation(command, message)
|
||||
} else if lower.contains("check constraint failed") {
|
||||
enrich_check_violation(database, command, message).await
|
||||
} else if lower.contains("foreign key constraint failed") {
|
||||
enrich_fk_violation(database, command).await
|
||||
} else {
|
||||
@@ -1255,6 +1257,41 @@ pub async fn enrich_dsl_failure(
|
||||
}
|
||||
}
|
||||
|
||||
/// Enrich a `CHECK` violation (ADR-0029 §10). The engine
|
||||
/// reports `CHECK constraint failed: <column>` — the column the
|
||||
/// constraint sits on, unqualified. We pair that with the
|
||||
/// command's table, the value the user supplied for the column,
|
||||
/// and the column's compiled `CHECK` expression so the friendly
|
||||
/// error can name the rule that was broken.
|
||||
async fn enrich_check_violation(
|
||||
database: &Database,
|
||||
command: &Command,
|
||||
message: &str,
|
||||
) -> crate::friendly::FailureContext {
|
||||
let mut facts = crate::friendly::FailureContext::default();
|
||||
let Some((_, after)) = message.split_once(':') else {
|
||||
return facts;
|
||||
};
|
||||
let column = after.trim();
|
||||
let table = command.target_table();
|
||||
if column.is_empty() || table.is_empty() {
|
||||
return facts;
|
||||
}
|
||||
facts.column = Some(column.to_string());
|
||||
facts.table = Some(table.to_string());
|
||||
// The value the user supplied for the constrained column.
|
||||
facts.value = user_value_for_column_with_schema(database, command, table, column)
|
||||
.await
|
||||
.map(|v| v.to_string());
|
||||
// The rule itself — the column's compiled CHECK expression.
|
||||
if let Ok(desc) = database.describe_table(table.to_string(), None).await
|
||||
&& let Some(col) = desc.columns.iter().find(|c| c.name == column)
|
||||
{
|
||||
facts.check_rule.clone_from(&col.check);
|
||||
}
|
||||
facts
|
||||
}
|
||||
|
||||
async fn enrich_unique_violation(
|
||||
database: &Database,
|
||||
command: &Command,
|
||||
|
||||
Reference in New Issue
Block a user