prax_sqlx/
error.rs

1//! Error types for SQLx operations.
2
3use prax_query::QueryError;
4use thiserror::Error;
5
6/// Result type alias for SQLx operations.
7pub type SqlxResult<T> = Result<T, SqlxError>;
8
9/// Errors that can occur during SQLx operations.
10#[derive(Error, Debug)]
11pub enum SqlxError {
12    /// SQLx database error
13    #[error("Database error: {0}")]
14    Sqlx(#[from] sqlx::Error),
15
16    /// Configuration error
17    #[error("Configuration error: {0}")]
18    Config(String),
19
20    /// Connection error
21    #[error("Connection error: {0}")]
22    Connection(String),
23
24    /// Query execution error
25    #[error("Query error: {0}")]
26    Query(String),
27
28    /// Row deserialization error
29    #[error("Deserialization error: {0}")]
30    Deserialization(String),
31
32    /// Type conversion error
33    #[error("Type conversion error: {0}")]
34    TypeConversion(String),
35
36    /// Pool error
37    #[error("Pool error: {0}")]
38    Pool(String),
39
40    /// Timeout error
41    #[error("Operation timed out after {0}ms")]
42    Timeout(u64),
43
44    /// Migration error
45    #[error("Migration error: {0}")]
46    Migration(String),
47
48    /// Internal error
49    #[error("Internal error: {0}")]
50    Internal(String),
51}
52
53impl From<SqlxError> for QueryError {
54    fn from(err: SqlxError) -> Self {
55        match err {
56            SqlxError::Sqlx(e) => {
57                let msg = e.to_string();
58                if msg.contains("connection") {
59                    QueryError::connection(msg)
60                } else if msg.contains("constraint") || msg.contains("duplicate") {
61                    QueryError::constraint_violation("unknown", msg)
62                } else {
63                    QueryError::database(msg)
64                }
65            }
66            SqlxError::Config(msg) => QueryError::connection(msg),
67            SqlxError::Connection(msg) => QueryError::connection(msg),
68            SqlxError::Query(msg) => QueryError::database(msg),
69            SqlxError::Deserialization(msg) => QueryError::serialization(msg),
70            SqlxError::TypeConversion(msg) => QueryError::serialization(msg),
71            SqlxError::Pool(msg) => QueryError::connection(msg),
72            SqlxError::Timeout(ms) => QueryError::timeout(ms),
73            SqlxError::Migration(msg) => QueryError::database(msg),
74            SqlxError::Internal(msg) => QueryError::internal(msg),
75        }
76    }
77}
78
79impl SqlxError {
80    /// Create a configuration error.
81    pub fn config(msg: impl Into<String>) -> Self {
82        Self::Config(msg.into())
83    }
84
85    /// Create a connection error.
86    pub fn connection(msg: impl Into<String>) -> Self {
87        Self::Connection(msg.into())
88    }
89
90    /// Create a query error.
91    pub fn query(msg: impl Into<String>) -> Self {
92        Self::Query(msg.into())
93    }
94
95    /// Create a pool error.
96    pub fn pool(msg: impl Into<String>) -> Self {
97        Self::Pool(msg.into())
98    }
99
100    /// Create a timeout error.
101    pub fn timeout(ms: u64) -> Self {
102        Self::Timeout(ms)
103    }
104
105    /// Create a type conversion error.
106    pub fn type_conversion(msg: impl Into<String>) -> Self {
107        Self::TypeConversion(msg.into())
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_error_creation() {
117        let err = SqlxError::config("test config error");
118        assert!(matches!(err, SqlxError::Config(_)));
119
120        let err = SqlxError::connection("test connection error");
121        assert!(matches!(err, SqlxError::Connection(_)));
122
123        let err = SqlxError::timeout(5000);
124        assert!(matches!(err, SqlxError::Timeout(5000)));
125    }
126
127    #[test]
128    fn test_error_to_query_error() {
129        let err = SqlxError::connection("connection failed");
130        let query_err: QueryError = err.into();
131        assert!(query_err.to_string().contains("connection"));
132
133        let err = SqlxError::timeout(1000);
134        let query_err: QueryError = err.into();
135        assert!(
136            query_err.to_string().contains("timeout") || query_err.to_string().contains("1000")
137        );
138    }
139}