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