hdbconnect_arrow/
error.rs1use thiserror::Error;
7
8#[derive(Error, Debug)]
28#[error("{kind}")]
29pub struct ArrowConversionError {
30 kind: ErrorKind,
31}
32
33#[derive(Error, Debug)]
38#[non_exhaustive]
39pub(crate) enum ErrorKind {
40 #[error("unsupported HANA type: {type_id:?}")]
42 UnsupportedType { type_id: i16 },
43
44 #[error("schema mismatch: expected {expected} columns, got {actual}")]
46 SchemaMismatch { expected: usize, actual: usize },
47
48 #[error("value conversion failed for column '{column}': {message}")]
50 ValueConversion { column: String, message: String },
51
52 #[error("decimal overflow: precision {precision}, scale {scale}")]
54 DecimalOverflow { precision: u8, scale: i8 },
55
56 #[error("arrow error: {0}")]
58 Arrow(#[from] arrow_schema::ArrowError),
59
60 #[error("hdbconnect error: {0}")]
62 Hdbconnect(String),
63
64 #[error("LOB streaming error: {message}")]
66 LobStreaming { message: String },
67
68 #[error("invalid precision: {0}")]
70 InvalidPrecision(String),
71
72 #[error("invalid scale: {0}")]
74 InvalidScale(String),
75}
76
77impl ArrowConversionError {
78 #[must_use]
84 pub const fn unsupported_type(type_id: i16) -> Self {
85 Self {
86 kind: ErrorKind::UnsupportedType { type_id },
87 }
88 }
89
90 #[must_use]
92 pub const fn schema_mismatch(expected: usize, actual: usize) -> Self {
93 Self {
94 kind: ErrorKind::SchemaMismatch { expected, actual },
95 }
96 }
97
98 #[must_use]
100 pub fn value_conversion(column: impl Into<String>, message: impl Into<String>) -> Self {
101 Self {
102 kind: ErrorKind::ValueConversion {
103 column: column.into(),
104 message: message.into(),
105 },
106 }
107 }
108
109 #[must_use]
111 pub const fn decimal_overflow(precision: u8, scale: i8) -> Self {
112 Self {
113 kind: ErrorKind::DecimalOverflow { precision, scale },
114 }
115 }
116
117 #[must_use]
119 pub fn lob_streaming(message: impl Into<String>) -> Self {
120 Self {
121 kind: ErrorKind::LobStreaming {
122 message: message.into(),
123 },
124 }
125 }
126
127 #[must_use]
129 pub fn invalid_precision(message: impl Into<String>) -> Self {
130 Self {
131 kind: ErrorKind::InvalidPrecision(message.into()),
132 }
133 }
134
135 #[must_use]
137 pub fn invalid_scale(message: impl Into<String>) -> Self {
138 Self {
139 kind: ErrorKind::InvalidScale(message.into()),
140 }
141 }
142
143 #[must_use]
149 pub const fn is_unsupported_type(&self) -> bool {
150 matches!(self.kind, ErrorKind::UnsupportedType { .. })
151 }
152
153 #[must_use]
155 pub const fn is_schema_mismatch(&self) -> bool {
156 matches!(self.kind, ErrorKind::SchemaMismatch { .. })
157 }
158
159 #[must_use]
161 pub const fn is_value_conversion(&self) -> bool {
162 matches!(self.kind, ErrorKind::ValueConversion { .. })
163 }
164
165 #[must_use]
167 pub const fn is_decimal_overflow(&self) -> bool {
168 matches!(self.kind, ErrorKind::DecimalOverflow { .. })
169 }
170
171 #[must_use]
173 pub const fn is_arrow_error(&self) -> bool {
174 matches!(self.kind, ErrorKind::Arrow(_))
175 }
176
177 #[must_use]
179 pub const fn is_hdbconnect_error(&self) -> bool {
180 matches!(self.kind, ErrorKind::Hdbconnect(_))
181 }
182
183 #[must_use]
185 pub const fn is_lob_streaming(&self) -> bool {
186 matches!(self.kind, ErrorKind::LobStreaming { .. })
187 }
188
189 #[must_use]
191 pub const fn is_invalid_precision(&self) -> bool {
192 matches!(self.kind, ErrorKind::InvalidPrecision(_))
193 }
194
195 #[must_use]
197 pub const fn is_invalid_scale(&self) -> bool {
198 matches!(self.kind, ErrorKind::InvalidScale(_))
199 }
200}
201
202impl From<hdbconnect::HdbError> for ArrowConversionError {
203 fn from(err: hdbconnect::HdbError) -> Self {
204 Self {
205 kind: ErrorKind::Hdbconnect(err.to_string()),
206 }
207 }
208}
209
210impl From<arrow_schema::ArrowError> for ArrowConversionError {
211 fn from(err: arrow_schema::ArrowError) -> Self {
212 Self {
213 kind: ErrorKind::Arrow(err),
214 }
215 }
216}
217
218pub type Result<T> = std::result::Result<T, ArrowConversionError>;
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_error_creation() {
227 let err = ArrowConversionError::unsupported_type(42);
228 assert!(err.is_unsupported_type());
229 assert!(!err.is_schema_mismatch());
230 }
231
232 #[test]
233 fn test_schema_mismatch() {
234 let err = ArrowConversionError::schema_mismatch(5, 3);
235 assert!(err.is_schema_mismatch());
236 assert!(err.to_string().contains("expected 5 columns, got 3"));
237 }
238
239 #[test]
240 fn test_value_conversion() {
241 let err = ArrowConversionError::value_conversion("col1", "invalid integer");
242 assert!(err.is_value_conversion());
243 assert!(err.to_string().contains("col1"));
244 }
245
246 #[test]
247 fn test_decimal_overflow() {
248 let err = ArrowConversionError::decimal_overflow(38, 10);
249 assert!(err.is_decimal_overflow());
250 }
251
252 #[test]
253 fn test_error_debug() {
254 let err = ArrowConversionError::unsupported_type(99);
255 let debug_str = format!("{err:?}");
257 assert!(debug_str.contains("ArrowConversionError"));
258 }
259
260 #[test]
261 fn test_error_display() {
262 let err = ArrowConversionError::lob_streaming("connection lost");
263 let display = err.to_string();
264 assert!(display.contains("LOB streaming error"));
265 assert!(display.contains("connection lost"));
266 }
267}