Skip to main content

prax_sqlite/
error.rs

1//! Error types for SQLite operations.
2
3use std::fmt;
4
5use prax_query::error::QueryError;
6
7/// Result type for SQLite operations.
8pub type SqliteResult<T> = Result<T, SqliteError>;
9
10/// Error type for SQLite operations.
11#[derive(Debug)]
12pub enum SqliteError {
13    /// Pool error.
14    Pool(String),
15    /// SQLite driver error.
16    Sqlite(tokio_rusqlite::Error),
17    /// Configuration error.
18    Config(String),
19    /// Connection error.
20    Connection(String),
21    /// Query error.
22    Query(String),
23    /// Deserialization error.
24    Deserialization(String),
25    /// Type conversion error.
26    TypeConversion(String),
27    /// Timeout error.
28    Timeout(String),
29    /// Internal error.
30    Internal(String),
31    /// Vector extension error (only present with the `vector` feature).
32    #[cfg(feature = "vector")]
33    Vector(crate::vector::error::VectorError),
34}
35
36impl SqliteError {
37    /// Create a pool error.
38    pub fn pool(msg: impl Into<String>) -> Self {
39        Self::Pool(msg.into())
40    }
41
42    /// Create a configuration error.
43    pub fn config(msg: impl Into<String>) -> Self {
44        Self::Config(msg.into())
45    }
46
47    /// Create a connection error.
48    pub fn connection(msg: impl Into<String>) -> Self {
49        Self::Connection(msg.into())
50    }
51
52    /// Create a query error.
53    pub fn query(msg: impl Into<String>) -> Self {
54        Self::Query(msg.into())
55    }
56
57    /// Create a deserialization error.
58    pub fn deserialization(msg: impl Into<String>) -> Self {
59        Self::Deserialization(msg.into())
60    }
61
62    /// Create a type conversion error.
63    pub fn type_conversion(msg: impl Into<String>) -> Self {
64        Self::TypeConversion(msg.into())
65    }
66
67    /// Create a timeout error.
68    pub fn timeout(msg: impl Into<String>) -> Self {
69        Self::Timeout(msg.into())
70    }
71
72    /// Create an internal error.
73    pub fn internal(msg: impl Into<String>) -> Self {
74        Self::Internal(msg.into())
75    }
76}
77
78impl fmt::Display for SqliteError {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match self {
81            Self::Pool(msg) => write!(f, "Pool error: {}", msg),
82            Self::Sqlite(e) => write!(f, "SQLite error: {}", e),
83            Self::Config(msg) => write!(f, "Configuration error: {}", msg),
84            Self::Connection(msg) => write!(f, "Connection error: {}", msg),
85            Self::Query(msg) => write!(f, "Query error: {}", msg),
86            Self::Deserialization(msg) => write!(f, "Deserialization error: {}", msg),
87            Self::TypeConversion(msg) => write!(f, "Type conversion error: {}", msg),
88            Self::Timeout(msg) => write!(f, "Timeout error: {}", msg),
89            Self::Internal(msg) => write!(f, "Internal error: {}", msg),
90            #[cfg(feature = "vector")]
91            Self::Vector(e) => write!(f, "Vector error: {}", e),
92        }
93    }
94}
95
96impl std::error::Error for SqliteError {
97    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
98        match self {
99            Self::Sqlite(e) => Some(e),
100            #[cfg(feature = "vector")]
101            Self::Vector(e) => Some(e),
102            _ => None,
103        }
104    }
105}
106
107impl From<tokio_rusqlite::Error> for SqliteError {
108    fn from(err: tokio_rusqlite::Error) -> Self {
109        Self::Sqlite(err)
110    }
111}
112
113impl From<rusqlite::Error> for SqliteError {
114    fn from(err: rusqlite::Error) -> Self {
115        Self::Sqlite(tokio_rusqlite::Error::Rusqlite(err))
116    }
117}
118
119#[cfg(feature = "vector")]
120impl From<crate::vector::error::VectorError> for SqliteError {
121    fn from(err: crate::vector::error::VectorError) -> Self {
122        Self::Vector(err)
123    }
124}
125
126impl From<SqliteError> for QueryError {
127    fn from(err: SqliteError) -> Self {
128        match err {
129            SqliteError::Pool(msg) => QueryError::connection(msg),
130            SqliteError::Sqlite(e) => QueryError::database(e.to_string()),
131            SqliteError::Config(msg) => QueryError::internal(format!("config: {}", msg)),
132            SqliteError::Connection(msg) => QueryError::connection(msg),
133            SqliteError::Query(msg) => QueryError::database(msg),
134            SqliteError::Deserialization(msg) => QueryError::serialization(msg),
135            SqliteError::TypeConversion(msg) => QueryError::serialization(format!("type: {}", msg)),
136            SqliteError::Timeout(msg) => {
137                // No construct site records the actual duration, so keep
138                // the default-duration placeholder and preserve the
139                // original message as attached context.
140                QueryError::timeout(5000).with_context(format!("SQLite reported: {}", msg))
141            }
142            SqliteError::Internal(msg) => QueryError::internal(msg),
143            #[cfg(feature = "vector")]
144            SqliteError::Vector(e) => QueryError::database(e.to_string()),
145        }
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    #[test]
154    fn test_error_display() {
155        let err = SqliteError::config("invalid path");
156        assert!(err.to_string().contains("Configuration error"));
157        assert!(err.to_string().contains("invalid path"));
158    }
159
160    #[test]
161    fn test_error_constructors() {
162        assert!(matches!(SqliteError::pool("test"), SqliteError::Pool(_)));
163        assert!(matches!(
164            SqliteError::config("test"),
165            SqliteError::Config(_)
166        ));
167        assert!(matches!(
168            SqliteError::connection("test"),
169            SqliteError::Connection(_)
170        ));
171        assert!(matches!(SqliteError::query("test"), SqliteError::Query(_)));
172    }
173
174    #[test]
175    fn test_error_conversion() {
176        let err = SqliteError::timeout("connection timed out");
177        let query_err: QueryError = err.into();
178        assert!(query_err.is_timeout());
179    }
180}