diesel/query_builder/
where_clause.rs

1use super::from_clause::AsQuerySource;
2use super::*;
3use crate::backend::DieselReserveSpecialization;
4use crate::expression::grouped::Grouped;
5use crate::expression::operators::{And, Or};
6use crate::expression::*;
7use crate::sql_types::BoolOrNullableBool;
8
9/// Add `Predicate` to the current `WHERE` clause, joining with `AND` if
10/// applicable.
11pub trait WhereAnd<Predicate> {
12    /// What is the type of the resulting `WHERE` clause?
13    type Output;
14
15    /// See the trait-level docs.
16    fn and(self, predicate: Predicate) -> Self::Output;
17}
18
19/// Add `Predicate` to the current `WHERE` clause, joining with `OR` if
20/// applicable.
21pub trait WhereOr<Predicate> {
22    /// What is the type of the resulting `WHERE` clause?
23    type Output;
24
25    /// See the trait-level docs.
26    fn or(self, predicate: Predicate) -> Self::Output;
27}
28
29/// Represents that a query has no `WHERE` clause.
30#[derive(Debug, Clone, Copy, QueryId)]
31pub struct NoWhereClause;
32
33impl<DB> QueryFragment<DB> for NoWhereClause
34where
35    DB: Backend + DieselReserveSpecialization,
36{
37    fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
38        Ok(())
39    }
40}
41
42impl<Predicate> WhereAnd<Predicate> for NoWhereClause
43where
44    Predicate: Expression,
45    Predicate::SqlType: BoolOrNullableBool,
46{
47    type Output = WhereClause<Predicate>;
48
49    fn and(self, predicate: Predicate) -> Self::Output {
50        WhereClause(predicate)
51    }
52}
53
54impl<Predicate> WhereOr<Predicate> for NoWhereClause
55where
56    Predicate: Expression,
57    Predicate::SqlType: BoolOrNullableBool,
58{
59    type Output = WhereClause<Predicate>;
60
61    fn or(self, predicate: Predicate) -> Self::Output {
62        WhereClause(predicate)
63    }
64}
65
66impl<DB> From<NoWhereClause> for BoxedWhereClause<'_, DB> {
67    fn from(_: NoWhereClause) -> Self {
68        BoxedWhereClause::None
69    }
70}
71
72/// The `WHERE` clause of a query.
73#[derive(Debug, Clone, Copy)]
74pub struct WhereClause<Expr>(Expr);
75
76impl<Expr: diesel::query_builder::QueryId> diesel::query_builder::QueryId for WhereClause<Expr> {
77    type QueryId = WhereClause<<Expr as diesel::query_builder::QueryId>::QueryId>;
78    const HAS_STATIC_QUERY_ID: bool =
79        <Expr as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID && true;
80
81    const IS_WINDOW_FUNCTION: bool = const {
82        if Expr::IS_WINDOW_FUNCTION {
83            panic!("Using window functions in WHERE clauses is not supported");
84        }
85        false
86    };
87}
88
89impl<DB, Expr> QueryFragment<DB> for WhereClause<Expr>
90where
91    DB: Backend + DieselReserveSpecialization,
92    Expr: QueryFragment<DB>,
93{
94    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
95        out.push_sql(" WHERE ");
96        self.0.walk_ast(out.reborrow())?;
97        Ok(())
98    }
99}
100
101impl<Expr, Predicate> WhereAnd<Predicate> for WhereClause<Expr>
102where
103    Expr: Expression,
104    Expr::SqlType: BoolOrNullableBool,
105    Predicate: Expression,
106    Predicate::SqlType: BoolOrNullableBool,
107{
108    type Output = WhereClause<Grouped<And<Expr, Predicate>>>;
109
110    fn and(self, predicate: Predicate) -> Self::Output {
111        WhereClause(Grouped(And::new(self.0, predicate)))
112    }
113}
114
115impl<Expr, Predicate> WhereOr<Predicate> for WhereClause<Expr>
116where
117    Expr: Expression,
118    Expr::SqlType: BoolOrNullableBool,
119    Predicate: Expression,
120    Predicate::SqlType: BoolOrNullableBool,
121{
122    type Output = WhereClause<Grouped<Or<Expr, Predicate>>>;
123
124    fn or(self, predicate: Predicate) -> Self::Output {
125        WhereClause(Grouped(Or::new(self.0, predicate)))
126    }
127}
128
129impl<'a, DB, Predicate> From<WhereClause<Predicate>> for BoxedWhereClause<'a, DB>
130where
131    DB: Backend,
132    Predicate: QueryFragment<DB> + Send + 'a,
133{
134    fn from(where_clause: WhereClause<Predicate>) -> Self {
135        BoxedWhereClause::Where(Box::new(where_clause.0))
136    }
137}
138
139/// Marker trait indicating that a `WHERE` clause is valid for a given query
140/// source.
141pub trait ValidWhereClause<QS> {}
142
143impl<QS> ValidWhereClause<QS> for NoWhereClause {}
144
145impl<QS, Expr> ValidWhereClause<QS> for WhereClause<Expr>
146where
147    Expr: AppearsOnTable<QS::QuerySource>,
148    QS: AsQuerySource,
149{
150}
151
152impl<Expr> ValidWhereClause<NoFromClause> for WhereClause<Expr> where
153    Expr: AppearsOnTable<NoFromClause>
154{
155}
156
157#[allow(missing_debug_implementations)] // We can't...
158pub enum BoxedWhereClause<'a, DB> {
159    Where(Box<dyn QueryFragment<DB> + Send + 'a>),
160    None,
161}
162
163impl<DB> QueryFragment<DB> for BoxedWhereClause<'_, DB>
164where
165    DB: Backend + DieselReserveSpecialization,
166{
167    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
168        match *self {
169            BoxedWhereClause::Where(ref where_clause) => {
170                out.push_sql(" WHERE ");
171                where_clause.walk_ast(out)
172            }
173            BoxedWhereClause::None => Ok(()),
174        }
175    }
176}
177
178impl<DB> QueryId for BoxedWhereClause<'_, DB> {
179    type QueryId = ();
180
181    const HAS_STATIC_QUERY_ID: bool = false;
182}
183
184impl<'a, DB, Predicate> WhereAnd<Predicate> for BoxedWhereClause<'a, DB>
185where
186    DB: Backend + 'a,
187    Predicate: QueryFragment<DB> + Send + 'a,
188    Grouped<And<Box<dyn QueryFragment<DB> + Send + 'a>, Predicate>>: QueryFragment<DB>,
189{
190    type Output = Self;
191
192    fn and(self, predicate: Predicate) -> Self::Output {
193        use self::BoxedWhereClause::Where;
194
195        match self {
196            Where(where_clause) => Where(Box::new(Grouped(And::new(where_clause, predicate)))),
197            BoxedWhereClause::None => Where(Box::new(predicate)),
198        }
199    }
200}
201
202impl<'a, DB, Predicate> WhereOr<Predicate> for BoxedWhereClause<'a, DB>
203where
204    DB: Backend + 'a,
205    Predicate: QueryFragment<DB> + Send + 'a,
206    Grouped<Or<Box<dyn QueryFragment<DB> + Send + 'a>, Predicate>>: QueryFragment<DB>,
207{
208    type Output = Self;
209
210    fn or(self, predicate: Predicate) -> Self::Output {
211        use self::BoxedWhereClause::Where;
212
213        match self {
214            Where(where_clause) => Where(Box::new(Grouped(Or::new(where_clause, predicate)))),
215            BoxedWhereClause::None => Where(Box::new(predicate)),
216        }
217    }
218}