rust_queries_derive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput, Data, Fields};
6
7/// Derive macro to generate Queryable implementations
8/// 
9/// # Example
10/// 
11/// ```ignore
12/// #[derive(Queryable)]
13/// struct Product {
14///     id: u32,
15///     name: String,
16///     price: f64,
17/// }
18/// ```
19#[proc_macro_derive(Queryable)]
20pub fn derive_queryable(input: TokenStream) -> TokenStream {
21    let input = parse_macro_input!(input as DeriveInput);
22    let name = &input.ident;
23    let generics = &input.generics;
24    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
25
26    let expanded = quote! {
27        impl #impl_generics rust_queries_core::Queryable<#name #ty_generics> for Vec<#name #ty_generics> #where_clause {
28            fn query_iter(&self) -> Box<dyn Iterator<Item = &#name #ty_generics> + '_> {
29                Box::new(self.iter())
30            }
31        }
32    };
33
34    TokenStream::from(expanded)
35}
36
37/// Derive macro to generate helper methods for query building
38/// 
39/// This macro generates convenience methods for common query patterns
40/// 
41/// # Example
42/// 
43/// ```ignore
44/// #[derive(QueryBuilder)]
45/// struct Product {
46///     id: u32,
47///     name: String,
48///     price: f64,
49/// }
50/// ```
51#[proc_macro_derive(QueryBuilder)]
52pub fn derive_query_builder(input: TokenStream) -> TokenStream {
53    let input = parse_macro_input!(input as DeriveInput);
54    let name = &input.ident;
55    
56    // Extract field names for documentation
57    let fields = match &input.data {
58        Data::Struct(data) => {
59            match &data.fields {
60                Fields::Named(fields) => {
61                    fields.named.iter().map(|f| f.ident.as_ref().unwrap()).collect::<Vec<_>>()
62                }
63                _ => vec![],
64            }
65        }
66        _ => vec![],
67    };
68
69    let field_docs = if !fields.is_empty() {
70        let field_list = fields.iter().map(|f| format!("- {}", f)).collect::<Vec<_>>().join("\n///   ");
71        format!("/// Available fields:\n///   {}", field_list)
72    } else {
73        String::new()
74    };
75
76    let expanded = quote! {
77        impl #name {
78            #[doc = #field_docs]
79            /// Creates a new eager Query from a slice of items
80            pub fn query(items: &[Self]) -> rust_queries_core::Query<Self> {
81                rust_queries_core::Query::new(items)
82            }
83
84            #[doc = #field_docs]
85            /// Creates a new lazy Query from a slice of items
86            pub fn lazy_query(items: &[Self]) -> rust_queries_core::LazyQuery<Self, impl Iterator<Item = &Self>> {
87                rust_queries_core::LazyQuery::new(items)
88            }
89        }
90    };
91
92    TokenStream::from(expanded)
93}