1use crate::backend::{Backend, DieselReserveSpecialization};
12use crate::dsl::AsExprOf;
13use crate::expression::subselect::ValidSubselect;
14use crate::expression::IntoSql;
15use crate::expression::NonAggregate;
16use crate::query_builder::insert_statement::InsertFromSelect;
17use crate::query_builder::limit_clause::{LimitClause, NoLimitClause};
18use crate::query_builder::limit_offset_clause::LimitOffsetClause;
19use crate::query_builder::offset_clause::{NoOffsetClause, OffsetClause};
20use crate::query_builder::order_clause::{NoOrderClause, OrderClause};
21use crate::query_builder::{AsQuery, AstPass, Query, QueryFragment, QueryId, SelectQuery};
22use crate::query_dsl::methods::*;
23use crate::query_dsl::positional_order_dsl::{IntoPositionalOrderExpr, PositionalOrderDsl};
24use crate::sql_types::BigInt;
25use crate::{CombineDsl, Insertable, QueryDsl, QueryResult, RunQueryDsl, Table};
26
27#[derive(Debug, Copy, Clone, QueryId)]
28#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
29pub struct CombinationClause<
32 Combinator,
33 Rule,
34 Source,
35 Rhs,
36 Order = NoOrderClause,
37 LimitOffset = LimitOffsetClause<NoLimitClause, NoOffsetClause>,
38> {
39 combinator: Combinator,
40 duplicate_rule: Rule,
41 source: ParenthesisWrapper<Source>,
42 rhs: ParenthesisWrapper<Rhs>,
43 order: Order,
45 limit_offset: LimitOffset,
47}
48
49impl<Combinator, Rule, Source, Rhs> CombinationClause<Combinator, Rule, Source, Rhs> {
50 pub(crate) fn new(
52 combinator: Combinator,
53 duplicate_rule: Rule,
54 source: Source,
55 rhs: Rhs,
56 ) -> Self {
57 CombinationClause {
58 combinator,
59 duplicate_rule,
60 source: ParenthesisWrapper { inner: source },
61 rhs: ParenthesisWrapper { inner: rhs },
62 order: NoOrderClause,
63 limit_offset: LimitOffsetClause {
64 limit_clause: NoLimitClause,
65 offset_clause: NoOffsetClause,
66 },
67 }
68 }
69}
70
71impl<Combinator, Rule, Source, Rhs, O, LOf> QueryDsl
72 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
73{
74}
75
76impl<Combinator, Rule, Source, Rhs, O, LOf> Query
77 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
78where
79 Source: Query,
80 Rhs: Query<SqlType = Source::SqlType>,
81{
82 type SqlType = Source::SqlType;
83}
84
85impl<Combinator, Rule, Source, Rhs, O, LOf> SelectQuery
86 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
87where
88 Source: SelectQuery,
89 Rhs: SelectQuery<SqlType = Source::SqlType>,
90{
91 type SqlType = Source::SqlType;
92}
93
94impl<Combinator, Rule, Source, Rhs, O, LOf, QS> ValidSubselect<QS>
95 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
96where
97 Source: ValidSubselect<QS>,
98 Rhs: ValidSubselect<QS>,
99{
100}
101
102impl<Combinator, Rule, Source, Rhs, O, LOf, Conn> RunQueryDsl<Conn>
103 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
104{
105}
106
107impl<Combinator, Rule, Source, Rhs, O, LOf, T> Insertable<T>
108 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
109where
110 T: Table,
111 T::AllColumns: NonAggregate,
112 Self: Query,
113{
114 type Values = InsertFromSelect<Self, T::AllColumns>;
115
116 fn values(self) -> Self::Values {
117 InsertFromSelect::new(self)
118 }
119}
120
121impl<Combinator, Rule, Source, OriginRhs, O, LOf> CombineDsl
122 for CombinationClause<Combinator, Rule, Source, OriginRhs, O, LOf>
123where
124 Self: Query,
125{
126 type Query = Self;
127
128 fn union<Rhs>(self, rhs: Rhs) -> crate::dsl::Union<Self, Rhs>
129 where
130 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
131 {
132 CombinationClause::new(Union, Distinct, self, rhs.as_query())
133 }
134
135 fn union_all<Rhs>(self, rhs: Rhs) -> crate::dsl::UnionAll<Self, Rhs>
136 where
137 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
138 {
139 CombinationClause::new(Union, All, self, rhs.as_query())
140 }
141
142 fn intersect<Rhs>(self, rhs: Rhs) -> crate::dsl::Intersect<Self, Rhs>
143 where
144 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
145 {
146 CombinationClause::new(Intersect, Distinct, self, rhs.as_query())
147 }
148
149 fn intersect_all<Rhs>(self, rhs: Rhs) -> crate::dsl::IntersectAll<Self, Rhs>
150 where
151 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
152 {
153 CombinationClause::new(Intersect, All, self, rhs.as_query())
154 }
155
156 fn except<Rhs>(self, rhs: Rhs) -> crate::dsl::Except<Self, Rhs>
157 where
158 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
159 {
160 CombinationClause::new(Except, Distinct, self, rhs.as_query())
161 }
162
163 fn except_all<Rhs>(self, rhs: Rhs) -> crate::dsl::ExceptAll<Self, Rhs>
164 where
165 Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
166 {
167 CombinationClause::new(Except, All, self, rhs.as_query())
168 }
169}
170
171impl<Combinator, Rule, Source, Rhs, O, LOf, DB: Backend> QueryFragment<DB>
172 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
173where
174 Combinator: QueryFragment<DB>,
175 Rule: QueryFragment<DB>,
176 ParenthesisWrapper<Source>: QueryFragment<DB>,
177 ParenthesisWrapper<Rhs>: QueryFragment<DB>,
178 O: QueryFragment<DB>,
179 LOf: QueryFragment<DB>,
180 DB: Backend + SupportsCombinationClause<Combinator, Rule> + DieselReserveSpecialization,
181{
182 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
183 self.source.walk_ast(out.reborrow())?;
184 self.combinator.walk_ast(out.reborrow())?;
185 self.duplicate_rule.walk_ast(out.reborrow())?;
186 self.rhs.walk_ast(out.reborrow())?;
187 self.order.walk_ast(out.reborrow())?;
188 self.limit_offset.walk_ast(out)
189 }
190}
191
192impl<ST, Combinator, Rule, Source, Rhs, O, LOf, RawExpr, Expr> PositionalOrderDsl<RawExpr>
193 for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
194where
195 Self: SelectQuery<SqlType = ST>,
196 CombinationClause<Combinator, Rule, Source, Rhs, OrderClause<Expr>, LOf>:
197 SelectQuery<SqlType = ST>,
198 RawExpr: IntoPositionalOrderExpr<Output = Expr>,
199{
200 type Output = CombinationClause<Combinator, Rule, Source, Rhs, OrderClause<Expr>, LOf>;
201
202 fn positional_order_by(self, expr: RawExpr) -> Self::Output {
203 let order = OrderClause(expr.into_positional_expr());
204
205 CombinationClause {
206 combinator: self.combinator,
207 duplicate_rule: self.duplicate_rule,
208 source: self.source,
209 rhs: self.rhs,
210 order,
211 limit_offset: self.limit_offset,
212 }
213 }
214}
215
216#[doc(hidden)]
217type Limit = AsExprOf<i64, BigInt>;
218
219impl<ST, Combinator, Rule, Source, Rhs, O, L, Of> LimitDsl
220 for CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, Of>>
221where
222 Self: SelectQuery<SqlType = ST>,
223 CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<LimitClause<Limit>, Of>>:
224 SelectQuery<SqlType = ST>,
225{
226 type Output = CombinationClause<
227 Combinator,
228 Rule,
229 Source,
230 Rhs,
231 O,
232 LimitOffsetClause<LimitClause<Limit>, Of>,
233 >;
234
235 fn limit(self, limit: i64) -> Self::Output {
236 let limit_clause = LimitClause(limit.into_sql::<BigInt>());
237 CombinationClause {
238 combinator: self.combinator,
239 duplicate_rule: self.duplicate_rule,
240 source: self.source,
241 rhs: self.rhs,
242 order: self.order,
243 limit_offset: LimitOffsetClause {
244 limit_clause,
245 offset_clause: self.limit_offset.offset_clause,
246 },
247 }
248 }
249}
250
251#[doc(hidden)]
252type Offset = Limit;
253
254impl<ST, Combinator, Rule, Source, Rhs, O, L, Of> OffsetDsl
255 for CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, Of>>
256where
257 Self: SelectQuery<SqlType = ST>,
258 CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, OffsetClause<Offset>>>:
259 SelectQuery<SqlType = ST>,
260{
261 type Output = CombinationClause<
262 Combinator,
263 Rule,
264 Source,
265 Rhs,
266 O,
267 LimitOffsetClause<L, OffsetClause<Offset>>,
268 >;
269
270 fn offset(self, offset: i64) -> Self::Output {
271 let offset_clause = OffsetClause(offset.into_sql::<BigInt>());
272 CombinationClause {
273 combinator: self.combinator,
274 duplicate_rule: self.duplicate_rule,
275 source: self.source,
276 rhs: self.rhs,
277 order: self.order,
278 limit_offset: LimitOffsetClause {
279 limit_clause: self.limit_offset.limit_clause,
280 offset_clause,
281 },
282 }
283 }
284}
285
286#[derive(Debug, Copy, Clone, QueryId)]
287pub struct Union;
289
290impl<DB> QueryFragment<DB> for Union
291where
292 DB: Backend + DieselReserveSpecialization,
293{
294 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
295 out.push_sql(" UNION ");
296 Ok(())
297 }
298}
299
300#[derive(Debug, Copy, Clone, QueryId)]
301pub struct Intersect;
303
304impl<DB> QueryFragment<DB> for Intersect
305where
306 DB: Backend + DieselReserveSpecialization,
307{
308 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
309 out.push_sql(" INTERSECT ");
310 Ok(())
311 }
312}
313
314#[derive(Debug, Copy, Clone, QueryId)]
315pub struct Except;
317
318impl<DB> QueryFragment<DB> for Except
319where
320 DB: Backend + DieselReserveSpecialization,
321{
322 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
323 out.push_sql(" EXCEPT ");
324 Ok(())
325 }
326}
327
328#[derive(Debug, Copy, Clone, QueryId)]
329pub struct Distinct;
331
332impl<DB> QueryFragment<DB> for Distinct
333where
334 DB: Backend + DieselReserveSpecialization,
335{
336 fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
337 Ok(())
338 }
339}
340
341#[derive(Debug, Copy, Clone, QueryId)]
342pub struct All;
344
345impl<DB> QueryFragment<DB> for All
346where
347 DB: Backend + DieselReserveSpecialization,
348{
349 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
350 out.push_sql("ALL ");
351 Ok(())
352 }
353}
354
355pub trait SupportsCombinationClause<Combinator, Rule> {}
357
358#[derive(Debug, Copy, Clone, QueryId)]
359#[diesel_derives::__diesel_public_if(
361 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
362 public_fields(inner)
363)]
364pub struct ParenthesisWrapper<T> {
365 #[allow(dead_code)]
367 inner: T,
368}
369
370#[cfg(feature = "postgres_backend")]
371mod postgres {
372 use super::*;
373 use crate::pg::Pg;
374
375 impl<T: QueryFragment<Pg>> QueryFragment<Pg> for ParenthesisWrapper<T> {
376 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
377 out.push_sql("(");
378 self.inner.walk_ast(out.reborrow())?;
379 out.push_sql(")");
380 Ok(())
381 }
382 }
383
384 impl SupportsCombinationClause<Union, Distinct> for Pg {}
385 impl SupportsCombinationClause<Union, All> for Pg {}
386 impl SupportsCombinationClause<Intersect, Distinct> for Pg {}
387 impl SupportsCombinationClause<Intersect, All> for Pg {}
388 impl SupportsCombinationClause<Except, Distinct> for Pg {}
389 impl SupportsCombinationClause<Except, All> for Pg {}
390}
391
392#[cfg(feature = "mysql_backend")]
393mod mysql {
394 use super::*;
395 use crate::mysql::Mysql;
396
397 impl<T: QueryFragment<Mysql>> QueryFragment<Mysql> for ParenthesisWrapper<T> {
398 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Mysql>) -> QueryResult<()> {
399 out.push_sql("(");
400 self.inner.walk_ast(out.reborrow())?;
401 out.push_sql(")");
402 Ok(())
403 }
404 }
405
406 impl SupportsCombinationClause<Union, Distinct> for Mysql {}
407 impl SupportsCombinationClause<Union, All> for Mysql {}
408}
409
410#[cfg(feature = "sqlite")]
411mod sqlite {
412 use super::*;
413 use crate::sqlite::Sqlite;
414
415 impl<T: QueryFragment<Sqlite>> QueryFragment<Sqlite> for ParenthesisWrapper<T> {
416 fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
417 out.push_sql("SELECT * FROM (");
421 self.inner.walk_ast(out.reborrow())?;
422 out.push_sql(")");
423 Ok(())
424 }
425 }
426
427 impl SupportsCombinationClause<Union, Distinct> for Sqlite {}
428 impl SupportsCombinationClause<Union, All> for Sqlite {}
429 impl SupportsCombinationClause<Intersect, Distinct> for Sqlite {}
430 impl SupportsCombinationClause<Except, Distinct> for Sqlite {}
431}