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