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 pub(crate) fn adapter_with_code(
69 kind: AdapterErrorKind,
70 code: impl Into<String>,
71 message: impl Into<String>,
72 ) -> Self {
73 Self::Adapter {
74 kind,
75 code: Some(code.into()),
76 message: message.into(),
77 }
78 }
79
80 pub fn adapter_kind(&self) -> Option<AdapterErrorKind> {
81 match self {
82 Self::Adapter { kind, .. } => Some(*kind),
83 _ => None,
84 }
85 }
86
87 pub fn adapter_code(&self) -> Option<&str> {
89 match self {
90 Self::Adapter { code, .. } => code.as_deref(),
91 _ => None,
92 }
93 }
94
95 pub fn is_retryable(&self) -> bool {
96 matches!(
97 self.adapter_kind(),
98 Some(
99 AdapterErrorKind::Busy
100 | AdapterErrorKind::Locked
101 | AdapterErrorKind::Timeout
102 | AdapterErrorKind::Unavailable,
103 )
104 )
105 }
106}