georm-macros 0.2.1

Macro support for Georm. Not intended to be used directly.
Documentation
use super::ir::GeormField;
use quote::quote;

#[derive(Debug)]
pub enum IdType {
    Simple {
        field_name: syn::Ident,
        field_type: syn::Type,
    },
    Composite {
        fields: Vec<IdField>,
        field_type: syn::Ident,
    },
}

#[derive(Debug, Clone)]
pub struct IdField {
    pub name: syn::Ident,
    pub ty: syn::Type,
}

fn field_to_code(field: &GeormField) -> proc_macro2::TokenStream {
    let ident = field.ident.clone();
    let ty = field.ty.clone();
    quote! {
        pub #ident: #ty
    }
}

fn generate_struct(
    ast: &syn::DeriveInput,
    fields: &[GeormField],
) -> (syn::Ident, proc_macro2::TokenStream) {
    let struct_name = &ast.ident;
    let id_struct_name = quote::format_ident!("{struct_name}Id");
    let vis = &ast.vis;
    let fields: Vec<proc_macro2::TokenStream> = fields
        .iter()
        .filter_map(|field| {
            if field.id {
                Some(field_to_code(field))
            } else {
                None
            }
        })
        .collect();
    let code = quote! {
        #vis struct #id_struct_name {
            #(#fields),*
        }
    };
    (id_struct_name, code)
}

pub fn create_primary_key(
    ast: &syn::DeriveInput,
    fields: &[GeormField],
) -> (IdType, proc_macro2::TokenStream) {
    let georm_id_fields: Vec<&GeormField> = fields.iter().filter(|field| field.id).collect();
    let id_fields: Vec<IdField> = georm_id_fields
        .iter()
        .map(|field| IdField {
            name: field.ident.clone(),
            ty: field.ty.clone(),
        })
        .collect();
    match id_fields.len() {
        0 => panic!("No ID field found"),
        1 => (
            IdType::Simple {
                field_name: id_fields[0].name.clone(),
                field_type: id_fields[0].ty.clone(),
            },
            quote! {},
        ),
        _ => {
            let (struct_name, struct_code) = generate_struct(ast, fields);
            (
                IdType::Composite {
                    fields: id_fields.clone(),
                    field_type: struct_name,
                },
                struct_code,
            )
        }
    }
}