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