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#[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 select: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
48 from: QS,
50 distinct: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
52 where_clause: BoxedCloneWhereClause<'a, DB>,
54 order: Option<Arc<dyn QueryFragment<DB> + Send + Sync + 'a>>,
56 limit_offset: BoxedCloneLimitOffsetClause<'a, DB>,
58 group_by: Arc<dyn QueryFragment<DB> + Send + Sync + 'a>,
60 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#[doc(hidden)] pub 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
434impl<'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}