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}