diesel_derives/
has_query.rs

1use 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    // other required traits
9    let mut checks = Punctuated::new();
10    if truecfg!(feature = "postgres") {
11        checks.push(::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, "pg");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Pg");
        _s
    })parse_quote! {diesel::pg::Pg});
12    }
13    if truecfg!(feature = "sqlite") {
14        checks.push(::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, "sqlite");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Sqlite");
        _s
    })parse_quote! {diesel::sqlite::Sqlite});
15    }
16    if truecfg!(feature = "mysql") {
17        checks.push(::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, "mysql");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Mysql");
        _s
    })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(::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));
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(::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))
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            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_lt(&mut _s);
        ::quote::ToTokens::to_tokens(&table_name, &mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "table");
        ::quote::__private::push_ident(&mut _s, "as");
        ::quote::__private::push_ident(&mut _s, "diesel");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "query_builder");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "AsQuery");
        ::quote::__private::push_gt(&mut _s);
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "Query");
        _s
    })parse_quote!(<#table_name::table as diesel::query_builder::AsQuery>::Query);
65
66        let query_expr = ::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, "query_builder");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "AsQuery");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "as_query");
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Parenthesis,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::ToTokens::to_tokens(&table_name, &mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "table");
                _s
            });
        _s
    })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({
    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, "HasQuery");
    ::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(&ident, &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, "BaseQuery");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&query_type, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "base_query");
            ::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, "BaseQuery");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&query_expr, &mut _s);
                    _s
                });
            _s
        });
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut errors, i) = errors.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let errors =
                match errors.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&errors, &mut _s);
        }
    }
    _s
}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}