Skip to main content

dactyl_db/
error.rs

1//! Errors returned by the Dactyl driver.
2
3use thiserror::Error;
4
5/// Coarse operational categories stable enough for callers to branch on.
6#[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/// The backend-neutral public error surface.
36#[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    /// Stable remote/provider code, when the adapter received one.
88    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}