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