1use thiserror::Error;
6
7#[derive(Error, Debug)]
12pub enum QueryError {
13 #[error("Connection error: {message}")]
15 ConnectionError { message: String },
16
17 #[error("Query execution failed: {message}")]
19 ExecutionError { message: String },
20
21 #[error("Query parsing error: {message}")]
23 ParseError { message: String },
24
25 #[error("Type mismatch: expected {expected}, got {actual}")]
27 TypeMismatch { expected: String, actual: String },
28
29 #[error("Missing required field: {field}")]
31 MissingField { field: String },
32
33 #[error("Transaction error: {message}")]
35 TransactionError { message: String },
36
37 #[error("Unsupported query language: {language}")]
39 UnsupportedLanguage { language: String },
40
41 #[error("Invalid parameter binding: {message}")]
43 ParameterError { message: String },
44
45 #[error("Row not found")]
47 RowNotFound,
48
49 #[error("Expected one row, found {count}")]
51 MultipleRowsFound { count: usize },
52
53 #[error("I/O error: {0}")]
55 IoError(#[from] std::io::Error),
56
57 #[error("Serialization error: {message}")]
59 SerializationError { message: String },
60
61 #[error("{0}")]
63 Other(String),
64}
65
66impl QueryError {
67 pub fn connection<S: Into<String>>(message: S) -> Self {
69 QueryError::ConnectionError {
70 message: message.into(),
71 }
72 }
73
74 pub fn execution<S: Into<String>>(message: S) -> Self {
76 QueryError::ExecutionError {
77 message: message.into(),
78 }
79 }
80
81 pub fn parse<S: Into<String>>(message: S) -> Self {
83 QueryError::ParseError {
84 message: message.into(),
85 }
86 }
87
88 pub fn type_mismatch<S: Into<String>>(expected: S, actual: S) -> Self {
90 QueryError::TypeMismatch {
91 expected: expected.into(),
92 actual: actual.into(),
93 }
94 }
95
96 pub fn missing_field<S: Into<String>>(field: S) -> Self {
98 QueryError::MissingField {
99 field: field.into(),
100 }
101 }
102
103 pub fn transaction<S: Into<String>>(message: S) -> Self {
105 QueryError::TransactionError {
106 message: message.into(),
107 }
108 }
109
110 pub fn parameter<S: Into<String>>(message: S) -> Self {
112 QueryError::ParameterError {
113 message: message.into(),
114 }
115 }
116
117 pub fn serialization<S: Into<String>>(message: S) -> Self {
119 QueryError::SerializationError {
120 message: message.into(),
121 }
122 }
123
124 pub fn other<S: Into<String>>(message: S) -> Self {
126 QueryError::Other(message.into())
127 }
128}
129
130pub type Result<T> = std::result::Result<T, QueryError>;
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 #[test]
138 fn test_connection_error() {
139 let err = QueryError::connection("Failed to connect");
140 assert!(matches!(err, QueryError::ConnectionError { .. }));
141 assert_eq!(err.to_string(), "Connection error: Failed to connect");
142 }
143
144 #[test]
145 fn test_execution_error() {
146 let err = QueryError::execution("Query failed");
147 assert!(matches!(err, QueryError::ExecutionError { .. }));
148 }
149
150 #[test]
151 fn test_type_mismatch() {
152 let err = QueryError::type_mismatch("String", "Integer");
153 assert!(matches!(err, QueryError::TypeMismatch { .. }));
154 assert!(err.to_string().contains("String"));
155 assert!(err.to_string().contains("Integer"));
156 }
157
158 #[test]
159 fn test_missing_field() {
160 let err = QueryError::missing_field("id");
161 assert!(matches!(err, QueryError::MissingField { .. }));
162 assert!(err.to_string().contains("id"));
163 }
164
165 #[test]
166 fn test_row_not_found() {
167 let err = QueryError::RowNotFound;
168 assert_eq!(err.to_string(), "Row not found");
169 }
170
171 #[test]
172 fn test_multiple_rows_found() {
173 let err = QueryError::MultipleRowsFound { count: 5 };
174 assert!(err.to_string().contains("5"));
175 }
176
177 #[test]
178 fn test_unsupported_language() {
179 let err = QueryError::UnsupportedLanguage {
180 language: "gremlin".to_string(),
181 };
182 assert!(err.to_string().contains("gremlin"));
183 }
184
185 #[test]
186 fn test_io_error_conversion() {
187 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
188 let err: QueryError = io_err.into();
189 assert!(matches!(err, QueryError::IoError(_)));
190 }
191
192 #[test]
193 fn test_result_alias() {
194 let ok_result: Result<i32> = Ok(42);
195 assert!(ok_result.is_ok());
196
197 let err_result: Result<i32> = Err(QueryError::RowNotFound);
198 assert!(err_result.is_err());
199 }
200}