use serde::{Deserialize, Serialize};
use std::fmt;
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExpressionError {
pub error_type: ExpressionErrorType,
pub message: String,
pub position: Option<ExpressionPosition>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ExpressionErrorType {
TypeError,
UndefinedVariable,
UndefinedFunction,
UnknownFunction,
FunctionError,
ArgumentCountError,
InvalidArgumentCount,
Overflow,
IndexOutOfBounds,
NullError,
SyntaxError,
InvalidOperation,
PropertyNotFound,
RuntimeError,
UnsupportedOperation,
TypeConversionError,
OperatorError,
LabelNotFound,
EdgeNotFound,
PathError,
RangeError,
AggregateError,
ValidationError,
FunctionExecutionError,
}
impl std::fmt::Display for ExpressionErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExpressionErrorType::TypeError => write!(f, "Type error"),
ExpressionErrorType::UndefinedVariable => write!(f, "Undefined variable"),
ExpressionErrorType::UndefinedFunction => write!(f, "Undefined function"),
ExpressionErrorType::UnknownFunction => write!(f, "Unknown function"),
ExpressionErrorType::FunctionError => write!(f, "Function error"),
ExpressionErrorType::ArgumentCountError => write!(f, "Argument count error"),
ExpressionErrorType::InvalidArgumentCount => write!(f, "Invalid argument count"),
ExpressionErrorType::Overflow => write!(f, "Overflow error"),
ExpressionErrorType::IndexOutOfBounds => write!(f, "Index out of bounds"),
ExpressionErrorType::NullError => write!(f, "Null error"),
ExpressionErrorType::SyntaxError => write!(f, "Syntax error"),
ExpressionErrorType::InvalidOperation => write!(f, "Invalid operation"),
ExpressionErrorType::PropertyNotFound => write!(f, "Property not found"),
ExpressionErrorType::RuntimeError => write!(f, "Runtime error"),
ExpressionErrorType::UnsupportedOperation => write!(f, "Unsupported operation"),
ExpressionErrorType::TypeConversionError => write!(f, "Type conversion error"),
ExpressionErrorType::OperatorError => write!(f, "Operator error"),
ExpressionErrorType::LabelNotFound => write!(f, "Label not found"),
ExpressionErrorType::EdgeNotFound => write!(f, "Edge not found"),
ExpressionErrorType::PathError => write!(f, "Path error"),
ExpressionErrorType::RangeError => write!(f, "Range error"),
ExpressionErrorType::AggregateError => write!(f, "Aggregate error"),
ExpressionErrorType::ValidationError => write!(f, "Validation error"),
ExpressionErrorType::FunctionExecutionError => write!(f, "Function execution error"),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExpressionPosition {
pub line: usize,
pub column: usize,
pub offset: usize,
pub length: usize,
}
impl ExpressionError {
pub fn new(error_type: ExpressionErrorType, message: impl Into<String>) -> Self {
Self {
error_type,
message: message.into(),
position: None,
}
}
pub fn with_position(
mut self,
line: usize,
column: usize,
offset: usize,
length: usize,
) -> Self {
self.position = Some(ExpressionPosition {
line,
column,
offset,
length,
});
self
}
pub fn type_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::TypeError, message)
}
pub fn undefined_variable(name: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::UndefinedVariable,
format!("Undefined variable: {}", name.into()),
)
}
pub fn undefined_parameter(name: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::UndefinedVariable,
format!("Undefined parameter: {}", name.into()),
)
}
pub fn undefined_function(name: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::UndefinedFunction,
format!("Undefined function: {}", name.into()),
)
}
pub fn argument_count_error(expected: usize, actual: usize) -> Self {
Self::new(
ExpressionErrorType::ArgumentCountError,
format!(
"Argument count error: expected {}, got {}",
expected, actual
),
)
}
pub fn overflow(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::Overflow, message)
}
pub fn index_out_of_bounds(index: isize, size: usize) -> Self {
Self::new(
ExpressionErrorType::IndexOutOfBounds,
format!("Index out of bounds: index {}, size {}", index, size),
)
}
pub fn null_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::NullError, message)
}
pub fn syntax_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::SyntaxError, message)
}
pub fn runtime_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::RuntimeError, message)
}
pub fn function_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::FunctionError, message)
}
pub fn invalid_operation(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::InvalidOperation, message)
}
pub fn property_not_found(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::PropertyNotFound, message)
}
pub fn unknown_function(name: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::UnknownFunction,
format!("Unknown function: {}", name.into()),
)
}
pub fn invalid_argument_count(name: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::InvalidArgumentCount,
format!("Invalid argument count: {}", name.into()),
)
}
pub fn invalid_arity(name: &str, expected: usize, actual: usize) -> Self {
Self::new(
ExpressionErrorType::InvalidArgumentCount,
format!(
"function '{}' expects {} argument(s), got {}",
name, expected, actual
),
)
}
pub fn unsupported_operation(
operation: impl Into<String>,
suggestion: impl Into<String>,
) -> Self {
Self::new(
ExpressionErrorType::UnsupportedOperation,
format!(
"Unsupported operation: {}, suggestion: {}",
operation.into(),
suggestion.into()
),
)
}
pub fn type_conversion_error(from_type: impl Into<String>, to_type: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::TypeConversionError,
format!(
"Type conversion error: cannot convert from {} to {}",
from_type.into(),
to_type.into()
),
)
}
pub fn operator_error(operator: impl Into<String>, message: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::OperatorError,
format!("Operator error: {}: {}", operator.into(), message.into()),
)
}
pub fn label_not_found(label: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::LabelNotFound,
format!("Label not found: {}", label.into()),
)
}
pub fn edge_not_found(edge: impl Into<String>) -> Self {
Self::new(
ExpressionErrorType::EdgeNotFound,
format!("Edge not found: {}", edge.into()),
)
}
pub fn path_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::PathError, message)
}
pub fn range_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::RangeError, message)
}
pub fn aggregate_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::AggregateError, message)
}
pub fn validation_error(message: impl Into<String>) -> Self {
Self::new(ExpressionErrorType::ValidationError, message)
}
}
impl fmt::Display for ExpressionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}: {}", self.error_type, self.message)
}
}
impl From<ExpressionError> for linkrs_core::error::DBError {
fn from(e: ExpressionError) -> Self {
let msg = e.to_string();
Self::expression(msg).with_source(Box::new(e))
}
}