Skip to main content

yugendb_core/
error.rs

1//! Structured error model for yugendb.
2
3use thiserror::Error;
4
5/// Result alias used throughout yugendb.
6pub type Result<T> = std::result::Result<T, YugenDbError>;
7
8/// Stable cross-language error codes.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum ErrorCode {
11    /// A requested record was not found when the operation required it.
12    NotFound,
13    /// A backend connection could not be opened or used.
14    ConnectionError,
15    /// A value could not be serialised.
16    SerialisationError,
17    /// Stored bytes could not be deserialised into the requested type.
18    DeserialisationError,
19    /// An operation exceeded its allowed time.
20    Timeout,
21    /// An operation conflicted with existing data or concurrent work.
22    Conflict,
23    /// A transaction was aborted.
24    TransactionAborted,
25    /// The selected driver does not support the requested feature.
26    UnsupportedFeature,
27    /// A storage constraint was violated.
28    ConstraintViolation,
29    /// A key was invalid.
30    InvalidKey,
31    /// A namespace was invalid.
32    InvalidNamespace,
33    /// A collection name was invalid.
34    InvalidCollection,
35    /// A value was invalid.
36    InvalidValue,
37    /// A driver reported a backend-specific failure.
38    DriverError,
39    /// A yugendb invariant failed.
40    InternalError,
41}
42
43impl ErrorCode {
44    /// Returns the stable string used in public APIs.
45    #[must_use]
46    pub const fn as_str(self) -> &'static str {
47        match self {
48            Self::NotFound => "NOT_FOUND",
49            Self::ConnectionError => "CONNECTION_ERROR",
50            Self::SerialisationError => "SERIALISATION_ERROR",
51            Self::DeserialisationError => "DESERIALISATION_ERROR",
52            Self::Timeout => "TIMEOUT",
53            Self::Conflict => "CONFLICT",
54            Self::TransactionAborted => "TRANSACTION_ABORTED",
55            Self::UnsupportedFeature => "UNSUPPORTED_FEATURE",
56            Self::ConstraintViolation => "CONSTRAINT_VIOLATION",
57            Self::InvalidKey => "INVALID_KEY",
58            Self::InvalidNamespace => "INVALID_NAMESPACE",
59            Self::InvalidCollection => "INVALID_COLLECTION",
60            Self::InvalidValue => "INVALID_VALUE",
61            Self::DriverError => "DRIVER_ERROR",
62            Self::InternalError => "INTERNAL_ERROR",
63        }
64    }
65}
66
67impl std::fmt::Display for ErrorCode {
68    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        formatter.write_str(self.as_str())
70    }
71}
72
73/// Main structured error type for yugendb.
74#[derive(Debug, Error)]
75pub enum YugenDbError {
76    /// A requested record was not found when the operation required it.
77    #[error("record was not found: {message}")]
78    NotFound { message: String },
79
80    /// A backend connection could not be opened or used.
81    #[error("connection error: {message}")]
82    ConnectionError { message: String },
83
84    /// A value could not be serialised.
85    #[error("serialisation error: {message}")]
86    SerialisationError { message: String },
87
88    /// Stored bytes could not be deserialised into the requested type.
89    #[error("deserialisation error: {message}")]
90    DeserialisationError { message: String },
91
92    /// An operation exceeded its allowed time.
93    #[error("operation timed out: {message}")]
94    Timeout { message: String },
95
96    /// An operation conflicted with existing data or concurrent work.
97    #[error("conflict: {message}")]
98    Conflict { message: String },
99
100    /// A transaction was aborted.
101    #[error("transaction aborted: {message}")]
102    TransactionAborted { message: String },
103
104    /// The selected driver does not support the requested feature.
105    #[error("unsupported feature `{feature}`: {message}")]
106    UnsupportedFeature { feature: String, message: String },
107
108    /// A storage constraint was violated.
109    #[error("constraint violation: {message}")]
110    ConstraintViolation { message: String },
111
112    /// A key was invalid.
113    #[error("invalid key: {message}")]
114    InvalidKey { message: String },
115
116    /// A namespace was invalid.
117    #[error("invalid namespace: {message}")]
118    InvalidNamespace { message: String },
119
120    /// A collection name was invalid.
121    #[error("invalid collection: {message}")]
122    InvalidCollection { message: String },
123
124    /// A value was invalid.
125    #[error("invalid value: {message}")]
126    InvalidValue { message: String },
127
128    /// A driver reported a backend-specific failure.
129    #[error("driver error from `{driver}`: {message}")]
130    DriverError { driver: String, message: String },
131
132    /// A yugendb invariant failed.
133    #[error("internal error: {message}")]
134    InternalError { message: String },
135}
136
137impl YugenDbError {
138    /// Returns the stable cross-language error code.
139    #[must_use]
140    pub const fn code(&self) -> ErrorCode {
141        match self {
142            Self::NotFound { .. } => ErrorCode::NotFound,
143            Self::ConnectionError { .. } => ErrorCode::ConnectionError,
144            Self::SerialisationError { .. } => ErrorCode::SerialisationError,
145            Self::DeserialisationError { .. } => ErrorCode::DeserialisationError,
146            Self::Timeout { .. } => ErrorCode::Timeout,
147            Self::Conflict { .. } => ErrorCode::Conflict,
148            Self::TransactionAborted { .. } => ErrorCode::TransactionAborted,
149            Self::UnsupportedFeature { .. } => ErrorCode::UnsupportedFeature,
150            Self::ConstraintViolation { .. } => ErrorCode::ConstraintViolation,
151            Self::InvalidKey { .. } => ErrorCode::InvalidKey,
152            Self::InvalidNamespace { .. } => ErrorCode::InvalidNamespace,
153            Self::InvalidCollection { .. } => ErrorCode::InvalidCollection,
154            Self::InvalidValue { .. } => ErrorCode::InvalidValue,
155            Self::DriverError { .. } => ErrorCode::DriverError,
156            Self::InternalError { .. } => ErrorCode::InternalError,
157        }
158    }
159
160    /// Creates a not found error.
161    #[must_use]
162    pub fn not_found(message: impl Into<String>) -> Self {
163        Self::NotFound {
164            message: message.into(),
165        }
166    }
167
168    /// Creates a connection error.
169    #[must_use]
170    pub fn connection_error(message: impl Into<String>) -> Self {
171        Self::ConnectionError {
172            message: message.into(),
173        }
174    }
175
176    /// Creates a serialisation error.
177    #[must_use]
178    pub fn serialisation_error(message: impl Into<String>) -> Self {
179        Self::SerialisationError {
180            message: message.into(),
181        }
182    }
183
184    /// Creates a deserialisation error.
185    #[must_use]
186    pub fn deserialisation_error(message: impl Into<String>) -> Self {
187        Self::DeserialisationError {
188            message: message.into(),
189        }
190    }
191
192    /// Creates a timeout error.
193    #[must_use]
194    pub fn timeout(message: impl Into<String>) -> Self {
195        Self::Timeout {
196            message: message.into(),
197        }
198    }
199
200    /// Creates a conflict error.
201    #[must_use]
202    pub fn conflict(message: impl Into<String>) -> Self {
203        Self::Conflict {
204            message: message.into(),
205        }
206    }
207
208    /// Creates a transaction aborted error.
209    #[must_use]
210    pub fn transaction_aborted(message: impl Into<String>) -> Self {
211        Self::TransactionAborted {
212            message: message.into(),
213        }
214    }
215
216    /// Creates an unsupported feature error.
217    #[must_use]
218    pub fn unsupported_feature(feature: impl Into<String>, message: impl Into<String>) -> Self {
219        Self::UnsupportedFeature {
220            feature: feature.into(),
221            message: message.into(),
222        }
223    }
224
225    /// Creates a constraint violation error.
226    #[must_use]
227    pub fn constraint_violation(message: impl Into<String>) -> Self {
228        Self::ConstraintViolation {
229            message: message.into(),
230        }
231    }
232
233    /// Creates an invalid key error.
234    #[must_use]
235    pub fn invalid_key(message: impl Into<String>) -> Self {
236        Self::InvalidKey {
237            message: message.into(),
238        }
239    }
240
241    /// Creates an invalid namespace error.
242    #[must_use]
243    pub fn invalid_namespace(message: impl Into<String>) -> Self {
244        Self::InvalidNamespace {
245            message: message.into(),
246        }
247    }
248
249    /// Creates an invalid collection error.
250    #[must_use]
251    pub fn invalid_collection(message: impl Into<String>) -> Self {
252        Self::InvalidCollection {
253            message: message.into(),
254        }
255    }
256
257    /// Creates an invalid value error.
258    #[must_use]
259    pub fn invalid_value(message: impl Into<String>) -> Self {
260        Self::InvalidValue {
261            message: message.into(),
262        }
263    }
264
265    /// Creates a driver error.
266    #[must_use]
267    pub fn driver_error(driver: impl Into<String>, message: impl Into<String>) -> Self {
268        Self::DriverError {
269            driver: driver.into(),
270            message: message.into(),
271        }
272    }
273
274    /// Creates an invariant error.
275    #[must_use]
276    pub fn internal_error(message: impl Into<String>) -> Self {
277        Self::InternalError {
278            message: message.into(),
279        }
280    }
281}
282
283impl From<std::convert::Infallible> for YugenDbError {
284    fn from(error: std::convert::Infallible) -> Self {
285        match error {}
286    }
287}