Skip to main content

rullst_orm/
error.rs

1use std::error::Error;
2use std::fmt;
3
4/// The standard error type for rullst-orm, shielding users from internal dependency errors.
5#[derive(Debug, Clone)]
6#[non_exhaustive]
7pub enum RullstError {
8    /// The global ORM state has not been initialized yet.
9    NotInitialized,
10    /// The global ORM state was already initialized by an earlier call.
11    AlreadyInitialized,
12    /// A record was not found in the database.
13    RecordNotFound,
14    /// A general database or query error.
15    DatabaseError(String),
16    /// A serialization or deserialization error (e.g., JSON).
17    SerializationError(String),
18    /// A cache or event-related error.
19    CacheError(String),
20    /// A database commit succeeded, but one or more post-commit effects failed.
21    PostCommit(String),
22    /// A validation error, such as invalid SQL identifiers.
23    Validation(String),
24    /// Other internal errors.
25    Internal(String),
26}
27
28impl fmt::Display for RullstError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            RullstError::NotInitialized => {
32                write!(
33                    f,
34                    "Orm is not initialized. Call Orm::init() before querying."
35                )
36            }
37            RullstError::AlreadyInitialized => write!(f, "Orm has already been initialized"),
38            RullstError::RecordNotFound => write!(f, "Record not found"),
39            RullstError::DatabaseError(msg) => write!(f, "Database error: {}", msg),
40            RullstError::SerializationError(msg) => write!(f, "Serialization error: {}", msg),
41            RullstError::CacheError(msg) => write!(f, "Cache error: {}", msg),
42            RullstError::PostCommit(msg) => {
43                write!(
44                    f,
45                    "Database committed, but a post-commit effect failed: {}",
46                    msg
47                )
48            }
49            RullstError::Validation(msg) => write!(f, "Validation error: {}", msg),
50            RullstError::Internal(msg) => write!(f, "Internal error: {}", msg),
51        }
52    }
53}
54
55impl Error for RullstError {}
56
57impl From<sqlx::Error> for RullstError {
58    fn from(err: sqlx::Error) -> Self {
59        match err {
60            sqlx::Error::RowNotFound => RullstError::RecordNotFound,
61            _ => RullstError::DatabaseError(err.to_string()),
62        }
63    }
64}
65
66impl From<serde_json::Error> for RullstError {
67    fn from(err: serde_json::Error) -> Self {
68        RullstError::SerializationError(err.to_string())
69    }
70}
71
72impl From<crate::privacy::PrivacyError> for RullstError {
73    fn from(err: crate::privacy::PrivacyError) -> Self {
74        RullstError::Internal(err.to_string())
75    }
76}
77
78#[cfg(feature = "redis")]
79impl From<redis::RedisError> for RullstError {
80    #[cfg_attr(test, mutants::skip)]
81    fn from(err: redis::RedisError) -> Self {
82        RullstError::CacheError(err.to_string())
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_rullst_error_display() {
92        assert_eq!(
93            RullstError::NotInitialized.to_string(),
94            "Orm is not initialized. Call Orm::init() before querying."
95        );
96        assert_eq!(
97            RullstError::AlreadyInitialized.to_string(),
98            "Orm has already been initialized"
99        );
100        assert_eq!(RullstError::RecordNotFound.to_string(), "Record not found");
101        assert_eq!(
102            RullstError::DatabaseError("msg".to_string()).to_string(),
103            "Database error: msg"
104        );
105        assert_eq!(
106            RullstError::SerializationError("msg".to_string()).to_string(),
107            "Serialization error: msg"
108        );
109        assert_eq!(
110            RullstError::PostCommit("msg".to_string()).to_string(),
111            "Database committed, but a post-commit effect failed: msg"
112        );
113        assert_eq!(
114            RullstError::Validation("msg".to_string()).to_string(),
115            "Validation error: msg"
116        );
117        assert_eq!(
118            RullstError::Internal("msg".to_string()).to_string(),
119            "Internal error: msg"
120        );
121    }
122
123    #[test]
124    fn test_rullst_error_from() {
125        let sqlx_err = sqlx::Error::RowNotFound;
126        let err: RullstError = sqlx_err.into();
127        assert!(matches!(err, RullstError::RecordNotFound));
128
129        let sqlx_other_err = sqlx::Error::PoolClosed;
130        let err2: RullstError = sqlx_other_err.into();
131        assert!(matches!(err2, RullstError::DatabaseError(_)));
132    }
133
134    #[test]
135    fn test_serde_json_error_from() {
136        let json_err = serde_json::from_str::<serde_json::Value>("{invalid}").unwrap_err();
137        let err: RullstError = json_err.into();
138        assert!(matches!(err, RullstError::SerializationError(_)));
139        assert!(err.to_string().contains("Serialization error:"));
140    }
141
142    #[cfg(feature = "redis")]
143    #[test]
144    fn test_redis_error_from() {
145        let redis_err = redis::RedisError::from((redis::ErrorKind::Io, "redis io error"));
146        let err: RullstError = redis_err.into();
147        assert!(matches!(err, RullstError::CacheError(_)));
148        assert_eq!(err.to_string(), "Cache error: redis io error - Io");
149    }
150}