diesel_derives/
as_expression.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::parse_quote;
4use syn::DeriveInput;
5use syn::Result;
6
7use crate::model::Model;
8use crate::util::{ty_for_foreign_derive, wrap_in_dummy_mod};
9
10pub fn derive(item: DeriveInput) -> Result<TokenStream> {
11    let model = Model::from_item(&item, true, false)?;
12
13    if model.sql_types.is_empty() {
14        return Err(syn::Error::new(
15            proc_macro2::Span::call_site(),
16            "At least one `sql_type` is needed for deriving `AsExpression` on a structure.",
17        ));
18    }
19
20    let struct_ty = ty_for_foreign_derive(&item, &model)?;
21
22    // type generics are already handled by `ty_for_foreign_derive`
23    let (impl_generics_plain, _, where_clause_plain) = item.generics.split_for_impl();
24
25    let mut generics = item.generics.clone();
26    generics.params.push(parse_quote!('__expr));
27
28    let (impl_generics, _, where_clause) = generics.split_for_impl();
29
30    let mut generics2 = generics.clone();
31    generics2.params.push(parse_quote!('__expr2));
32    let (impl_generics2, _, where_clause2) = generics2.split_for_impl();
33
34    let tokens = model.sql_types.iter().map(|sql_type| {
35
36        let mut to_sql_generics = item.generics.clone();
37        to_sql_generics.params.push(parse_quote!(__DB));
38        to_sql_generics.make_where_clause().predicates.push(parse_quote!(__DB: diesel::backend::Backend));
39        to_sql_generics.make_where_clause().predicates.push(parse_quote!(Self: diesel::serialize::ToSql<#sql_type, __DB>));
40        let (to_sql_impl_generics, _, to_sql_where_clause) = to_sql_generics.split_for_impl();
41
42        let tokens = quote!(
43            impl #impl_generics diesel::expression::AsExpression<#sql_type>
44                for &'__expr #struct_ty #where_clause
45            {
46                type Expression = diesel::internal::derives::as_expression::Bound<#sql_type, Self>;
47
48                fn as_expression(self) -> <Self as diesel::expression::AsExpression<#sql_type>>::Expression {
49                    diesel::internal::derives::as_expression::Bound::new(self)
50                }
51            }
52
53            impl #impl_generics diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>>
54                for &'__expr #struct_ty #where_clause
55            {
56                type Expression = diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<#sql_type>, Self>;
57
58                fn as_expression(self) -> <Self as diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>>>::Expression {
59                    diesel::internal::derives::as_expression::Bound::new(self)
60                }
61            }
62
63            impl #impl_generics2 diesel::expression::AsExpression<#sql_type>
64                for &'__expr2 &'__expr #struct_ty #where_clause2
65            {
66                type Expression = diesel::internal::derives::as_expression::Bound<#sql_type, Self>;
67
68                fn as_expression(self) -> <Self as diesel::expression::AsExpression<#sql_type>>::Expression {
69                    diesel::internal::derives::as_expression::Bound::new(self)
70                }
71            }
72
73            impl #impl_generics2 diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>>
74                for &'__expr2 &'__expr #struct_ty #where_clause2
75            {
76                type Expression = diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<#sql_type>, Self>;
77
78                fn as_expression(self) -> <Self as diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>>>::Expression {
79                    diesel::internal::derives::as_expression::Bound::new(self)
80                }
81            }
82
83            impl #to_sql_impl_generics diesel::serialize::ToSql<diesel::sql_types::Nullable<#sql_type>, __DB>
84                for #struct_ty #to_sql_where_clause
85            {
86                fn to_sql<'__b>(&'__b self, out: &mut diesel::serialize::Output<'__b, '_, __DB>) -> diesel::serialize::Result
87                {
88                    diesel::serialize::ToSql::<#sql_type, __DB>::to_sql(self, out)
89                }
90            }
91        );
92
93        if model.not_sized {
94            tokens
95        } else {
96            quote!(
97                #tokens
98
99                impl #impl_generics_plain diesel::expression::AsExpression<#sql_type> for #struct_ty #where_clause_plain {
100                    type Expression = diesel::internal::derives::as_expression::Bound<#sql_type, Self>;
101
102                    fn as_expression(self) -> <Self as diesel::expression::AsExpression<#sql_type>>::Expression {
103                        diesel::internal::derives::as_expression::Bound::new(self)
104                    }
105                }
106
107                impl #impl_generics_plain diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>> for #struct_ty
108                #where_clause_plain
109                {
110                    type Expression = diesel::internal::derives::as_expression::Bound<diesel::sql_types::Nullable<#sql_type>, Self>;
111
112                    fn as_expression(self) -> <Self as diesel::expression::AsExpression<diesel::sql_types::Nullable<#sql_type>>>::Expression {
113                        diesel::internal::derives::as_expression::Bound::new(self)
114                    }
115                }
116            )
117        }
118    });
119
120    Ok(wrap_in_dummy_mod(quote! {
121        #(#tokens)*
122    }))
123}