Skip to main content

vantage_sql/primitives/
logical.rs

1//! Logical combinators for SQL conditions: `or_()` and `and_()`.
2//!
3//! These combine two expressions with `OR` / `AND`, wrapping each side
4//! in parentheses to preserve precedence.
5
6use vantage_expressions::{Expression, Expressive, ExpressiveEnum};
7
8/// Combines two conditions with `OR`: `(lhs) OR (rhs)`.
9///
10/// ```ignore
11/// use vantage_sql::primitives::*;
12///
13/// or_(ident("role").eq("admin"), ident("role").eq("superuser"))
14/// // => ("role" = 'admin') OR ("role" = 'superuser')
15/// ```
16pub fn or_<T>(lhs: impl Expressive<T>, rhs: impl Expressive<T>) -> Expression<T> {
17    Expression::new(
18        "({}) OR ({})",
19        vec![
20            ExpressiveEnum::Nested(lhs.expr()),
21            ExpressiveEnum::Nested(rhs.expr()),
22        ],
23    )
24}
25
26/// Combines two conditions with `AND`: `(lhs) AND (rhs)`.
27///
28/// Useful when you need explicit grouping — `with_condition()` already
29/// combines multiple conditions with `AND`, but `and_()` lets you nest
30/// it inside an `or_()`:
31///
32/// ```ignore
33/// use vantage_sql::primitives::*;
34///
35/// // (price > 100 AND in_stock = 1) OR (featured = 1)
36/// or_(
37///     and_(ident("price").gt(100), ident("in_stock").eq(true)),
38///     ident("featured").eq(true),
39/// )
40/// ```
41pub fn and_<T>(lhs: impl Expressive<T>, rhs: impl Expressive<T>) -> Expression<T> {
42    Expression::new(
43        "({}) AND ({})",
44        vec![
45            ExpressiveEnum::Nested(lhs.expr()),
46            ExpressiveEnum::Nested(rhs.expr()),
47        ],
48    )
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn test_or_preview() {
57        let expr: Expression<i32> = or_(
58            Expression::new("a = {}", vec![ExpressiveEnum::Scalar(1)]),
59            Expression::new("b = {}", vec![ExpressiveEnum::Scalar(2)]),
60        );
61        assert_eq!(expr.preview(), "(a = 1) OR (b = 2)");
62    }
63
64    #[test]
65    fn test_and_preview() {
66        let expr: Expression<i32> = and_(
67            Expression::new("a = {}", vec![ExpressiveEnum::Scalar(1)]),
68            Expression::new("b = {}", vec![ExpressiveEnum::Scalar(2)]),
69        );
70        assert_eq!(expr.preview(), "(a = 1) AND (b = 2)");
71    }
72
73    #[test]
74    fn test_nested_or_and() {
75        let expr: Expression<i32> = or_(
76            and_(
77                Expression::new("a = {}", vec![ExpressiveEnum::Scalar(1)]),
78                Expression::new("b = {}", vec![ExpressiveEnum::Scalar(2)]),
79            ),
80            Expression::new("c = {}", vec![ExpressiveEnum::Scalar(3)]),
81        );
82        assert_eq!(expr.preview(), "((a = 1) AND (b = 2)) OR (c = 3)");
83    }
84}