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