keelson_core/expr/
case.rs1use super::convert::IntoExpr;
2use super::node::Expr;
3
4#[derive(Debug, Clone, Default)]
20pub struct CaseBuilder {
21 whens: Vec<(Expr, Expr)>,
22}
23
24impl CaseBuilder {
25 pub fn new() -> CaseBuilder {
28 CaseBuilder::default()
29 }
30
31 #[must_use]
33 pub fn when(mut self, condition: impl IntoExpr, then: impl IntoExpr) -> CaseBuilder {
34 self.whens.push((condition.into_expr(), then.into_expr()));
35 self
36 }
37
38 #[must_use]
40 pub fn else_(self, then: impl IntoExpr) -> Expr {
41 Expr::Case {
42 whens: self.whens,
43 else_: Some(Box::new(then.into_expr())),
44 }
45 .grouped()
46 }
47
48 #[must_use]
50 pub fn end(self) -> Expr {
51 Expr::Case {
52 whens: self.whens,
53 else_: None,
54 }
55 .grouped()
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use keelson_sqlcheck::testing::assert_frag_sql;
62
63 use super::super::{arg, case, literal, quote};
64 use super::*;
65 use crate::dialect::testing::Numbered;
66 use crate::expr::Chain;
67 use crate::writer::build;
68
69 const VALUE: &str = "SELECT {} FROM users";
70
71 fn sql(e: Expr) -> String {
72 build(&Numbered, &e).expect("render").0
73 }
74
75 #[test]
78 fn a_case_with_an_else_branch() {
79 let e = case()
80 .when(quote("id").eq(literal("1")), literal("A"))
81 .else_(literal("B"))
82 .as_("C");
83 assert_frag_sql(
84 VALUE,
85 &sql(e),
86 r#"(CASE WHEN ("id" = '1') THEN 'A' ELSE 'B' END) AS "C""#,
87 );
88 }
89
90 #[test]
92 fn a_case_without_an_else_branch() {
93 let e = case()
94 .when(quote("id").eq(literal("1")), literal("A"))
95 .end()
96 .as_("C");
97 assert_frag_sql(
98 VALUE,
99 &sql(e),
100 r#"(CASE WHEN ("id" = '1') THEN 'A' END) AS "C""#,
101 );
102 }
103
104 #[test]
105 fn branches_render_in_the_order_they_were_added() {
106 let e = case()
107 .when(quote("is_active"), arg(1i32))
108 .when(Expr::raw("age > 1"), arg(2i32))
109 .else_(arg(3i32));
110 let (s, args) = build(&Numbered, &e).unwrap();
111 assert_frag_sql(
116 r#"SELECT "id" FROM users WHERE "age" = CAST({} AS integer)"#,
117 &s,
118 r#"(CASE WHEN "is_active" THEN $1 WHEN age > 1 THEN $2 ELSE $3 END)"#,
119 );
120 assert_eq!(args.len(), 3);
121 }
122
123 #[test]
124 fn a_case_with_no_branches_refuses_to_build() {
125 assert!(build(&Numbered, &CaseBuilder::new().end()).is_err());
126 }
127}