diesel/query_source/aliasing/
field_alias_mapper.rs

1use super::{Alias, AliasSource, AliasedField};
2
3use crate::expression;
4use crate::query_source::{Column, Table, TableNotEqual};
5
6/// Serves to map `Self` to `Alias<S>`
7///
8/// Any column `Self` that belongs to `S::Table` will be transformed into `AliasedField<S, Self>`
9///
10/// Any column `Self` that does not belong to `S::Table` will be left untouched.
11///
12/// This also works with tuples and some expressions.
13// This first part is implemented by the `table!` macro.
14// The second part is useful to implement the joins, and may be useful to an end-user for
15// ergonomics.
16pub trait FieldAliasMapper<S> {
17    /// Output type when mapping `C` to `Alias<S>`
18    ///
19    /// If `C: Column<Table = S::Table>`, `Out = AliasedField<S, C>`  
20    /// Otherwise, `Out = C`
21    type Out;
22
23    /// Does the mapping
24    fn map(self, alias: &Alias<S>) -> Self::Out;
25}
26
27#[doc(hidden)]
28/// Allows implementing `FieldAliasMapper` in external crates without running into conflicting impl
29/// errors due to https://github.com/rust-lang/rust/issues/20400
30///
31/// We will always have `Self = S::Table` and `CT = C::Table`
32pub trait FieldAliasMapperAssociatedTypesDisjointnessTrick<CT, S, C> {
33    type Out;
34    fn map(column: C, alias: &Alias<S>) -> Self::Out;
35}
36impl<S, C> FieldAliasMapper<S> for C
37where
38    S: AliasSource,
39    C: Column,
40    S::Target: FieldAliasMapperAssociatedTypesDisjointnessTrick<C::Table, S, C>,
41{
42    type Out = <S::Target as FieldAliasMapperAssociatedTypesDisjointnessTrick<C::Table, S, C>>::Out;
43
44    fn map(self, alias: &Alias<S>) -> Self::Out {
45        <S::Target as FieldAliasMapperAssociatedTypesDisjointnessTrick<C::Table, S, C>>::map(
46            self, alias,
47        )
48    }
49}
50
51impl<TS, TC, S, C> FieldAliasMapperAssociatedTypesDisjointnessTrick<TC, S, C> for TS
52where
53    S: AliasSource<Target = TS>,
54    C: Column<Table = TC>,
55    TC: Table,
56    TS: TableNotEqual<TC>,
57{
58    type Out = C;
59
60    fn map(column: C, _alias: &Alias<S>) -> Self::Out {
61        // left untouched because the tables are different
62        column
63    }
64}
65
66macro_rules! field_alias_mapper {
67    ($(
68        $Tuple:tt {
69            $(($idx:tt) -> $T:ident, $ST:ident, $TT:ident,)+
70        }
71    )+) => {
72        $(
73            impl<_S, $($T,)*> FieldAliasMapper<_S> for ($($T,)*)
74            where
75                _S: AliasSource,
76                $($T: FieldAliasMapper<_S>,)*
77            {
78                type Out = ($(<$T as FieldAliasMapper<_S>>::Out,)*);
79
80                fn map(self, alias: &Alias<_S>) -> Self::Out {
81                    (
82                        $(self.$idx.map(alias),)*
83                    )
84                }
85            }
86        )*
87    }
88}
89
90diesel_derives::__diesel_for_each_tuple!(field_alias_mapper);
91
92// The following `FieldAliasMapper` impls are useful for the generic join implementations.
93// More may be added.
94impl<SPrev, SNew, F> FieldAliasMapper<SNew> for AliasedField<SPrev, F>
95where
96    SNew: AliasSource,
97{
98    type Out = Self;
99
100    fn map(self, _alias: &Alias<SNew>) -> Self::Out {
101        // left untouched because it has already been aliased
102        self
103    }
104}
105
106impl<S, F> FieldAliasMapper<S> for expression::nullable::Nullable<F>
107where
108    F: FieldAliasMapper<S>,
109{
110    type Out = expression::nullable::Nullable<<F as FieldAliasMapper<S>>::Out>;
111
112    fn map(self, alias: &Alias<S>) -> Self::Out {
113        expression::nullable::Nullable::new(self.0.map(alias))
114    }
115}
116
117impl<S, F> FieldAliasMapper<S> for expression::grouped::Grouped<F>
118where
119    F: FieldAliasMapper<S>,
120{
121    type Out = expression::grouped::Grouped<<F as FieldAliasMapper<S>>::Out>;
122
123    fn map(self, alias: &Alias<S>) -> Self::Out {
124        expression::grouped::Grouped(self.0.map(alias))
125    }
126}