use thiserror::Error;
pub type Result<T> = std::result::Result<T, TqlError>;
#[derive(Error, Debug, Clone, PartialEq)]
pub enum TqlError {
#[error("Parse error at position {position}: {message}")]
ParseError {
message: String,
position: usize,
query: Option<String>,
},
#[error("Syntax error: {message}")]
SyntaxError {
message: String,
position: Option<usize>,
query: Option<String>,
suggestions: Vec<String>,
},
#[error("Field error: {0}")]
FieldError(String),
#[error("Type error: {0}")]
TypeError(String),
#[error("Type error: {0}")]
TypeHintCoercion(String),
#[error("Operator error: {0}")]
OperatorError(String),
#[error("Value error: {0}")]
ValueError(String),
#[error("Execution error: {0}")]
ExecutionError(String),
#[error("Validation error: {0}")]
ValidationError(String),
#[error("Unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("I/O error: {0}")]
IoError(String),
#[error("Network error: {0}")]
NetworkError(String),
#[error("Mutator error: {0}")]
MutatorError(String),
}
impl From<std::io::Error> for TqlError {
fn from(err: std::io::Error) -> Self {
TqlError::IoError(err.to_string())
}
}
impl From<serde_json::Error> for TqlError {
fn from(err: serde_json::Error) -> Self {
TqlError::ExecutionError(format!("JSON error: {}", err))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = TqlError::ParseError {
message: "Unexpected token".to_string(),
position: 5,
query: Some("field eq".to_string()),
};
assert!(err.to_string().contains("position 5"));
}
#[test]
fn test_syntax_error_with_suggestions() {
let err = TqlError::SyntaxError {
message: "Missing value".to_string(),
position: Some(8),
query: Some("field eq".to_string()),
suggestions: vec!["field eq 'value'".to_string()],
};
assert!(err.to_string().contains("Syntax error"));
}
#[test]
fn test_io_error_conversion() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let tql_err: TqlError = io_err.into();
assert!(matches!(tql_err, TqlError::IoError(_)));
}
}