use crate::types::{BinOper, ColumnRef, DynIden, UnOper, WindowStatement};
use crate::value::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SubQueryOper {
Exists,
NotExists,
In,
NotIn,
All,
Any,
Some,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum SimpleExpr {
Column(ColumnRef),
TableColumn(DynIden, DynIden),
Value(Value),
Unary(UnOper, Box<SimpleExpr>),
Binary(Box<SimpleExpr>, BinOper, Box<SimpleExpr>),
FunctionCall(DynIden, Vec<SimpleExpr>),
SubQuery(Option<SubQueryOper>, Box<crate::query::SelectStatement>),
Tuple(Vec<SimpleExpr>),
Custom(String),
CustomWithExpr(String, Vec<SimpleExpr>),
Constant(Keyword),
Asterisk,
Case(Box<CaseStatement>),
AsEnum(DynIden, Box<SimpleExpr>),
ExprAlias(Box<SimpleExpr>, DynIden),
Cast(Box<SimpleExpr>, DynIden),
Window {
func: Box<SimpleExpr>,
window: WindowStatement,
},
WindowNamed {
func: Box<SimpleExpr>,
name: DynIden,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Keyword {
Null,
True,
False,
Default,
CurrentTimestamp,
CurrentDate,
CurrentTime,
}
impl Keyword {
#[must_use]
pub fn as_str(&self) -> &'static str {
match self {
Self::Null => "NULL",
Self::True => "TRUE",
Self::False => "FALSE",
Self::Default => "DEFAULT",
Self::CurrentTimestamp => "CURRENT_TIMESTAMP",
Self::CurrentDate => "CURRENT_DATE",
Self::CurrentTime => "CURRENT_TIME",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct CaseStatement {
pub when_clauses: Vec<(SimpleExpr, SimpleExpr)>,
pub else_clause: Option<SimpleExpr>,
}
impl CaseStatement {
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn when<C, R>(mut self, condition: C, result: R) -> Self
where
C: Into<SimpleExpr>,
R: Into<SimpleExpr>,
{
self.when_clauses.push((condition.into(), result.into()));
self
}
#[must_use]
pub fn else_result<E>(mut self, result: E) -> Self
where
E: Into<SimpleExpr>,
{
self.else_clause = Some(result.into());
self
}
}
impl SimpleExpr {
pub fn binary(self, op: crate::types::BinOper, right: SimpleExpr) -> Self {
Self::Binary(Box::new(self), op, Box::new(right))
}
}
impl From<Value> for SimpleExpr {
fn from(v: Value) -> Self {
Self::Value(v)
}
}
impl From<ColumnRef> for SimpleExpr {
fn from(c: ColumnRef) -> Self {
Self::Column(c)
}
}
impl From<bool> for SimpleExpr {
fn from(b: bool) -> Self {
Self::Value(Value::Bool(Some(b)))
}
}
impl From<i32> for SimpleExpr {
fn from(i: i32) -> Self {
Self::Value(Value::Int(Some(i)))
}
}
impl From<i64> for SimpleExpr {
fn from(i: i64) -> Self {
Self::Value(Value::BigInt(Some(i)))
}
}
impl From<f32> for SimpleExpr {
fn from(f: f32) -> Self {
Self::Value(Value::Float(Some(f)))
}
}
impl From<f64> for SimpleExpr {
fn from(f: f64) -> Self {
Self::Value(Value::Double(Some(f)))
}
}
impl From<&str> for SimpleExpr {
fn from(s: &str) -> Self {
Self::Value(Value::String(Some(Box::new(s.to_string()))))
}
}
impl From<String> for SimpleExpr {
fn from(s: String) -> Self {
Self::Value(Value::String(Some(Box::new(s))))
}
}
impl From<Keyword> for SimpleExpr {
fn from(k: Keyword) -> Self {
Self::Constant(k)
}
}
impl From<CaseStatement> for SimpleExpr {
fn from(case: CaseStatement) -> Self {
Self::Case(Box::new(case))
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::rstest;
#[rstest]
fn test_simple_expr_from_value() {
let expr: SimpleExpr = Value::Int(Some(42)).into();
assert!(matches!(expr, SimpleExpr::Value(Value::Int(Some(42)))));
}
#[rstest]
fn test_simple_expr_from_bool() {
let expr: SimpleExpr = true.into();
assert!(matches!(expr, SimpleExpr::Value(Value::Bool(Some(true)))));
}
#[rstest]
fn test_simple_expr_from_i32() {
let expr: SimpleExpr = 42i32.into();
assert!(matches!(expr, SimpleExpr::Value(Value::Int(Some(42)))));
}
#[rstest]
fn test_simple_expr_from_str() {
let expr: SimpleExpr = "hello".into();
if let SimpleExpr::Value(Value::String(Some(s))) = expr {
assert_eq!(*s, "hello");
} else {
panic!("Expected String value");
}
}
#[rstest]
fn test_simple_expr_column() {
let col = ColumnRef::column("name");
let expr: SimpleExpr = col.into();
assert!(matches!(expr, SimpleExpr::Column(_)));
}
#[rstest]
fn test_keyword_as_str() {
assert_eq!(Keyword::Null.as_str(), "NULL");
assert_eq!(Keyword::True.as_str(), "TRUE");
assert_eq!(Keyword::False.as_str(), "FALSE");
assert_eq!(Keyword::CurrentTimestamp.as_str(), "CURRENT_TIMESTAMP");
}
#[rstest]
fn test_case_statement_builder() {
let case = CaseStatement::new()
.when(true, 1i32)
.when(false, 0i32)
.else_result(-1i32);
assert_eq!(case.when_clauses.len(), 2);
assert!(case.else_clause.is_some());
}
#[rstest]
fn test_simple_expr_binary() {
let left = SimpleExpr::Column(ColumnRef::column("age"));
let right = SimpleExpr::Value(Value::Int(Some(18)));
let binary =
SimpleExpr::Binary(Box::new(left), BinOper::GreaterThanOrEqual, Box::new(right));
assert!(matches!(
binary,
SimpleExpr::Binary(_, BinOper::GreaterThanOrEqual, _)
));
}
#[rstest]
fn test_simple_expr_unary() {
let inner = SimpleExpr::Value(Value::Bool(Some(true)));
let unary = SimpleExpr::Unary(UnOper::Not, Box::new(inner));
assert!(matches!(unary, SimpleExpr::Unary(UnOper::Not, _)));
}
}