Skip to main content

diesel_derives/
query_id.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::DeriveInput;
4use syn::parse_quote;
5
6use crate::util::wrap_in_dummy_mod;
7
8pub fn derive(mut item: DeriveInput) -> TokenStream {
9    for ty_param in item.generics.type_params_mut() {
10        ty_param
11            .bounds
12            .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, "query_builder");
        ::quote::__private::push_colon2(&mut _s);
        ::quote::__private::push_ident(&mut _s, "QueryId");
        _s
    })parse_quote!(diesel::query_builder::QueryId));
13    }
14    let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
15    let is_window_function = item.attrs.iter().any(|a| {
16        if a.path().is_ident("diesel") {
17            match a.parse_args_with(
18                syn::punctuated::Punctuated::<syn::Meta, ::syn::token::Commasyn::Token![,]>::parse_terminated,
19            ) {
20                Ok(nested) => nested.iter().any(|n| match n {
21                    syn::Meta::NameValue(n) => {
22                        n.path.is_ident("diesel_internal_is_window")
23                            && #[allow(non_exhaustive_omitted_patterns)] match n.value {
    syn::Expr::Lit(syn::ExprLit {
        lit: syn::Lit::Bool(syn::LitBool { value: true, .. }), .. }) => true,
    _ => false,
}matches!(
24                                n.value,
25                                syn::Expr::Lit(syn::ExprLit {
26                                    lit: syn::Lit::Bool(syn::LitBool { value: true, .. }),
27                                    ..
28                                })
29                            )
30                    }
31                    _ => false,
32                }),
33                _ => false,
34            }
35        } else {
36            false
37        }
38    });
39
40    let struct_name = &item.ident;
41    // Arguments must follow the declaration order of the parameters, so walk them in
42    // order rather than grouping by kind. Lifetimes become `'static`, which is both
43    // required (`Any` implies `'static`) and correct (a lifetime cannot change the SQL).
44    let query_id_args = item.generics.params.iter().map(|param| match param {
45        syn::GenericParam::Lifetime(_) => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lifetime(&mut _s, "\'static");
    _s
}quote!('static),
46        syn::GenericParam::Type(ty_param) => {
47            let ident = &ty_param.ident;
48            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::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, "QueryId");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QueryId");
    _s
}quote!(<#ident as diesel::query_builder::QueryId>::QueryId)
49        }
50        syn::GenericParam::Const(const_param) => {
51            let ident = &const_param.ident;
52            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    _s
}quote!(#ident)
53        }
54    });
55
56    let ty_params = item
57        .generics
58        .type_params()
59        .map(|ty_param| &ty_param.ident)
60        .collect::<Vec<_>>();
61
62    let has_static_query_id = ty_params
63        .iter()
64        .map(|ty_param| {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ty_param, &mut _s);
    ::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, "QueryId");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "HAS_STATIC_QUERY_ID");
    _s
}quote!(<#ty_param as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID));
65    let is_window_function_list = ty_params
66        .iter()
67        .map(|ty_param| {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&ty_param, &mut _s);
    ::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, "QueryId");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "IS_WINDOW_FUNCTION");
    _s
}quote!(<#ty_param as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION));
68    let is_window_function = if is_window_function {
69        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "true");
    _s
}quote! { true }
70    } else {
71        {
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut is_window_function_list, i) =
            is_window_function_list.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let is_window_function_list =
                match is_window_function_list.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&is_window_function_list, &mut _s);
            ::quote::__private::push_or_or(&mut _s);
        }
    }
    ::quote::__private::push_ident(&mut _s, "false");
    _s
}quote! { #(#is_window_function_list ||)* false }
72    };
73
74    wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "allow");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s,
                        "non_camel_case_types");
                    _s
                });
            _s
        });
    ::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, "query_builder");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "QueryId");
    ::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, "QueryId");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&struct_name, &mut _s);
            ::quote::__private::push_lt(&mut _s);
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut query_id_args, i) = query_id_args.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let query_id_args =
                        match query_id_args.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&query_id_args, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "HAS_STATIC_QUERY_ID");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_eq(&mut _s);
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut has_static_query_id, i) =
                    has_static_query_id.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let has_static_query_id =
                        match has_static_query_id.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&has_static_query_id, &mut _s);
                    ::quote::__private::push_and_and(&mut _s);
                }
            }
            ::quote::__private::push_ident(&mut _s, "true");
            ::quote::__private::push_semi(&mut _s);
            ::quote::__private::push_ident(&mut _s, "const");
            ::quote::__private::push_ident(&mut _s, "IS_WINDOW_FUNCTION");
            ::quote::__private::push_colon(&mut _s);
            ::quote::__private::push_ident(&mut _s, "bool");
            ::quote::__private::push_eq(&mut _s);
            ::quote::ToTokens::to_tokens(&is_window_function, &mut _s);
            ::quote::__private::push_semi(&mut _s);
            _s
        });
    _s
}quote! {
75        #[allow(non_camel_case_types)]
76        impl #impl_generics diesel::query_builder::QueryId for #struct_name #ty_generics
77        #where_clause
78        {
79            type QueryId = #struct_name<#(#query_id_args,)*>;
80
81            const HAS_STATIC_QUERY_ID: bool = #(#has_static_query_id &&)* true;
82
83            const IS_WINDOW_FUNCTION: bool = #is_window_function;
84        }
85    })
86}