Skip to main content

diesel/query_builder/select_statement/
boxed_clone.rs

1use core::marker::PhantomData;
2
3use crate::backend::{DieselReserveSpecialization, sql_dialect};
4use crate::dsl::AsExprOf;
5use crate::expression::subselect::ValidSubselect;
6use crate::expression::*;
7use crate::insertable::Insertable;
8use crate::query_builder::combination_clause::*;
9use crate::query_builder::distinct_clause::DistinctClause;
10use crate::query_builder::group_by_clause::ValidGroupByClause;
11use crate::query_builder::having_clause::HavingClause;
12use crate::query_builder::insert_statement::InsertFromSelect;
13use crate::query_builder::limit_clause::LimitClause;
14use crate::query_builder::limit_offset_clause::BoxedCloneLimitOffsetClause;
15use crate::query_builder::offset_clause::OffsetClause;
16use crate::query_builder::order_clause::OrderClause;
17use crate::query_builder::where_clause::{BoxedCloneWhereClause, WhereAnd, WhereOr};
18use crate::query_builder::*;
19use crate::query_dsl::methods::*;
20use crate::query_dsl::*;
21use crate::query_source::joins::*;
22use crate::query_source::{QuerySource, Table};
23use crate::sql_types::{BigInt, BoolOrNullableBool, IntoNullable};
24use alloc::sync::Arc;
25
26// This is used by the table macro internally
27/// This type represents a boxed select query
28///
29/// Using this type directly is only meaningful for custom backends
30/// that need to provide a custom [`QueryFragment`] implementation
31#[allow(missing_debug_implementations)]
32#[doc = " This type represents a boxed select query"]
#[doc = ""]
#[doc = " Using this type directly is only meaningful for custom backends"]
#[doc = " that need to provide a custom [`QueryFragment`] implementation"]
#[allow(missing_debug_implementations)]
#[non_exhaustive]
pub struct BoxedCloneSelectStatement<'a, ST, QS, DB, GB = ()> {
    #[doc = " The select clause of the query"]
    pub select: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
    #[doc = " The from clause of the query"]
    pub from: QS,
    #[doc = " The distinct clause of the query"]
    pub distinct: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
    #[doc = " The where clause of the query"]
    pub where_clause: BoxedCloneWhereClause<'a, DB>,
    #[doc = " The order clause of the query"]
    pub order: Option<Arc<dyn QueryFragment<DB> + Send + Sync + 'a>>,
    #[doc = " The combined limit/offset clause of the query"]
    pub limit_offset: BoxedCloneLimitOffsetClause<'a, DB>,
    #[doc = " The group by clause of the query"]
    pub group_by: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
    #[doc = " The having clause of the query"]
    pub having: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
    _marker: PhantomData<(ST, GB)>,
}#[diesel_derives::__diesel_public_if(
33    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
34    public_fields(
35        select,
36        from,
37        distinct,
38        where_clause,
39        order,
40        limit_offset,
41        group_by,
42        having
43    )
44)]
45pub struct BoxedCloneSelectStatement<'a, ST, QS, DB, GB = ()> {
46    /// The select clause of the query
47    select: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
48    /// The from clause of the query
49    from: QS,
50    /// The distinct clause of the query
51    distinct: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
52    /// The where clause of the query
53    where_clause: BoxedCloneWhereClause<'a, DB>,
54    /// The order clause of the query
55    order: Option<Arc<dyn QueryFragment<DB> + Send + Sync + 'a>>,
56    /// The combined limit/offset clause of the query
57    limit_offset: BoxedCloneLimitOffsetClause<'a, DB>,
58    /// The group by clause of the query
59    group_by: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
60    /// The having clause of the query
61    having: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
62    _marker: PhantomData<(ST, GB)>,
63}
64
65impl<ST, QS: Clone, DB, GB> Clone for BoxedCloneSelectStatement<'_, ST, QS, DB, GB> {
66    fn clone(&self) -> Self {
67        Self {
68            select: Arc::clone(&self.select),
69            from: self.from.clone(),
70            distinct: Arc::clone(&self.distinct),
71            where_clause: self.where_clause.clone(),
72            order: self.order.as_ref().map(Arc::clone),
73            limit_offset: self.limit_offset.clone(),
74            group_by: Arc::clone(&self.group_by),
75            having: Arc::clone(&self.having),
76            _marker: PhantomData,
77        }
78    }
79}
80
81impl<'a, ST, QS: QuerySource, DB, GB> BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB> {
82    #[allow(clippy::too_many_arguments)]
83    pub(crate) fn new<S, G>(
84        select: S,
85        from: FromClause<QS>,
86        distinct: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
87        where_clause: BoxedCloneWhereClause<'a, DB>,
88        order: Option<Arc<dyn QueryFragment<DB> + Send + Sync + 'a>>,
89        limit_offset: BoxedCloneLimitOffsetClause<'a, DB>,
90        group_by: G,
91        having: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
92    ) -> Self
93    where
94        DB: Backend,
95        G: ValidGroupByClause<Expressions = GB> + QueryFragment<DB> + Send + Sync + 'a,
96        S: SelectClauseExpression<FromClause<QS>, SelectClauseSqlType = ST>
97            + QueryFragment<DB>
98            + Send
99            + Sync
100            + 'a,
101        S::Selection: ValidGrouping<GB>,
102    {
103        BoxedCloneSelectStatement {
104            select: Arc::new(select),
105            from,
106            distinct,
107            where_clause,
108            order,
109            limit_offset,
110            group_by: Arc::new(group_by),
111            having,
112            _marker: PhantomData,
113        }
114    }
115}
116
117impl<'a, ST, DB, GB> BoxedCloneSelectStatement<'a, ST, NoFromClause, DB, GB> {
118    #[allow(clippy::too_many_arguments)]
119    pub(crate) fn new_no_from_clause<S, G>(
120        select: S,
121        from: NoFromClause,
122        distinct: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
123        where_clause: BoxedCloneWhereClause<'a, DB>,
124        order: Option<Arc<dyn QueryFragment<DB> + Send + Sync + 'a>>,
125        limit_offset: BoxedCloneLimitOffsetClause<'a, DB>,
126        group_by: G,
127        having: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
128    ) -> Self
129    where
130        DB: Backend,
131        G: ValidGroupByClause<Expressions = GB> + QueryFragment<DB> + Send + Sync + 'a,
132        S: SelectClauseExpression<NoFromClause, SelectClauseSqlType = ST>
133            + QueryFragment<DB>
134            + Send
135            + Sync
136            + 'a,
137        S::Selection: ValidGrouping<GB>,
138    {
139        BoxedCloneSelectStatement {
140            select: Arc::new(select),
141            from,
142            distinct,
143            where_clause,
144            order,
145            limit_offset,
146            group_by: Arc::new(group_by),
147            having,
148            _marker: PhantomData,
149        }
150    }
151}
152
153// that's a trait to control who can access these methods
154#[doc(hidden)] // exported via internal::derives::multiconnection
155pub trait BoxedCloneQueryHelper<'a, QS, DB> {
156    fn build_query<'b, 'c>(
157        &'b self,
158        out: AstPass<'_, 'c, DB>,
159        where_clause_handler: impl Fn(
160            &'b BoxedCloneWhereClause<'a, DB>,
161            AstPass<'_, 'c, DB>,
162        ) -> QueryResult<()>,
163    ) -> QueryResult<()>
164    where
165        DB: Backend,
166        QS: QueryFragment<DB>,
167        BoxedCloneLimitOffsetClause<'a, DB>: QueryFragment<DB>,
168        'b: 'c;
169}
170
171impl<'a, ST, QS, DB, GB> BoxedCloneQueryHelper<'a, QS, DB>
172    for BoxedCloneSelectStatement<'a, ST, QS, DB, GB>
173{
174    fn build_query<'b, 'c>(
175        &'b self,
176        mut out: AstPass<'_, 'c, DB>,
177        where_clause_handler: impl Fn(
178            &'b BoxedCloneWhereClause<'a, DB>,
179            AstPass<'_, 'c, DB>,
180        ) -> QueryResult<()>,
181    ) -> QueryResult<()>
182    where
183        DB: Backend,
184        QS: QueryFragment<DB>,
185        BoxedCloneLimitOffsetClause<'a, DB>: QueryFragment<DB>,
186        'b: 'c,
187    {
188        out.push_sql("SELECT ");
189        self.distinct.walk_ast(out.reborrow())?;
190        self.select.walk_ast(out.reborrow())?;
191        self.from.walk_ast(out.reborrow())?;
192        where_clause_handler(&self.where_clause, out.reborrow())?;
193        self.group_by.walk_ast(out.reborrow())?;
194        self.having.walk_ast(out.reborrow())?;
195
196        if let Some(ref order) = self.order {
197            out.push_sql(" ORDER BY ");
198            order.walk_ast(out.reborrow())?;
199        }
200        self.limit_offset.walk_ast(out.reborrow())?;
201        Ok(())
202    }
203}
204
205impl<ST, QS, DB, GB> Query for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
206where
207    DB: Backend,
208{
209    type SqlType = ST;
210}
211
212impl<ST, QS, DB, GB> SelectQuery for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
213where
214    DB: Backend,
215{
216    type SqlType = ST;
217}
218
219impl<ST, QS, QS2, DB, GB> ValidSubselect<QS2> for BoxedCloneSelectStatement<'_, ST, QS, DB, GB> where
220    Self: Query<SqlType = ST>
221{
222}
223
224impl<ST, QS, DB, GB> QueryFragment<DB> for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
225where
226    DB: Backend,
227    Self: QueryFragment<DB, DB::SelectStatementSyntax>,
228{
229    fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
230        <Self as QueryFragment<DB, DB::SelectStatementSyntax>>::walk_ast(self, pass)
231    }
232}
233
234impl<'a, ST, QS, DB, GB>
235    QueryFragment<DB, sql_dialect::select_statement_syntax::AnsiSqlSelectStatement>
236    for BoxedCloneSelectStatement<'a, ST, QS, DB, GB>
237where
238    DB: Backend<
239            SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement,
240        > + DieselReserveSpecialization,
241    QS: QueryFragment<DB>,
242    BoxedCloneLimitOffsetClause<'a, DB>: QueryFragment<DB>,
243{
244    fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
245        self.build_query(out, |where_clause, out| where_clause.walk_ast(out))
246    }
247}
248
249impl<ST, QS, DB, GB> QueryId for BoxedCloneSelectStatement<'_, ST, QS, DB, GB> {
250    type QueryId = ();
251
252    const HAS_STATIC_QUERY_ID: bool = false;
253}
254
255impl<'a, ST, QS, DB, Rhs, Kind, On, GB> InternalJoinDsl<Rhs, Kind, On>
256    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
257where
258    QS: QuerySource,
259    Rhs: QuerySource,
260    JoinOn<Join<QS, Rhs, Kind>, On>: QuerySource,
261    BoxedCloneSelectStatement<'a, ST, FromClause<JoinOn<Join<QS, Rhs, Kind>, On>>, DB, GB>: AsQuery,
262{
263    type Output =
264        BoxedCloneSelectStatement<'a, ST, FromClause<JoinOn<Join<QS, Rhs, Kind>, On>>, DB, GB>;
265
266    fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
267        BoxedCloneSelectStatement {
268            select: self.select,
269            from: FromClause::new(Join::new(self.from.source, rhs, kind).on(on)),
270            distinct: self.distinct,
271            where_clause: self.where_clause,
272            order: self.order,
273            limit_offset: self.limit_offset,
274            group_by: self.group_by,
275            having: self.having,
276            _marker: PhantomData,
277        }
278    }
279}
280
281impl<ST, QS, DB, GB> DistinctDsl for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
282where
283    DB: Backend,
284    DistinctClause: QueryFragment<DB>,
285{
286    type Output = Self;
287
288    fn distinct(mut self) -> Self::Output {
289        self.distinct = Arc::new(DistinctClause);
290        self
291    }
292}
293
294impl<'a, ST, QS, DB, Selection, GB> SelectDsl<Selection>
295    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
296where
297    DB: Backend,
298    QS: QuerySource,
299    Selection: SelectableExpression<QS> + QueryFragment<DB> + ValidGrouping<GB> + Send + Sync + 'a,
300{
301    type Output = BoxedCloneSelectStatement<'a, Selection::SqlType, FromClause<QS>, DB, GB>;
302
303    fn select(self, selection: Selection) -> Self::Output {
304        BoxedCloneSelectStatement {
305            select: Arc::new(selection),
306            from: self.from,
307            distinct: self.distinct,
308            where_clause: self.where_clause,
309            order: self.order,
310            limit_offset: self.limit_offset,
311            group_by: self.group_by,
312            having: self.having,
313            _marker: PhantomData,
314        }
315    }
316}
317
318impl<'a, ST, DB, Selection, GB> SelectDsl<Selection>
319    for BoxedCloneSelectStatement<'a, ST, NoFromClause, DB, GB>
320where
321    DB: Backend,
322    Selection: SelectableExpression<NoFromClause>
323        + QueryFragment<DB>
324        + ValidGrouping<GB>
325        + Send
326        + Sync
327        + 'a,
328{
329    type Output = BoxedCloneSelectStatement<'a, Selection::SqlType, NoFromClause, DB, GB>;
330
331    fn select(self, selection: Selection) -> Self::Output {
332        BoxedCloneSelectStatement {
333            select: Arc::new(selection),
334            from: self.from,
335            distinct: self.distinct,
336            where_clause: self.where_clause,
337            order: self.order,
338            limit_offset: self.limit_offset,
339            group_by: self.group_by,
340            having: self.having,
341            _marker: PhantomData,
342        }
343    }
344}
345
346impl<'a, ST, QS, DB, Predicate, GB> FilterDsl<Predicate>
347    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
348where
349    QS: QuerySource,
350    BoxedCloneWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedCloneWhereClause<'a, DB>>,
351    Predicate: AppearsOnTable<QS> + NonAggregate,
352    Predicate::SqlType: BoolOrNullableBool,
353{
354    type Output = Self;
355
356    fn filter(mut self, predicate: Predicate) -> Self::Output {
357        self.where_clause = self.where_clause.and(predicate);
358        self
359    }
360}
361
362impl<'a, ST, DB, Predicate, GB> FilterDsl<Predicate>
363    for BoxedCloneSelectStatement<'a, ST, NoFromClause, DB, GB>
364where
365    BoxedCloneWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedCloneWhereClause<'a, DB>>,
366    Predicate: AppearsOnTable<NoFromClause> + NonAggregate,
367    Predicate::SqlType: BoolOrNullableBool,
368{
369    type Output = Self;
370
371    fn filter(mut self, predicate: Predicate) -> Self::Output {
372        self.where_clause = self.where_clause.and(predicate);
373        self
374    }
375}
376
377impl<'a, ST, QS, DB, Predicate, GB> OrFilterDsl<Predicate>
378    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
379where
380    QS: QuerySource,
381    BoxedCloneWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedCloneWhereClause<'a, DB>>,
382    Predicate: AppearsOnTable<QS> + NonAggregate,
383    Predicate::SqlType: BoolOrNullableBool,
384{
385    type Output = Self;
386
387    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
388        self.where_clause = self.where_clause.or(predicate);
389        self
390    }
391}
392
393impl<'a, ST, DB, Predicate, GB> OrFilterDsl<Predicate>
394    for BoxedCloneSelectStatement<'a, ST, NoFromClause, DB, GB>
395where
396    BoxedCloneWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedCloneWhereClause<'a, DB>>,
397    Predicate: AppearsOnTable<NoFromClause> + NonAggregate,
398    Predicate::SqlType: BoolOrNullableBool,
399{
400    type Output = Self;
401
402    fn or_filter(mut self, predicate: Predicate) -> Self::Output {
403        self.where_clause = self.where_clause.or(predicate);
404        self
405    }
406}
407
408impl<ST, QS, DB, GB> LimitDsl for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
409where
410    DB: Backend,
411    LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
412{
413    type Output = Self;
414
415    fn limit(mut self, limit: i64) -> Self::Output {
416        self.limit_offset.limit = Some(Arc::new(LimitClause(limit.into_sql::<BigInt>())));
417        self
418    }
419}
420
421impl<ST, QS, DB, GB> OffsetDsl for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
422where
423    DB: Backend,
424    OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
425{
426    type Output = Self;
427
428    fn offset(mut self, offset: i64) -> Self::Output {
429        self.limit_offset.offset = Some(Arc::new(OffsetClause(offset.into_sql::<BigInt>())));
430        self
431    }
432}
433
434// no impls for `NoFromClause` here because order is not really supported there yet
435impl<'a, ST, QS, DB, Order, GB> OrderDsl<Order>
436    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
437where
438    DB: Backend,
439    QS: QuerySource,
440    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + Sync + 'a,
441{
442    type Output = Self;
443
444    fn order(mut self, order: Order) -> Self::Output {
445        self.order = OrderClause(order).into();
446        self
447    }
448}
449
450impl<'a, ST, QS, DB, Order, GB> ThenOrderDsl<Order>
451    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
452where
453    DB: Backend + 'a,
454    QS: QuerySource,
455    Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + Sync + 'a,
456{
457    type Output = Self;
458
459    fn then_order_by(mut self, order: Order) -> Self::Output {
460        self.order = match self.order {
461            Some(old) => Some(Arc::new((old, order))),
462            None => Some(Arc::new(order)),
463        };
464        self
465    }
466}
467
468impl<ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedCloneSelectStatement<'_, ST, FromClause<QS>, DB, ()>
469where
470    QS: JoinTo<Rhs> + QuerySource,
471{
472    type FromClause = <QS as JoinTo<Rhs>>::FromClause;
473    type OnClause = QS::OnClause;
474
475    fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
476        QS::join_target(rhs)
477    }
478}
479
480impl<ST, QS, DB, GB> QueryDsl for BoxedCloneSelectStatement<'_, ST, QS, DB, GB> {}
481
482impl<ST, QS, DB, GB> RunQueryDslSupport for BoxedCloneSelectStatement<'_, ST, QS, DB, GB> {}
483
484impl<ST, QS, DB, T, GB> Insertable<T> for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
485where
486    T: Table,
487    Self: Query,
488    <T::AllColumns as ValidGrouping<()>>::IsAggregate:
489        MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
490{
491    type Values = InsertFromSelect<Self, T::AllColumns>;
492
493    fn values(self) -> Self::Values {
494        InsertFromSelect::new(self)
495    }
496}
497
498impl<ST, QS, DB, T, GB> Insertable<T> for &BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
499where
500    T: Table,
501    Self: Query,
502    <T::AllColumns as ValidGrouping<()>>::IsAggregate:
503        MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
504{
505    type Values = InsertFromSelect<Self, T::AllColumns>;
506
507    fn values(self) -> Self::Values {
508        InsertFromSelect::new(self)
509    }
510}
511
512impl<'a, ST, QS, DB, GB> SelectNullableDsl for BoxedCloneSelectStatement<'a, ST, QS, DB, GB>
513where
514    ST: IntoNullable,
515{
516    type Output = BoxedCloneSelectStatement<'a, ST::Nullable, QS, DB>;
517
518    fn nullable(self) -> Self::Output {
519        BoxedCloneSelectStatement {
520            select: self.select,
521            from: self.from,
522            distinct: self.distinct,
523            where_clause: self.where_clause,
524            order: self.order,
525            limit_offset: self.limit_offset,
526            group_by: self.group_by,
527            having: self.having,
528            _marker: PhantomData,
529        }
530    }
531}
532
533impl<'a, ST, QS, DB, GB, Predicate> HavingDsl<Predicate>
534    for BoxedCloneSelectStatement<'a, ST, FromClause<QS>, DB, GB>
535where
536    QS: QuerySource,
537    DB: Backend,
538    GB: Expression,
539    HavingClause<Predicate>: QueryFragment<DB> + Send + Sync + 'a,
540    Predicate: AppearsOnTable<QS>,
541    Predicate::SqlType: BoolOrNullableBool,
542{
543    type Output = Self;
544
545    fn having(mut self, predicate: Predicate) -> Self::Output {
546        self.having = Arc::new(HavingClause(predicate));
547        self
548    }
549}
550
551impl<ST, QS, DB, GB> CombineDsl for BoxedCloneSelectStatement<'_, ST, QS, DB, GB>
552where
553    Self: Query,
554{
555    type Query = Self;
556
557    fn union<Rhs>(self, rhs: Rhs) -> crate::dsl::Union<Self, Rhs>
558    where
559        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
560    {
561        CombinationClause::new(Union, Distinct, self, rhs.as_query())
562    }
563
564    fn union_all<Rhs>(self, rhs: Rhs) -> crate::dsl::UnionAll<Self, Rhs>
565    where
566        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
567    {
568        CombinationClause::new(Union, All, self, rhs.as_query())
569    }
570
571    fn intersect<Rhs>(self, rhs: Rhs) -> crate::dsl::Intersect<Self, Rhs>
572    where
573        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
574    {
575        CombinationClause::new(Intersect, Distinct, self, rhs.as_query())
576    }
577
578    fn intersect_all<Rhs>(self, rhs: Rhs) -> crate::dsl::IntersectAll<Self, Rhs>
579    where
580        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
581    {
582        CombinationClause::new(Intersect, All, self, rhs.as_query())
583    }
584
585    fn except<Rhs>(self, rhs: Rhs) -> crate::dsl::Except<Self, Rhs>
586    where
587        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
588    {
589        CombinationClause::new(Except, Distinct, self, rhs.as_query())
590    }
591
592    fn except_all<Rhs>(self, rhs: Rhs) -> crate::dsl::ExceptAll<Self, Rhs>
593    where
594        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
595    {
596        CombinationClause::new(Except, All, self, rhs.as_query())
597    }
598}
599
600#[cfg(test)]
601mod tests {
602    use crate::prelude::*;
603
604    table! {
605        users {
606            id -> Integer,
607        }
608    }
609
610    fn assert_send<T>(_: T)
611    where
612        T: Send,
613    {
614    }
615
616    macro_rules! assert_boxed_query_send {
617        ($backend:ty) => {{
618            assert_send(users::table.into_boxed_clone::<$backend>());
619            assert_send(
620                users::table
621                    .filter(users::id.eq(10))
622                    .into_boxed_clone::<$backend>(),
623            );
624        };};
625    }
626
627    #[diesel_test_helper::test]
628    fn boxed_is_send() {
629        #[cfg(feature = "postgres")]
630        assert_boxed_query_send!(crate::pg::Pg);
631
632        #[cfg(feature = "__sqlite-shared")]
633        assert_boxed_query_send!(crate::sqlite::Sqlite);
634
635        #[cfg(feature = "mysql")]
636        assert_boxed_query_send!(crate::mysql::Mysql);
637
638        #[cfg(feature = "mariadb")]
639        assert_boxed_query_send!(crate::mariadb::Mariadb);
640    }
641}