#[derive(Debug, Default, PartialEq, Eq, derive_new::new)]
pub struct Model {
#[new(default)]
pub field_idents: Vec<syn::Ident>,
}
pub fn analyze(parsed: &crate::parse::merge_patch::Parsed<'_>) -> syn::Result<Model> {
let mut model = Model::new();
let mut errors = crate::errors::Errors::default();
for field in &parsed.named_fields.named {
let Some(field_ident) = &field.ident else {
continue;
};
if errors.check(crate::attributes::is_skipped(field, "merge_patch")) == Some(false) {
model.field_idents.push(field_ident.clone());
}
}
errors.finish(model)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
fn analyze_named_fields(
named_fields_input: proc_macro2::TokenStream,
) -> syn::Result<super::Model> {
let named_fields = &syn::parse2(named_fields_input).unwrap();
let parsed = crate::parse::merge_patch::Parsed {
ident: "e::format_ident!("OrderModel"),
named_fields,
};
super::analyze(&parsed)
}
#[test]
fn test_analysis_keeps_the_fields_that_are_not_skipped() {
let model = analyze_named_fields(quote::quote! {
{
client: Option<String>,
capacity: OrderCapacity,
#[merge_patch(skip)]
created_by_user_with_id: u32,
}
})
.unwrap();
pretty_assertions::assert_eq!(
model.field_idents,
vec![
quote::format_ident!("client"),
quote::format_ident!("capacity"),
]
);
}
#[rstest]
#[case(quote::quote! { { #[merge_patch()] client: Option<String>, } })]
#[case(quote::quote! { { #[merge_patch] client: Option<String>, } })]
#[case(quote::quote! { { #[merge_patch(ignore)] client: Option<String>, } })]
fn test_analysis_fails(#[case] named_fields_input: proc_macro2::TokenStream) {
assert!(analyze_named_fields(named_fields_input).is_err());
}
}