Skip to main content

toasty_core/stmt/
expr_in_subquery.rs

1use crate::stmt::{Node, Visit, VisitMut};
2
3use super::{Expr, Query};
4
5/// Tests whether a value is in the results of a subquery.
6///
7/// Returns `true` if `expr` matches any row returned by `query`, or the
8/// opposite when `negated` is set. The flag makes `NOT IN` a predicate in
9/// its own right rather than the negation of `IN`: statement normalization
10/// attaches variant guards to the predicate before expanding the negated
11/// form to `not(in_subquery(..))`, so the guards end up outside the
12/// negation.
13///
14/// # Examples
15///
16/// ```text
17/// in_subquery(x, select(...))      // returns `true` if `x` is in the subquery results
18/// not_in_subquery(x, select(...))  // returns `true` if `x` is not in the subquery results
19/// ```
20#[derive(Debug, Clone, PartialEq)]
21pub struct ExprInSubquery {
22    /// The value to search for.
23    pub expr: Box<Expr>,
24
25    /// The subquery to search within.
26    pub query: Box<Query>,
27
28    /// Whether the check is `NOT IN`.
29    pub negated: bool,
30}
31
32impl Expr {
33    /// Creates an `IN (subquery)` expression: `lhs IN (SELECT ...)`.
34    pub fn in_subquery(lhs: impl Into<Self>, rhs: impl Into<Query>) -> Self {
35        ExprInSubquery {
36            expr: Box::new(lhs.into()),
37            query: Box::new(rhs.into()),
38            negated: false,
39        }
40        .into()
41    }
42
43    /// Creates a `NOT IN (subquery)` expression: `lhs NOT IN (SELECT ...)`.
44    pub fn not_in_subquery(lhs: impl Into<Self>, rhs: impl Into<Query>) -> Self {
45        ExprInSubquery {
46            expr: Box::new(lhs.into()),
47            query: Box::new(rhs.into()),
48            negated: true,
49        }
50        .into()
51    }
52
53    /// Returns `true` if this expression is an `IN (subquery)` check.
54    pub fn is_in_subquery(&self) -> bool {
55        matches!(self, Self::InSubquery(_))
56    }
57}
58
59impl Node for ExprInSubquery {
60    fn visit<V: Visit>(&self, mut visit: V) {
61        visit.visit_expr_in_subquery(self);
62    }
63
64    fn visit_mut<V: VisitMut>(&mut self, mut visit: V) {
65        visit.visit_expr_in_subquery_mut(self);
66    }
67}
68
69impl From<ExprInSubquery> for Expr {
70    fn from(value: ExprInSubquery) -> Self {
71        Self::InSubquery(value)
72    }
73}