Skip to main content

vantage_sql/primitives/
ternary.rs

1use std::fmt::{Debug, Display};
2
3use vantage_expressions::{Expression, Expressive, ExpressiveEnum};
4
5/// Vendor-aware inline conditional expression.
6///
7/// Renders as:
8/// - **SQLite:**    `IIF(cond, true_val, false_val)`
9/// - **MySQL:**     `IF(cond, true_val, false_val)`
10/// - **PostgreSQL:** `CASE WHEN cond THEN true_val ELSE false_val END`
11///
12/// # Examples
13///
14/// ```ignore
15/// use vantage_sql::primitives::ternary::ternary;
16///
17/// // With Identifier + Operation:
18/// ternary(Identifier::new("role").eq("admin"), "Yes", "No")
19///     .as_alias("is_admin")
20///
21/// // With vendor expression for the condition:
22/// ternary(
23///     postgres_expr!("{} > {}", (Identifier::new("salary")), 100000.0f64),
24///     "high",
25///     "low",
26/// )
27/// ```
28#[derive(Debug, Clone)]
29pub struct Ternary<T: Debug + Display + Clone> {
30    condition: Expression<T>,
31    true_val: Expression<T>,
32    false_val: Expression<T>,
33}
34
35impl<T: Debug + Display + Clone> Ternary<T> {
36    pub fn new(
37        condition: impl Expressive<T>,
38        true_val: impl Expressive<T>,
39        false_val: impl Expressive<T>,
40    ) -> Self {
41        Self {
42            condition: condition.expr(),
43            true_val: true_val.expr(),
44            false_val: false_val.expr(),
45        }
46    }
47
48    fn args(&self) -> Vec<ExpressiveEnum<T>> {
49        vec![
50            ExpressiveEnum::Nested(self.condition.clone()),
51            ExpressiveEnum::Nested(self.true_val.clone()),
52            ExpressiveEnum::Nested(self.false_val.clone()),
53        ]
54    }
55}
56
57/// Shorthand for `Ternary::new(condition, true_val, false_val)`.
58pub fn ternary<T: Debug + Display + Clone>(
59    condition: impl Expressive<T>,
60    true_val: impl Expressive<T>,
61    false_val: impl Expressive<T>,
62) -> Ternary<T> {
63    Ternary::new(condition, true_val, false_val)
64}
65
66// -- SQLite: IIF(cond, true, false) -----------------------------------------
67
68#[cfg(feature = "sqlite")]
69impl Expressive<crate::sqlite::types::AnySqliteType>
70    for Ternary<crate::sqlite::types::AnySqliteType>
71{
72    fn expr(&self) -> Expression<crate::sqlite::types::AnySqliteType> {
73        Expression::new("IIF({}, {}, {})", self.args())
74    }
75}
76
77// -- MySQL: IF(cond, true, false) --------------------------------------------
78
79#[cfg(feature = "mysql")]
80impl Expressive<crate::mysql::types::AnyMysqlType> for Ternary<crate::mysql::types::AnyMysqlType> {
81    fn expr(&self) -> Expression<crate::mysql::types::AnyMysqlType> {
82        Expression::new("IF({}, {}, {})", self.args())
83    }
84}
85
86// -- PostgreSQL: CASE WHEN cond THEN true ELSE false END ---------------------
87
88#[cfg(feature = "postgres")]
89impl Expressive<crate::postgres::types::AnyPostgresType>
90    for Ternary<crate::postgres::types::AnyPostgresType>
91{
92    fn expr(&self) -> Expression<crate::postgres::types::AnyPostgresType> {
93        Expression::new("CASE WHEN {} THEN {} ELSE {} END", self.args())
94    }
95}