Skip to main content

diesel_derives/
queryable_by_name.rs

1use diesel_attribute_parser::AttributeSpanWrapper;
2use diesel_attribute_parser::CheckForBackend;
3use proc_macro2::{Span, TokenStream};
4use quote::{quote, quote_spanned};
5use syn::spanned::Spanned;
6use syn::{DeriveInput, Ident, LitStr, Result, Type, parse_quote, parse_quote_spanned};
7
8use crate::field::{Field, FieldName};
9use crate::model::Model;
10use crate::util::wrap_in_dummy_mod;
11
12pub fn derive(item: DeriveInput) -> Result<TokenStream> {
13    let model = Model::from_item(&item, false, false)?;
14
15    let struct_name = &item.ident;
16    let fields = &model.fields().iter().map(get_ident).collect::<Vec<_>>();
17
18    let initial_field_expr = model
19        .fields()
20        .iter()
21        .map(|f| {
22            let field_ty = &f.ty;
23
24            if f.embed() {
25                Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_ident(&mut _s, "QueryableByName");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_shr(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "build");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "row");
            _s
        });
    ::quote::__private::push_question(&mut _s);
    _s
}quote!(<#field_ty as QueryableByName<__DB>>::build(row)?))
26            } else {
27                let st = sql_type(f, &model)?;
28                let deserialize_ty = f.ty_for_deserialize();
29                let name = f.column_name()?;
30                let name = LitStr::new(&name.to_string(), name.span());
31                Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "let");
            ::quote::__private::push_ident(&mut _s, "field");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "row");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "NamedRow");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "get");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&st, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::ToTokens::to_tokens(&deserialize_ty, &mut _s);
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "row");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::ToTokens::to_tokens(&name, &mut _s);
                    _s
                });
            ::quote::__private::push_question(&mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&deserialize_ty, &mut _s);
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "core");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "convert");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Into");
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
            ::quote::__private::push_shr(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "into");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "field");
                    _s
                });
            _s
        });
    _s
}quote!(
32                   {
33                       let field = diesel::row::NamedRow::get::<#st, #deserialize_ty>(row, #name)?;
34                       <#deserialize_ty as ::core::convert::Into<#field_ty>>::into(field)
35                   }
36                ))
37            }
38        })
39        .collect::<Result<Vec<_>>>()?;
40
41    let (_, ty_generics, ..) = item.generics.split_for_impl();
42    let mut generics = item.generics.clone();
43    generics
44        .params
45        .push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "__DB");
        ::quote::__private::push_colon(&mut _s);
        ::quote::__private::push_ident(&mut _s, "diesel");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "backend");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Backend");
        _s
    })parse_quote!(__DB: diesel::backend::Backend));
46
47    for field in model.fields() {
48        let where_clause = generics.where_clause.get_or_insert(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "where");
        _s
    })parse_quote!(where));
49        let span = Span::mixed_site().located_at(field.ty.span());
50        let field_ty = field.ty_for_deserialize();
51        if field.embed() {
52            where_clause.predicates.push(
53                ::syn::__private::parse_quote({
        let _span: ::quote::__private::Span =
            ::quote::__private::get_span(span).__into_span();
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
        ::quote::__private::push_colon_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "diesel");
        ::quote::__private::push_colon2_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "deserialize");
        ::quote::__private::push_colon2_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span,
            "QueryableByName");
        ::quote::__private::push_lt_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "__DB");
        ::quote::__private::push_gt_spanned(&mut _s, _span);
        _s
    })parse_quote_spanned!(span=> #field_ty: diesel::deserialize::QueryableByName<__DB>),
54            );
55        } else {
56            let st = sql_type(field, &model)?;
57            where_clause.predicates.push(
58                ::syn::__private::parse_quote({
        let _span: ::quote::__private::Span =
            ::quote::__private::get_span(span).__into_span();
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
        ::quote::__private::push_colon_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "diesel");
        ::quote::__private::push_colon2_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "deserialize");
        ::quote::__private::push_colon2_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "FromSql");
        ::quote::__private::push_lt_spanned(&mut _s, _span);
        ::quote::ToTokens::to_tokens(&st, &mut _s);
        ::quote::__private::push_comma_spanned(&mut _s, _span);
        ::quote::__private::push_ident_spanned(&mut _s, _span, "__DB");
        ::quote::__private::push_gt_spanned(&mut _s, _span);
        _s
    })parse_quote_spanned!(span=> #field_ty: diesel::deserialize::FromSql<#st, __DB>),
59            );
60        }
61    }
62    let model = &model;
63    let check_function = if let Some(ref backends) = model.check_for_backend {
64        let field_check_bound = model.fields().iter().filter(|f| !f.embed()).flat_map(|f| {
65            if let CheckForBackend::Backends(backends) = backends {
66                let iter = backends.iter().map(move |b| {
67                    let field_ty = f.ty_for_deserialize();
68                    let span = Span::mixed_site().located_at(f.ty.span());
69                    let ty = sql_type(f, model).unwrap();
70                    {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "diesel");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "deserialize");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "FromSqlRow");
    ::quote::__private::push_lt_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_comma_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&b, &mut _s);
    ::quote::__private::push_gt_spanned(&mut _s, _span);
    _s
}quote::quote_spanned! {span =>
71                        #field_ty: diesel::deserialize::FromSqlRow<#ty, #b>
72                    }
73                });
74                Box::new(iter) as Box<dyn Iterator<Item = _>>
75            } else {
76                Box::new(std::iter::empty())
77            }
78        });
79        Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "fn");
    ::quote::__private::push_ident(&mut _s, "_check_field_compatibility");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_ident(&mut _s, "where");
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut field_check_bound, i) = field_check_bound.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let field_check_bound =
                match field_check_bound.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&field_check_bound, &mut _s);
            ::quote::__private::push_comma(&mut _s);
        }
    }
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        ::quote::__private::TokenStream::new());
    _s
}quote::quote! {
80            fn _check_field_compatibility()
81            where
82                #(#field_check_bound,)*
83            {}
84        })
85    } else {
86        None
87    };
88
89    let (impl_generics, _, where_clause) = generics.split_for_impl();
90    let field_constructor = model.fields().iter().zip(fields).map(|(f, f_n)| {
91        let s = f.span;
92        let field_name = &f.name;
93        match field_name {
94            FieldName::Named(_) => {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(s).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&f_n, &mut _s);
    _s
}quote_spanned! {s=> #f_n},
95            FieldName::Unnamed(_) => {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(s).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    ::quote::__private::push_colon_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&f_n, &mut _s);
    _s
}quote_spanned! {s=> #field_name: #f_n},
96        }
97    });
98
99    Ok(wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&impl_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "deserialize");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QueryableByName");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
    ::quote::ToTokens::to_tokens(&ty_generics, &mut _s);
    ::quote::ToTokens::to_tokens(&where_clause, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "build");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_lifetime(&mut _s, "\'__a");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "row");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "impl");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "row");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "NamedRow");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_lifetime(&mut _s, "\'__a");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_gt(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "deserialize");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut fields, i) = fields.quote_into_iter();
                        let has_iter = has_iter | i;
                        #[allow(unused_mut)]
                        let (mut initial_field_expr, i) =
                            initial_field_expr.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let fields =
                                match fields.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            let initial_field_expr =
                                match initial_field_expr.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::__private::push_ident(&mut _s, "let");
                            ::quote::__private::push_ident(&mut _s, "mut");
                            ::quote::ToTokens::to_tokens(&fields, &mut _s);
                            ::quote::__private::push_eq(&mut _s);
                            ::quote::ToTokens::to_tokens(&initial_field_expr, &mut _s);
                            ::quote::__private::push_semi(&mut _s);
                        }
                    }
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "deserialize");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Result");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Ok");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "Self");
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Brace,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    {
                                        use ::quote::__private::ext::*;
                                        let has_iter = ::quote::__private::HasIterator::<false>;
                                        #[allow(unused_mut)]
                                        let (mut field_constructor, i) =
                                            field_constructor.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let field_constructor =
                                                match field_constructor.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&field_constructor, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                        }
                                    }
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&check_function, &mut _s);
    _s
}quote! {
100
101        impl #impl_generics diesel::deserialize::QueryableByName<__DB>
102            for #struct_name #ty_generics
103        #where_clause
104        {
105            fn build<'__a>(row: &impl diesel::row::NamedRow<'__a, __DB>) -> diesel::deserialize::Result<Self>
106            {
107                #(
108                    let mut #fields = #initial_field_expr;
109                )*
110                diesel::deserialize::Result::Ok(Self {
111                    #(#field_constructor,)*
112                })
113            }
114        }
115
116        #check_function
117    }))
118}
119
120fn get_ident(field: &Field) -> Ident {
121    match &field.name {
122        FieldName::Named(n) => n.clone(),
123        FieldName::Unnamed(i) => Ident::new(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("field_{0}", i.index))
    })format!("field_{}", i.index), i.span),
124    }
125}
126
127fn sql_type(field: &Field, model: &Model) -> Result<Type> {
128    let table_name = &model.table_names()[0];
129
130    match field.sql_type {
131        Some(AttributeSpanWrapper { item: ref st, .. }) => Ok(st.clone()),
132        None => {
133            let column_name = field.column_name()?.to_ident()?;
134            Ok(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "diesel");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "dsl");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "SqlTypeOf");
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&table_name, &mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::ToTokens::to_tokens(&column_name, &mut _s);
        ::quote::__private::push_gt(&mut _s);
        _s
    })parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>))
135        }
136    }
137}