Skip to main content

arrow_tiberius/
error.rs

1//! Error types for `arrow-tiberius`.
2
3use snafu::Snafu;
4
5use crate::{DiagnosticSet, WriteBackend};
6
7/// Crate-local result type.
8pub type Result<T> = std::result::Result<T, Error>;
9
10/// Error type for `arrow-tiberius` operations.
11#[derive(Debug, Snafu)]
12#[non_exhaustive]
13pub enum Error {
14    /// A SQL Server database compatibility level is not supported.
15    #[snafu(display("invalid compatibility level {level}"))]
16    InvalidCompatibilityLevel {
17        /// The unsupported compatibility level value.
18        level: u16,
19    },
20
21    /// A SQL Server identifier is invalid for the selected identifier policy.
22    #[snafu(display("invalid identifier: {reason}"))]
23    InvalidIdentifier {
24        /// Human-readable reason the identifier is invalid.
25        reason: String,
26    },
27
28    /// Arrow schema planning failed.
29    #[snafu(display("write planning failed with {} diagnostic(s)", diagnostics.len()))]
30    Planning {
31        /// Structured planning diagnostics.
32        diagnostics: DiagnosticSet,
33    },
34
35    /// Runtime value conversion failed.
36    #[snafu(display(
37        "value conversion failed with {} diagnostic(s)",
38        diagnostics.len()
39    ))]
40    ValueConversion {
41        /// Structured value conversion diagnostics.
42        diagnostics: DiagnosticSet,
43    },
44
45    /// Direct raw TDS encoding failed.
46    #[snafu(display(
47        "direct encoding failed with {} diagnostic(s)",
48        diagnostics.len()
49    ))]
50    DirectEncoding {
51        /// Structured direct encoding diagnostics.
52        diagnostics: DiagnosticSet,
53    },
54
55    /// A requested write backend is not available.
56    #[snafu(display("write backend {backend:?} is unavailable: {reason}"))]
57    BackendUnavailable {
58        /// Requested write backend.
59        backend: WriteBackend,
60        /// Human-readable reason the backend is unavailable.
61        reason: String,
62    },
63
64    /// Tiberius returned an error while executing a SQL Server operation.
65    #[snafu(display("tiberius operation failed: {source}"))]
66    Tiberius {
67        /// Source error returned by Tiberius.
68        source: tiberius::error::Error,
69    },
70}
71
72#[cfg(test)]
73mod tests {
74    use std::{borrow::Cow, error::Error as StdError};
75
76    use crate::{Diagnostic, DiagnosticCode, DiagnosticSet, Error};
77
78    #[test]
79    fn planning_error_display_includes_diagnostic_count() {
80        let diagnostics = DiagnosticSet::from(vec![Diagnostic::error(
81            DiagnosticCode::UnsupportedArrowType,
82            "unsupported",
83        )]);
84        let err = Error::Planning { diagnostics };
85
86        assert_eq!(
87            err.to_string(),
88            "write planning failed with 1 diagnostic(s)"
89        );
90    }
91
92    #[test]
93    fn value_conversion_error_display_includes_diagnostic_count() {
94        let diagnostics = DiagnosticSet::from(vec![Diagnostic::error(
95            DiagnosticCode::ValueConversionUnsupported,
96            "unsupported conversion",
97        )]);
98        let err = Error::ValueConversion { diagnostics };
99
100        assert_eq!(
101            err.to_string(),
102            "value conversion failed with 1 diagnostic(s)"
103        );
104    }
105
106    #[test]
107    fn direct_encoding_error_display_includes_diagnostic_count() {
108        let diagnostics = DiagnosticSet::from(vec![Diagnostic::error(
109            DiagnosticCode::DirectEncodingInvalidPayload,
110            "invalid payload",
111        )]);
112        let err = Error::DirectEncoding { diagnostics };
113
114        assert_eq!(
115            err.to_string(),
116            "direct encoding failed with 1 diagnostic(s)"
117        );
118    }
119
120    #[test]
121    fn backend_unavailable_error_display_includes_backend() {
122        let err = Error::BackendUnavailable {
123            backend: crate::WriteBackend::DirectRawBulk,
124            reason: "not implemented".to_owned(),
125        };
126
127        assert_eq!(
128            err.to_string(),
129            "write backend DirectRawBulk is unavailable: not implemented"
130        );
131    }
132
133    #[test]
134    fn tiberius_error_display_includes_source_error() {
135        let err = Error::Tiberius {
136            source: tiberius::error::Error::Protocol(Cow::Borrowed("invalid token")),
137        };
138
139        assert_eq!(
140            err.to_string(),
141            "tiberius operation failed: Protocol error: invalid token"
142        );
143    }
144
145    #[test]
146    fn tiberius_error_preserves_source_error() {
147        let err = Error::Tiberius {
148            source: tiberius::error::Error::BulkInput(Cow::Borrowed("row payload is malformed")),
149        };
150
151        let source = StdError::source(&err).expect("tiberius source should be preserved");
152        assert_eq!(
153            source.to_string(),
154            "BULK UPLOAD input failure: row payload is malformed"
155        );
156    }
157}