diesel_derives/
queryable.rs

1use proc_macro2::{Span, TokenStream};
2use quote::quote;
3use syn::{parse_quote, DeriveInput, Ident, Index, Result};
4
5use crate::field::Field;
6use crate::model::Model;
7use crate::util::wrap_in_dummy_mod;
8
9pub fn derive(item: DeriveInput) -> Result<TokenStream> {
10    let model = Model::from_item(&item, false, true)?;
11
12    let struct_name = &item.ident;
13    let field_ty = &model
14        .fields()
15        .iter()
16        .map(Field::ty_for_deserialize)
17        .collect::<Vec<_>>();
18    let build_expr = model.fields().iter().enumerate().map(|(i, f)| {
19        let field_name = &f.name;
20        let i = Index::from(i);
21        // we explicitly call `.try_into()` here
22        // instead of using the fully qualified variant
23        // to allow also using a `.try_into()` method on the type
24        // itself without going through the trait
25        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "row");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&i, &mut _s);
    ::quote::__private::push_dot(&mut _s);
    ::quote::__private::push_ident(&mut _s, "try_into");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    ::quote::__private::push_question(&mut _s);
    _s
}quote!(#field_name: row.#i.try_into()?)
26    });
27    let sql_type = &(0..model.fields().len())
28        .map(|i| {
29            let i = Ident::new(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("__ST{0}", i))
    })format!("__ST{i}"), Span::mixed_site());
30            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&i, &mut _s);
    _s
}quote!(#i)
31        })
32        .collect::<Vec<_>>();
33
34    let (_, ty_generics, _) = item.generics.split_for_impl();
35    let mut generics = item.generics.clone();
36    generics
37        .params
38        .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));
39    for id in 0..model.fields().len() {
40        let ident = Ident::new(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("__ST{0}", id))
    })format!("__ST{id}"), Span::mixed_site());
41        generics.params.push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&ident, &mut _s);
        _s
    })parse_quote!(#ident));
42    }
43    {
44        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));
45        where_clause
46            .predicates
47            .push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                {
                    use ::quote::__private::ext::*;
                    let has_iter = ::quote::__private::HasIterator::<false>;
                    #[allow(unused_mut)]
                    let (mut field_ty, i) = field_ty.quote_into_iter();
                    let has_iter = has_iter | i;
                    <_ as
                            ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                    while true {
                        let field_ty =
                            match field_ty.next() {
                                Some(_x) => ::quote::__private::RepInterp(_x),
                                None => break,
                            };
                        ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
                        ::quote::__private::push_comma(&mut _s);
                    }
                }
                _s
            });
        ::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, "deserialize");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "FromStaticSqlRow");
        ::quote::__private::push_lt(&mut _s);
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                {
                    use ::quote::__private::ext::*;
                    let has_iter = ::quote::__private::HasIterator::<false>;
                    #[allow(unused_mut)]
                    let (mut sql_type, i) = sql_type.quote_into_iter();
                    let has_iter = has_iter | i;
                    <_ as
                            ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                    while true {
                        let sql_type =
                            match sql_type.next() {
                                Some(_x) => ::quote::__private::RepInterp(_x),
                                None => break,
                            };
                        ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
                        ::quote::__private::push_comma(&mut _s);
                    }
                }
                _s
            });
        ::quote::__private::push_comma(&mut _s);
        ::quote::__private::push_ident(&mut _s, "__DB");
        ::quote::__private::push_gt(&mut _s);
        _s
    })parse_quote!((#(#field_ty,)*): diesel::deserialize::FromStaticSqlRow<(#(#sql_type,)*), __DB>));
48    }
49    let (impl_generics, _, where_clause) = generics.split_for_impl();
50
51    Ok(wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "use");
    ::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_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "Row");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_underscore(&mut _s);
            ::quote::__private::push_comma(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Field");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_underscore(&mut _s);
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    ::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, "Queryable");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut sql_type, i) = sql_type.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let sql_type =
                        match sql_type.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_comma(&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, "type");
            ::quote::__private::push_ident(&mut _s, "Row");
            ::quote::__private::push_eq(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut field_ty, i) = field_ty.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let field_ty =
                                match field_ty.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
                            ::quote::__private::push_comma(&mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::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");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut field_ty, i) = field_ty.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let field_ty =
                                        match field_ty.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
                                    ::quote::__private::push_comma(&mut _s);
                                }
                            }
                            _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();
                    ::quote::__private::push_ident(&mut _s, "use");
                    ::quote::__private::push_ident(&mut _s, "std");
                    ::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, "TryInto");
                    ::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 build_expr, i) = build_expr.quote_into_iter();
                                        let has_iter = has_iter | i;
                                        <_ as
                                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                        while true {
                                            let build_expr =
                                                match build_expr.next() {
                                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                                    None => break,
                                                };
                                            ::quote::ToTokens::to_tokens(&build_expr, &mut _s);
                                            ::quote::__private::push_comma(&mut _s);
                                        }
                                    }
                                    _s
                                });
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
52        use diesel::row::{Row as _, Field as _};
53
54        impl #impl_generics diesel::deserialize::Queryable<(#(#sql_type,)*), __DB> for #struct_name #ty_generics
55            #where_clause
56        {
57            type Row = (#(#field_ty,)*);
58
59            fn build(row: (#(#field_ty,)*)) -> diesel::deserialize::Result<Self> {
60                use std::convert::TryInto;
61                diesel::deserialize::Result::Ok(Self {
62                    #(#build_expr,)*
63                })
64            }
65        }
66    }))
67}