robin_sparkless_core/
error.rs1use std::fmt;
10
11#[derive(Debug)]
16pub enum EngineError {
17 User(String),
19 Internal(String),
21 Io(String),
23 Sql(String),
25 NotFound(String),
27 Other(String),
29}
30
31impl fmt::Display for EngineError {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 EngineError::User(s) => write!(f, "user error: {s}"),
35 EngineError::Internal(s) => write!(f, "internal error: {s}"),
36 EngineError::Io(s) => write!(f, "io error: {s}"),
37 EngineError::Sql(s) => write!(f, "sql error: {s}"),
38 EngineError::NotFound(s) => write!(f, "not found: {s}"),
39 EngineError::Other(s) => write!(f, "{s}"),
40 }
41 }
42}
43
44impl std::error::Error for EngineError {}
45
46impl EngineError {
47 pub fn user_message(&self) -> &str {
49 match self {
50 EngineError::User(s)
51 | EngineError::Internal(s)
52 | EngineError::Io(s)
53 | EngineError::Sql(s)
54 | EngineError::NotFound(s)
55 | EngineError::Other(s) => s.as_str(),
56 }
57 }
58}
59
60pub fn normalize_unresolved_column_message(msg: &str) -> String {
62 let lower = msg.to_lowercase();
63 if lower.contains("cannot be resolved") {
64 if lower.contains("unresolved_column") {
65 return msg.to_string();
66 }
67 return format!("unresolved_column: {msg}");
68 }
69 if lower.contains("cannot resolve") {
70 let msg = msg.replace("cannot resolve", "cannot be resolved");
71 if lower.contains("unresolved_column") {
72 return msg;
73 }
74 return format!("unresolved_column: {msg}");
75 }
76 if msg.contains("unable to find column")
77 || (msg.contains("not found") && lower.contains("column"))
78 || msg.contains("valid columns")
79 {
80 return format!("unresolved_column: cannot be resolved: {msg}");
81 }
82 msg.to_string()
83}
84
85impl From<serde_json::Error> for EngineError {
86 fn from(e: serde_json::Error) -> Self {
87 EngineError::Internal(e.to_string())
88 }
89}
90
91impl From<std::io::Error> for EngineError {
92 fn from(e: std::io::Error) -> Self {
93 EngineError::Io(e.to_string())
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn engine_error_display() {
103 assert_eq!(
104 EngineError::User("bad input".into()).to_string(),
105 "user error: bad input"
106 );
107 assert_eq!(
108 EngineError::Internal("panic".into()).to_string(),
109 "internal error: panic"
110 );
111 assert_eq!(
112 EngineError::Io("file not found".into()).to_string(),
113 "io error: file not found"
114 );
115 assert_eq!(
116 EngineError::Sql("parse error".into()).to_string(),
117 "sql error: parse error"
118 );
119 assert_eq!(
120 EngineError::NotFound("column x".into()).to_string(),
121 "not found: column x"
122 );
123 assert_eq!(EngineError::Other("misc".into()).to_string(), "misc");
124 }
125
126 #[test]
127 fn engine_error_from_io() {
128 let e = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
129 let err: EngineError = e.into();
130 assert!(err.to_string().contains("file missing"));
131 assert!(err.to_string().contains("io error"));
132 }
133
134 #[test]
135 fn engine_error_from_serde_json() {
136 let bad = b"\x80";
137 let e: Result<(), _> = serde_json::from_slice(bad);
138 let err: EngineError = e.unwrap_err().into();
139 assert!(err.to_string().contains("internal error"));
140 }
141}