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!(())
}
}
}
}