diesel/type_impls/
tuples.rs

1use crate::associations::BelongsTo;
2use crate::backend::Backend;
3use crate::deserialize::{
4    self, FromSqlRow, FromStaticSqlRow, Queryable, SqlTypeOrSelectable, StaticallySizedRow,
5};
6use crate::expression::{
7    is_contained_in_group_by, AppearsOnTable, AsExpression, AsExpressionList, Expression,
8    IsContainedInGroupBy, MixedAggregates, QueryMetadata, Selectable, SelectableExpression,
9    TypedExpressionType, ValidGrouping,
10};
11use crate::insertable::{CanInsertInSingleQuery, InsertValues, Insertable, InsertableOptionHelper};
12use crate::query_builder::*;
13use crate::query_dsl::load_dsl::CompatibleType;
14use crate::query_source::*;
15use crate::result::QueryResult;
16use crate::row::*;
17use crate::sql_types::{HasSqlType, IntoNullable, Nullable, OneIsNullable, SqlType};
18use crate::util::{TupleAppend, TupleSize};
19
20impl<T> TupleSize for T
21where
22    T: crate::sql_types::SingleValue,
23{
24    const SIZE: usize = 1;
25}
26
27macro_rules! tuple_impls {
28    ($(
29        $Tuple:tt {
30            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
31        }
32    )+) => {
33        $(
34            impl<$($T),+, __DB> HasSqlType<($($T,)+)> for __DB where
35                $(__DB: HasSqlType<$T>),+,
36                __DB: Backend,
37            {
38                fn metadata(_: &mut __DB::MetadataLookup) -> __DB::TypeMetadata {
39                    unreachable!("Tuples should never implement `ToSql` directly");
40                }
41            }
42
43            impl_from_sql_row!(($($T,)+), ($($ST,)+));
44
45
46            #[diagnostic::do_not_recommend]
47            impl<$($T: Expression),+> Expression for ($($T,)+)
48            where ($($T::SqlType, )*): TypedExpressionType
49            {
50                type SqlType = ($(<$T as Expression>::SqlType,)+);
51            }
52
53            impl<$($T: TypedExpressionType,)*> TypedExpressionType for ($($T,)*) {}
54            impl<$($T: SqlType + TypedExpressionType,)*> TypedExpressionType for Nullable<($($T,)*)>
55            where ($($T,)*): SqlType
56            {
57            }
58
59            impl<$($T: SqlType,)*> IntoNullable for ($($T,)*)
60                where Self: SqlType,
61            {
62                type Nullable = Nullable<($($T,)*)>;
63            }
64
65            impl<$($T,)+ __DB> Selectable<__DB> for ($($T,)+)
66            where
67                __DB: Backend,
68                $($T: Selectable<__DB>),+,
69            {
70                type SelectExpression = ($($T::SelectExpression,)+);
71
72                fn construct_selection() -> Self::SelectExpression {
73                    ($($T::construct_selection(),)+)
74                }
75            }
76
77            impl<$($T: QueryFragment<__DB>),+, __DB: Backend> QueryFragment<__DB> for ($($T,)+) {
78                #[allow(unused_assignments)]
79                fn walk_ast<'b>(&'b self, mut out: AstPass<'_, 'b, __DB>) -> QueryResult<()>
80                {
81                    let mut needs_comma = false;
82                    $(
83                        if !self.$idx.is_noop(out.backend())? {
84                            if needs_comma {
85                                out.push_sql(", ");
86                            }
87                            self.$idx.walk_ast(out.reborrow())?;
88                            needs_comma = true;
89                        }
90                    )+
91                    Ok(())
92                }
93            }
94
95            // cannot use `#[diagnostic::do_not_recommend]` here yet to hide tuple impls
96            // as this makes the error message worse (not saying which column is problematic)
97            impl<$($T,)+ Tab> ColumnList for ($($T,)+)
98            where
99                $($T: ColumnList<Table = Tab>,)+
100            {
101                type Table = Tab;
102
103                fn walk_ast<__DB: Backend>(&self, mut out: AstPass<'_, '_, __DB>) -> QueryResult<()> {
104                    $(
105                        if $idx != 0 {
106                            out.push_sql(", ");
107                        }
108                        self.$idx.walk_ast(out.reborrow())?;
109                    )+
110                    Ok(())
111                }
112            }
113
114            impl<$($T: QueryId),+> QueryId for ($($T,)+) {
115                type QueryId = ($($T::QueryId,)+);
116
117                const HAS_STATIC_QUERY_ID: bool = $($T::HAS_STATIC_QUERY_ID &&)+ true;
118            }
119
120            impl_valid_grouping_for_tuple_of_columns!($($T,)*);
121
122            impl<$($T,)+ Tab> UndecoratedInsertRecord<Tab> for ($($T,)+)
123            where
124                $($T: UndecoratedInsertRecord<Tab>,)+
125            {
126            }
127
128            impl<$($T,)+ __DB> CanInsertInSingleQuery<__DB> for ($($T,)+)
129            where
130                __DB: Backend,
131                $($T: CanInsertInSingleQuery<__DB>,)+
132            {
133                fn rows_to_insert(&self) -> Option<usize> {
134                    $(debug_assert_eq!(self.$idx.rows_to_insert(), Some(1));)+
135                    Some(1)
136                }
137            }
138
139            impl<$($T,)+ $($ST,)+ Tab> Insertable<Tab> for ($($T,)+)
140            where
141                $($T: Insertable<Tab, Values = ValuesClause<$ST, Tab>>,)+
142            {
143                type Values = ValuesClause<($($ST,)+), Tab>;
144
145                fn values(self) -> Self::Values {
146                    ValuesClause::new(($(self.$idx.values().values,)+))
147                }
148            }
149
150            impl<'a, $($T,)+ Tab> Insertable<Tab> for &'a ($($T,)+)
151            where
152                ($(&'a $T,)+): Insertable<Tab>,
153            {
154                type Values = <($(&'a $T,)+) as Insertable<Tab>>::Values;
155
156                fn values(self) -> Self::Values {
157                    ($(&self.$idx,)+).values()
158                }
159            }
160
161            #[allow(unused_assignments)]
162            impl<$($T,)+ Tab, __DB> InsertValues<__DB, Tab> for ($($T,)+)
163            where
164                Tab: Table,
165                __DB: Backend,
166                $($T: InsertValues<__DB, Tab>,)+
167            {
168                fn column_names(&self, mut out: AstPass<'_, '_, __DB>) -> QueryResult<()> {
169                    let mut needs_comma = false;
170                    $(
171                        let noop_element = self.$idx.is_noop(out.backend())?;
172                        if !noop_element {
173                            if needs_comma {
174                                out.push_sql(", ");
175                            }
176                            self.$idx.column_names(out.reborrow())?;
177                            needs_comma = true;
178                        }
179                    )+
180                    Ok(())
181                }
182            }
183
184            impl<__T, $($ST,)* Tab> Insertable<Tab> for InsertableOptionHelper<__T, ($($ST,)*)>
185            where
186                __T: Insertable<Tab>,
187                __T::Values: Default,
188            {
189                type Values = __T::Values;
190
191                fn values(self) -> Self::Values {
192                    self.0.map(|v| v.values()).unwrap_or_default()
193                }
194            }
195
196            // not possible to use diagnostic::do_not_recommend to hide the tuple impls
197            // yet as it gives worse error messages
198            // (doesn't show anymore which tuple element doesn't implement the trait)
199            impl<$($T,)+ QS> SelectableExpression<QS> for ($($T,)+) where
200                $($T: SelectableExpression<QS>,)+
201                ($($T,)+): AppearsOnTable<QS>,
202            {
203            }
204
205            impl<$($T,)+ QS> AppearsOnTable<QS> for ($($T,)+) where
206                $($T: AppearsOnTable<QS>,)+
207                ($($T,)+): Expression,
208            {
209            }
210
211            impl<Target, $($T,)+> AsChangeset for ($($T,)+) where
212                $($T: AsChangeset<Target=Target>,)+
213                Target: QuerySource,
214            {
215                type Target = Target;
216                type Changeset = ($($T::Changeset,)+);
217
218                fn as_changeset(self) -> Self::Changeset {
219                    ($(self.$idx.as_changeset(),)+)
220                }
221            }
222
223            impl<$($T,)+ Parent> BelongsTo<Parent> for ($($T,)+) where
224                T0: BelongsTo<Parent>,
225            {
226                type ForeignKey = T0::ForeignKey;
227                type ForeignKeyColumn = T0::ForeignKeyColumn;
228
229                fn foreign_key(&self) -> Option<&Self::ForeignKey> {
230                    self.0.foreign_key()
231                }
232
233                fn foreign_key_column() -> Self::ForeignKeyColumn {
234                    T0::foreign_key_column()
235                }
236            }
237
238            impl<$($T,)+ Next> TupleAppend<Next> for ($($T,)+) {
239                type Output = ($($T,)+ Next);
240
241                #[allow(non_snake_case)]
242                fn tuple_append(self, next: Next) -> Self::Output {
243                    let ($($T,)+) = self;
244                    ($($T,)+ next)
245                }
246            }
247
248            impl<$($T,)+ ST> AsExpressionList<ST> for ($($T,)+) where
249                $($T: AsExpression<ST>,)+
250                ST: SqlType + TypedExpressionType,
251            {
252                type Expression = ($($T::Expression,)+);
253
254                fn as_expression_list(self) -> Self::Expression {
255                    ($(self.$idx.as_expression(),)+)
256                }
257            }
258
259            impl_sql_type!($($T,)*);
260
261            impl<$($T,)* __DB, $($ST,)*> Queryable<($($ST,)*), __DB> for ($($T,)*)
262            where __DB: Backend,
263                  Self: FromStaticSqlRow<($($ST,)*), __DB>,
264            {
265                type Row = Self;
266
267                fn build(row: Self::Row) -> deserialize::Result<Self> {
268                    Ok(row)
269                }
270            }
271
272            impl<__T, $($ST,)*  __DB> FromStaticSqlRow<Nullable<($($ST,)*)>, __DB> for Option<__T> where
273                __DB: Backend,
274                ($($ST,)*): SqlType,
275                __T: FromSqlRow<($($ST,)*), __DB>,
276            {
277
278                #[allow(non_snake_case, unused_variables, unused_mut)]
279                fn build_from_row<'a>(row: &impl Row<'a, __DB>)
280                                      -> deserialize::Result<Self>
281                {
282                    match <__T as FromSqlRow<($($ST,)*), __DB>>::build_from_row(row) {
283                        Ok(v) => Ok(Some(v)),
284                        Err(e) if e.is::<crate::result::UnexpectedNullError>() => Ok(None),
285                        Err(e) => Err(e)
286                    }
287                }
288            }
289
290            impl<__T,  __DB, $($ST,)*> Queryable<Nullable<($($ST,)*)>, __DB> for Option<__T>
291            where __DB: Backend,
292                  Self: FromStaticSqlRow<Nullable<($($ST,)*)>, __DB>,
293                  ($($ST,)*): SqlType,
294            {
295                type Row = Self;
296
297                fn build(row: Self::Row) -> deserialize::Result<Self> {
298                    Ok(row)
299                }
300            }
301
302            impl<$($T,)*> TupleSize for ($($T,)*)
303                where $($T: TupleSize,)*
304            {
305                const SIZE: usize = $($T::SIZE +)* 0;
306            }
307
308            impl<$($T,)*> TupleSize for Nullable<($($T,)*)>
309            where $($T: TupleSize,)*
310                  ($($T,)*): SqlType,
311            {
312                const SIZE: usize = $($T::SIZE +)* 0;
313            }
314
315            impl<$($T,)* __DB> QueryMetadata<($($T,)*)> for __DB
316            where __DB: Backend,
317                 $(__DB: QueryMetadata<$T>,)*
318            {
319                fn row_metadata(lookup: &mut Self::MetadataLookup, row: &mut Vec<Option<__DB::TypeMetadata>>) {
320                    $(
321                        <__DB as QueryMetadata<$T>>::row_metadata(lookup, row);
322                    )*
323                }
324            }
325
326            impl<$($T,)* __DB> QueryMetadata<Nullable<($($T,)*)>> for __DB
327            where __DB: Backend,
328                  $(__DB: QueryMetadata<$T>,)*
329            {
330                fn row_metadata(lookup: &mut Self::MetadataLookup, row: &mut Vec<Option<__DB::TypeMetadata>>) {
331                    $(
332                        <__DB as QueryMetadata<$T>>::row_metadata(lookup, row);
333                    )*
334                }
335            }
336
337            impl<$($T,)* __DB> deserialize::QueryableByName< __DB> for ($($T,)*)
338            where __DB: Backend,
339            $($T: deserialize::QueryableByName<__DB>,)*
340            {
341                fn build<'a>(row: &impl NamedRow<'a, __DB>) -> deserialize::Result<Self> {
342                    Ok(($(
343                        <$T as deserialize::QueryableByName<__DB>>::build(row)?,
344                    )*))
345                }
346            }
347
348            #[diagnostic::do_not_recommend]
349            impl<__T, $($ST,)* __DB> CompatibleType<__T, __DB> for ($($ST,)*)
350            where
351                __DB: Backend,
352                __T: FromSqlRow<($($ST,)*), __DB>,
353            {
354                type SqlType = Self;
355            }
356
357            impl<__T, $($ST,)* __DB> CompatibleType<Option<__T>, __DB> for Nullable<($($ST,)*)>
358            where
359                __DB: Backend,
360                ($($ST,)*): CompatibleType<__T, __DB>
361            {
362                type SqlType = Nullable<<($($ST,)*) as CompatibleType<__T, __DB>>::SqlType>;
363            }
364
365            impl<$($ST,)*> SqlTypeOrSelectable for ($($ST,)*)
366            where $($ST: SqlTypeOrSelectable,)*
367            {}
368
369            impl<$($ST,)*> SqlTypeOrSelectable for Nullable<($($ST,)*)>
370            where ($($ST,)*): SqlTypeOrSelectable
371            {}
372        )+
373    }
374}
375
376macro_rules! impl_from_sql_row {
377    (($T1: ident,), ($ST1: ident,)) => {
378        impl<$T1, $ST1, __DB> crate::deserialize::FromStaticSqlRow<($ST1,), __DB> for ($T1,) where
379            __DB: Backend,
380            $ST1: CompatibleType<$T1, __DB>,
381            $T1: FromSqlRow<<$ST1 as CompatibleType<$T1, __DB>>::SqlType, __DB>,
382        {
383
384            #[allow(non_snake_case, unused_variables, unused_mut)]
385            fn build_from_row<'a>(row: &impl Row<'a, __DB>)
386                                                       -> deserialize::Result<Self>
387            {
388                Ok(($T1::build_from_row(row)?,))
389            }
390        }
391    };
392    (($T1: ident, $($T: ident,)*), ($ST1: ident, $($ST: ident,)*)) => {
393        #[diagnostic::do_not_recommend]
394        impl<$T1, $($T,)* $($ST,)* __DB> FromSqlRow<($($ST,)* crate::sql_types::Untyped), __DB> for ($($T,)* $T1)
395        where __DB: Backend,
396              $T1: FromSqlRow<crate::sql_types::Untyped, __DB>,
397            $(
398                $T: FromSqlRow<$ST, __DB> + StaticallySizedRow<$ST, __DB>,
399        )*
400        {
401            #[allow(non_snake_case, unused_variables, unused_mut)]
402            fn build_from_row<'a>(full_row: &impl Row<'a, __DB>)
403                -> deserialize::Result<Self>
404            {
405                let field_count = full_row.field_count();
406
407                let mut static_field_count = 0;
408                $(
409                    let row = full_row.partial_row(static_field_count..static_field_count + $T::FIELD_COUNT);
410                    static_field_count += $T::FIELD_COUNT;
411                    let $T = $T::build_from_row(&row)?;
412                )*
413
414                let row = full_row.partial_row(static_field_count..field_count);
415
416                Ok(($($T,)* $T1::build_from_row(&row)?,))
417            }
418        }
419
420        impl<$T1, $ST1, $($T,)* $($ST,)* __DB> FromStaticSqlRow<($($ST,)* $ST1,), __DB> for ($($T,)* $T1,) where
421            __DB: Backend,
422            $ST1: CompatibleType<$T1, __DB>,
423            $T1: FromSqlRow<<$ST1 as CompatibleType<$T1, __DB>>::SqlType, __DB>,
424            $(
425                $ST: CompatibleType<$T, __DB>,
426                $T: FromSqlRow<<$ST as CompatibleType<$T, __DB>>::SqlType, __DB> + StaticallySizedRow<<$ST as CompatibleType<$T, __DB>>::SqlType, __DB>,
427            )*
428
429        {
430
431            #[allow(non_snake_case, unused_variables, unused_mut)]
432            fn build_from_row<'a>(full_row: &impl Row<'a, __DB>)
433                -> deserialize::Result<Self>
434            {
435                let field_count = full_row.field_count();
436
437                let mut static_field_count = 0;
438                $(
439                    let row = full_row.partial_row(static_field_count..static_field_count + $T::FIELD_COUNT);
440                    static_field_count += $T::FIELD_COUNT;
441                    let $T = <$T as FromSqlRow<<$ST as CompatibleType<$T, __DB>>::SqlType, __DB>>::build_from_row(&row)?;
442                )*
443
444                let row = full_row.partial_row(static_field_count..field_count);
445
446                Ok(($($T,)* $T1::build_from_row(&row)?,))
447            }
448        }
449    }
450}
451
452macro_rules! impl_valid_grouping_for_tuple_of_columns {
453    ($T1: ident, $($T: ident,)+) => {
454        impl<$T1, $($T,)* __GroupByClause> ValidGrouping<__GroupByClause> for ($T1, $($T,)*)
455        where
456            $T1: ValidGrouping<__GroupByClause>,
457            ($($T,)*): ValidGrouping<__GroupByClause>,
458            $T1::IsAggregate: MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>,
459        {
460            type IsAggregate = <$T1::IsAggregate as MixedAggregates<<($($T,)*) as ValidGrouping<__GroupByClause>>::IsAggregate>>::Output;
461        }
462
463        impl<$T1, $($T,)* Col> IsContainedInGroupBy<Col> for ($T1, $($T,)*)
464        where Col: Column,
465              ($($T,)*): IsContainedInGroupBy<Col>,
466              $T1: IsContainedInGroupBy<Col>,
467              $T1::Output: is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy<Col>>::Output>
468        {
469            type Output = <$T1::Output as is_contained_in_group_by::IsAny<<($($T,)*) as IsContainedInGroupBy<Col>>::Output>>::Output;
470        }
471    };
472    ($T1: ident,) => {
473        impl<$T1, Col> IsContainedInGroupBy<Col> for ($T1,)
474        where Col: Column,
475              $T1: IsContainedInGroupBy<Col>
476        {
477            type Output = <$T1 as IsContainedInGroupBy<Col>>::Output;
478        }
479
480        impl<$T1, __GroupByClause> ValidGrouping<__GroupByClause> for ($T1,)
481            where $T1: ValidGrouping<__GroupByClause>
482        {
483            type IsAggregate = $T1::IsAggregate;
484        }
485    };
486}
487
488macro_rules! impl_sql_type {
489    (
490        @build
491        start_ts = [$($ST: ident,)*],
492        ts = [$T1: ident,],
493        bounds = [$($bounds: tt)*],
494        is_null = [$($is_null: tt)*],
495    )=> {
496        impl<$($ST,)*> SqlType for ($($ST,)*)
497        where
498            $($ST: SqlType,)*
499            $($bounds)*
500            $T1::IsNull: OneIsNullable<$($is_null)*>,
501        {
502            type IsNull = <$T1::IsNull as OneIsNullable<$($is_null)*>>::Out;
503        }
504
505    };
506    (
507        @build
508        start_ts = [$($ST: ident,)*],
509        ts = [$T1: ident, $($T: ident,)+],
510        bounds = [$($bounds: tt)*],
511        is_null = [$($is_null: tt)*],
512    )=> {
513        impl_sql_type!{
514            @build
515            start_ts = [$($ST,)*],
516            ts = [$($T,)*],
517            bounds = [$($bounds)* $T1::IsNull: OneIsNullable<$($is_null)*>,],
518            is_null = [<$T1::IsNull as OneIsNullable<$($is_null)*>>::Out],
519        }
520    };
521    ($T1: ident, $($T: ident,)+) => {
522        impl_sql_type!{
523            @build
524            start_ts = [$T1, $($T,)*],
525            ts = [$($T,)*],
526            bounds = [],
527            is_null = [$T1::IsNull],
528        }
529    };
530    ($T1: ident,) => {
531        impl<$T1> SqlType for ($T1,)
532        where $T1: SqlType,
533        {
534            type IsNull = $T1::IsNull;
535        }
536    }
537}
538
539diesel_derives::__diesel_for_each_tuple!(tuple_impls);