style: format the whole tree with cargo fmt (stock defaults, #35)
One-time, mechanical reformat — no functional changes. The tree was not rustfmt-clean (~1800 hunks across ~100 files); this brings it to stock `cargo fmt` defaults so a `cargo fmt --check` CI gate can follow. Behaviour-preserving: 2509 pass / 0 fail / 1 ignored (unchanged baseline), clippy clean. A .git-blame-ignore-revs entry follows so `git blame` skips this commit.
This commit is contained in:
+79
-76
@@ -201,11 +201,7 @@ impl TranslateContext {
|
||||
/// Combine schema-resolved facts with operation and
|
||||
/// verbosity to build the full translator input.
|
||||
#[must_use]
|
||||
pub fn from_facts(
|
||||
operation: Operation,
|
||||
verbosity: Verbosity,
|
||||
facts: FailureContext,
|
||||
) -> Self {
|
||||
pub fn from_facts(operation: Operation, verbosity: Verbosity, facts: FailureContext) -> Self {
|
||||
Self {
|
||||
operation: Some(operation),
|
||||
table: facts.table,
|
||||
@@ -234,15 +230,15 @@ pub fn translate(error: &DbError, ctx: &TranslateContext) -> FriendlyError {
|
||||
// refusal sites). Catalog entries exist for the typed
|
||||
// invalid-value cases but the migration sweep
|
||||
// (ADR-0019 §9) is what wires them. For now, passthrough.
|
||||
DbError::Unsupported(message) | DbError::InvalidValue(message) => {
|
||||
passthrough(message)
|
||||
}
|
||||
DbError::Unsupported(message) | DbError::InvalidValue(message) => passthrough(message),
|
||||
DbError::PersistenceFatal { message, .. }
|
||||
| DbError::RebuildRowFailed { detail: message, .. }
|
||||
| DbError::RebuildRowFailed {
|
||||
detail: message, ..
|
||||
}
|
||||
| DbError::Io(message) => passthrough(message),
|
||||
DbError::WorkerGone => passthrough(
|
||||
"the database worker is no longer available — the application must restart",
|
||||
),
|
||||
DbError::WorkerGone => {
|
||||
passthrough("the database worker is no longer available — the application must restart")
|
||||
}
|
||||
};
|
||||
// Attach the row pinpoint when the runtime resolved one.
|
||||
// The translator never builds the table itself — it only
|
||||
@@ -320,11 +316,7 @@ const fn fk_hint_class(ctx: &TranslateContext) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_sqlite(
|
||||
message: &str,
|
||||
kind: SqliteErrorKind,
|
||||
ctx: &TranslateContext,
|
||||
) -> FriendlyError {
|
||||
fn translate_sqlite(message: &str, kind: SqliteErrorKind, ctx: &TranslateContext) -> FriendlyError {
|
||||
// `change column ... --dont-convert` lets the engine
|
||||
// accept or refuse each cell. Whatever the engine returns
|
||||
// (constraint, datatype mismatch, …) means "the new type
|
||||
@@ -392,8 +384,8 @@ fn translate_constraint(message: &str, ctx: &TranslateContext) -> FriendlyError
|
||||
// ---- UNIQUE -----------------------------------------------------
|
||||
|
||||
fn translate_unique(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
let (table, column) = parse_qualified_target(message)
|
||||
.unwrap_or_else(|| (ctx_table(ctx), ctx_column(ctx)));
|
||||
let (table, column) =
|
||||
parse_qualified_target(message).unwrap_or_else(|| (ctx_table(ctx), ctx_column(ctx)));
|
||||
let value = ctx_value(ctx);
|
||||
match ctx.operation {
|
||||
Some(Operation::Update) => fe(
|
||||
@@ -405,11 +397,7 @@ fn translate_unique(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
),
|
||||
verbose_hint(
|
||||
ctx,
|
||||
t!(
|
||||
"error.unique.update.hint",
|
||||
table = table,
|
||||
column = column
|
||||
),
|
||||
t!("error.unique.update.hint", table = table, column = column),
|
||||
),
|
||||
),
|
||||
// Default to the INSERT variant — it's the most common
|
||||
@@ -425,11 +413,7 @@ fn translate_unique(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
),
|
||||
verbose_hint(
|
||||
ctx,
|
||||
t!(
|
||||
"error.unique.insert.hint",
|
||||
table = table,
|
||||
column = column
|
||||
),
|
||||
t!("error.unique.insert.hint", table = table, column = column),
|
||||
),
|
||||
),
|
||||
}
|
||||
@@ -542,8 +526,8 @@ fn fk_parent_side_update(ctx: &TranslateContext) -> FriendlyError {
|
||||
// ---- NOT NULL --------------------------------------------------
|
||||
|
||||
fn translate_not_null(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
let (table, column) = parse_qualified_target(message)
|
||||
.unwrap_or_else(|| (ctx_table(ctx), ctx_column(ctx)));
|
||||
let (table, column) =
|
||||
parse_qualified_target(message).unwrap_or_else(|| (ctx_table(ctx), ctx_column(ctx)));
|
||||
match ctx.operation {
|
||||
Some(Operation::Update) => fe(
|
||||
t!(
|
||||
@@ -576,9 +560,17 @@ fn translate_check(_message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
let column = ctx_column(ctx);
|
||||
let is_update = matches!(ctx.operation, Some(Operation::Update));
|
||||
let headline = if is_update {
|
||||
t!("error.check.update.headline", table = table, column = column)
|
||||
t!(
|
||||
"error.check.update.headline",
|
||||
table = table,
|
||||
column = column
|
||||
)
|
||||
} else {
|
||||
t!("error.check.insert.headline", table = table, column = column)
|
||||
t!(
|
||||
"error.check.insert.headline",
|
||||
table = table,
|
||||
column = column
|
||||
)
|
||||
};
|
||||
let hint = ctx.check_rule.as_ref().map_or_else(
|
||||
|| {
|
||||
@@ -613,8 +605,7 @@ fn translate_check(_message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
// ---- not_found / already_exists --------------------------------
|
||||
|
||||
fn translate_not_found_table(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
let name = parse_after_colon(message)
|
||||
.map_or_else(|| ctx_table(ctx), str::to_string);
|
||||
let name = parse_after_colon(message).map_or_else(|| ctx_table(ctx), str::to_string);
|
||||
headline_only(t!("error.not_found.table.headline", name = name))
|
||||
}
|
||||
|
||||
@@ -656,17 +647,11 @@ fn translate_already_exists(message: &str, ctx: &TranslateContext) -> FriendlyEr
|
||||
column = column
|
||||
));
|
||||
}
|
||||
return headline_only(t!(
|
||||
"error.already_exists.table.headline",
|
||||
name = name
|
||||
));
|
||||
return headline_only(t!("error.already_exists.table.headline", name = name));
|
||||
}
|
||||
// No backticks — engine-style "table T already exists".
|
||||
if let Some(name) = parse_after_word(message, "table") {
|
||||
return headline_only(t!(
|
||||
"error.already_exists.table.headline",
|
||||
name = name
|
||||
));
|
||||
return headline_only(t!("error.already_exists.table.headline", name = name));
|
||||
}
|
||||
if let Some(name) = parse_after_word(message, "relationship") {
|
||||
return headline_only(t!(
|
||||
@@ -696,36 +681,25 @@ fn translate_generic(message: &str, ctx: &TranslateContext) -> FriendlyError {
|
||||
if lower.contains("misuse of aggregate") {
|
||||
return headline_only(t!("engine.aggregate_misuse", name = "?"));
|
||||
}
|
||||
if lower.contains("group by")
|
||||
|| lower.contains("must appear in")
|
||||
{
|
||||
if lower.contains("group by") || lower.contains("must appear in") {
|
||||
return headline_only(t!("engine.group_by_required"));
|
||||
}
|
||||
if (lower.contains("union")
|
||||
|| lower.contains("intersect")
|
||||
|| lower.contains("except"))
|
||||
if (lower.contains("union") || lower.contains("intersect") || lower.contains("except"))
|
||||
&& lower.contains("result columns")
|
||||
{
|
||||
// Last-resort safety net — the pre-flight pass in 2d.1
|
||||
// catches this in most cases; if the engine surfaces it
|
||||
// anyway, route it through the engine-neutral key.
|
||||
return headline_only(t!(
|
||||
"engine.compound_arity_mismatch",
|
||||
op = "set operator"
|
||||
));
|
||||
return headline_only(t!("engine.compound_arity_mismatch", op = "set operator"));
|
||||
}
|
||||
if lower.contains("scalar subquery") || lower.contains("more than one row") {
|
||||
return headline_only(t!("engine.scalar_subquery_too_many_rows"));
|
||||
}
|
||||
if lower.contains("recursive")
|
||||
&& (lower.contains("cte") || lower.contains("union"))
|
||||
{
|
||||
if lower.contains("recursive") && (lower.contains("cte") || lower.contains("union")) {
|
||||
return headline_only(t!("engine.recursive_cte_malformed"));
|
||||
}
|
||||
|
||||
let operation = ctx
|
||||
.operation
|
||||
.map_or("operation", Operation::keyword);
|
||||
let operation = ctx.operation.map_or("operation", Operation::keyword);
|
||||
// F2 (ADR-0035 Amendment 1): when no table is in context, use the
|
||||
// table-less hint so a contextless `friendly_message()` (replay, undo,
|
||||
// rebuild, export) never renders a literal `{table}` placeholder.
|
||||
@@ -789,23 +763,33 @@ fn ctx_table(ctx: &TranslateContext) -> String {
|
||||
}
|
||||
|
||||
fn ctx_column(ctx: &TranslateContext) -> String {
|
||||
ctx.column.clone().unwrap_or_else(|| "the column".to_string())
|
||||
ctx.column
|
||||
.clone()
|
||||
.unwrap_or_else(|| "the column".to_string())
|
||||
}
|
||||
|
||||
fn ctx_value(ctx: &TranslateContext) -> String {
|
||||
ctx.value.clone().unwrap_or_else(|| "that value".to_string())
|
||||
ctx.value
|
||||
.clone()
|
||||
.unwrap_or_else(|| "that value".to_string())
|
||||
}
|
||||
|
||||
fn ctx_parent_table(ctx: &TranslateContext) -> String {
|
||||
ctx.parent_table.clone().unwrap_or_else(|| "the referenced table".to_string())
|
||||
ctx.parent_table
|
||||
.clone()
|
||||
.unwrap_or_else(|| "the referenced table".to_string())
|
||||
}
|
||||
|
||||
fn ctx_parent_column(ctx: &TranslateContext) -> String {
|
||||
ctx.parent_column.clone().unwrap_or_else(|| "the referenced column".to_string())
|
||||
ctx.parent_column
|
||||
.clone()
|
||||
.unwrap_or_else(|| "the referenced column".to_string())
|
||||
}
|
||||
|
||||
fn ctx_child_table(ctx: &TranslateContext) -> String {
|
||||
ctx.child_table.clone().unwrap_or_else(|| "the referencing table".to_string())
|
||||
ctx.child_table
|
||||
.clone()
|
||||
.unwrap_or_else(|| "the referencing table".to_string())
|
||||
}
|
||||
|
||||
/// Extract `T.col` from a message like
|
||||
@@ -847,11 +831,7 @@ fn parse_after_word<'a>(message: &'a str, keyword: &str) -> Option<&'a str> {
|
||||
let rest = message[pos..].trim_start();
|
||||
let token_end = rest.find(|c: char| c.is_whitespace()).unwrap_or(rest.len());
|
||||
let token = rest[..token_end].trim_matches(|c: char| c == '`' || c == '\'');
|
||||
if token.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(token)
|
||||
}
|
||||
if token.is_empty() { None } else { Some(token) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -876,15 +856,24 @@ mod tests {
|
||||
};
|
||||
let d = TranslateContext::default;
|
||||
assert_eq!(
|
||||
error_hint_class(&sqlite(SqliteErrorKind::NoSuchTable, "no such table: X"), &d()),
|
||||
error_hint_class(
|
||||
&sqlite(SqliteErrorKind::NoSuchTable, "no such table: X"),
|
||||
&d()
|
||||
),
|
||||
Some("not_found")
|
||||
);
|
||||
assert_eq!(
|
||||
error_hint_class(&sqlite(SqliteErrorKind::NoSuchColumn, "no such column: X"), &d()),
|
||||
error_hint_class(
|
||||
&sqlite(SqliteErrorKind::NoSuchColumn, "no such column: X"),
|
||||
&d()
|
||||
),
|
||||
Some("not_found")
|
||||
);
|
||||
assert_eq!(
|
||||
error_hint_class(&sqlite(SqliteErrorKind::AlreadyExists, "already exists"), &d()),
|
||||
error_hint_class(
|
||||
&sqlite(SqliteErrorKind::AlreadyExists, "already exists"),
|
||||
&d()
|
||||
),
|
||||
Some("already_exists")
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -933,13 +922,19 @@ mod tests {
|
||||
parent_table: Some("Parent".to_string()),
|
||||
..TranslateContext::default()
|
||||
};
|
||||
assert_eq!(error_hint_class(&fk(), &ctx), Some("foreign_key.child_side"));
|
||||
assert_eq!(
|
||||
error_hint_class(&fk(), &ctx),
|
||||
Some("foreign_key.child_side")
|
||||
);
|
||||
// child_table populated → parent-side.
|
||||
let ctx = TranslateContext {
|
||||
child_table: Some("Child".to_string()),
|
||||
..TranslateContext::default()
|
||||
};
|
||||
assert_eq!(error_hint_class(&fk(), &ctx), Some("foreign_key.parent_side"));
|
||||
assert_eq!(
|
||||
error_hint_class(&fk(), &ctx),
|
||||
Some("foreign_key.parent_side")
|
||||
);
|
||||
// No enrichment: operation is the tiebreaker.
|
||||
assert_eq!(
|
||||
error_hint_class(&fk(), &ctx_with(Operation::Delete)),
|
||||
@@ -1049,14 +1044,22 @@ mod tests {
|
||||
ctx.parent_column = Some("country, code".to_string());
|
||||
ctx.value = Some("7, 8".to_string());
|
||||
let f = translate(&err, &ctx);
|
||||
assert!(f.headline.contains("no parent row"), "child-side: {}", f.headline);
|
||||
assert!(
|
||||
f.headline.contains("no parent row"),
|
||||
"child-side: {}",
|
||||
f.headline
|
||||
);
|
||||
assert!(f.headline.contains("Region"));
|
||||
assert!(
|
||||
f.headline.contains("country, code"),
|
||||
"both parent columns must appear: {}",
|
||||
f.headline
|
||||
);
|
||||
assert!(f.headline.contains("`7, 8`"), "joined value: {}", f.headline);
|
||||
assert!(
|
||||
f.headline.contains("`7, 8`"),
|
||||
"joined value: {}",
|
||||
f.headline
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user