use super::convert::IntoExpr;
use super::node::Expr;
#[derive(Debug, Clone, Default)]
pub struct CaseBuilder {
whens: Vec<(Expr, Expr)>,
}
impl CaseBuilder {
pub fn new() -> CaseBuilder {
CaseBuilder::default()
}
#[must_use]
pub fn when(mut self, condition: impl IntoExpr, then: impl IntoExpr) -> CaseBuilder {
self.whens.push((condition.into_expr(), then.into_expr()));
self
}
#[must_use]
pub fn else_(self, then: impl IntoExpr) -> Expr {
Expr::Case {
whens: self.whens,
else_: Some(Box::new(then.into_expr())),
}
.grouped()
}
#[must_use]
pub fn end(self) -> Expr {
Expr::Case {
whens: self.whens,
else_: None,
}
.grouped()
}
}
#[cfg(test)]
mod tests {
use keelson_sqlcheck::testing::assert_frag_sql;
use super::super::{arg, case, literal, quote};
use super::*;
use crate::dialect::testing::Numbered;
use crate::expr::Chain;
use crate::writer::build;
const VALUE: &str = "SELECT {} FROM users";
fn sql(e: Expr) -> String {
build(&Numbered, &e).expect("render").0
}
#[test]
fn a_case_with_an_else_branch() {
let e = case()
.when(quote("id").eq(literal("1")), literal("A"))
.else_(literal("B"))
.as_("C");
assert_frag_sql(
VALUE,
&sql(e),
r#"(CASE WHEN ("id" = '1') THEN 'A' ELSE 'B' END) AS "C""#,
);
}
#[test]
fn a_case_without_an_else_branch() {
let e = case()
.when(quote("id").eq(literal("1")), literal("A"))
.end()
.as_("C");
assert_frag_sql(
VALUE,
&sql(e),
r#"(CASE WHEN ("id" = '1') THEN 'A' END) AS "C""#,
);
}
#[test]
fn branches_render_in_the_order_they_were_added() {
let e = case()
.when(quote("is_active"), arg(1i32))
.when(Expr::raw("age > 1"), arg(2i32))
.else_(arg(3i32));
let (s, args) = build(&Numbered, &e).unwrap();
assert_frag_sql(
r#"SELECT "id" FROM users WHERE "age" = CAST({} AS integer)"#,
&s,
r#"(CASE WHEN "is_active" THEN $1 WHEN age > 1 THEN $2 ELSE $3 END)"#,
);
assert_eq!(args.len(), 3);
}
#[test]
fn a_case_with_no_branches_refuses_to_build() {
assert!(build(&Numbered, &CaseBuilder::new().end()).is_err());
}
}