diesel/pg/expression/
array.rs

1use crate::dsl;
2use crate::expression::array_comparison::{AsInExpression, InExpression};
3use crate::expression::subselect::Subselect;
4use crate::expression::{
5    AppearsOnTable, AsExpression, Expression, SelectableExpression, TypedExpressionType,
6    ValidGrouping,
7};
8use crate::pg::Pg;
9use crate::query_builder::combination_clause::CombinationClause;
10use crate::query_builder::{
11    AstPass, BoxedSelectStatement, QueryFragment, QueryId, SelectQuery, SelectStatement,
12};
13use crate::sql_types::{self, SqlType};
14use std::marker::PhantomData;
15
16/// Creates an `ARRAY[e1, e2, ...]` or `ARRAY(subselect)` expression.
17///
18/// The argument should be a tuple of expressions which can be represented by the
19/// same SQL type, or a subquery.
20///
21/// # Examples
22///
23/// ```rust
24/// # include!("../../doctest_setup.rs");
25/// #
26/// # fn main() {
27/// #     run_test().unwrap();
28/// # }
29/// #
30/// # fn run_test() -> QueryResult<()> {
31/// #     use schema::users::dsl::*;
32/// #     use diesel::dsl::array;
33/// #     use diesel::sql_types::Integer;
34/// #     let connection = &mut establish_connection();
35/// let ints = diesel::select(array::<Integer, _>((1, 2))).get_result::<Vec<i32>>(connection)?;
36/// assert_eq!(vec![1, 2], ints);
37///
38/// let ids = users
39///     .select(array((id, id * 2)))
40///     .get_results::<Vec<i32>>(connection)?;
41/// let expected = vec![vec![1, 2], vec![2, 4]];
42/// assert_eq!(expected, ids);
43///
44/// let ids = diesel::select(array(users.select(id))).first::<Vec<i32>>(connection)?;
45/// assert_eq!(vec![1, 2], ids);
46/// #     Ok(())
47/// # }
48/// ```
49pub fn array<ST, T>(elements: T) -> dsl::array<ST, T>
50where
51    T: IntoArrayExpression<ST>,
52    ST: SqlType + TypedExpressionType,
53{
54    elements.into_array_expression()
55}
56
57/// Return type of [`array(tuple_or_subselect)`](super::dsl::array())
58#[allow(non_camel_case_types)]
59#[cfg(feature = "postgres_backend")]
60pub type array<ST, T> = <T as IntoArrayExpression<ST>>::ArrayExpression;
61
62/// Trait for types which can be converted into an expression of type `Array`
63///
64/// This includes tuples of expressions with the same SQL type, and subselects with a single column.
65#[diagnostic::on_unimplemented(
66    message = "cannot convert `{Self}` into an expression of type `Array<{ST}>`",
67    note = "`the trait bound `{Self}: IntoArrayExpression<{ST}>` is not satisfied. \
68        (`AsExpressionList` is a deprecated trait alias for `IntoArrayExpression`)"
69)]
70pub trait IntoArrayExpression<ST: SqlType + TypedExpressionType> {
71    /// Type of the expression returned by [IntoArrayExpression::into_array_expression]
72    type ArrayExpression: Expression<SqlType = sql_types::Array<ST>>;
73
74    /// Construct the diesel query dsl representation of
75    /// the `ARRAY (values)` clause for the given type
76    fn into_array_expression(self) -> Self::ArrayExpression;
77}
78
79/// Implement as a no-op for expressions that were already arrays (that is, don't wrap in ARRAY[]).
80impl<ST, T> IntoArrayExpression<ST> for T
81where
82    T: AsExpression<sql_types::Array<ST>>,
83    ST: SqlType + TypedExpressionType + 'static,
84{
85    type ArrayExpression = <T as AsExpression<sql_types::Array<ST>>>::Expression;
86
87    fn into_array_expression(self) -> Self::ArrayExpression {
88        <T as AsExpression<sql_types::Array<ST>>>::as_expression(self)
89    }
90}
91
92// This has to be implemented for each tuple directly because an intermediate trait would cause
93// conflicting impls. (Compiler says people could implement AsExpression<CustomSqlType> for
94// SelectStatement<CustomType, ...>)
95// This is not implemented with other tuple impls because this is feature-flagged by
96// `postgres-backend`
97macro_rules! tuple_impls {
98    ($(
99        $Tuple:tt {
100            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
101        }
102    )+) => {
103        $(
104            impl<$($T,)+ ST> IntoArrayExpression<ST> for ($($T,)+) where
105                $($T: AsExpression<ST>,)+
106                ST: SqlType + TypedExpressionType,
107            {
108                type ArrayExpression = ArrayLiteral<($($T::Expression,)+), ST>;
109
110                fn into_array_expression(self) -> Self::ArrayExpression {
111                    ArrayLiteral {
112                        elements: ($(self.$idx.as_expression(),)+),
113                        _marker: PhantomData,
114                    }
115                }
116            }
117        )+
118    }
119}
120
121impl<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16,
    T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31,
    ST> IntoArrayExpression<ST> for
    (T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16,
    T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31)
    where T: AsExpression<ST>, T1: AsExpression<ST>, T2: AsExpression<ST>,
    T3: AsExpression<ST>, T4: AsExpression<ST>, T5: AsExpression<ST>,
    T6: AsExpression<ST>, T7: AsExpression<ST>, T8: AsExpression<ST>,
    T9: AsExpression<ST>, T10: AsExpression<ST>, T11: AsExpression<ST>,
    T12: AsExpression<ST>, T13: AsExpression<ST>, T14: AsExpression<ST>,
    T15: AsExpression<ST>, T16: AsExpression<ST>, T17: AsExpression<ST>,
    T18: AsExpression<ST>, T19: AsExpression<ST>, T20: AsExpression<ST>,
    T21: AsExpression<ST>, T22: AsExpression<ST>, T23: AsExpression<ST>,
    T24: AsExpression<ST>, T25: AsExpression<ST>, T26: AsExpression<ST>,
    T27: AsExpression<ST>, T28: AsExpression<ST>, T29: AsExpression<ST>,
    T30: AsExpression<ST>, T31: AsExpression<ST>, ST: SqlType +
    TypedExpressionType {
    type ArrayExpression =
        ArrayLiteral<(T::Expression, T1::Expression, T2::Expression,
        T3::Expression, T4::Expression, T5::Expression, T6::Expression,
        T7::Expression, T8::Expression, T9::Expression, T10::Expression,
        T11::Expression, T12::Expression, T13::Expression, T14::Expression,
        T15::Expression, T16::Expression, T17::Expression, T18::Expression,
        T19::Expression, T20::Expression, T21::Expression, T22::Expression,
        T23::Expression, T24::Expression, T25::Expression, T26::Expression,
        T27::Expression, T28::Expression, T29::Expression, T30::Expression,
        T31::Expression), ST>;
    fn into_array_expression(self) -> Self::ArrayExpression {
        ArrayLiteral {
            elements: (self.0.as_expression(), self.1.as_expression(),
                self.2.as_expression(), self.3.as_expression(),
                self.4.as_expression(), self.5.as_expression(),
                self.6.as_expression(), self.7.as_expression(),
                self.8.as_expression(), self.9.as_expression(),
                self.10.as_expression(), self.11.as_expression(),
                self.12.as_expression(), self.13.as_expression(),
                self.14.as_expression(), self.15.as_expression(),
                self.16.as_expression(), self.17.as_expression(),
                self.18.as_expression(), self.19.as_expression(),
                self.20.as_expression(), self.21.as_expression(),
                self.22.as_expression(), self.23.as_expression(),
                self.24.as_expression(), self.25.as_expression(),
                self.26.as_expression(), self.27.as_expression(),
                self.28.as_expression(), self.29.as_expression(),
                self.30.as_expression(), self.31.as_expression()),
            _marker: PhantomData,
        }
    }
}diesel_derives::__diesel_for_each_tuple!(tuple_impls);
122
123/// An ARRAY[...] literal.
124#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, ST: ::core::fmt::Debug> ::core::fmt::Debug for
    ArrayLiteral<T, ST> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "ArrayLiteral",
            "elements", &self.elements, "_marker", &&self._marker)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone, ST: ::core::clone::Clone> ::core::clone::Clone
    for ArrayLiteral<T, ST> {
    #[inline]
    fn clone(&self) -> ArrayLiteral<T, ST> {
        ArrayLiteral {
            elements: ::core::clone::Clone::clone(&self.elements),
            _marker: ::core::clone::Clone::clone(&self._marker),
        }
    }
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy, ST: ::core::marker::Copy> ::core::marker::Copy
    for ArrayLiteral<T, ST> {
}Copy, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl<T: diesel::query_builder::QueryId,
            ST: diesel::query_builder::QueryId> diesel::query_builder::QueryId
            for ArrayLiteral<T, ST> {
            type QueryId =
                ArrayLiteral<<T as diesel::query_builder::QueryId>::QueryId,
                <ST as diesel::query_builder::QueryId>::QueryId>;
            const HAS_STATIC_QUERY_ID: bool =
                <T as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                        <ST as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID
                    && true;
            const IS_WINDOW_FUNCTION: bool =
                <T as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION ||
                        <ST as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
                    || false;
        }
    };QueryId)]
125pub struct ArrayLiteral<T, ST> {
126    elements: T,
127    _marker: PhantomData<ST>,
128}
129
130impl<T, ST> Expression for ArrayLiteral<T, ST>
131where
132    ST: 'static,
133    T: Expression,
134{
135    type SqlType = sql_types::Array<ST>;
136}
137
138impl<T, ST> QueryFragment<Pg> for ArrayLiteral<T, ST>
139where
140    T: QueryFragment<Pg>,
141{
142    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> crate::result::QueryResult<()> {
143        out.push_sql("ARRAY[");
144        QueryFragment::walk_ast(&self.elements, out.reborrow())?;
145        out.push_sql("]");
146        Ok(())
147    }
148}
149
150impl<T, ST, QS> SelectableExpression<QS> for ArrayLiteral<T, ST>
151where
152    T: SelectableExpression<QS>,
153    ArrayLiteral<T, ST>: AppearsOnTable<QS>,
154{
155}
156
157impl<T, ST, QS> AppearsOnTable<QS> for ArrayLiteral<T, ST>
158where
159    T: AppearsOnTable<QS>,
160    ArrayLiteral<T, ST>: Expression,
161{
162}
163
164impl<T, ST, GB> ValidGrouping<GB> for ArrayLiteral<T, ST>
165where
166    T: ValidGrouping<GB>,
167{
168    type IsAggregate = T::IsAggregate;
169}
170
171impl<T, ST> InExpression for ArrayLiteral<T, ST>
172where
173    Self: Expression<SqlType = sql_types::Array<ST>>,
174    ST: SqlType,
175{
176    type SqlType = ST;
177
178    fn is_empty(&self) -> bool {
179        false
180    }
181
182    fn is_array(&self) -> bool {
183        // we want to use the `= ANY(_)` syntax
184        false
185    }
186}
187
188impl<T, ST> AsInExpression<ST> for ArrayLiteral<T, ST>
189where
190    Self: Expression<SqlType = sql_types::Array<ST>>,
191    ST: SqlType,
192{
193    type InExpression = Self;
194
195    fn as_in_expression(self) -> Self::InExpression {
196        self
197    }
198}
199
200impl<ST, F, S, D, W, O, LOf, G, H, LC> IntoArrayExpression<ST>
201    for SelectStatement<F, S, D, W, O, LOf, G, H, LC>
202where
203    ST: SqlType + TypedExpressionType,
204    ArraySubselect<Self, ST>: Expression<SqlType = sql_types::Array<ST>>,
205    Self: SelectQuery<SqlType = ST>,
206{
207    type ArrayExpression = ArraySubselect<Self, ST>;
208
209    fn into_array_expression(self) -> Self::ArrayExpression {
210        ArraySubselect::new(self)
211    }
212}
213
214impl<'a, ST, QS, DB, GB> IntoArrayExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB, GB>
215where
216    ST: SqlType + TypedExpressionType,
217    ArraySubselect<BoxedSelectStatement<'a, ST, QS, DB, GB>, ST>:
218        Expression<SqlType = sql_types::Array<ST>>,
219{
220    type ArrayExpression = ArraySubselect<Self, ST>;
221
222    fn into_array_expression(self) -> Self::ArrayExpression {
223        ArraySubselect::new(self)
224    }
225}
226
227impl<ST, Combinator, Rule, Source, Rhs> IntoArrayExpression<ST>
228    for CombinationClause<Combinator, Rule, Source, Rhs>
229where
230    ST: SqlType + TypedExpressionType,
231    Self: SelectQuery<SqlType = ST>,
232    ArraySubselect<Self, ST>: Expression<SqlType = sql_types::Array<ST>>,
233{
234    type ArrayExpression = ArraySubselect<Self, ST>;
235
236    fn into_array_expression(self) -> Self::ArrayExpression {
237        ArraySubselect::new(self)
238    }
239}
240
241/// An ARRAY(...) subselect.
242#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, ST: ::core::fmt::Debug> ::core::fmt::Debug for
    ArraySubselect<T, ST> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "ArraySubselect", "subquery", &&self.subquery)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone, ST: ::core::clone::Clone> ::core::clone::Clone
    for ArraySubselect<T, ST> {
    #[inline]
    fn clone(&self) -> ArraySubselect<T, ST> {
        ArraySubselect {
            subquery: ::core::clone::Clone::clone(&self.subquery),
        }
    }
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy, ST: ::core::marker::Copy> ::core::marker::Copy
    for ArraySubselect<T, ST> {
}Copy, const _: () =
    {
        use diesel;
        #[allow(non_camel_case_types)]
        impl<T: diesel::query_builder::QueryId,
            ST: diesel::query_builder::QueryId> diesel::query_builder::QueryId
            for ArraySubselect<T, ST> {
            type QueryId =
                ArraySubselect<<T as diesel::query_builder::QueryId>::QueryId,
                <ST as diesel::query_builder::QueryId>::QueryId>;
            const HAS_STATIC_QUERY_ID: bool =
                <T as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID &&
                        <ST as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID
                    && true;
            const IS_WINDOW_FUNCTION: bool =
                <T as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION ||
                        <ST as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION
                    || false;
        }
    };QueryId)]
243pub struct ArraySubselect<T, ST> {
244    subquery: Subselect<T, ST>,
245}
246
247impl<T, ST> ArraySubselect<T, ST> {
248    pub(crate) fn new(elements: T) -> Self {
249        Self {
250            subquery: Subselect::new(elements),
251        }
252    }
253}
254
255impl<T, ST> Expression for ArraySubselect<T, ST>
256where
257    ST: 'static,
258    Subselect<T, ST>: Expression<SqlType = ST>,
259{
260    type SqlType = sql_types::Array<ST>;
261}
262
263impl<T, ST> QueryFragment<Pg> for ArraySubselect<T, ST>
264where
265    Subselect<T, ST>: QueryFragment<Pg>,
266{
267    fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, Pg>) -> crate::result::QueryResult<()> {
268        out.push_sql("ARRAY(");
269        QueryFragment::walk_ast(&self.subquery, out.reborrow())?;
270        out.push_sql(")");
271        Ok(())
272    }
273}
274
275impl<T, ST, QS> SelectableExpression<QS> for ArraySubselect<T, ST>
276where
277    Subselect<T, ST>: SelectableExpression<QS>,
278    ArraySubselect<T, ST>: AppearsOnTable<QS>,
279{
280}
281
282impl<T, ST, QS> AppearsOnTable<QS> for ArraySubselect<T, ST>
283where
284    Subselect<T, ST>: AppearsOnTable<QS>,
285    ArraySubselect<T, ST>: Expression,
286{
287}
288
289impl<T, ST, GB> ValidGrouping<GB> for ArraySubselect<T, ST>
290where
291    Subselect<T, ST>: ValidGrouping<GB>,
292{
293    type IsAggregate = <Subselect<T, ST> as ValidGrouping<GB>>::IsAggregate;
294}
295
296impl<T, ST> InExpression for ArraySubselect<T, ST>
297where
298    Self: Expression<SqlType = sql_types::Array<ST>>,
299    ST: SqlType,
300{
301    type SqlType = ST;
302
303    fn is_empty(&self) -> bool {
304        false
305    }
306
307    fn is_array(&self) -> bool {
308        // we want to use the `= ANY(_)` syntax
309        false
310    }
311}
312
313impl<T, ST> AsInExpression<ST> for ArraySubselect<T, ST>
314where
315    Self: Expression<SqlType = sql_types::Array<ST>>,
316    ST: SqlType,
317{
318    type InExpression = Self;
319
320    fn as_in_expression(self) -> Self::InExpression {
321        self
322    }
323}