diesel_derives/
has_query.rs1use proc_macro2::TokenStream;
2use syn::punctuated::Punctuated;
3use syn::{parse_quote, DeriveInput};
4
5use crate::model::{CheckForBackend, Model};
6
7pub(crate) fn derive(item: DeriveInput) -> syn::Result<TokenStream> {
8 let mut checks = Punctuated::new();
10 if cfg!(feature = "postgres") {
11 checks.push(parse_quote! {diesel::pg::Pg});
12 }
13 if cfg!(feature = "sqlite") {
14 checks.push(parse_quote! {diesel::sqlite::Sqlite});
15 }
16 if cfg!(feature = "mysql") {
17 checks.push(parse_quote! {diesel::mysql::Mysql});
18 }
19 let selectable = super::selectable::derive(
20 item.clone(),
21 (!checks.is_empty()).then_some(CheckForBackend::Backends(checks)),
22 )?;
23 let queryable = super::queryable::derive(item.clone())?;
24
25 let ident = &item.ident;
26 let model = Model::from_item(&item, false, false)?;
27 let (_original_impl_generics, ty_generics, _original_where_clause) =
28 item.generics.split_for_impl();
29
30 let mut generics = item.generics.clone();
31 generics
32 .params
33 .push(parse_quote!(__DB: diesel::backend::Backend));
34
35 let (impl_generics, _, where_clause) = generics.split_for_impl();
36
37 let mut errors = Vec::new();
38
39 let (query_expr, query_type) = if let Some(base_query) = model.base_query {
40 if let Some(query_type) = model.base_query_type {
41 (base_query, query_type)
42 } else {
43 use dsl_auto_type::auto_type::expression_type_inference as type_inference;
44
45 let (inferred_type, infer_errors) = type_inference::infer_expression_type(
46 &base_query,
47 None,
48 &type_inference::InferrerSettings::builder()
49 .dsl_path(parse_quote!(diesel::dsl))
50 .function_types_case(crate::AUTO_TYPE_DEFAULT_FUNCTION_TYPE_CASE)
51 .method_types_case(crate::AUTO_TYPE_DEFAULT_METHOD_TYPE_CASE)
52 .build(),
53 );
54
55 errors = infer_errors
56 .into_iter()
57 .map(|e| e.into_compile_error())
58 .collect();
59 (base_query, inferred_type)
60 }
61 } else {
62 let table_name = &model.table_names()[0];
63 let query_type =
64 parse_quote!(<#table_name::table as diesel::query_builder::AsQuery>::Query);
65
66 let query_expr = parse_quote! {
67 diesel::query_builder::AsQuery::as_query(#table_name::table)
68 };
69 (query_expr, query_type)
70 };
71
72 let mut query_model = crate::util::wrap_in_dummy_mod(quote::quote! {
73 impl #impl_generics diesel::HasQuery<__DB> for #ident #ty_generics #where_clause {
74 type BaseQuery = #query_type;
75
76 fn base_query() -> Self::BaseQuery {
77 #query_expr
78 }
79
80 }
81 #(#errors)*
82 });
83 query_model.extend(selectable);
84 query_model.extend(queryable);
85 Ok(query_model)
86}