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    #[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    /// Stable remote/provider code, when the adapter received one.
89    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}