use std::fmt;
#[derive(Debug)]
pub enum EngineError {
User(String),
Internal(String),
Io(String),
Sql(String),
NotFound(String),
Other(String),
}
impl fmt::Display for EngineError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EngineError::User(s) => write!(f, "user error: {s}"),
EngineError::Internal(s) => write!(f, "internal error: {s}"),
EngineError::Io(s) => write!(f, "io error: {s}"),
EngineError::Sql(s) => write!(f, "sql error: {s}"),
EngineError::NotFound(s) => write!(f, "not found: {s}"),
EngineError::Other(s) => write!(f, "{s}"),
}
}
}
impl std::error::Error for EngineError {}
impl EngineError {
pub fn user_message(&self) -> &str {
match self {
EngineError::User(s)
| EngineError::Internal(s)
| EngineError::Io(s)
| EngineError::Sql(s)
| EngineError::NotFound(s)
| EngineError::Other(s) => s.as_str(),
}
}
}
pub fn normalize_unresolved_column_message(msg: &str) -> String {
let lower = msg.to_lowercase();
if lower.contains("cannot be resolved") {
return msg.to_string();
}
if lower.contains("cannot resolve") {
return msg.replace("cannot resolve", "cannot be resolved");
}
if msg.contains("unable to find column")
|| (msg.contains("not found") && lower.contains("column"))
|| msg.contains("valid columns")
{
return format!("unresolved_column: cannot be resolved: {msg}");
}
msg.to_string()
}
impl From<serde_json::Error> for EngineError {
fn from(e: serde_json::Error) -> Self {
EngineError::Internal(e.to_string())
}
}
impl From<std::io::Error> for EngineError {
fn from(e: std::io::Error) -> Self {
EngineError::Io(e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn engine_error_display() {
assert_eq!(
EngineError::User("bad input".into()).to_string(),
"user error: bad input"
);
assert_eq!(
EngineError::Internal("panic".into()).to_string(),
"internal error: panic"
);
assert_eq!(
EngineError::Io("file not found".into()).to_string(),
"io error: file not found"
);
assert_eq!(
EngineError::Sql("parse error".into()).to_string(),
"sql error: parse error"
);
assert_eq!(
EngineError::NotFound("column x".into()).to_string(),
"not found: column x"
);
assert_eq!(EngineError::Other("misc".into()).to_string(), "misc");
}
#[test]
fn engine_error_from_io() {
let e = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
let err: EngineError = e.into();
assert!(err.to_string().contains("file missing"));
assert!(err.to_string().contains("io error"));
}
#[test]
fn engine_error_from_serde_json() {
let bad = b"\x80";
let e: Result<(), _> = serde_json::from_slice(bad);
let err: EngineError = e.unwrap_err().into();
assert!(err.to_string().contains("internal error"));
}
}