Skip to main content

aegis_client/
error.rs

1//! Aegis Client Error Types
2//!
3//! Error types for client operations.
4//!
5//! @version 0.1.0
6//! @author AutomataNexus Development Team
7
8use std::fmt;
9
10// =============================================================================
11// Client Error
12// =============================================================================
13
14/// Errors that can occur during client operations.
15#[derive(Debug, Clone)]
16pub enum ClientError {
17    /// Connection failed.
18    ConnectionFailed(String),
19    /// Connection timeout.
20    ConnectionTimeout,
21    /// Connection closed.
22    ConnectionClosed,
23    /// Query execution failed.
24    QueryFailed(String),
25    /// Transaction failed.
26    TransactionFailed(String),
27    /// Invalid configuration.
28    InvalidConfig(String),
29    /// Invalid URL format.
30    InvalidUrl(String),
31    /// Authentication failed.
32    AuthenticationFailed(String),
33    /// Pool exhausted.
34    PoolExhausted,
35    /// Pool timeout.
36    PoolTimeout,
37    /// Serialization error.
38    SerializationError(String),
39    /// IO error.
40    IoError(String),
41    /// Protocol error.
42    ProtocolError(String),
43    /// Server error.
44    ServerError { code: i32, message: String },
45    /// Not connected.
46    NotConnected,
47    /// Transaction not started.
48    NoTransaction,
49    /// Transaction already started.
50    TransactionAlreadyStarted,
51}
52
53impl fmt::Display for ClientError {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        match self {
56            Self::ConnectionFailed(msg) => write!(f, "Connection failed: {}", msg),
57            Self::ConnectionTimeout => write!(f, "Connection timeout"),
58            Self::ConnectionClosed => write!(f, "Connection closed"),
59            Self::QueryFailed(msg) => write!(f, "Query failed: {}", msg),
60            Self::TransactionFailed(msg) => write!(f, "Transaction failed: {}", msg),
61            Self::InvalidConfig(msg) => write!(f, "Invalid configuration: {}", msg),
62            Self::InvalidUrl(msg) => write!(f, "Invalid URL: {}", msg),
63            Self::AuthenticationFailed(msg) => write!(f, "Authentication failed: {}", msg),
64            Self::PoolExhausted => write!(f, "Connection pool exhausted"),
65            Self::PoolTimeout => write!(f, "Connection pool timeout"),
66            Self::SerializationError(msg) => write!(f, "Serialization error: {}", msg),
67            Self::IoError(msg) => write!(f, "IO error: {}", msg),
68            Self::ProtocolError(msg) => write!(f, "Protocol error: {}", msg),
69            Self::ServerError { code, message } => {
70                write!(f, "Server error [{}]: {}", code, message)
71            }
72            Self::NotConnected => write!(f, "Not connected"),
73            Self::NoTransaction => write!(f, "No transaction in progress"),
74            Self::TransactionAlreadyStarted => write!(f, "Transaction already started"),
75        }
76    }
77}
78
79impl std::error::Error for ClientError {}
80
81impl ClientError {
82    /// Check if the error is retryable.
83    pub fn is_retryable(&self) -> bool {
84        matches!(
85            self,
86            Self::ConnectionTimeout
87                | Self::ConnectionClosed
88                | Self::PoolExhausted
89                | Self::PoolTimeout
90                | Self::IoError(_)
91        )
92    }
93
94    /// Check if the error is a connection error.
95    pub fn is_connection_error(&self) -> bool {
96        matches!(
97            self,
98            Self::ConnectionFailed(_)
99                | Self::ConnectionTimeout
100                | Self::ConnectionClosed
101                | Self::NotConnected
102        )
103    }
104
105    /// Check if the error is a server error.
106    pub fn is_server_error(&self) -> bool {
107        matches!(self, Self::ServerError { .. })
108    }
109}
110
111// =============================================================================
112// Tests
113// =============================================================================
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_error_display() {
121        let err = ClientError::ConnectionFailed("refused".to_string());
122        assert_eq!(err.to_string(), "Connection failed: refused");
123
124        let err = ClientError::ServerError {
125            code: 500,
126            message: "Internal error".to_string(),
127        };
128        assert_eq!(err.to_string(), "Server error [500]: Internal error");
129    }
130
131    #[test]
132    fn test_is_retryable() {
133        assert!(ClientError::ConnectionTimeout.is_retryable());
134        assert!(ClientError::PoolExhausted.is_retryable());
135        assert!(!ClientError::QueryFailed("syntax".to_string()).is_retryable());
136    }
137
138    #[test]
139    fn test_is_connection_error() {
140        assert!(ClientError::ConnectionFailed("refused".to_string()).is_connection_error());
141        assert!(ClientError::NotConnected.is_connection_error());
142        assert!(!ClientError::QueryFailed("error".to_string()).is_connection_error());
143    }
144}