diesel_derives/
identifiable.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::parse_quote;
4use syn::DeriveInput;
5use syn::Result;
6
7use crate::attrs::AttributeSpanWrapper;
8use crate::field::Field;
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 table_name = &model.table_names()[0];
17
18    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
19    let mut ref_generics = item.generics.clone();
20    ref_generics.params.push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lifetime(&mut _s, "\'ident");
        _s
    })parse_quote!('ident));
21    let (ref_generics, ..) = ref_generics.split_for_impl();
22
23    let mut field_ty = Vec::new();
24    let mut field_name = Vec::new();
25    for pk in model.primary_key_names.iter() {
26        let Field {
27            ty,
28            name,
29            serialize_as,
30            ..
31        } = &model.find_column(pk)?;
32        if let Some(AttributeSpanWrapper { item: ty, .. }) = serialize_as.as_ref() {
33            field_ty.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    _s
}quote!(#ty));
34            field_name.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_colon2(&mut _s);
    ::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, "Into");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    ::quote::__private::push_gt(&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, "self");
            ::quote::__private::push_dot(&mut _s);
            ::quote::ToTokens::to_tokens(&name, &mut _s);
            ::quote::__private::push_dot(&mut _s);
            ::quote::__private::push_ident(&mut _s, "clone");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            _s
        });
    _s
}quote!(::std::convert::Into::<#ty>::into(self.#name.clone())));
35        } else {
36            field_ty.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'ident");
    ::quote::ToTokens::to_tokens(&ty, &mut _s);
    _s
}quote!(&'ident #ty));
37            field_name.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_ident(&mut _s, "self");
    ::quote::__private::push_dot(&mut _s);
    ::quote::ToTokens::to_tokens(&name, &mut _s);
    _s
}quote!(&self.#name));
38        }
39    }
40
41    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, "associations");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "HasTable");
    ::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, "Table");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&table_name, &mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "table");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "table");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "associations");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "HasTable");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Table");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&table_name, &mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "table");
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&ref_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "associations");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Identifiable");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'ident");
    ::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, "Id");
            ::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 mut _i = 0usize;
                        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,
                                };
                            if _i > 0 { ::quote::__private::push_comma(&mut _s); }
                            _i += 1;
                            ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "id");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "associations");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Identifiable");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Id");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    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 mut _i = 0usize;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut field_name, i) = field_name.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let field_name =
                                        match field_name.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    if _i > 0 { ::quote::__private::push_comma(&mut _s); }
                                    _i += 1;
                                    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
                                }
                            }
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::ToTokens::to_tokens(&ref_generics, &mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "associations");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Identifiable");
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'_");
    ::quote::__private::push_and(&mut _s);
    ::quote::__private::push_lifetime(&mut _s, "\'ident");
    ::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, "Id");
            ::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 mut _i = 0usize;
                        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,
                                };
                            if _i > 0 { ::quote::__private::push_comma(&mut _s); }
                            _i += 1;
                            ::quote::ToTokens::to_tokens(&field_ty, &mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "id");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "self");
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_ident(&mut _s, "as");
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "associations");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Identifiable");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Id");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    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 mut _i = 0usize;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut field_name, i) = field_name.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let field_name =
                                        match field_name.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    if _i > 0 { ::quote::__private::push_comma(&mut _s); }
                                    _i += 1;
                                    ::quote::ToTokens::to_tokens(&field_name, &mut _s);
                                }
                            }
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote! {
42        impl #impl_generics diesel::associations::HasTable for #struct_name #ty_generics
43        #where_clause
44        {
45            type Table = #table_name::table;
46
47            fn table() -> <Self as diesel::associations::HasTable>::Table {
48                #table_name::table
49            }
50        }
51
52        impl #ref_generics diesel::associations::Identifiable for &'ident #struct_name #ty_generics
53        #where_clause
54        {
55            type Id = (#(#field_ty),*);
56
57            fn id(self) -> <Self as diesel::associations::Identifiable>::Id {
58                (#(#field_name),*)
59            }
60        }
61
62        impl #ref_generics diesel::associations::Identifiable for &'_ &'ident #struct_name #ty_generics
63            #where_clause
64        {
65            type Id = (#(#field_ty),*);
66
67            fn id(self) -> <Self as diesel::associations::Identifiable>::Id {
68                (#(#field_name),*)
69            }
70        }
71    }))
72}