use arrow::compute::can_cast_types;
use arrow::datatypes::DataType;
use arrow_schema::Schema;
use uuid::Uuid;
use crate::catalog::{INTERNAL_ROW_ID_FIELD_NAME, Scalar};
use crate::expr::like::Like;
use crate::expr::{BinaryExpr, BinaryOp, Case, Cast, Expr, Function, InList, Literal, TryCast};
use crate::{ILError, ILResult};
impl Expr {
pub fn eq(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::Eq,
right: Box::new(other),
})
}
pub fn neq(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::NotEq,
right: Box::new(other),
})
}
pub fn gt(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::Gt,
right: Box::new(other),
})
}
pub fn gteq(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::GtEq,
right: Box::new(other),
})
}
pub fn lt(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::Lt,
right: Box::new(other),
})
}
pub fn lteq(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::LtEq,
right: Box::new(other),
})
}
pub fn plus(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::Plus,
right: Box::new(other),
})
}
pub fn and(self, other: Expr) -> Expr {
Expr::BinaryExpr(BinaryExpr {
left: Box::new(self),
op: BinaryOp::And,
right: Box::new(other),
})
}
pub fn is_null(self) -> Expr {
Expr::IsNull(Box::new(self))
}
pub fn is_not_null(self) -> Expr {
Expr::IsNotNull(Box::new(self))
}
pub fn like(self, other: Expr) -> Expr {
Expr::Like(Like::new(false, Box::new(self), Box::new(other), false))
}
pub fn not_like(self, other: Expr) -> Expr {
Expr::Like(Like::new(true, Box::new(self), Box::new(other), false))
}
pub fn ilike(self, other: Expr) -> Expr {
Expr::Like(Like::new(false, Box::new(self), Box::new(other), true))
}
pub fn not_ilike(self, other: Expr) -> Expr {
Expr::Like(Like::new(true, Box::new(self), Box::new(other), true))
}
}
pub fn col(name: &str) -> Expr {
Expr::Column(name.to_string())
}
pub fn lit(value: impl Into<Scalar>) -> Expr {
Expr::Literal(Literal {
value: value.into(),
})
}
pub fn func(name: impl Into<String>, args: Vec<Expr>, return_type: DataType) -> Expr {
Expr::Function(Function {
name: name.into(),
args,
return_type,
})
}
pub fn try_cast(expr: Expr, schema: &Schema, cast_type: DataType) -> ILResult<Expr> {
let expr_type = expr.data_type(schema)?;
if expr_type == cast_type {
Ok(expr)
} else if can_cast_types(&expr_type, &cast_type) {
Ok(Expr::TryCast(TryCast {
expr: Box::new(expr),
cast_type,
}))
} else {
Err(ILError::not_supported(format!(
"Unsupported TRY_CAST from {expr_type} to {cast_type}"
)))
}
}
pub fn row_ids_in_list_expr(row_ids: Vec<Uuid>) -> Expr {
let col = col(INTERNAL_ROW_ID_FIELD_NAME);
let mut list = Vec::new();
for row_id in row_ids {
let scalar = Scalar::FixedSizeBinary(16, Some(row_id.into_bytes().to_vec()));
list.push(lit(scalar));
}
Expr::InList(InList {
expr: Box::new(col),
list,
negated: false,
})
}
impl From<Scalar> for Expr {
fn from(value: Scalar) -> Self {
Expr::Literal(Literal { value })
}
}
impl From<BinaryExpr> for Expr {
fn from(value: BinaryExpr) -> Self {
Expr::BinaryExpr(value)
}
}
impl From<Cast> for Expr {
fn from(value: Cast) -> Self {
Expr::Cast(value)
}
}
impl From<TryCast> for Expr {
fn from(value: TryCast) -> Self {
Expr::TryCast(value)
}
}
impl From<Like> for Expr {
fn from(value: Like) -> Self {
Expr::Like(value)
}
}
impl From<Case> for Expr {
fn from(value: Case) -> Self {
Expr::Case(value)
}
}