diesel_derives/
query_id.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::parse_quote;
4use syn::DeriveInput;
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(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            if let Ok(nested) = a.parse_args_with(
18                syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated,
19            ) {
20                nested.iter().any(|n| match n {
21                    syn::Meta::NameValue(n) => {
22                        n.path.is_ident("diesel_internal_is_window")
23                            && 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            } else {
34                false
35            }
36        } else {
37            false
38        }
39    });
40
41    let struct_name = &item.ident;
42    let lifetimes = item.generics.lifetimes();
43
44    let ty_params = item
45        .generics
46        .type_params()
47        .map(|ty_param| &ty_param.ident)
48        .collect::<Vec<_>>();
49
50    let consts = item
51        .generics
52        .const_params()
53        .map(|const_param| &const_param.ident)
54        .collect::<Vec<_>>();
55
56    let query_id_ty_params = ty_params
57        .iter()
58        .map(|ty_param| quote!(<#ty_param as diesel::query_builder::QueryId>::QueryId));
59    let has_static_query_id = ty_params
60        .iter()
61        .map(|ty_param| quote!(<#ty_param as diesel::query_builder::QueryId>::HAS_STATIC_QUERY_ID));
62    let is_window_function_list = ty_params
63        .iter()
64        .map(|ty_param| quote!(<#ty_param as diesel::query_builder::QueryId>::IS_WINDOW_FUNCTION));
65    let is_window_function = if is_window_function {
66        quote! { true }
67    } else {
68        quote! { #(#is_window_function_list ||)* false }
69    };
70
71    wrap_in_dummy_mod(quote! {
72        #[allow(non_camel_case_types)]
73        impl #impl_generics diesel::query_builder::QueryId for #struct_name #ty_generics
74        #where_clause
75        {
76            type QueryId = #struct_name<#(#lifetimes,)* #(#query_id_ty_params,)* #(#consts,)*>;
77
78            const HAS_STATIC_QUERY_ID: bool = #(#has_static_query_id &&)* true;
79
80            const IS_WINDOW_FUNCTION: bool = #is_window_function;
81        }
82    })
83}