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 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 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);