use std::borrow::Cow;
use crate::expr::BinaryOp;
use crate::expr::Expr;
use crate::expr::write_expr;
use crate::types::IntoColumnRef;
use crate::types::IntoIden;
use crate::writer::SqlWriter;
#[derive(Debug, Clone, PartialEq, Eq)]
enum Func {
Max,
Min,
Sum,
Avg,
Cast,
Count,
Coalesce,
Lower,
Upper,
Custom(Cow<'static, str>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionCall {
func: Func,
args: Vec<Expr>,
}
impl FunctionCall {
pub fn max<T>(expr: T) -> Self
where
T: Into<Expr>,
{
Self {
func: Func::Max,
args: vec![expr.into()],
}
}
pub fn min<T>(expr: T) -> Self
where
T: Into<Expr>,
{
Self {
func: Func::Min,
args: vec![expr.into()],
}
}
pub fn sum<T>(expr: T) -> Self
where
T: Into<Expr>,
{
Self {
func: Func::Sum,
args: vec![expr.into()],
}
}
pub fn avg<T>(expr: T) -> Self
where
T: Into<Expr>,
{
Self {
func: Func::Avg,
args: vec![expr.into()],
}
}
pub fn count<T>(expr: T) -> Self
where
T: Into<Expr>,
{
Self {
func: Func::Count,
args: vec![expr.into()],
}
}
pub fn count_all() -> Self {
Self {
func: Func::Count,
args: vec![Expr::Asterisk],
}
}
pub fn coalesce<A, B>(a: A, b: B) -> Self
where
A: Into<Expr>,
B: Into<Expr>,
{
Self {
func: Func::Coalesce,
args: vec![a.into(), b.into()],
}
}
pub fn lower<T>(expr: T) -> FunctionCall
where
T: Into<Expr>,
{
FunctionCall {
func: Func::Lower,
args: vec![expr.into()],
}
}
pub fn upper<T>(expr: T) -> FunctionCall
where
T: Into<Expr>,
{
FunctionCall {
func: Func::Upper,
args: vec![expr.into()],
}
}
pub fn cast_as<V, I>(expr: V, iden: I) -> FunctionCall
where
V: Into<Expr>,
I: IntoIden,
{
let expr = expr.into();
FunctionCall {
func: Func::Cast,
args: vec![expr.binary(BinaryOp::As, Expr::custom(iden.into_iden().into_inner()))],
}
}
pub fn custom<N, T, I>(name: N, args: I) -> Self
where
N: Into<Cow<'static, str>>,
I: IntoIterator<Item = T>,
T: Into<Expr>,
{
Self {
func: Func::Custom(name.into()),
args: args.into_iter().map(|arg| arg.into()).collect(),
}
}
}
impl From<FunctionCall> for Expr {
fn from(call: FunctionCall) -> Self {
Expr::FunctionCall(call)
}
}
pub(crate) fn write_function_call<W: SqlWriter>(w: &mut W, call: &FunctionCall) {
match &call.func {
Func::Max => w.push_str("MAX"),
Func::Min => w.push_str("MIN"),
Func::Sum => w.push_str("SUM"),
Func::Avg => w.push_str("AVG"),
Func::Cast => w.push_str("CAST"),
Func::Count => w.push_str("COUNT"),
Func::Coalesce => w.push_str("COALESCE"),
Func::Lower => w.push_str("LOWER"),
Func::Upper => w.push_str("UPPER"),
Func::Custom(name) => w.push_str(name),
}
w.push_char('(');
for (i, arg) in call.args.iter().enumerate() {
if i > 0 {
w.push_str(", ");
}
write_expr(w, arg);
}
w.push_char(')');
}
pub fn col<T>(col: T) -> Expr
where
T: IntoColumnRef,
{
Expr::column(col)
}