use proc_macro2::TokenStream;
mod create_graphql_impl;
use create_graphql_impl::create_graphql_impl;
use proc_macro2::Ident;
use proc_macro_crate::crate_name;
use std::iter::Map;
use syn::punctuated::Iter;
use syn::{Field, Fields, FieldsNamed, Item, ItemStruct, Type};
pub fn process_entity(item: Item) -> TokenStream {
let struct_item = match item {
Item::Struct(item) => item,
_ => panic!("entity only accepts Structs"),
};
let name = struct_item.ident.clone();
let fields = struct_item.fields.clone();
let named_fields = match &fields {
Fields::Named(named) => named,
_ => panic!("Expected named fields"),
};
let graphql_impl = create_graphql_impl(&name, &fields);
let fn_impls = create_field_name_getters(struct_item.ident.clone(), &named_fields);
let struct_name = struct_item.ident.clone();
let field_mapped_struct = map_struct_fields(&struct_item);
let mongodb_result = crate_name("mongodb");
let mongodb_name = match mongodb_result {
Ok(_) => quote!(mongodb),
Err(_) => quote!(idkthings_core::mongodb),
};
let output = quote!(
#[derive(serde::Deserialize, serde::Serialize, Clone, Debug)]
#field_mapped_struct
#graphql_impl
#(#fn_impls)*
impl From<#struct_name> for bson::Bson {
fn from(doc: #struct_name) -> Self {
#mongodb_name::bson::to_bson(&doc).unwrap()
}
}
);
output
}
fn create_field_name_getters<'a>(
struct_name: Ident,
fields_named: &'a FieldsNamed,
) -> Map<Iter<Field>, impl FnMut(&'a Field) -> TokenStream + 'a> {
fields_named.named.iter().map(move |field: &Field| {
let field_name = field.ident.as_ref().unwrap();
let fn_name = syn::Ident::new(
&format!("get_field_name_{}", &field_name),
field_name.span(),
);
let return_value = format!("{}", &field_name);
quote!(
impl #struct_name {
pub fn #fn_name() -> String {
#return_value.to_string()
}
}
)
})
}
fn map_struct_fields(struct_item: &ItemStruct) -> TokenStream {
let mapped_fields = struct_item.fields.iter().map(|field| match &field.ty {
Type::Path(type_path) => {
if type_path.path.segments.last().unwrap().ident.to_string() == "Uuid" {
quote!(
#[serde(with = "bson::serde_helpers::uuid_1_as_binary")]
#field
)
} else {
quote!(
#field
)
}
}
_ => quote!(
#field
),
});
let struct_name = struct_item.ident.clone();
let vis = struct_item.vis.clone();
quote!(
#vis struct #struct_name {
#(#mapped_fields),*
}
)
}