use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Lit};
#[proc_macro_derive(ObjectStore, attributes(store, index))]
pub fn derive_object_store(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let store_name = name.to_string();
let mut key_path: Option<String> = None;
let mut auto_increment = false;
let mut store_name = store_name;
for attr in &input.attrs {
if attr.path().is_ident("store") {
let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident("key_path") {
let value: Lit = meta.value()?.parse()?;
if let Lit::Str(s) = value {
key_path = Some(s.value());
}
} else if meta.path.is_ident("auto_increment") {
auto_increment = true;
} else if meta.path.is_ident("name") {
let value: Lit = meta.value()?.parse()?;
if let Lit::Str(s) = value {
store_name = s.value();
}
}
Ok(())
});
}
}
let key_path = key_path.expect("#[store(key_path = \"...\")] is required");
let mut indexes = Vec::new();
if let syn::Data::Struct(data) = &input.data {
for field in &data.fields {
let field_name = field
.ident
.as_ref()
.map(|i| i.to_string())
.expect("named fields only");
for attr in &field.attrs {
if attr.path().is_ident("index") {
let mut unique = false;
let mut index_name = field_name.clone();
let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident("unique") {
unique = true;
} else if meta.path.is_ident("name") {
let value: Lit = meta.value()?.parse()?;
if let Lit::Str(s) = value {
index_name = s.value();
}
}
Ok(())
});
indexes.push((index_name, field_name.clone(), unique));
}
}
}
}
let index_calls: Vec<_> = indexes
.iter()
.map(|(idx_name, field_name, unique)| {
let u = *unique;
quote! {
.with_index(#idx_name, &[#field_name], #u)
}
})
.collect();
let auto_inc = if auto_increment {
quote! { .with_auto_increment() }
} else {
quote! {}
};
let expanded = quote! {
impl flowdb::jsondb::ObjectStore for #name {
fn store_def() -> flowdb::jsondb::StoreSchema {
flowdb::jsondb::StoreSchema::new(#store_name, #key_path)
#(#index_calls)*
#auto_inc
}
}
};
expanded.into()
}