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}