use crate::types::Value;
use crate::VeloxxError;
#[derive(Debug, Clone)]
pub enum Expr {
Column(String),
Literal(Value),
Add(Box<Expr>, Box<Expr>),
Subtract(Box<Expr>, Box<Expr>),
Multiply(Box<Expr>, Box<Expr>),
Divide(Box<Expr>, Box<Expr>),
Equals(Box<Expr>, Box<Expr>),
NotEquals(Box<Expr>, Box<Expr>),
GreaterThan(Box<Expr>, Box<Expr>),
LessThan(Box<Expr>, Box<Expr>),
GreaterThanOrEqual(Box<Expr>, Box<Expr>),
LessThanOrEqual(Box<Expr>, Box<Expr>),
And(Box<Expr>, Box<Expr>),
Or(Box<Expr>, Box<Expr>),
Not(Box<Expr>),
}
impl Expr {
pub fn evaluate(
&self,
df: &crate::dataframe::DataFrame,
row_index: usize,
) -> Result<Value, VeloxxError> {
match self {
Expr::Column(col_name) => {
let series = df
.get_column(col_name)
.ok_or(VeloxxError::ColumnNotFound(col_name.to_string()))?;
series
.get_value(row_index)
.ok_or(VeloxxError::InvalidOperation(format!(
"Null value at row {row_index} in column {col_name}"
)))
}
Expr::Literal(value) => Ok(value.clone()),
Expr::Add(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::I32(l + r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::F64(l + r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for addition".to_string(),
)),
}
}
Expr::Subtract(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::I32(l - r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::F64(l - r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for subtraction".to_string(),
)),
}
}
Expr::Multiply(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::I32(l * r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::F64(l * r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for multiplication".to_string(),
)),
}
}
Expr::Divide(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => {
if r == 0 {
return Err(VeloxxError::InvalidOperation(
"Division by zero".to_string(),
));
}
Ok(Value::I32(l / r))
}
(Value::F64(l), Value::F64(r)) => {
if r == 0.0 {
return Err(VeloxxError::InvalidOperation(
"Division by zero".to_string(),
));
}
Ok(Value::F64(l / r))
}
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for division".to_string(),
)),
}
}
Expr::Equals(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
Ok(Value::Bool(left_val == right_val))
}
Expr::NotEquals(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
Ok(Value::Bool(left_val != right_val))
}
Expr::GreaterThan(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::Bool(l > r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::Bool(l > r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for comparison".to_string(),
)),
}
}
Expr::LessThan(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::Bool(l < r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::Bool(l < r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for comparison".to_string(),
)),
}
}
Expr::GreaterThanOrEqual(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::Bool(l >= r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::Bool(l >= r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for comparison".to_string(),
)),
}
}
Expr::LessThanOrEqual(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::I32(l), Value::I32(r)) => Ok(Value::Bool(l <= r)),
(Value::F64(l), Value::F64(r)) => Ok(Value::Bool(l <= r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for comparison".to_string(),
)),
}
}
Expr::And(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(l && r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for logical AND".to_string(),
)),
}
}
Expr::Or(left, right) => {
let left_val = left.evaluate(df, row_index)?;
let right_val = right.evaluate(df, row_index)?;
match (left_val, right_val) {
(Value::Bool(l), Value::Bool(r)) => Ok(Value::Bool(l || r)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported types for logical OR".to_string(),
)),
}
}
Expr::Not(expr) => {
let val = expr.evaluate(df, row_index)?;
match val {
Value::Bool(b) => Ok(Value::Bool(!b)),
_ => Err(VeloxxError::InvalidOperation(
"Unsupported type for logical NOT".to_string(),
)),
}
}
}
}
}