Skip to main content

diesel_derives/
has_query.rs

1use proc_macro2::TokenStream;
2use syn::punctuated::Punctuated;
3use syn::{DeriveInput, parse_quote};
4
5use crate::model::Model;
6use crate::selectable::FieldSelectExpressionTyBuilder;
7
8fn generate_default_checks(
9    model: &Model,
10    original_impl_generics: &syn::ImplGenerics<'_>,
11    original_where_clause: Option<&syn::WhereClause>,
12    field_select_expression_type_builders: &[FieldSelectExpressionTyBuilder<'_>],
13) -> syn::Result<TokenStream> {
14    let checks = [
15        (
16            {
    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, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "derives");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "has_query");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "expand_pg");
    ::quote::__private::push_bang(&mut _s);
    _s
}quote::quote! {
17                diesel::internal::derives::has_query::expand_pg!
18            },
19            ::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},
20            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s,
            "_check_field_compatibility_pg");
        _s
    })parse_quote! {_check_field_compatibility_pg},
21        ),
22        (
23            {
    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, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "derives");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "has_query");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "expand_sqlite");
    ::quote::__private::push_bang(&mut _s);
    _s
}quote::quote! {
24                diesel::internal::derives::has_query::expand_sqlite!
25            },
26            ::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},
27            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s,
            "_check_field_compatibility_sqlite");
        _s
    })parse_quote! {_check_field_compatibility_sqlite},
28        ),
29        (
30            {
    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, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "derives");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "has_query");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "expand_mysql");
    ::quote::__private::push_bang(&mut _s);
    _s
}quote::quote! {
31                diesel::internal::derives::has_query::expand_mysql!
32            },
33            ::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},
34            ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s,
            "_check_field_compatibility_mysql");
        _s
    })parse_quote! {_check_field_compatibility_mysql},
35        ),
36    ]
37    .into_iter()
38    .map(|(backend_macro, backend_ty, function)| {
39        let mut backend = Punctuated::new();
40        backend.push(backend_ty);
41
42        let check = super::selectable::generate_check_function(
43            model,
44            original_impl_generics,
45            original_where_clause,
46            field_select_expression_type_builders,
47            &backend,
48            function,
49        )?;
50        Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&backend_macro, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&check, &mut _s);
            _s
        });
    _s
}quote::quote! {
51            #backend_macro {#check}
52        })
53    })
54    .collect::<syn::Result<Vec<_>>>()?;
55
56    Ok({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut checks, i) = checks.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let checks =
                match checks.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&checks, &mut _s);
        }
    }
    _s
}quote::quote! { #(#checks)*})
57}
58
59pub(crate) fn derive(item: DeriveInput) -> syn::Result<TokenStream> {
60    // other required traits
61
62    let selectable = super::selectable::derive(item.clone(), Some(generate_default_checks))?;
63    let queryable = super::queryable::derive(item.clone())?;
64
65    let ident = &item.ident;
66    let model = Model::from_item(&item, false, false)?;
67    let (_original_impl_generics, ty_generics, _original_where_clause) =
68        item.generics.split_for_impl();
69
70    let mut generics = item.generics.clone();
71    generics
72        .params
73        .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));
74
75    let (impl_generics, _, where_clause) = generics.split_for_impl();
76
77    let mut errors = Vec::new();
78
79    let (query_expr, query_type) = if let Some(base_query) = model.base_query {
80        if let Some(query_type) = model.base_query_type {
81            (base_query, query_type)
82        } else {
83            use dsl_auto_type::auto_type::expression_type_inference as type_inference;
84
85            let (inferred_type, infer_errors) = type_inference::infer_expression_type(
86                &base_query,
87                None,
88                &type_inference::InferrerSettings::builder()
89                    .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))
90                    .function_types_case(crate::AUTO_TYPE_DEFAULT_FUNCTION_TYPE_CASE)
91                    .method_types_case(crate::AUTO_TYPE_DEFAULT_METHOD_TYPE_CASE)
92                    .build(),
93            );
94
95            errors = infer_errors
96                .into_iter()
97                .map(|e| e.into_compile_error())
98                .collect();
99            (base_query, inferred_type)
100        }
101    } else {
102        let table_name = &model.table_names()[0];
103        let query_type =
104            ::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);
105
106        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! {
107            diesel::query_builder::AsQuery::as_query(#table_name::table)
108        };
109        (query_expr, query_type)
110    };
111
112    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! {
113        impl #impl_generics diesel::HasQuery<__DB> for #ident #ty_generics #where_clause {
114            type BaseQuery = #query_type;
115
116            fn base_query() -> Self::BaseQuery {
117                #query_expr
118            }
119
120        }
121        #(#errors)*
122    });
123    query_model.extend(selectable);
124    query_model.extend(queryable);
125    Ok(query_model)
126}