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