snowflake_connector_rs/error/
decode.rs1use std::{
2 borrow::Cow,
3 error::Error as StdError,
4 fmt::{self, Display},
5};
6
7use crate::result_table::ColumnType;
8
9use super::{SchemaError, VALUE_PREVIEW_MAX_CHARS, truncate_preview_chars};
10
11pub type CellDecodeResult<T> = std::result::Result<T, CellConversionError>;
13
14#[derive(Debug)]
18pub struct CellConversionError {
19 reason: Box<str>,
20 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
21}
22
23impl CellConversionError {
24 pub fn new(reason: impl Into<Box<str>>) -> Self {
26 Self::builder(reason).build()
27 }
28
29 pub fn builder(reason: impl Into<Box<str>>) -> CellConversionErrorBuilder {
30 CellConversionErrorBuilder {
31 reason: reason.into(),
32 source: None,
33 }
34 }
35
36 pub fn reason(&self) -> &str {
37 &self.reason
38 }
39
40 pub fn source(&self) -> Option<&(dyn StdError + Send + Sync + 'static)> {
41 self.source.as_deref()
42 }
43}
44
45impl Display for CellConversionError {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f.write_str(&self.reason)
48 }
49}
50
51impl StdError for CellConversionError {
52 fn source(&self) -> Option<&(dyn StdError + 'static)> {
53 self.source.as_deref().map(|source| source as _)
54 }
55}
56
57#[derive(Debug)]
58pub struct CellConversionErrorBuilder {
59 reason: Box<str>,
60 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
61}
62
63impl CellConversionErrorBuilder {
64 pub fn source(mut self, source: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
65 self.source = Some(source.into());
66 self
67 }
68
69 pub fn build(self) -> CellConversionError {
70 CellConversionError {
71 reason: self.reason,
72 source: self.source,
73 }
74 }
75}
76
77#[derive(Debug)]
86pub struct CustomPlanError {
87 reason: Box<str>,
88 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
89 column_index: Option<usize>,
90 column_name: Option<Box<str>>,
91}
92
93impl CustomPlanError {
94 pub fn new(reason: impl Into<Box<str>>) -> Self {
96 Self::builder(reason).build()
97 }
98
99 pub fn builder(reason: impl Into<Box<str>>) -> CustomPlanErrorBuilder {
100 CustomPlanErrorBuilder {
101 reason: reason.into(),
102 source: None,
103 }
104 }
105
106 pub fn reason(&self) -> &str {
107 &self.reason
108 }
109
110 pub fn source(&self) -> Option<&(dyn StdError + Send + Sync + 'static)> {
111 self.source.as_deref()
112 }
113
114 pub fn column_index(&self) -> Option<usize> {
117 self.column_index
118 }
119
120 pub fn column_name(&self) -> Option<&str> {
121 self.column_name.as_deref()
122 }
123
124 pub(crate) fn set_column_context(
128 &mut self,
129 column_index: usize,
130 column_name: impl Into<Box<str>>,
131 ) {
132 if self.column_index.is_some() {
133 return;
134 }
135 self.column_index = Some(column_index);
136 self.column_name = Some(column_name.into());
137 }
138}
139
140impl Display for CustomPlanError {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 match (self.column_index, &self.column_name) {
143 (Some(column_index), Some(column_name)) => write!(
144 f,
145 "decode plan error at column_index {column_index} ({column_name}): {}",
146 self.reason
147 ),
148 _ => write!(f, "decode plan error: {}", self.reason),
149 }
150 }
151}
152
153impl StdError for CustomPlanError {
154 fn source(&self) -> Option<&(dyn StdError + 'static)> {
155 self.source.as_deref().map(|source| source as _)
156 }
157}
158
159#[derive(Debug)]
160pub struct CustomPlanErrorBuilder {
161 reason: Box<str>,
162 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
163}
164
165impl CustomPlanErrorBuilder {
166 pub fn source(mut self, source: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
167 self.source = Some(source.into());
168 self
169 }
170
171 pub fn build(self) -> CustomPlanError {
172 CustomPlanError {
173 reason: self.reason,
174 source: self.source,
175 column_index: None,
176 column_name: None,
177 }
178 }
179}
180
181#[derive(Debug)]
189pub struct RowConversionError {
190 reason: Box<str>,
191 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
192 row_index: Option<usize>,
193}
194
195impl RowConversionError {
196 pub fn new(reason: impl Into<Box<str>>) -> Self {
198 Self::builder(reason).build()
199 }
200
201 pub fn builder(reason: impl Into<Box<str>>) -> RowConversionErrorBuilder {
202 RowConversionErrorBuilder {
203 reason: reason.into(),
204 source: None,
205 }
206 }
207
208 pub fn reason(&self) -> &str {
209 &self.reason
210 }
211
212 pub fn source(&self) -> Option<&(dyn StdError + Send + Sync + 'static)> {
213 self.source.as_deref()
214 }
215
216 pub fn row_index(&self) -> Option<usize> {
218 self.row_index
219 }
220
221 pub(crate) fn set_row_index(&mut self, row_index: usize) {
223 if self.row_index.is_none() {
224 self.row_index = Some(row_index);
225 }
226 }
227}
228
229impl Display for RowConversionError {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 match self.row_index {
232 Some(row_index) => {
233 write!(
234 f,
235 "row conversion error at row_index {row_index}: {}",
236 self.reason
237 )
238 }
239 None => write!(f, "row conversion error: {}", self.reason),
240 }
241 }
242}
243
244impl StdError for RowConversionError {
245 fn source(&self) -> Option<&(dyn StdError + 'static)> {
246 self.source.as_deref().map(|source| source as _)
247 }
248}
249
250#[derive(Debug)]
251pub struct RowConversionErrorBuilder {
252 reason: Box<str>,
253 source: Option<Box<dyn StdError + Send + Sync + 'static>>,
254}
255
256impl RowConversionErrorBuilder {
257 pub fn source(mut self, source: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {
258 self.source = Some(source.into());
259 self
260 }
261
262 pub fn build(self) -> RowConversionError {
263 RowConversionError {
264 reason: self.reason,
265 source: self.source,
266 row_index: None,
267 }
268 }
269}
270
271#[derive(Debug)]
273pub struct CellDecodeError {
274 inner: Box<CellDecodeErrorInner>,
275}
276
277#[derive(Debug)]
278struct CellDecodeErrorInner {
279 row_index: usize,
280 column_index: usize,
281 column_name: Box<str>,
282 target_type_name: Cow<'static, str>,
283 actual_column_type: ColumnType,
284 raw_value_preview: Option<Box<str>>,
285 issue: CellConversionError,
286}
287
288impl CellDecodeError {
289 pub(crate) fn new(
290 row_index: usize,
291 column_index: usize,
292 column_name: impl Into<Box<str>>,
293 target_type_name: impl Into<Cow<'static, str>>,
294 actual_column_type: ColumnType,
295 raw_value_preview: Option<&str>,
296 issue: CellConversionError,
297 ) -> Self {
298 Self {
299 inner: Box::new(CellDecodeErrorInner {
300 row_index,
301 column_index,
302 column_name: column_name.into(),
303 target_type_name: target_type_name.into(),
304 actual_column_type,
305 raw_value_preview: raw_value_preview
306 .map(|preview| truncate_preview_chars(preview, VALUE_PREVIEW_MAX_CHARS)),
307 issue,
308 }),
309 }
310 }
311
312 pub fn row_index(&self) -> usize {
313 self.inner.row_index
314 }
315
316 pub fn column_index(&self) -> usize {
317 self.inner.column_index
318 }
319
320 pub fn column_name(&self) -> &str {
321 &self.inner.column_name
322 }
323
324 pub fn target_type_name(&self) -> &str {
325 &self.inner.target_type_name
326 }
327
328 pub fn actual_column_type(&self) -> &ColumnType {
329 &self.inner.actual_column_type
330 }
331
332 pub fn raw_value_preview(&self) -> Option<&str> {
333 self.inner.raw_value_preview.as_deref()
334 }
335
336 pub fn conversion_error(&self) -> &CellConversionError {
337 &self.inner.issue
338 }
339}
340
341impl Display for CellDecodeError {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 let inner = &*self.inner;
344 write!(
345 f,
346 "row_index {} column_index {} ({}): target_type {}, found {}",
347 inner.row_index,
348 inner.column_index,
349 inner.column_name,
350 inner.target_type_name,
351 inner.actual_column_type
352 )?;
353 if let Some(preview) = &inner.raw_value_preview {
354 write!(f, ", value: {preview:?}")?;
355 }
356 if !inner.issue.reason().is_empty() {
357 write!(f, " ({})", inner.issue.reason())?;
358 }
359 Ok(())
360 }
361}
362
363impl StdError for CellDecodeError {
364 fn source(&self) -> Option<&(dyn StdError + 'static)> {
365 self.inner
366 .issue
367 .source()
368 .map(|_| &self.inner.issue as &(dyn StdError + 'static))
369 }
370}
371
372#[derive(Debug)]
381#[non_exhaustive]
382pub enum PlanBuildError {
383 Schema(SchemaError),
385 Custom(CustomPlanError),
387}
388
389#[derive(Debug)]
394#[non_exhaustive]
395pub enum RowDecodeError {
396 Schema(SchemaError),
398 Cell(CellDecodeError),
400 Conversion(RowConversionError),
402}
403
404pub type PlanBuildResult<T> = std::result::Result<T, PlanBuildError>;
406
407pub type RowDecodeResult<T> = std::result::Result<T, RowDecodeError>;
409
410impl Display for PlanBuildError {
411 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412 match self {
413 Self::Schema(error) => Display::fmt(error, f),
414 Self::Custom(error) => Display::fmt(error, f),
415 }
416 }
417}
418
419impl StdError for PlanBuildError {
420 fn source(&self) -> Option<&(dyn StdError + 'static)> {
421 match self {
422 Self::Schema(error) => StdError::source(error),
423 Self::Custom(error) => StdError::source(error),
424 }
425 }
426}
427
428impl Display for RowDecodeError {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 match self {
431 Self::Schema(error) => Display::fmt(error, f),
432 Self::Cell(error) => Display::fmt(error, f),
433 Self::Conversion(error) => Display::fmt(error, f),
434 }
435 }
436}
437
438impl StdError for RowDecodeError {
439 fn source(&self) -> Option<&(dyn StdError + 'static)> {
440 match self {
441 Self::Schema(error) => StdError::source(error),
442 Self::Cell(error) => StdError::source(error),
443 Self::Conversion(error) => StdError::source(error),
444 }
445 }
446}
447
448impl From<SchemaError> for PlanBuildError {
449 fn from(error: SchemaError) -> Self {
450 Self::Schema(error)
451 }
452}
453
454impl From<CustomPlanError> for PlanBuildError {
455 fn from(error: CustomPlanError) -> Self {
456 Self::Custom(error)
457 }
458}
459
460impl From<SchemaError> for RowDecodeError {
461 fn from(error: SchemaError) -> Self {
462 Self::Schema(error)
463 }
464}
465
466impl From<CellDecodeError> for RowDecodeError {
467 fn from(error: CellDecodeError) -> Self {
468 Self::Cell(error)
469 }
470}
471
472impl From<RowConversionError> for RowDecodeError {
473 fn from(error: RowConversionError) -> Self {
474 Self::Conversion(error)
475 }
476}