use crate::query::QueryBuilder;
#[derive(Clone)]
pub enum Condition<'a> {
Eq(String, Value<'a>),
Ne(String, Value<'a>),
Lt(String, Value<'a>),
Gt(String, Value<'a>),
Le(String, Value<'a>),
Ge(String, Value<'a>),
And(Box<Condition<'a>>, Box<Condition<'a>>),
Or(Box<Condition<'a>>, Box<Condition<'a>>),
In(String, Vec<Value<'a>>),
NotIn(String, Vec<Value<'a>>),
}
#[derive(Clone)]
pub enum Value<'a> {
Literal(String),
LiteralList(Vec<String>),
Subquery(Box<dyn QueryBuilder<'a> + 'a>),
}
impl<'a> Value<'a> {
pub fn is_numeric(&self) -> bool {
match self {
Value::Literal(literal) => Condition::is_numeric(literal),
_ => false,
}
}
}
impl<'a> std::fmt::Display for Value<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Literal(literal) => write!(f, "{}", literal),
Value::Subquery(subquery) => write!(f, "{}", subquery.to_sql()),
Value::LiteralList(literals) => {
let mut result = String::new();
for (i, literal) in literals.iter().enumerate() {
if i > 0 {
result.push_str(", ");
}
result.push_str(literal);
}
write!(f, "({})", result)
}
}
}
}
impl<'a> Condition<'a> {
fn is_numeric(value: &str) -> bool {
value.parse::<f64>().is_ok() || value.parse::<i64>().is_ok()
}
pub fn build(&self) -> String {
match self {
Condition::Eq(column, value) => {
if column.contains('.') {
format!("{} = {}", column, value)
} else if value.is_numeric() {
format!("{} = {}", column, value)
} else {
format!("{} = '{}'", column, value)
}
}
Condition::Ne(column, value) => {
if value.is_numeric() {
format!("{} <> {}", column, value)
} else {
format!("{} <> '{}'", column, value)
}
}
Condition::Lt(column, value) => {
if value.is_numeric() {
format!("{} < {}", column, value)
} else {
format!("{} < '{}'", column, value)
}
}
Condition::Gt(column, value) => {
if value.is_numeric() {
format!("{} > {}", column, value)
} else {
format!("{} > '{}'", column, value)
}
}
Condition::Le(column, value) => {
if value.is_numeric() {
format!("{} <= {}", column, value)
} else {
format!("{} <= '{}'", column, value)
}
}
Condition::Ge(column, value) => {
if value.is_numeric() {
format!("{} >= {}", column, value)
} else {
format!("{} >= '{}'", column, value)
}
}
Condition::And(left, right) => format!("({}) AND ({})", left.build(), right.build()),
Condition::Or(left, right) => format!("({}) OR ({})", left.build(), right.build()),
Condition::In(column, values) => {
let values = values
.iter()
.map(|v| format!("'{}'", v))
.collect::<Vec<String>>()
.join(", ");
format!("{} IN ({})", column, values)
}
Condition::NotIn(column, values) => {
let values = values
.iter()
.map(|v| format!("'{}'", v))
.collect::<Vec<String>>()
.join(", ");
format!("{} NOT IN ({})", column, values)
}
}
}
}