use crate::item::ColumnRef;
use crate::item::FuncCall;
use crate::stmt::data::Data;
use crate::stmt::select::Select;
use crate::stmt::values::Values;
use crate::value::Value;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr<'a> {
Column(ColumnRef<'a>),
Literal(Value<'a>),
FuncCall(FuncCall<'a>),
Prefix(&'static str, Box<Expr<'a>>),
Infix(Box<Expr<'a>>, &'static str, Box<Expr<'a>>),
Postfix(Box<Expr<'a>>, &'static str),
Paren(Box<Expr<'a>>),
SubQuery(Data<'a>),
}
crate::macros::gen_display!(Expr<'_>);
impl<'a> std::convert::From<ColumnRef<'a>> for Expr<'a> {
#[inline]
fn from(val: ColumnRef<'a>) -> Self {
Expr::Column(val)
}
}
impl<'a> std::convert::From<&'a str> for Expr<'a> {
#[inline]
fn from(val: &'a str) -> Self {
Expr::Column(val.into())
}
}
impl<'a> std::convert::From<(&'a str, &'a str)> for Expr<'a> {
#[inline]
fn from(val: (&'a str, &'a str)) -> Self {
Expr::Column(val.into())
}
}
impl<'a> std::convert::From<(&'a str, &'a str, &'a str)> for Expr<'a> {
#[inline]
fn from(val: (&'a str, &'a str, &'a str)) -> Self {
Expr::Column(val.into())
}
}
impl<'a, T> std::convert::From<T> for Expr<'a>
where
T: Into<Value<'a>>,
{
#[inline]
fn from(val: T) -> Self {
Expr::Literal(val.into())
}
}
impl<'a> std::convert::From<FuncCall<'a>> for Expr<'a> {
#[inline]
fn from(val: FuncCall<'a>) -> Self {
Expr::FuncCall(val)
}
}
impl<'a> std::convert::From<Data<'a>> for Expr<'a> {
#[inline]
fn from(val: Data<'a>) -> Self {
Expr::SubQuery(val)
}
}
impl<'a> std::convert::From<Select<'a>> for Expr<'a> {
#[inline]
fn from(val: Select<'a>) -> Self {
Expr::SubQuery(val.into())
}
}
impl<'a> std::convert::From<Values<'a>> for Expr<'a> {
#[inline]
fn from(val: Values<'a>) -> Self {
Expr::SubQuery(val.into())
}
}
#[cfg(test)]
mod tests {
use crate::expr::Expr;
use crate::func::avg;
use crate::func::count;
use crate::func::sum;
use crate::item::ColumnRef;
use crate::item::Ident;
use crate::item::Order;
use crate::item::Sort;
use crate::ops::*;
use crate::value::Value;
#[test]
fn literal() {
assert_eq!(Into::<Expr>::into(true), Expr::Literal(Value::Bool(true)));
assert_eq!(Into::<Expr>::into(false), Expr::Literal(Value::Bool(false)));
assert_eq!(Into::<Expr>::into(8_i8), Expr::Literal(Value::TinyInt(8)));
assert_eq!(
Into::<Expr>::into(16_i16),
Expr::Literal(Value::SmallInt(16))
);
assert_eq!(Into::<Expr>::into(32_i32), Expr::Literal(Value::Int(32)));
assert_eq!(Into::<Expr>::into(64_i64), Expr::Literal(Value::BigInt(64)));
assert_eq!(
Into::<Expr>::into(&"text".to_string()),
Expr::Literal(Value::Text("text"))
);
}
#[test]
fn literal_fmt() {
assert_eq!(Into::<Expr>::into(true).to_string(), "true");
assert_eq!(Into::<Expr>::into(false).to_string(), "false");
assert_eq!(Into::<Expr>::into(8_i8).to_string(), "8");
assert_eq!(Into::<Expr>::into(16_i16).to_string(), "16");
assert_eq!(Into::<Expr>::into(32_i32).to_string(), "32");
assert_eq!(Into::<Expr>::into(64_i64).to_string(), "64");
assert_eq!(
Into::<Expr>::into(&"text".to_string()).to_string(),
"'text'"
);
}
#[test]
fn option() {
assert_eq!(Into::<Expr>::into(None::<i32>).to_string(), "null");
assert_eq!(Into::<Expr>::into(Some(1)).to_string(), "1");
}
#[test]
fn column_ref() {
assert_eq!(
Into::<Expr>::into("id"),
Expr::Column(ColumnRef::Column(Ident("id")))
);
assert_eq!(
Into::<Expr>::into(("user", "id")),
Expr::Column(ColumnRef::TableColumn(Ident("user"), Ident("id")))
);
assert_eq!(
Into::<Expr>::into(("public", "user", "id")),
Expr::Column(ColumnRef::SchemaTableColumn(
Ident("public"),
Ident("user"),
Ident("id")
))
);
}
#[test]
fn func_call() {
assert_eq!(sum("num").to_string(), "sum(num)");
assert_eq!(count("id").to_string(), "count(id)");
assert_eq!(avg("age").to_string(), "avg(age)");
}
#[test]
fn column_ref_fmt() {
assert_eq!(Into::<Expr>::into("id").to_string(), "id",);
assert_eq!(Into::<Expr>::into(("user", "id")).to_string(), "user.id");
assert_eq!(
Into::<Expr>::into(("public", "user", "id")).to_string(),
"public.user.id"
);
}
#[test]
#[rustfmt::skip]
fn ops() {
assert_eq!(add(1, 2), Expr::Infix(Box::new(1.into()), "+", Box::new(2.into())));
assert_eq!(sub(1, 2), Expr::Infix(Box::new(1.into()), "-", Box::new(2.into())));
assert_eq!(mul(1, 2), Expr::Infix(Box::new(1.into()), "*", Box::new(2.into())));
assert_eq!(div(1, 2), Expr::Infix(Box::new(1.into()), "/", Box::new(2.into())));
assert_eq!(rem(1, 2), Expr::Infix(Box::new(1.into()), "%", Box::new(2.into())));
assert_eq!(eq(1, 2), Expr::Infix(Box::new(1.into()), "=", Box::new(2.into())));
assert_eq!(ne(1, 2), Expr::Infix(Box::new(1.into()), "<>", Box::new(2.into())));
assert_eq!(gt(1, 2), Expr::Infix(Box::new(1.into()), ">", Box::new(2.into())));
assert_eq!(ge(1, 2), Expr::Infix(Box::new(1.into()), ">=", Box::new(2.into())));
assert_eq!(lt(1, 2), Expr::Infix(Box::new(1.into()), "<", Box::new(2.into())));
assert_eq!(le(1, 2), Expr::Infix(Box::new(1.into()), "<=", Box::new(2.into())));
assert_eq!(and(1, 2), Expr::Infix(Box::new(1.into()), "AND", Box::new(2.into())));
assert_eq!(or(1, 2), Expr::Infix(Box::new(1.into()), "OR", Box::new(2.into())));
assert_eq!(like(1, 2), Expr::Infix(Box::new(1.into()), "LIKE", Box::new(2.into())));
assert_eq!(ilike(1, 2), Expr::Infix(Box::new(1.into()), "ILIKE", Box::new(2.into())));
assert_eq!(asc("id"), Order(Expr::Column(ColumnRef::Column("id".into())), Some(Sort::Asc)));
assert_eq!(desc("id"), Order(Expr::Column(ColumnRef::Column("id".into())), Some(Sort::Desc)));
assert_eq!(not(true), Expr::Prefix("NOT", Box::new(true.into())));
assert_eq!(isnull("expr"), Expr::Postfix(Box::new("expr".into()), "ISNULL"));
}
#[test]
fn parenthesis() {
let cond1 = or("a", "b");
let cond2 = or("c", "d");
let cond = and(paren(cond1), paren(cond2));
assert_eq!(cond.to_string(), "(a OR b) AND (c OR d)");
}
#[test]
fn subquery() {
use crate::stmt::select;
use crate::stmt::values;
let query = and(select([true]), values([(false,)]));
assert_eq!(query.to_string(), "(SELECT true) AND (VALUES (false))");
}
}