Skip to main content

mongreldb_kit/
error.rs

1//! Error model for `mongreldb-kit`.
2//!
3//! Storage errors from MongrelDB core and validation errors from the core model
4//! are folded into a small, stable set of categories so consumers can handle
5//! failures without depending on internal crate details.
6
7use thiserror::Error;
8
9pub type Result<T> = std::result::Result<T, KitError>;
10
11/// A storage/transaction error in kit terminology.
12#[derive(Debug, Error, Clone, PartialEq)]
13pub enum KitError {
14    #[error("validation error: {0}")]
15    Validation(String),
16    #[error("duplicate key: {0}")]
17    Duplicate(String),
18    #[error("foreign key violation: {0}")]
19    ForeignKey(String),
20    #[error("restrict violation: {0}")]
21    Restrict(String),
22    #[error("migration error: {0}")]
23    Migration(String),
24    #[error("conflict: {0}")]
25    Conflict(String),
26    #[error("trigger validation error: {0}")]
27    TriggerValidation(String),
28    #[error("storage error: {0}")]
29    Storage(String),
30    #[error("integrity error: {0}")]
31    Integrity(String),
32}
33
34impl From<std::io::Error> for KitError {
35    fn from(e: std::io::Error) -> Self {
36        KitError::Storage(e.to_string())
37    }
38}
39
40impl From<mongreldb_core::MongrelError> for KitError {
41    fn from(e: mongreldb_core::MongrelError) -> Self {
42        use mongreldb_core::MongrelError;
43        match e {
44            MongrelError::Conflict(msg) if is_trigger_error(&msg) => {
45                KitError::TriggerValidation(msg)
46            }
47            MongrelError::Conflict(msg) => KitError::Conflict(msg),
48            MongrelError::InvalidArgument(msg) if is_trigger_error(&msg) => {
49                KitError::TriggerValidation(msg)
50            }
51            MongrelError::InvalidArgument(msg) => KitError::Validation(msg),
52            MongrelError::Schema(msg) => KitError::Validation(msg),
53            MongrelError::ColumnNotFound(msg) => KitError::Integrity(msg),
54            MongrelError::NotFound(msg) => KitError::Integrity(msg),
55            MongrelError::Io(e) => KitError::Storage(e.to_string()),
56            MongrelError::Serialization(e) => KitError::Storage(e.to_string()),
57            MongrelError::ChecksumMismatch { .. }
58            | MongrelError::MagicMismatch { .. }
59            | MongrelError::CorruptWal { .. }
60            | MongrelError::TornWrite { .. } => KitError::Integrity(e.to_string()),
61            MongrelError::EncryptionDisabled
62            | MongrelError::Encryption(_)
63            | MongrelError::Decryption(_) => KitError::Integrity(e.to_string()),
64            MongrelError::Full(msg) => KitError::Storage(msg),
65            MongrelError::Other(msg) => KitError::Storage(msg),
66            _ => KitError::Storage(e.to_string()),
67        }
68    }
69}
70
71fn is_trigger_error(message: &str) -> bool {
72    message.contains("trigger ")
73        || message.contains("Trigger ")
74        || message.contains("external trigger bridge")
75}
76
77impl From<mongreldb_kit_core::schema::SchemaError> for KitError {
78    fn from(e: mongreldb_kit_core::schema::SchemaError) -> Self {
79        KitError::Validation(e.to_string())
80    }
81}
82
83impl From<mongreldb_kit_core::validation::ValidationError> for KitError {
84    fn from(e: mongreldb_kit_core::validation::ValidationError) -> Self {
85        KitError::Validation(e.to_string())
86    }
87}
88
89impl From<mongreldb_kit_core::planner::PlannerError> for KitError {
90    fn from(e: mongreldb_kit_core::planner::PlannerError) -> Self {
91        match e {
92            mongreldb_kit_core::planner::PlannerError::TableNotFound(msg) => {
93                KitError::Integrity(msg)
94            }
95            mongreldb_kit_core::planner::PlannerError::CircularDelete(msg) => {
96                KitError::Restrict(msg)
97            }
98        }
99    }
100}
101
102impl From<serde_json::Error> for KitError {
103    fn from(e: serde_json::Error) -> Self {
104        KitError::Storage(e.to_string())
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::KitError;
111
112    #[test]
113    fn maps_trigger_core_errors_to_trigger_validation() {
114        let conflict = KitError::from(mongreldb_core::MongrelError::Conflict(
115            "trigger raised".into(),
116        ));
117        assert_eq!(
118            conflict,
119            KitError::TriggerValidation("trigger raised".into())
120        );
121
122        let invalid = KitError::from(mongreldb_core::MongrelError::InvalidArgument(
123            "external trigger bridge rejected".into(),
124        ));
125        assert_eq!(
126            invalid,
127            KitError::TriggerValidation("external trigger bridge rejected".into())
128        );
129    }
130}