1use proc_macro2::{Span, TokenStream};
2use quote::{quote, quote_spanned};
3use std::borrow::Cow;
4use syn::spanned::Spanned;
5use syn::{DeriveInput, Ident, Result, parse_quote};
6
7use crate::field::Field;
8use crate::model::Model;
9use crate::util::wrap_in_dummy_mod;
10use diesel_attribute_parser::CheckForBackend;
11
12type DefaultCheckCallback = fn(
13 &Model,
14 &syn::ImplGenerics<'_>,
15 Option<&syn::WhereClause>,
16 &[FieldSelectExpressionTyBuilder<'_>],
17) -> std::prelude::v1::Result<TokenStream, syn::Error>;
18
19pub fn derive(
20 item: DeriveInput,
21 default_check: Option<DefaultCheckCallback>,
22) -> Result<TokenStream> {
23 let model = Model::from_item(&item, false, false)?;
24
25 let (original_impl_generics, ty_generics, original_where_clause) =
26 item.generics.split_for_impl();
27
28 let mut generics = item.generics.clone();
29 generics
30 .params
31 .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));
32
33 for embed_field in model.fields().iter().filter(|f| f.embed()) {
34 let embed_ty = &embed_field.ty;
35 generics
36 .make_where_clause()
37 .predicates
38 .push(::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&embed_ty, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "Selectable");
::quote::__private::push_lt(&mut _s);
::quote::__private::push_ident(&mut _s, "__DB");
::quote::__private::push_gt(&mut _s);
_s
})parse_quote!(#embed_ty: Selectable<__DB>));
39 }
40
41 let (impl_generics, _, where_clause) = generics.split_for_impl();
42
43 let struct_name = &item.ident;
44
45 let mut compile_errors: Vec<syn::Error> = Vec::new();
46 let field_select_expression_type_builders = model
47 .fields()
48 .iter()
49 .map(|f| field_select_expression_ty_builder(f, &model, &mut compile_errors))
50 .collect::<Result<Vec<_>>>()?;
51 let field_select_expression_types = field_select_expression_type_builders
52 .iter()
53 .map(|f| f.type_with_backend(&::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "__DB");
_s
})parse_quote!(__DB)))
54 .collect::<Vec<_>>();
55 let field_select_expressions = model
56 .fields()
57 .iter()
58 .map(|f| field_column_inst(f, &model))
59 .collect::<Result<Vec<_>>>()?;
60
61 let check_function = match model.check_for_backend.as_ref() {
62 Some(CheckForBackend::Backends(backends)) => Some(generate_check_function(
63 &model,
64 &original_impl_generics,
65 original_where_clause,
66 &field_select_expression_type_builders,
67 backends,
68 ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "_check_field_compatibility");
_s
})parse_quote!(_check_field_compatibility),
69 )?),
70 Some(CheckForBackend::Disabled(_lit)) => None,
71 None => default_check
72 .map(|c| {
73 c(
74 &model,
75 &original_impl_generics,
76 original_where_clause,
77 &field_select_expression_type_builders,
78 )
79 })
80 .transpose()?,
81 };
82
83 let errors: TokenStream = compile_errors
84 .into_iter()
85 .map(|e| e.into_compile_error())
86 .collect();
87
88 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, "expression");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Selectable");
::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, "Selectable");
::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, "type");
::quote::__private::push_ident(&mut _s, "SelectExpression");
::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_select_expression_types, i) =
field_select_expression_types.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let field_select_expression_types =
match field_select_expression_types.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&field_select_expression_types,
&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, "construct_selection");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::__private::push_rarrow(&mut _s);
::quote::__private::push_ident(&mut _s, "Self");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SelectExpression");
::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 has_iter = ::quote::__private::HasIterator::<false>;
#[allow(unused_mut)]
let (mut field_select_expressions, i) =
field_select_expressions.quote_into_iter();
let has_iter = has_iter | i;
<_ as
::quote::__private::CheckHasIterator<true>>::check(has_iter);
while true {
let field_select_expressions =
match field_select_expressions.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&field_select_expressions,
&mut _s);
::quote::__private::push_comma(&mut _s);
}
}
_s
});
_s
});
_s
});
::quote::ToTokens::to_tokens(&check_function, &mut _s);
::quote::ToTokens::to_tokens(&errors, &mut _s);
_s
}quote! {
89 use diesel::expression::Selectable;
90
91 impl #impl_generics Selectable<__DB>
92 for #struct_name #ty_generics
93 #where_clause
94 {
95 type SelectExpression = (#(#field_select_expression_types,)*);
96
97 fn construct_selection() -> Self::SelectExpression {
98 (#(#field_select_expressions,)*)
99 }
100 }
101
102 #check_function
103
104 #errors
105 }))
106}
107
108pub fn generate_check_function(
109 model: &Model,
110 original_impl_generics: &syn::ImplGenerics<'_>,
111 original_where_clause: Option<&syn::WhereClause>,
112 field_select_expression_type_builders: &[FieldSelectExpressionTyBuilder<'_>],
113 backends: &syn::punctuated::Punctuated<syn::TypePath, syn::token::Comma>,
114 function_name: Ident,
115) -> Result<TokenStream> {
116 let field_check_bound = model
117 .fields()
118 .iter()
119 .zip(field_select_expression_type_builders)
120 .flat_map(|(f, ty_builder)| {
121 backends.iter().map(move |b| {
122 let span = Span::mixed_site().located_at(f.ty.span());
123 let field_ty = to_field_ty_bound(f.ty_for_deserialize())?;
124 let ty = ty_builder.type_with_backend(b);
125 Ok(::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, "FromSqlRow");
::quote::__private::push_lt_spanned(&mut _s, _span);
::quote::__private::push_lt_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, "dsl");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "SqlTypeOf");
::quote::__private::push_lt_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&ty, &mut _s);
::quote::__private::push_gt_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "as");
::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, "internal");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "derives");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "selectable");
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span,
"SqlTypeLikeMarker");
::quote::__private::push_gt_spanned(&mut _s, _span);
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::__private::push_ident_spanned(&mut _s, _span, "SqlType");
::quote::__private::push_comma_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&b, &mut _s);
::quote::__private::push_comma_spanned(&mut _s, _span);
::quote::__private::push_gt_spanned(&mut _s, _span);
_s
})syn::parse_quote_spanned! {span =>
126 #field_ty: diesel::deserialize::FromSqlRow<
127 <diesel::dsl::SqlTypeOf<#ty> as diesel::internal::derives::selectable::SqlTypeLikeMarker>::SqlType,
128 #b,
129 >
130 })
131 })
132 })
133 .collect::<Result<Vec<_>>>()?;
134 let where_clause = &mut original_where_clause.cloned();
135 let where_clause = where_clause.get_or_insert_with(|| ::syn::__private::parse_quote({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "where");
_s
})parse_quote!(where));
136 for field_check in field_check_bound {
137 where_clause.predicates.push(field_check);
138 }
139 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "fn");
::quote::ToTokens::to_tokens(&function_name, &mut _s);
::quote::ToTokens::to_tokens(&original_impl_generics, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
::quote::ToTokens::to_tokens(&where_clause, &mut _s);
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Brace,
::quote::__private::TokenStream::new());
_s
}quote::quote! {
140 fn #function_name #original_impl_generics()
141 #where_clause
142 {}
143 })
144}
145
146fn to_field_ty_bound(field_ty: &syn::Type) -> Result<TokenStream> {
147 match field_ty {
148 syn::Type::Reference(r) => {
149 use crate::quote::ToTokens;
150 Err(syn::Error::new(
154 field_ty.span(),
155 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("references are not supported in `Queryable` types\nconsider using `std::borrow::Cow<\'{0}, {1}>` instead",
r.lifetime.as_ref().expect("It's a struct field so it must have a named lifetime").ident,
r.elem.to_token_stream()))
})format!(
156 "references are not supported in `Queryable` types\n\
157 consider using `std::borrow::Cow<'{}, {}>` instead",
158 r.lifetime
159 .as_ref()
160 .expect("It's a struct field so it must have a named lifetime")
161 .ident,
162 r.elem.to_token_stream()
163 ),
164 ))
165 }
166 field_ty => Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&field_ty, &mut _s);
_s
}quote::quote! {
167 #field_ty
168 }),
169 }
170}
171
172fn field_select_expression_ty_builder<'a>(
173 field: &'a Field,
174 model: &Model,
175 compile_errors: &mut Vec<syn::Error>,
176) -> Result<FieldSelectExpressionTyBuilder<'a>> {
177 if let Some(ref select_expression) = field.select_expression {
178 use dsl_auto_type::auto_type::expression_type_inference as type_inference;
179 let expr = &select_expression.item;
180 let (inferred_type, errors) = type_inference::infer_expression_type(
181 expr,
182 field.select_expression_type.as_ref().map(|t| &t.item),
183 &type_inference::InferrerSettings::builder()
184 .dsl_path(::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");
_s
})parse_quote!(diesel::dsl))
185 .function_types_case(crate::AUTO_TYPE_DEFAULT_FUNCTION_TYPE_CASE)
186 .method_types_case(crate::AUTO_TYPE_DEFAULT_METHOD_TYPE_CASE)
187 .build(),
188 );
189 compile_errors.extend(errors);
190 Ok(FieldSelectExpressionTyBuilder::Always(
191 {
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&inferred_type, &mut _s);
_s
}quote::quote!(#inferred_type),
192 ))
193 } else if let Some(ref select_expression_type) = field.select_expression_type {
194 let ty = &select_expression_type.item;
195 Ok(FieldSelectExpressionTyBuilder::Always({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&ty, &mut _s);
_s
}quote!(#ty)))
196 } else if field.embed() {
197 Ok(FieldSelectExpressionTyBuilder::EmbedSelectable {
198 embed_ty: &field.ty,
199 })
200 } else {
201 let table_name = &model.table_names()[0];
202 let column_name = field.column_name()?.to_ident()?;
203 let span = Span::call_site();
204 Ok(FieldSelectExpressionTyBuilder::Always(
205 {
let _span: ::quote::__private::Span =
::quote::__private::get_span(span).__into_span();
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&table_name, &mut _s);
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&column_name, &mut _s);
_s
}quote_spanned!(span=> #table_name::#column_name),
206 ))
207 }
208}
209
210pub enum FieldSelectExpressionTyBuilder<'a> {
211 Always(TokenStream),
212 EmbedSelectable { embed_ty: &'a syn::Type },
213}
214
215impl FieldSelectExpressionTyBuilder<'_> {
216 fn type_with_backend(&self, backend: &syn::TypePath) -> Cow<'_, TokenStream> {
217 match self {
218 FieldSelectExpressionTyBuilder::Always(ty) => Cow::Borrowed(ty),
219 FieldSelectExpressionTyBuilder::EmbedSelectable { embed_ty } => {
220 Cow::Owned({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&embed_ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "Selectable");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&backend, &mut _s);
::quote::__private::push_shr(&mut _s);
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "SelectExpression");
_s
}quote!(<#embed_ty as Selectable<#backend>>::SelectExpression))
221 }
222 }
223 }
224}
225
226fn field_column_inst(field: &Field, model: &Model) -> Result<TokenStream> {
227 if let Some(ref select_expression) = field.select_expression {
228 let expr = &select_expression.item;
229 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&expr, &mut _s);
_s
}quote!(#expr))
230 } else if field.embed() {
231 let embed_ty = &field.ty;
232 Ok({
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&embed_ty, &mut _s);
::quote::__private::push_ident(&mut _s, "as");
::quote::__private::push_ident(&mut _s, "Selectable");
::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, "construct_selection");
::quote::__private::push_group(&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new());
_s
}quote!(<#embed_ty as Selectable<__DB>>::construct_selection()))
233 } else {
234 let table_name = &model.table_names()[0];
235 let column_name = field.column_name()?.to_ident()?;
236 let span = Span::call_site();
237 Ok({
let _span: ::quote::__private::Span =
::quote::__private::get_span(span).__into_span();
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&table_name, &mut _s);
::quote::__private::push_colon2_spanned(&mut _s, _span);
::quote::ToTokens::to_tokens(&column_name, &mut _s);
_s
}quote_spanned!(span=> #table_name::#column_name))
238 }
239}