xql_derive/
lib.rs

1#[proc_macro_derive(Schema)]
2pub fn derive_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
3    let input = syn::parse_macro_input!(input as syn::DeriveInput);
4    let vis = &input.vis;
5    let name = &input.ident;
6    let table_name = syn::Ident::new(
7        convert_case::Casing::to_case(&input.ident.to_string(), convert_case::Case::Snake).as_str(),
8        input.ident.span(),
9    );
10
11    let fields = match input.data {
12        syn::Data::Struct(syn::DataStruct {
13            fields: syn::Fields::Named(syn::FieldsNamed { named, .. }),
14            ..
15        }) => named,
16        _ => unimplemented!(),
17    };
18
19    let column_names = fields.iter().map(|f| {
20        let col_name = &f.ident;
21        let vis = &f.vis;
22
23        quote::quote! {
24            #[allow(non_upper_case_globals)]
25            #vis const #col_name: ::xql::item::ColumnRef<'static> = ::xql::item::ColumnRef::TableColumn(
26                xql::item::Ident(stringify!(#table_name)),
27                xql::item::Ident(stringify!(#col_name)),
28            );
29        }
30    });
31
32    let num_cols = column_names.len();
33
34    let column_array = fields.iter().map(|f| {
35        let col_name = &f.ident;
36        quote::quote! {
37            ::xql::item::ColumnRef::TableColumn(
38                xql::item::Ident(stringify!(#table_name)),
39                xql::item::Ident(stringify!(#col_name)),
40            )
41        }
42    });
43
44    let expanded = quote::quote! {
45        #[allow(non_upper_case_globals)]
46        #vis const #name: ::xql::item::TableRef<'static> = ::xql::item::TableRef::Table(
47            ::xql::item::Ident(stringify!(#table_name)),
48        );
49
50        impl #name {
51            #(#column_names)*
52        }
53
54        impl ::xql::Schema<#num_cols> for #name {
55            #[inline]
56            fn table() -> ::xql::item::TableRef<'static> {
57                ::xql::item::TableRef::Table(
58                    ::xql::item::Ident(stringify!(#table_name)),
59                )
60            }
61
62            fn columns() -> [::xql::item::ColumnRef<'static>; #num_cols] {
63                [#(#column_array,)*]
64            }
65        }
66    };
67
68    proc_macro::TokenStream::from(expanded)
69}