1use std::marker::PhantomData;
2
3use crate::backend::{sql_dialect, DieselReserveSpecialization};
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::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> QueryFragment<DB> for BoxedSelectStatement<'_, ST, QS, DB, GB>
205where
206 DB: Backend,
207 Self: QueryFragment<DB, DB::SelectStatementSyntax>,
208{
209 fn walk_ast<'b>(&'b self, pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
210 <Self as QueryFragment<DB, DB::SelectStatementSyntax>>::walk_ast(self, pass)
211 }
212}
213
214impl<'a, ST, QS, DB, GB>
215 QueryFragment<DB, sql_dialect::select_statement_syntax::AnsiSqlSelectStatement>
216 for BoxedSelectStatement<'a, ST, QS, DB, GB>
217where
218 DB: Backend<
219 SelectStatementSyntax = sql_dialect::select_statement_syntax::AnsiSqlSelectStatement,
220 > + DieselReserveSpecialization,
221 QS: QueryFragment<DB>,
222 BoxedLimitOffsetClause<'a, DB>: QueryFragment<DB>,
223{
224 fn walk_ast<'b>(&'b self, out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
225 self.build_query(out, |where_clause, out| where_clause.walk_ast(out))
226 }
227}
228
229impl<ST, QS, DB, GB> QueryId for BoxedSelectStatement<'_, ST, QS, DB, GB> {
230 type QueryId = ();
231
232 const HAS_STATIC_QUERY_ID: bool = false;
233}
234
235impl<'a, ST, QS, DB, Rhs, Kind, On, GB> InternalJoinDsl<Rhs, Kind, On>
236 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
237where
238 QS: QuerySource,
239 Rhs: QuerySource,
240 JoinOn<Join<QS, Rhs, Kind>, On>: QuerySource,
241 BoxedSelectStatement<'a, ST, FromClause<JoinOn<Join<QS, Rhs, Kind>, On>>, DB, GB>: AsQuery,
242{
243 type Output = BoxedSelectStatement<'a, ST, FromClause<JoinOn<Join<QS, Rhs, Kind>, On>>, DB, GB>;
244
245 fn join(self, rhs: Rhs, kind: Kind, on: On) -> Self::Output {
246 BoxedSelectStatement {
247 select: self.select,
248 from: FromClause::new(Join::new(self.from.source, rhs, kind).on(on)),
249 distinct: self.distinct,
250 where_clause: self.where_clause,
251 order: self.order,
252 limit_offset: self.limit_offset,
253 group_by: self.group_by,
254 having: self.having,
255 _marker: PhantomData,
256 }
257 }
258}
259
260impl<ST, QS, DB, GB> DistinctDsl for BoxedSelectStatement<'_, ST, QS, DB, GB>
261where
262 DB: Backend,
263 DistinctClause: QueryFragment<DB>,
264{
265 type Output = Self;
266
267 fn distinct(mut self) -> Self::Output {
268 self.distinct = Box::new(DistinctClause);
269 self
270 }
271}
272
273impl<'a, ST, QS, DB, Selection, GB> SelectDsl<Selection>
274 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
275where
276 DB: Backend,
277 QS: QuerySource,
278 Selection: SelectableExpression<QS> + QueryFragment<DB> + ValidGrouping<GB> + Send + 'a,
279{
280 type Output = BoxedSelectStatement<'a, Selection::SqlType, FromClause<QS>, DB, GB>;
281
282 fn select(self, selection: Selection) -> Self::Output {
283 BoxedSelectStatement {
284 select: Box::new(selection),
285 from: self.from,
286 distinct: self.distinct,
287 where_clause: self.where_clause,
288 order: self.order,
289 limit_offset: self.limit_offset,
290 group_by: self.group_by,
291 having: self.having,
292 _marker: PhantomData,
293 }
294 }
295}
296
297impl<'a, ST, DB, Selection, GB> SelectDsl<Selection>
298 for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
299where
300 DB: Backend,
301 Selection:
302 SelectableExpression<NoFromClause> + QueryFragment<DB> + ValidGrouping<GB> + Send + 'a,
303{
304 type Output = BoxedSelectStatement<'a, Selection::SqlType, NoFromClause, DB, GB>;
305
306 fn select(self, selection: Selection) -> Self::Output {
307 BoxedSelectStatement {
308 select: Box::new(selection),
309 from: self.from,
310 distinct: self.distinct,
311 where_clause: self.where_clause,
312 order: self.order,
313 limit_offset: self.limit_offset,
314 group_by: self.group_by,
315 having: self.having,
316 _marker: PhantomData,
317 }
318 }
319}
320
321impl<'a, ST, QS, DB, Predicate, GB> FilterDsl<Predicate>
322 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
323where
324 QS: QuerySource,
325 BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
326 Predicate: AppearsOnTable<QS> + NonAggregate,
327 Predicate::SqlType: BoolOrNullableBool,
328{
329 type Output = Self;
330
331 fn filter(mut self, predicate: Predicate) -> Self::Output {
332 self.where_clause = self.where_clause.and(predicate);
333 self
334 }
335}
336
337impl<'a, ST, DB, Predicate, GB> FilterDsl<Predicate>
338 for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
339where
340 BoxedWhereClause<'a, DB>: WhereAnd<Predicate, Output = BoxedWhereClause<'a, DB>>,
341 Predicate: AppearsOnTable<NoFromClause> + NonAggregate,
342 Predicate::SqlType: BoolOrNullableBool,
343{
344 type Output = Self;
345
346 fn filter(mut self, predicate: Predicate) -> Self::Output {
347 self.where_clause = self.where_clause.and(predicate);
348 self
349 }
350}
351
352impl<'a, ST, QS, DB, Predicate, GB> OrFilterDsl<Predicate>
353 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
354where
355 QS: QuerySource,
356 BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
357 Predicate: AppearsOnTable<QS> + NonAggregate,
358 Predicate::SqlType: BoolOrNullableBool,
359{
360 type Output = Self;
361
362 fn or_filter(mut self, predicate: Predicate) -> Self::Output {
363 self.where_clause = self.where_clause.or(predicate);
364 self
365 }
366}
367
368impl<'a, ST, DB, Predicate, GB> OrFilterDsl<Predicate>
369 for BoxedSelectStatement<'a, ST, NoFromClause, DB, GB>
370where
371 BoxedWhereClause<'a, DB>: WhereOr<Predicate, Output = BoxedWhereClause<'a, DB>>,
372 Predicate: AppearsOnTable<NoFromClause> + NonAggregate,
373 Predicate::SqlType: BoolOrNullableBool,
374{
375 type Output = Self;
376
377 fn or_filter(mut self, predicate: Predicate) -> Self::Output {
378 self.where_clause = self.where_clause.or(predicate);
379 self
380 }
381}
382
383impl<ST, QS, DB, GB> LimitDsl for BoxedSelectStatement<'_, ST, QS, DB, GB>
384where
385 DB: Backend,
386 LimitClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
387{
388 type Output = Self;
389
390 fn limit(mut self, limit: i64) -> Self::Output {
391 self.limit_offset.limit = Some(Box::new(LimitClause(limit.into_sql::<BigInt>())));
392 self
393 }
394}
395
396impl<ST, QS, DB, GB> OffsetDsl for BoxedSelectStatement<'_, ST, QS, DB, GB>
397where
398 DB: Backend,
399 OffsetClause<AsExprOf<i64, BigInt>>: QueryFragment<DB>,
400{
401 type Output = Self;
402
403 fn offset(mut self, offset: i64) -> Self::Output {
404 self.limit_offset.offset = Some(Box::new(OffsetClause(offset.into_sql::<BigInt>())));
405 self
406 }
407}
408
409impl<'a, ST, QS, DB, Order, GB> OrderDsl<Order>
411 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
412where
413 DB: Backend,
414 QS: QuerySource,
415 Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
416{
417 type Output = Self;
418
419 fn order(mut self, order: Order) -> Self::Output {
420 self.order = OrderClause(order).into();
421 self
422 }
423}
424
425impl<'a, ST, QS, DB, Order, GB> ThenOrderDsl<Order>
426 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
427where
428 DB: Backend + 'a,
429 QS: QuerySource,
430 Order: QueryFragment<DB> + AppearsOnTable<QS> + Send + 'a,
431{
432 type Output = Self;
433
434 fn then_order_by(mut self, order: Order) -> Self::Output {
435 self.order = match self.order {
436 Some(old) => Some(Box::new((old, order))),
437 None => Some(Box::new(order)),
438 };
439 self
440 }
441}
442
443impl<ST, QS, DB, Rhs> JoinTo<Rhs> for BoxedSelectStatement<'_, ST, FromClause<QS>, DB, ()>
444where
445 QS: JoinTo<Rhs> + QuerySource,
446{
447 type FromClause = <QS as JoinTo<Rhs>>::FromClause;
448 type OnClause = QS::OnClause;
449
450 fn join_target(rhs: Rhs) -> (Self::FromClause, Self::OnClause) {
451 QS::join_target(rhs)
452 }
453}
454
455impl<ST, QS, DB, GB> QueryDsl for BoxedSelectStatement<'_, ST, QS, DB, GB> {}
456
457impl<ST, QS, DB, Conn, GB> RunQueryDsl<Conn> for BoxedSelectStatement<'_, ST, QS, DB, GB> {}
458
459impl<ST, QS, DB, T, GB> Insertable<T> for BoxedSelectStatement<'_, ST, QS, DB, GB>
460where
461 T: Table,
462 Self: Query,
463 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
464 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
465{
466 type Values = InsertFromSelect<Self, T::AllColumns>;
467
468 fn values(self) -> Self::Values {
469 InsertFromSelect::new(self)
470 }
471}
472
473impl<ST, QS, DB, T, GB> Insertable<T> for &BoxedSelectStatement<'_, ST, QS, DB, GB>
474where
475 T: Table,
476 Self: Query,
477 <T::AllColumns as ValidGrouping<()>>::IsAggregate:
478 MixedAggregates<is_aggregate::No, Output = is_aggregate::No>,
479{
480 type Values = InsertFromSelect<Self, T::AllColumns>;
481
482 fn values(self) -> Self::Values {
483 InsertFromSelect::new(self)
484 }
485}
486
487impl<'a, ST, QS, DB, GB> SelectNullableDsl for BoxedSelectStatement<'a, ST, QS, DB, GB>
488where
489 ST: IntoNullable,
490{
491 type Output = BoxedSelectStatement<'a, ST::Nullable, QS, DB>;
492
493 fn nullable(self) -> Self::Output {
494 BoxedSelectStatement {
495 select: self.select,
496 from: self.from,
497 distinct: self.distinct,
498 where_clause: self.where_clause,
499 order: self.order,
500 limit_offset: self.limit_offset,
501 group_by: self.group_by,
502 having: self.having,
503 _marker: PhantomData,
504 }
505 }
506}
507
508impl<'a, ST, QS, DB, GB, Predicate> HavingDsl<Predicate>
509 for BoxedSelectStatement<'a, ST, FromClause<QS>, DB, GB>
510where
511 QS: QuerySource,
512 DB: Backend,
513 GB: Expression,
514 HavingClause<Predicate>: QueryFragment<DB> + Send + 'a,
515 Predicate: AppearsOnTable<QS>,
516 Predicate::SqlType: BoolOrNullableBool,
517{
518 type Output = Self;
519
520 fn having(mut self, predicate: Predicate) -> Self::Output {
521 self.having = Box::new(HavingClause(predicate));
522 self
523 }
524}
525
526impl<ST, QS, DB, GB> CombineDsl for BoxedSelectStatement<'_, ST, QS, DB, GB>
527where
528 Self: Query,
529{
530 type Query = Self;
531
532 fn union<Rhs>(self, rhs: Rhs) -> crate::dsl::Union<Self, Rhs>
533 where
534 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
535 {
536 CombinationClause::new(Union, Distinct, self, rhs.as_query())
537 }
538
539 fn union_all<Rhs>(self, rhs: Rhs) -> crate::dsl::UnionAll<Self, Rhs>
540 where
541 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
542 {
543 CombinationClause::new(Union, All, self, rhs.as_query())
544 }
545
546 fn intersect<Rhs>(self, rhs: Rhs) -> crate::dsl::Intersect<Self, Rhs>
547 where
548 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
549 {
550 CombinationClause::new(Intersect, Distinct, self, rhs.as_query())
551 }
552
553 fn intersect_all<Rhs>(self, rhs: Rhs) -> crate::dsl::IntersectAll<Self, Rhs>
554 where
555 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
556 {
557 CombinationClause::new(Intersect, All, self, rhs.as_query())
558 }
559
560 fn except<Rhs>(self, rhs: Rhs) -> crate::dsl::Except<Self, Rhs>
561 where
562 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
563 {
564 CombinationClause::new(Except, Distinct, self, rhs.as_query())
565 }
566
567 fn except_all<Rhs>(self, rhs: Rhs) -> crate::dsl::ExceptAll<Self, Rhs>
568 where
569 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
570 {
571 CombinationClause::new(Except, All, self, rhs.as_query())
572 }
573}
574
575#[cfg(test)]
576mod tests {
577 use crate::prelude::*;
578
579 table! {
580 users {
581 id -> Integer,
582 }
583 }
584
585 fn assert_send<T>(_: T)
586 where
587 T: Send,
588 {
589 }
590
591 macro_rules! assert_boxed_query_send {
592 ($backend:ty) => {{
593 assert_send(users::table.into_boxed::<$backend>());
594 assert_send(
595 users::table
596 .filter(users::id.eq(10))
597 .into_boxed::<$backend>(),
598 );
599 };};
600 }
601
602 #[diesel_test_helper::test]
603 fn boxed_is_send() {
604 #[cfg(feature = "postgres")]
605 assert_boxed_query_send!(crate::pg::Pg);
606
607 #[cfg(feature = "sqlite")]
608 assert_boxed_query_send!(crate::sqlite::Sqlite);
609
610 #[cfg(feature = "mysql")]
611 assert_boxed_query_send!(crate::mysql::Mysql);
612 }
613}