use crate::util::{escape_rust_keyword, field_not_ignored, trim_starting_raw_identifier}; use heck::CamelCase; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::{punctuated::Punctuated, token::Comma, Data, DataStruct, Field, Fields, Lit, Meta, Type}; pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result { let fields = match data { Data::Struct(DataStruct { fields: Fields::Named(named), .. }) => named.named, _ => { return Ok(quote_spanned! { ident.span() => compile_error!("you can only derive DeriveActiveModel on structs"); }) } } .into_iter() .filter(field_not_ignored); let field: Vec = fields .clone() .into_iter() .map(|Field { ident, .. }| format_ident!("{}", ident.unwrap().to_string())) .collect(); let name: Vec = fields .clone() .into_iter() .map(|field| { let ident = field.ident.as_ref().unwrap().to_string(); let ident = trim_starting_raw_identifier(ident).to_camel_case(); let ident = escape_rust_keyword(ident); let mut ident = format_ident!("{}", &ident); for attr in field.attrs.iter() { if let Some(ident) = attr.path.get_ident() { if ident != "sea_orm" { continue; } } else { continue; } if let Ok(list) = attr.parse_args_with(Punctuated::::parse_terminated) { for meta in list.iter() { if let Meta::NameValue(nv) = meta { if let Some(name) = nv.path.get_ident() { if name == "enum_name" { if let Lit::Str(litstr) = &nv.lit { ident = syn::parse_str(&litstr.value()).unwrap(); } } } } } } } ident }) .collect(); let ty: Vec = fields.into_iter().map(|Field { ty, .. }| ty).collect(); Ok(quote!( #[derive(Clone, Debug, PartialEq)] pub struct ActiveModel { #(pub #field: sea_orm::ActiveValue<#ty>),* } impl std::default::Default for ActiveModel { fn default() -> Self { ::new() } } impl std::convert::From<::Model> for ActiveModel { fn from(m: ::Model) -> Self { Self { #(#field: sea_orm::unchanged_active_value_not_intended_for_public_use(m.#field)),* } } } impl sea_orm::IntoActiveModel for ::Model { fn into_active_model(self) -> ActiveModel { self.into() } } impl sea_orm::ActiveModelTrait for ActiveModel { type Entity = Entity; fn take(&mut self, c: ::Column) -> sea_orm::ActiveValue { match c { #(::Column::#name => { let mut value = sea_orm::ActiveValue::unset(); std::mem::swap(&mut value, &mut self.#field); value.into_wrapped_value() },)* _ => sea_orm::ActiveValue::unset(), } } fn get(&self, c: ::Column) -> sea_orm::ActiveValue { match c { #(::Column::#name => self.#field.clone().into_wrapped_value(),)* _ => sea_orm::ActiveValue::unset(), } } fn set(&mut self, c: ::Column, v: sea_orm::Value) { match c { #(::Column::#name => self.#field = sea_orm::ActiveValue::set(v.unwrap()),)* _ => panic!("This ActiveModel does not have this field"), } } fn unset(&mut self, c: ::Column) { match c { #(::Column::#name => self.#field = sea_orm::ActiveValue::unset(),)* _ => {}, } } fn is_unset(&self, c: ::Column) -> bool { match c { #(::Column::#name => self.#field.is_unset(),)* _ => panic!("This ActiveModel does not have this field"), } } fn default() -> Self { Self { #(#field: sea_orm::ActiveValue::unset()),* } } } )) }