1use snafu::Snafu;
4
5use crate::{DiagnosticSet, WriteBackend};
6
7pub type Result<T> = std::result::Result<T, Error>;
9
10#[derive(Debug, Snafu)]
12#[non_exhaustive]
13pub enum Error {
14 #[snafu(display("invalid compatibility level {level}"))]
16 InvalidCompatibilityLevel {
17 level: u16,
19 },
20
21 #[snafu(display("invalid identifier: {reason}"))]
23 InvalidIdentifier {
24 reason: String,
26 },
27
28 #[snafu(display("write planning failed with {} diagnostic(s)", diagnostics.len()))]
30 Planning {
31 diagnostics: DiagnosticSet,
33 },
34
35 #[snafu(display(
37 "value conversion failed with {} diagnostic(s)",
38 diagnostics.len()
39 ))]
40 ValueConversion {
41 diagnostics: DiagnosticSet,
43 },
44
45 #[snafu(display(
47 "direct encoding failed with {} diagnostic(s)",
48 diagnostics.len()
49 ))]
50 DirectEncoding {
51 diagnostics: DiagnosticSet,
53 },
54
55 #[snafu(display("write backend {backend:?} is unavailable: {reason}"))]
57 BackendUnavailable {
58 backend: WriteBackend,
60 reason: String,
62 },
63
64 #[snafu(display("tiberius operation failed: {source}"))]
66 Tiberius {
67 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}