Skip to main content

diesel/query_builder/
combination_clause.rs

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