use crate::provider::DbValue;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AggKind {
Count,
Sum,
Avg,
Min,
Max,
}
impl AggKind {
pub fn sql_name(&self) -> &'static str {
match self {
AggKind::Count => "COUNT",
AggKind::Sum => "SUM",
AggKind::Avg => "AVG",
AggKind::Min => "MIN",
AggKind::Max => "MAX",
}
}
pub fn from_name(name: &str) -> Option<Self> {
match name.to_uppercase().as_str() {
"COUNT" => Some(AggKind::Count),
"SUM" => Some(AggKind::Sum),
"AVG" => Some(AggKind::Avg),
"MIN" => Some(AggKind::Min),
"MAX" => Some(AggKind::Max),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompareOp {
Eq,
Ne,
Gt,
Ge,
Lt,
Le,
}
impl CompareOp {
pub fn sql_name(&self) -> &'static str {
match self {
CompareOp::Eq => "=",
CompareOp::Ne => "!=",
CompareOp::Gt => ">",
CompareOp::Ge => ">=",
CompareOp::Lt => "<",
CompareOp::Le => "<=",
}
}
pub fn from_symbol(symbol: &str) -> Option<Self> {
match symbol {
"=" => Some(CompareOp::Eq),
"!=" => Some(CompareOp::Ne),
">" => Some(CompareOp::Gt),
">=" => Some(CompareOp::Ge),
"<" => Some(CompareOp::Lt),
"<=" => Some(CompareOp::Le),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub enum HavingExpr {
Compare {
agg: AggKind,
col: String,
op: CompareOp,
value: DbValue,
},
And(Box<HavingExpr>, Box<HavingExpr>),
Or(Box<HavingExpr>, Box<HavingExpr>),
Not(Box<HavingExpr>),
CompareAgg {
left_agg: AggKind,
left_col: String,
op: CompareOp,
right_agg: AggKind,
right_col: String,
},
}
impl HavingExpr {
pub fn to_sql(
&self,
gen: &dyn crate::provider::ISqlGenerator,
param_idx: &mut usize,
) -> String {
match self {
Self::Compare {
agg,
col,
op,
value: _,
} => {
let placeholder = gen.parameter_placeholder(*param_idx);
*param_idx += 1;
format!(
"{}({}) {} {}",
agg.sql_name(),
col,
op.sql_name(),
placeholder
)
}
Self::And(left, right) => format!(
"({} AND {})",
left.to_sql(gen, param_idx),
right.to_sql(gen, param_idx)
),
Self::Or(left, right) => format!(
"({} OR {})",
left.to_sql(gen, param_idx),
right.to_sql(gen, param_idx)
),
Self::Not(inner) => format!("NOT ({})", inner.to_sql(gen, param_idx)),
Self::CompareAgg {
left_agg,
left_col,
op,
right_agg,
right_col,
} => format!(
"{}({}) {} {}({})",
left_agg.sql_name(),
left_col,
op.sql_name(),
right_agg.sql_name(),
right_col
),
}
}
pub fn collect_params(&self) -> Vec<DbValue> {
match self {
Self::Compare { value, .. } => vec![value.clone()],
Self::And(left, right) | Self::Or(left, right) => {
let mut v = left.collect_params();
v.extend(right.collect_params());
v
}
Self::Not(inner) => inner.collect_params(),
Self::CompareAgg { .. } => Vec::new(),
}
}
}