use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields};
use crate::attrs;
pub(crate) fn expand(input: DeriveInput) -> syn::Result<TokenStream> {
let ident = &input.ident;
let Data::Struct(data) = &input.data else {
return Err(syn::Error::new_spanned(
ident,
"DeriveIntoActiveModel only supports structs",
));
};
let Fields::Named(fields) = &data.fields else {
return Err(syn::Error::new_spanned(
ident,
"DeriveIntoActiveModel needs named fields",
));
};
let mut active_model: syn::Path = syn::parse_quote! { ActiveModel };
for item in attrs::parse(&input.attrs)? {
match item.key.as_str() {
"active_model" => active_model = syn::parse_str(&item.str_value()?)?,
other => {
return Err(syn::Error::new(
item.span,
format!("unknown into-active-model attribute `{other}`"),
));
}
}
}
let mut sets = Vec::new();
for f in &fields.named {
let name = f.ident.as_ref().expect("named");
let mut ignore = false;
for item in attrs::parse(&f.attrs)? {
match item.key.as_str() {
"ignore" => ignore = item.bool_value()?,
other => {
return Err(syn::Error::new(
item.span,
format!("unknown into-active-model field attribute `{other}`"),
));
}
}
}
if !ignore {
sets.push(quote! {
am.#name = ::turso_orm::entity::IntoActiveValue::into_active_value(self.#name);
});
}
}
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
Ok(quote! {
impl #impl_generics ::turso_orm::entity::IntoActiveModel<#active_model> for #ident #ty_generics #where_clause {
fn into_active_model(self) -> #active_model {
let mut am = <#active_model as ::core::default::Default>::default();
#(#sets)*
am
}
}
})
}