sea_query/query/case.rs
1use crate::{Condition, IntoCondition, SimpleExpr};
2
3#[derive(Debug, Clone, PartialEq)]
4pub(crate) struct CaseStatementCondition {
5 pub(crate) condition: Condition,
6 pub(crate) result: SimpleExpr,
7}
8
9#[derive(Debug, Clone, Default, PartialEq)]
10pub struct CaseStatement {
11 pub(crate) when: Vec<CaseStatementCondition>,
12 pub(crate) r#else: Option<SimpleExpr>,
13}
14
15impl CaseStatement {
16 /// Creates a new case statement expression
17 ///
18 /// # Examples
19 ///
20 /// ```
21 /// use sea_query::{*, tests_cfg::*};
22 ///
23 /// let query = Query::select()
24 /// .expr_as(
25 /// CaseStatement::new()
26 /// .case(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([2, 4]), true)
27 /// .finally(false),
28 /// Alias::new("is_even")
29 /// )
30 /// .from(Glyph::Table)
31 /// .to_owned();
32 ///
33 /// assert_eq!(
34 /// query.to_string(PostgresQueryBuilder),
35 /// r#"SELECT (CASE WHEN ("glyph"."aspect" IN (2, 4)) THEN TRUE ELSE FALSE END) AS "is_even" FROM "glyph""#
36 /// );
37 /// ```
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 /// Adds new `CASE WHEN` to existing case statement.
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// use sea_query::{*, tests_cfg::*};
48 ///
49 /// let query = Query::select()
50 /// .expr_as(
51 /// Expr::case(
52 /// Expr::col((Glyph::Table, Glyph::Aspect)).gt(0),
53 /// "positive"
54 /// )
55 /// .case(
56 /// Expr::col((Glyph::Table, Glyph::Aspect)).lt(0),
57 /// "negative"
58 /// )
59 /// .finally("zero"),
60 /// Alias::new("polarity")
61 /// )
62 /// .from(Glyph::Table)
63 /// .to_owned();
64 ///
65 /// assert_eq!(
66 /// query.to_string(PostgresQueryBuilder),
67 /// r#"SELECT (CASE WHEN ("glyph"."aspect" > 0) THEN 'positive' WHEN ("glyph"."aspect" < 0) THEN 'negative' ELSE 'zero' END) AS "polarity" FROM "glyph""#
68 /// );
69 /// ```
70 pub fn case<C, T>(mut self, cond: C, then: T) -> Self
71 where
72 C: IntoCondition,
73 T: Into<SimpleExpr>,
74 {
75 self.when.push(CaseStatementCondition {
76 condition: cond.into_condition(),
77 result: then.into(),
78 });
79 self
80 }
81
82 /// Ends the case statement with the final `ELSE` result.
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// use sea_query::{*, tests_cfg::*};
88 ///
89 /// let query = Query::select()
90 /// .expr_as(
91 /// Expr::case(
92 /// Cond::any()
93 /// .add(Expr::col((Character::Table, Character::FontSize)).gt(48))
94 /// .add(Expr::col((Character::Table, Character::SizeW)).gt(500)),
95 /// "large"
96 /// )
97 /// .case(
98 /// Cond::any()
99 /// .add(Expr::col((Character::Table, Character::FontSize)).between(24,48))
100 /// .add(Expr::col((Character::Table, Character::SizeW)).between(300,500)),
101 /// "medium"
102 /// )
103 /// .finally("small"),
104 /// Alias::new("char_size"))
105 /// .from(Character::Table)
106 /// .to_owned();
107 ///
108 /// assert_eq!(
109 /// query.to_string(PostgresQueryBuilder),
110 /// [
111 /// r#"SELECT"#,
112 /// r#"(CASE WHEN ("character"."font_size" > 48 OR "character"."size_w" > 500) THEN 'large'"#,
113 /// r#"WHEN (("character"."font_size" BETWEEN 24 AND 48) OR ("character"."size_w" BETWEEN 300 AND 500)) THEN 'medium'"#,
114 /// r#"ELSE 'small' END) AS "char_size""#,
115 /// r#"FROM "character""#
116 /// ]
117 /// .join(" ")
118 /// );
119 /// ```
120 pub fn finally<E>(mut self, r#else: E) -> Self
121 where
122 E: Into<SimpleExpr>,
123 {
124 self.r#else = Some(r#else.into());
125 self
126 }
127}
128
129#[allow(clippy::from_over_into)]
130impl Into<SimpleExpr> for CaseStatement {
131 fn into(self) -> SimpleExpr {
132 SimpleExpr::Case(Box::new(self))
133 }
134}
135
136#[cfg(test)]
137mod test {
138 use crate::*;
139
140 #[test]
141 #[cfg(feature = "backend-postgres")]
142 fn test_where_case_eq() {
143 let case_statement: SimpleExpr = Expr::case(
144 Expr::col(Alias::new("col")).lt(5),
145 Expr::col(Alias::new("othercol")),
146 )
147 .finally(Expr::col(Alias::new("finalcol")))
148 .into();
149
150 let result = Query::select()
151 .column(Asterisk)
152 .from(Alias::new("tbl"))
153 .and_where(case_statement.eq(10))
154 .to_string(PostgresQueryBuilder);
155 assert_eq!(
156 result,
157 r#"SELECT * FROM "tbl" WHERE (CASE WHEN ("col" < 5) THEN "othercol" ELSE "finalcol" END) = 10"#
158 );
159 }
160}