1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
use proc_macro2::{self, Ident, Span}; use syn; use field::*; use model::*; use util::*; pub fn derive(item: syn::DeriveInput) -> Result<proc_macro2::TokenStream, Diagnostic> { let model = Model::from_item(&item)?; let struct_name = &item.ident; let field_expr = model .fields() .iter() .map(|f| field_expr(f, &model)) .collect::<Result<Vec<_>, _>>()?; let (_, ty_generics, ..) = item.generics.split_for_impl(); let mut generics = item.generics.clone(); generics .params .push(parse_quote!(__DB: diesel::backend::Backend)); for field in model.fields() { let where_clause = generics.where_clause.get_or_insert(parse_quote!(where)); let field_ty = field.ty_for_deserialize()?; if field.has_flag("embed") { where_clause .predicates .push(parse_quote!(#field_ty: QueryableByName<__DB>)); } else { let st = sql_type(field, &model); where_clause .predicates .push(parse_quote!(#field_ty: diesel::deserialize::FromSql<#st, __DB>)); } } let (impl_generics, _, where_clause) = generics.split_for_impl(); Ok(wrap_in_dummy_mod( model.dummy_mod_name("queryable_by_name"), quote! { use diesel::deserialize::{self, QueryableByName}; use diesel::row::NamedRow; impl #impl_generics QueryableByName<__DB> for #struct_name #ty_generics #where_clause { fn build<__R: NamedRow<__DB>>(row: &__R) -> deserialize::Result<Self> { std::result::Result::Ok(Self { #(#field_expr,)* }) } } }, )) } fn field_expr(field: &Field, model: &Model) -> Result<syn::FieldValue, Diagnostic> { if field.has_flag("embed") { Ok(field .name .assign(parse_quote!(QueryableByName::build(row)?))) } else { let column_name = field.column_name(); let ty = field.ty_for_deserialize()?; let st = sql_type(field, model); Ok(field .name .assign(parse_quote!(row.get::<#st, #ty>(stringify!(#column_name))?.into()))) } } fn sql_type(field: &Field, model: &Model) -> syn::Type { let table_name = model.table_name(); let column_name = field.column_name(); match field.sql_type { Some(ref st) => st.clone(), None => { if model.has_table_name_attribute() { parse_quote!(diesel::dsl::SqlTypeOf<#table_name::#column_name>) } else { let field_name = match field.name { FieldName::Named(ref x) => x.clone(), _ => Ident::new("field", Span::call_site()), }; field .span .error(format!("Cannot determine the SQL type of {}", field_name)) .help( "Your struct must either be annotated with `#[table_name = \"foo\"]` \ or have all of its fields annotated with `#[sql_type = \"Integer\"]`", ) .emit(); parse_quote!(()) } } } }