Skip to main content

khive_storage/
error.rs

1//! Storage error types shared across all backend implementations.
2
3use std::borrow::Cow;
4use std::error::Error as StdError;
5
6use thiserror::Error;
7
8use crate::capability::StorageCapability;
9
10/// Unified error type for all storage operations.
11#[derive(Debug, Error)]
12pub enum StorageError {
13    #[error("{capability:?} resource not found: {resource} ({key})")]
14    NotFound {
15        capability: StorageCapability,
16        resource: &'static str,
17        key: String,
18    },
19
20    #[error("{capability:?} resource already exists: {resource} ({key})")]
21    AlreadyExists {
22        capability: StorageCapability,
23        resource: &'static str,
24        key: String,
25    },
26
27    #[error("conflict in {capability:?} during {operation}: {message}")]
28    Conflict {
29        capability: StorageCapability,
30        operation: Cow<'static, str>,
31        message: String,
32    },
33
34    #[error("invalid input for {capability:?} during {operation}: {message}")]
35    InvalidInput {
36        capability: StorageCapability,
37        operation: Cow<'static, str>,
38        message: String,
39    },
40
41    #[error("unsupported operation for {capability:?}: {operation} ({message})")]
42    Unsupported {
43        capability: StorageCapability,
44        operation: Cow<'static, str>,
45        message: String,
46    },
47
48    #[error("pool failure during {operation}: {message}")]
49    Pool {
50        operation: Cow<'static, str>,
51        message: String,
52    },
53
54    #[error("timeout during {operation}")]
55    Timeout { operation: Cow<'static, str> },
56
57    #[error("sql transaction failure during {operation}: {message}")]
58    Transaction {
59        operation: Cow<'static, str>,
60        message: String,
61    },
62
63    #[error("serialization failure in {capability:?}: {message}")]
64    Serialization {
65        capability: StorageCapability,
66        message: String,
67    },
68
69    #[error("index maintenance failure in {capability:?}: {message}")]
70    IndexMaintenance {
71        capability: StorageCapability,
72        message: String,
73    },
74
75    #[error("backend driver error in {capability:?} during {operation}: {source}")]
76    Driver {
77        capability: StorageCapability,
78        operation: Cow<'static, str>,
79        #[source]
80        source: Box<dyn StdError + Send + Sync>,
81    },
82}
83
84impl StorageError {
85    /// Construct a `Driver` error wrapping a backend-specific error source.
86    pub fn driver(
87        capability: StorageCapability,
88        operation: impl Into<Cow<'static, str>>,
89        source: impl StdError + Send + Sync + 'static,
90    ) -> Self {
91        Self::Driver {
92            capability,
93            operation: operation.into(),
94            source: Box::new(source),
95        }
96    }
97
98    /// Return the storage capability surface that produced this error, if any.
99    pub fn capability(&self) -> Option<StorageCapability> {
100        match self {
101            Self::NotFound { capability, .. }
102            | Self::AlreadyExists { capability, .. }
103            | Self::Conflict { capability, .. }
104            | Self::InvalidInput { capability, .. }
105            | Self::Unsupported { capability, .. }
106            | Self::Serialization { capability, .. }
107            | Self::IndexMaintenance { capability, .. }
108            | Self::Driver { capability, .. } => Some(*capability),
109            Self::Pool { .. } | Self::Timeout { .. } | Self::Transaction { .. } => None,
110        }
111    }
112
113    /// Whether this error is transient and the operation may succeed on retry.
114    pub fn is_retryable(&self) -> bool {
115        matches!(
116            self,
117            Self::Pool { .. } | Self::Timeout { .. } | Self::Transaction { .. }
118        )
119    }
120}