1use thiserror::Error;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum AdapterErrorKind {
8 Busy,
9 Locked,
10 Timeout,
11 Constraint,
12 Conflict,
13 VersionConflict,
14 TransactionAborted,
15 IdempotencyConflict,
16 IdempotencyInProgress,
17 Query,
18 InvalidOperation,
19 ReadOnly,
20 Capability,
21 Value,
22 Storage,
23 Transport,
24 Protocol,
25 Authentication,
26 Authorization,
27 RateLimited,
28 Quota,
29 NotFound,
30 Unavailable,
31 Cancellation,
32 Unknown,
33}
34
35#[derive(Debug, Error)]
37pub enum DactylError {
38 #[error("configuration error: {0}")]
39 Config(String),
40
41 #[error("adapter error ({kind:?}): {message}")]
42 Adapter {
43 kind: AdapterErrorKind,
44 code: Option<String>,
45 message: String,
46 },
47
48 #[error("unsupported datastore operation: {0}")]
49 UnsupportedOperation(String),
50
51 #[error("column not found: {0}")]
52 ColumnNotFound(String),
53
54 #[error("conversion error: {0}")]
55 Conversion(String),
56}
57
58impl DactylError {
59 #[allow(dead_code)]
60 pub(crate) fn adapter(kind: AdapterErrorKind, message: impl Into<String>) -> Self {
61 Self::Adapter {
62 kind,
63 code: None,
64 message: message.into(),
65 }
66 }
67
68 #[cfg(feature = "neon")]
69 pub(crate) fn adapter_with_code(
70 kind: AdapterErrorKind,
71 code: impl Into<String>,
72 message: impl Into<String>,
73 ) -> Self {
74 Self::Adapter {
75 kind,
76 code: Some(code.into()),
77 message: message.into(),
78 }
79 }
80
81 pub fn adapter_kind(&self) -> Option<AdapterErrorKind> {
82 match self {
83 Self::Adapter { kind, .. } => Some(*kind),
84 _ => None,
85 }
86 }
87
88 pub fn adapter_code(&self) -> Option<&str> {
90 match self {
91 Self::Adapter { code, .. } => code.as_deref(),
92 _ => None,
93 }
94 }
95
96 pub fn is_retryable(&self) -> bool {
97 matches!(
98 self.adapter_kind(),
99 Some(
100 AdapterErrorKind::Busy
101 | AdapterErrorKind::Locked
102 | AdapterErrorKind::Timeout
103 | AdapterErrorKind::Unavailable,
104 )
105 )
106 }
107}