1use crate::backend::{sql_dialect, Backend, SqlDialect};
5use crate::expression::subselect::Subselect;
6use crate::expression::{
7 AppearsOnTable, AsExpression, Expression, SelectableExpression, TypedExpressionType,
8 ValidGrouping,
9};
10use crate::query_builder::combination_clause::CombinationClause;
11use crate::query_builder::{
12 AstPass, BoxedSelectStatement, QueryFragment, QueryId, SelectQuery, SelectStatement,
13};
14use crate::result::QueryResult;
15use crate::serialize::ToSql;
16use crate::sql_types::{self, HasSqlType, SingleValue, SqlType};
17use std::marker::PhantomData;
18
19#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
31#[non_exhaustive]
32pub struct In<T, U> {
33 pub left: T,
35 pub values: U,
37}
38
39#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
51#[non_exhaustive]
52pub struct NotIn<T, U> {
53 pub left: T,
55 pub values: U,
57}
58
59impl<T, U> In<T, U> {
60 pub(crate) fn new(left: T, values: U) -> Self {
61 In { left, values }
62 }
63}
64
65impl<T, U> NotIn<T, U> {
66 pub(crate) fn new(left: T, values: U) -> Self {
67 NotIn { left, values }
68 }
69}
70
71impl<T, U> Expression for In<T, U>
72where
73 T: Expression,
74 U: Expression<SqlType = T::SqlType>,
75 T::SqlType: SqlType,
76 sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>:
77 sql_types::MaybeNullableType<sql_types::Bool>,
78{
79 type SqlType = sql_types::is_nullable::MaybeNullable<
80 sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>,
81 sql_types::Bool,
82 >;
83}
84
85impl<T, U> Expression for NotIn<T, U>
86where
87 T: Expression,
88 U: Expression<SqlType = T::SqlType>,
89 T::SqlType: SqlType,
90 sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>:
91 sql_types::MaybeNullableType<sql_types::Bool>,
92{
93 type SqlType = sql_types::is_nullable::MaybeNullable<
94 sql_types::is_nullable::IsSqlTypeNullable<T::SqlType>,
95 sql_types::Bool,
96 >;
97}
98
99impl<T, U, DB> QueryFragment<DB> for In<T, U>
100where
101 DB: Backend,
102 Self: QueryFragment<DB, DB::ArrayComparison>,
103{
104 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
105 <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
106 }
107}
108
109impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison> for In<T, U>
110where
111 DB: Backend
112 + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
113 T: QueryFragment<DB>,
114 U: QueryFragment<DB> + MaybeEmpty,
115{
116 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
117 if self.values.is_empty() {
118 out.push_sql("1=0");
119 } else {
120 self.left.walk_ast(out.reborrow())?;
121 out.push_sql(" IN (");
122 self.values.walk_ast(out.reborrow())?;
123 out.push_sql(")");
124 }
125 Ok(())
126 }
127}
128
129impl<T, U, DB> QueryFragment<DB> for NotIn<T, U>
130where
131 DB: Backend,
132 Self: QueryFragment<DB, DB::ArrayComparison>,
133{
134 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
135 <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
136 }
137}
138
139impl<T, U, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison>
140 for NotIn<T, U>
141where
142 DB: Backend
143 + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
144 T: QueryFragment<DB>,
145 U: QueryFragment<DB> + MaybeEmpty,
146{
147 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
148 if self.values.is_empty() {
149 out.push_sql("1=1");
150 } else {
151 self.left.walk_ast(out.reborrow())?;
152 out.push_sql(" NOT IN (");
153 self.values.walk_ast(out.reborrow())?;
154 out.push_sql(")");
155 }
156 Ok(())
157 }
158}
159
160impl_selectable_expression!(In<T, U>);
161impl_selectable_expression!(NotIn<T, U>);
162
163pub trait AsInExpression<T: SqlType + TypedExpressionType> {
180 type InExpression: MaybeEmpty + Expression<SqlType = T>;
182
183 #[allow(clippy::wrong_self_convention)]
186 fn as_in_expression(self) -> Self::InExpression;
189}
190
191impl<I, T, ST> AsInExpression<ST> for I
192where
193 I: IntoIterator<Item = T>,
194 T: AsExpression<ST>,
195 ST: SqlType + TypedExpressionType,
196{
197 type InExpression = Many<ST, T>;
198
199 fn as_in_expression(self) -> Self::InExpression {
200 Many {
201 values: self.into_iter().collect(),
202 p: PhantomData,
203 }
204 }
205}
206
207pub trait MaybeEmpty {
210 fn is_empty(&self) -> bool;
213}
214
215impl<ST, F, S, D, W, O, LOf, G, H, LC> AsInExpression<ST>
216 for SelectStatement<F, S, D, W, O, LOf, G, H, LC>
217where
218 ST: SqlType + TypedExpressionType,
219 Subselect<Self, ST>: Expression<SqlType = ST>,
220 Self: SelectQuery<SqlType = ST>,
221{
222 type InExpression = Subselect<Self, ST>;
223
224 fn as_in_expression(self) -> Self::InExpression {
225 Subselect::new(self)
226 }
227}
228
229impl<'a, ST, QS, DB, GB> AsInExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB, GB>
230where
231 ST: SqlType + TypedExpressionType,
232 Subselect<BoxedSelectStatement<'a, ST, QS, DB, GB>, ST>: Expression<SqlType = ST>,
233{
234 type InExpression = Subselect<Self, ST>;
235
236 fn as_in_expression(self) -> Self::InExpression {
237 Subselect::new(self)
238 }
239}
240
241impl<ST, Combinator, Rule, Source, Rhs> AsInExpression<ST>
242 for CombinationClause<Combinator, Rule, Source, Rhs>
243where
244 ST: SqlType + TypedExpressionType,
245 Self: SelectQuery<SqlType = ST>,
246 Subselect<Self, ST>: Expression<SqlType = ST>,
247{
248 type InExpression = Subselect<Self, ST>;
249
250 fn as_in_expression(self) -> Self::InExpression {
251 Subselect::new(self)
252 }
253}
254
255#[derive(Debug, Clone)]
268pub struct Many<ST, I> {
269 pub values: Vec<I>,
271 p: PhantomData<ST>,
272}
273
274impl<ST, I, GB> ValidGrouping<GB> for Many<ST, I>
275where
276 ST: SingleValue,
277 I: AsExpression<ST>,
278 I::Expression: ValidGrouping<GB>,
279{
280 type IsAggregate = <I::Expression as ValidGrouping<GB>>::IsAggregate;
281}
282
283impl<ST, I> Expression for Many<ST, I>
284where
285 ST: TypedExpressionType,
286{
287 type SqlType = ST;
288}
289
290impl<ST, I> MaybeEmpty for Many<ST, I> {
291 fn is_empty(&self) -> bool {
292 self.values.is_empty()
293 }
294}
295
296impl<ST, I, QS> SelectableExpression<QS> for Many<ST, I>
297where
298 Many<ST, I>: AppearsOnTable<QS>,
299 ST: SingleValue,
300 I: AsExpression<ST>,
301 <I as AsExpression<ST>>::Expression: SelectableExpression<QS>,
302{
303}
304
305impl<ST, I, QS> AppearsOnTable<QS> for Many<ST, I>
306where
307 Many<ST, I>: Expression,
308 I: AsExpression<ST>,
309 ST: SingleValue,
310 <I as AsExpression<ST>>::Expression: SelectableExpression<QS>,
311{
312}
313
314impl<ST, I, DB> QueryFragment<DB> for Many<ST, I>
315where
316 Self: QueryFragment<DB, DB::ArrayComparison>,
317 DB: Backend,
318{
319 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
320 <Self as QueryFragment<DB, DB::ArrayComparison>>::walk_ast(self, pass)
321 }
322}
323
324impl<ST, I, DB> QueryFragment<DB, sql_dialect::array_comparison::AnsiSqlArrayComparison>
325 for Many<ST, I>
326where
327 DB: Backend
328 + HasSqlType<ST>
329 + SqlDialect<ArrayComparison = sql_dialect::array_comparison::AnsiSqlArrayComparison>,
330 ST: SingleValue,
331 I: ToSql<ST, DB>,
332{
333 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
334 out.unsafe_to_cache_prepared();
335 let mut first = true;
336 for value in &self.values {
337 if first {
338 first = false;
339 } else {
340 out.push_sql(", ");
341 }
342 out.push_bind_param(value)?;
343 }
344 Ok(())
345 }
346}
347
348impl<ST, I> QueryId for Many<ST, I> {
349 type QueryId = ();
350
351 const HAS_STATIC_QUERY_ID: bool = false;
352}