Skip to main content

qail_core/
error.rs

1//! Error types for QAIL.
2
3/// Error types for QAIL operations.
4#[derive(Debug)]
5pub enum QailError {
6    /// Failed to parse the QAIL query string.
7    Parse {
8        /// Byte offset of the error.
9        position: usize,
10        /// Human-readable error message.
11        message: String,
12    },
13
14    /// Invalid action (must be get, set, del, or add).
15    InvalidAction(String),
16
17    /// Required syntax symbol is missing.
18    MissingSymbol {
19        /// The missing symbol.
20        symbol: &'static str,
21        /// Description of the expected symbol.
22        description: &'static str,
23    },
24
25    /// Invalid operator in expression.
26    InvalidOperator(String),
27
28    /// Invalid value in expression.
29    InvalidValue(String),
30
31    /// Database-layer error.
32    Database(String),
33
34    /// Connection-layer error.
35    Connection(String),
36
37    /// Execution-layer error.
38    Execution(String),
39
40    /// Validation error.
41    Validation(String),
42
43    /// Configuration error.
44    Config(String),
45
46    /// I/O error.
47    Io(std::io::Error),
48}
49
50impl QailError {
51    /// Create a parse error at the given position.
52    pub fn parse(position: usize, message: impl Into<String>) -> Self {
53        Self::Parse {
54            position,
55            message: message.into(),
56        }
57    }
58
59    /// Create a missing symbol error.
60    pub fn missing(symbol: &'static str, description: &'static str) -> Self {
61        Self::MissingSymbol {
62            symbol,
63            description,
64        }
65    }
66}
67
68impl std::fmt::Display for QailError {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            Self::Parse { position, message } => {
72                write!(f, "Parse error at position {position}: {message}")
73            }
74            Self::InvalidAction(action) => {
75                write!(
76                    f,
77                    "Invalid action: '{action}'. Expected: get, set, del, or add"
78                )
79            }
80            Self::MissingSymbol {
81                symbol,
82                description,
83            } => {
84                write!(f, "Missing required symbol: {symbol} ({description})")
85            }
86            Self::InvalidOperator(op) => write!(f, "Invalid operator: '{op}'"),
87            Self::InvalidValue(value) => write!(f, "Invalid value: {value}"),
88            Self::Database(msg) => write!(f, "Database error: {msg}"),
89            Self::Connection(msg) => write!(f, "Connection error: {msg}"),
90            Self::Execution(msg) => write!(f, "Execution error: {msg}"),
91            Self::Validation(msg) => write!(f, "Validation error: {msg}"),
92            Self::Config(msg) => write!(f, "Configuration error: {msg}"),
93            Self::Io(err) => write!(f, "IO error: {err}"),
94        }
95    }
96}
97
98impl std::error::Error for QailError {
99    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
100        match self {
101            Self::Io(err) => Some(err),
102            _ => None,
103        }
104    }
105}
106
107impl From<std::io::Error> for QailError {
108    fn from(value: std::io::Error) -> Self {
109        Self::Io(value)
110    }
111}
112
113/// Result type alias for QAIL operations.
114pub type QailResult<T> = Result<T, QailError>;
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_error_display() {
122        let err = QailError::parse(5, "unexpected character");
123        assert_eq!(
124            err.to_string(),
125            "Parse error at position 5: unexpected character"
126        );
127    }
128}