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::subselect::{ValidSubselect, ValidSubselectGrouping};
15use crate::expression::{MixedAggregates, 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::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) -> Self {
        Self {
            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, GB> ValidSubselectGrouping<GB>
104    for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
105where
106    Source: ValidSubselectGrouping<GB>,
107    Rhs: ValidSubselectGrouping<GB>,
108    Source::IsAggregate: MixedAggregates<Rhs::IsAggregate>,
109{
110    type IsAggregate = <Source::IsAggregate as MixedAggregates<Rhs::IsAggregate>>::Output;
111}
112
113impl<Combinator, Rule, Source, Rhs, O, LOf> RunQueryDslSupport
114    for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
115{
116}
117
118impl<Combinator, Rule, Source, Rhs, O, LOf, T> Insertable<T>
119    for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
120where
121    T: Table,
122    T::AllColumns: NonAggregate,
123    Self: Query,
124{
125    type Values = InsertFromSelect<Self, T::AllColumns>;
126
127    fn values(self) -> Self::Values {
128        InsertFromSelect::new(self)
129    }
130}
131
132impl<Combinator, Rule, Source, OriginRhs, O, LOf> CombineDsl
133    for CombinationClause<Combinator, Rule, Source, OriginRhs, O, LOf>
134where
135    Self: Query,
136{
137    type Query = Self;
138
139    fn union<Rhs>(self, rhs: Rhs) -> crate::dsl::Union<Self, Rhs>
140    where
141        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
142    {
143        CombinationClause::new(Union, Distinct, self, rhs.as_query())
144    }
145
146    fn union_all<Rhs>(self, rhs: Rhs) -> crate::dsl::UnionAll<Self, Rhs>
147    where
148        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
149    {
150        CombinationClause::new(Union, All, self, rhs.as_query())
151    }
152
153    fn intersect<Rhs>(self, rhs: Rhs) -> crate::dsl::Intersect<Self, Rhs>
154    where
155        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
156    {
157        CombinationClause::new(Intersect, Distinct, self, rhs.as_query())
158    }
159
160    fn intersect_all<Rhs>(self, rhs: Rhs) -> crate::dsl::IntersectAll<Self, Rhs>
161    where
162        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
163    {
164        CombinationClause::new(Intersect, All, self, rhs.as_query())
165    }
166
167    fn except<Rhs>(self, rhs: Rhs) -> crate::dsl::Except<Self, Rhs>
168    where
169        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
170    {
171        CombinationClause::new(Except, Distinct, self, rhs.as_query())
172    }
173
174    fn except_all<Rhs>(self, rhs: Rhs) -> crate::dsl::ExceptAll<Self, Rhs>
175    where
176        Rhs: AsQuery<SqlType = <Self::Query as Query>::SqlType>,
177    {
178        CombinationClause::new(Except, All, self, rhs.as_query())
179    }
180}
181
182impl<Combinator, Rule, Source, Rhs, O, LOf, DB: Backend> QueryFragment<DB>
183    for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
184where
185    Combinator: QueryFragment<DB>,
186    Rule: QueryFragment<DB>,
187    ParenthesisWrapper<Source>: QueryFragment<DB>,
188    ParenthesisWrapper<Rhs>: QueryFragment<DB>,
189    O: QueryFragment<DB>,
190    LOf: QueryFragment<DB>,
191    DB: Backend + SupportsCombinationClause<Combinator, Rule> + DieselReserveSpecialization,
192{
193    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
194        self.source.walk_ast(out.reborrow())?;
195        self.combinator.walk_ast(out.reborrow())?;
196        self.duplicate_rule.walk_ast(out.reborrow())?;
197        self.rhs.walk_ast(out.reborrow())?;
198        self.order.walk_ast(out.reborrow())?;
199        self.limit_offset.walk_ast(out)
200    }
201}
202
203impl<ST, Combinator, Rule, Source, Rhs, O, LOf, RawExpr, Expr> PositionalOrderDsl<RawExpr>
204    for CombinationClause<Combinator, Rule, Source, Rhs, O, LOf>
205where
206    Self: SelectQuery<SqlType = ST>,
207    CombinationClause<Combinator, Rule, Source, Rhs, OrderClause<Expr>, LOf>:
208        SelectQuery<SqlType = ST>,
209    RawExpr: IntoPositionalOrderExpr<Output = Expr>,
210{
211    type Output = CombinationClause<Combinator, Rule, Source, Rhs, OrderClause<Expr>, LOf>;
212
213    fn positional_order_by(self, expr: RawExpr) -> Self::Output {
214        let order = OrderClause(expr.into_positional_expr());
215
216        CombinationClause {
217            combinator: self.combinator,
218            duplicate_rule: self.duplicate_rule,
219            source: self.source,
220            rhs: self.rhs,
221            order,
222            limit_offset: self.limit_offset,
223        }
224    }
225}
226
227#[doc(hidden)]
228type Limit = AsExprOf<i64, BigInt>;
229
230impl<ST, Combinator, Rule, Source, Rhs, O, L, Of> LimitDsl
231    for CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, Of>>
232where
233    Self: SelectQuery<SqlType = ST>,
234    CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<LimitClause<Limit>, Of>>:
235        SelectQuery<SqlType = ST>,
236{
237    type Output = CombinationClause<
238        Combinator,
239        Rule,
240        Source,
241        Rhs,
242        O,
243        LimitOffsetClause<LimitClause<Limit>, Of>,
244    >;
245
246    fn limit(self, limit: i64) -> Self::Output {
247        let limit_clause = LimitClause(limit.into_sql::<BigInt>());
248        CombinationClause {
249            combinator: self.combinator,
250            duplicate_rule: self.duplicate_rule,
251            source: self.source,
252            rhs: self.rhs,
253            order: self.order,
254            limit_offset: LimitOffsetClause {
255                limit_clause,
256                offset_clause: self.limit_offset.offset_clause,
257            },
258        }
259    }
260}
261
262#[doc(hidden)]
263type Offset = Limit;
264
265impl<ST, Combinator, Rule, Source, Rhs, O, L, Of> OffsetDsl
266    for CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, Of>>
267where
268    Self: SelectQuery<SqlType = ST>,
269    CombinationClause<Combinator, Rule, Source, Rhs, O, LimitOffsetClause<L, OffsetClause<Offset>>>:
270        SelectQuery<SqlType = ST>,
271{
272    type Output = CombinationClause<
273        Combinator,
274        Rule,
275        Source,
276        Rhs,
277        O,
278        LimitOffsetClause<L, OffsetClause<Offset>>,
279    >;
280
281    fn offset(self, offset: i64) -> Self::Output {
282        let offset_clause = OffsetClause(offset.into_sql::<BigInt>());
283        CombinationClause {
284            combinator: self.combinator,
285            duplicate_rule: self.duplicate_rule,
286            source: self.source,
287            rhs: self.rhs,
288            order: self.order,
289            limit_offset: LimitOffsetClause {
290                limit_clause: self.limit_offset.limit_clause,
291                offset_clause,
292            },
293        }
294    }
295}
296
297#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Union { }
#[automatically_derived]
impl ::core::clone::Clone for Union {
    #[inline]
    fn clone(&self) -> Self { *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)]
298/// Computes the set union of the rows returned by the involved `SELECT` statements using SQL `UNION`
299pub struct Union;
300
301impl<DB> QueryFragment<DB> for Union
302where
303    DB: Backend + DieselReserveSpecialization,
304{
305    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
306        out.push_sql(" UNION ");
307        Ok(())
308    }
309}
310
311#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Intersect { }
#[automatically_derived]
impl ::core::clone::Clone for Intersect {
    #[inline]
    fn clone(&self) -> Self { *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)]
312/// Computes the set intersection of the rows returned by the involved `SELECT` statements using SQL `INTERSECT`
313pub struct Intersect;
314
315impl<DB> QueryFragment<DB> for Intersect
316where
317    DB: Backend + DieselReserveSpecialization,
318{
319    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
320        out.push_sql(" INTERSECT ");
321        Ok(())
322    }
323}
324
325#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Except { }
#[automatically_derived]
impl ::core::clone::Clone for Except {
    #[inline]
    fn clone(&self) -> Self { *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)]
326/// Computes the set difference of the rows returned by the involved `SELECT` statements using SQL `EXCEPT`
327pub struct Except;
328
329impl<DB> QueryFragment<DB> for Except
330where
331    DB: Backend + DieselReserveSpecialization,
332{
333    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
334        out.push_sql(" EXCEPT ");
335        Ok(())
336    }
337}
338
339#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Distinct { }
#[automatically_derived]
impl ::core::clone::Clone for Distinct {
    #[inline]
    fn clone(&self) -> Self { *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)]
340/// Remove duplicate rows in the result, this is the default behavior of `UNION`, `INTERSECT` and `EXCEPT`
341pub struct Distinct;
342
343impl<DB> QueryFragment<DB> for Distinct
344where
345    DB: Backend + DieselReserveSpecialization,
346{
347    fn walk_ast<'b>(&'b self, _: AstPass<'_, 'b, DB>) -> QueryResult<()> {
348        Ok(())
349    }
350}
351
352#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for All { }
#[automatically_derived]
impl ::core::clone::Clone for All {
    #[inline]
    fn clone(&self) -> Self { *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)]
353/// Keep duplicate rows in the result
354pub struct All;
355
356impl<DB> QueryFragment<DB> for All
357where
358    DB: Backend + DieselReserveSpecialization,
359{
360    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
361        out.push_sql("ALL ");
362        Ok(())
363    }
364}
365
366/// Marker trait used to indicate whenever a backend supports given combination
367pub trait SupportsCombinationClause<Combinator, Rule> {}
368
369#[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) -> Self {
        Self { 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)]
370/// Wrapper used to wrap rhs sql in parenthesis when supported by backend
371#[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(
372    feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
373    public_fields(inner)
374)]
375pub struct ParenthesisWrapper<T> {
376    /// the inner parenthesis definition
377    #[allow(dead_code)]
378    inner: T,
379}
380
381#[cfg(feature = "postgres_backend")]
382mod postgres {
383    use super::*;
384    use crate::pg::Pg;
385
386    impl<T: QueryFragment<Pg>> QueryFragment<Pg> for ParenthesisWrapper<T> {
387        fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> QueryResult<()> {
388            out.push_sql("(");
389            self.inner.walk_ast(out.reborrow())?;
390            out.push_sql(")");
391            Ok(())
392        }
393    }
394
395    impl SupportsCombinationClause<Union, Distinct> for Pg {}
396    impl SupportsCombinationClause<Union, All> for Pg {}
397    impl SupportsCombinationClause<Intersect, Distinct> for Pg {}
398    impl SupportsCombinationClause<Intersect, All> for Pg {}
399    impl SupportsCombinationClause<Except, Distinct> for Pg {}
400    impl SupportsCombinationClause<Except, All> for Pg {}
401}
402
403#[cfg(any(feature = "mysql_backend", feature = "mariadb_backend"))]
404mod mysql_like {
405    use super::*;
406    use crate::mysql_like::MysqlLikeBackend;
407
408    impl<DB, T> QueryFragment<DB> for ParenthesisWrapper<T>
409    where
410        DB: MysqlLikeBackend,
411        T: QueryFragment<DB>,
412    {
413        fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, DB>) -> QueryResult<()> {
414            out.push_sql("(");
415            self.inner.walk_ast(out.reborrow())?;
416            out.push_sql(")");
417            Ok(())
418        }
419    }
420
421    impl<DB: MysqlLikeBackend> SupportsCombinationClause<Union, Distinct> for DB {}
422    impl<DB: MysqlLikeBackend> SupportsCombinationClause<Union, All> for DB {}
423}
424
425#[cfg(feature = "mariadb_backend")]
426mod mariadb {
427    use super::*;
428    use crate::mariadb::Mariadb;
429
430    impl SupportsCombinationClause<Intersect, Distinct> for Mariadb {}
431    impl SupportsCombinationClause<Intersect, All> for Mariadb {}
432    impl SupportsCombinationClause<Except, Distinct> for Mariadb {}
433    impl SupportsCombinationClause<Except, All> for Mariadb {}
434}
435
436#[cfg(feature = "__sqlite-shared")]
437mod sqlite {
438    use super::*;
439    use crate::sqlite::Sqlite;
440
441    impl<T: QueryFragment<Sqlite>> QueryFragment<Sqlite> for ParenthesisWrapper<T> {
442        fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Sqlite>) -> QueryResult<()> {
443            // SQLite does not support parenthesis around this clause
444            // we can emulate this by construct a fake outer
445            // SELECT * FROM (inner_query) statement
446            out.push_sql("SELECT * FROM (");
447            self.inner.walk_ast(out.reborrow())?;
448            out.push_sql(")");
449            Ok(())
450        }
451    }
452
453    impl SupportsCombinationClause<Union, Distinct> for Sqlite {}
454    impl SupportsCombinationClause<Union, All> for Sqlite {}
455    impl SupportsCombinationClause<Intersect, Distinct> for Sqlite {}
456    impl SupportsCombinationClause<Except, Distinct> for Sqlite {}
457}