microrm-macros 0.2.4

Procedural macro implementations for the microrm crate.
Documentation
use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::parse_macro_input;

use convert_case::{Case, Casing};

type ColumnList = syn::punctuated::Punctuated<syn::ExprPath, syn::Token![,]>;
struct MakeIndexParams {
    unique: Option<syn::Token![!]>,
    name: syn::Ident,
    #[allow(dead_code)]
    comma: syn::Token![,],
    columns: ColumnList,
}

impl syn::parse::Parse for MakeIndexParams {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Self {
            unique: input.parse()?,
            name: input.parse()?,
            comma: input.parse()?,
            columns: ColumnList::parse_separated_nonempty(input)?,
        })
    }
}

pub(crate) fn do_make_index(
    tokens: TokenStream,
    microrm_ref: proc_macro2::TokenStream,
) -> TokenStream {
    let input = parse_macro_input!(tokens as MakeIndexParams);

    let index_struct_name = input.name;
    let index_sql_name = format!("{}", index_struct_name).to_case(Case::Snake);

    let columns = input.columns.clone().into_iter();

    let unique = input.unique.is_some();

    let first_column = columns.clone().next().unwrap();

    let columns_array_name = format_ident!(
        "INDEX_COLUMN_NAMES_{}",
        index_struct_name.to_string().to_case(Case::ScreamingSnake)
    );
    let column_count = columns.len();

    quote! {
        pub struct #index_struct_name ();

        #microrm_ref::re_export::lazy_static::lazy_static!{
            static ref #columns_array_name : [&'static str; #column_count] = {
                use #microrm_ref::entity::EntityColumn;
                [
                    #( #columns . name() ),*
                ]
            };
        }

        impl #microrm_ref::entity::Index for #index_struct_name {
            fn index_name() -> &'static str {
                #index_sql_name
            }
            fn table_name() -> &'static str {
                use #microrm_ref::entity::EntityColumn;
                #first_column.table_name()
            }
            fn column_names() -> &'static [&'static str] {
                #columns_array_name.as_ref()
            }
            fn unique() -> bool where Self: Sized {
                #unique
            }
        }
    }
    .into()
}