From 16e41be9dfdd9b897c69e7d2e89fa454c704bf6f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 13:11:04 +0800 Subject: [PATCH 1/4] Add & parse "ignore" macro attribute --- sea-orm-macros/src/derives/active_model.rs | 3 ++ sea-orm-macros/src/derives/entity_model.rs | 11 ++++- sea-orm-macros/src/derives/model.rs | 51 +++++++++++++++++++--- sea-orm-macros/src/lib.rs | 3 +- sea-orm-macros/src/util.rs | 26 +++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 sea-orm-macros/src/util.rs diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 16e09f2a..4c1b909f 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -1,3 +1,4 @@ +use crate::util::field_not_ignored; use heck::CamelCase; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote, quote_spanned}; @@ -16,6 +17,8 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result = fields .clone() .into_iter() diff --git a/sea-orm-macros/src/derives/entity_model.rs b/sea-orm-macros/src/derives/entity_model.rs index 66c5725f..768d3b7c 100644 --- a/sea-orm-macros/src/derives/entity_model.rs +++ b/sea-orm-macros/src/derives/entity_model.rs @@ -68,6 +68,7 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res let mut default_value = None; let mut default_expr = None; let mut indexed = false; + let mut ignore = false; let mut unique = false; let mut sql_type = None; // search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", nullable, indexed, unique)] @@ -120,7 +121,10 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res } Meta::Path(p) => { if let Some(name) = p.get_ident() { - if name == "primary_key" { + if name == "ignore" { + ignore = true; + break; + } else if name == "primary_key" { primary_keys.push(quote! { #field_name }); primary_key_types.push(field.ty.clone()); } else if name == "nullable" { @@ -138,6 +142,11 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec) -> syn::Res } } + if ignore { + columns_enum.pop(); + continue; + } + let field_type = match sql_type { Some(t) => t, None => { diff --git a/sea-orm-macros/src/derives/model.rs b/sea-orm-macros/src/derives/model.rs index 669dbe9e..9d619991 100644 --- a/sea-orm-macros/src/derives/model.rs +++ b/sea-orm-macros/src/derives/model.rs @@ -1,8 +1,9 @@ -use crate::attributes::derive_attr; +use crate::{attributes::derive_attr, util::field_not_ignored}; use heck::CamelCase; use proc_macro2::TokenStream; use quote::{format_ident, quote, quote_spanned}; use std::iter::FromIterator; +use syn::Ident; enum Error { InputNotStruct, @@ -14,6 +15,7 @@ struct DeriveModel { entity_ident: syn::Ident, field_idents: Vec, ident: syn::Ident, + ignore_attrs: Vec, } impl DeriveModel { @@ -48,11 +50,17 @@ impl DeriveModel { }) .collect(); + let ignore_attrs = fields + .iter() + .map(|field| !field_not_ignored(field)) + .collect(); + Ok(DeriveModel { column_idents, entity_ident, field_idents, ident, + ignore_attrs, }) } @@ -70,23 +78,56 @@ impl DeriveModel { let ident = &self.ident; let field_idents = &self.field_idents; let column_idents = &self.column_idents; + let field_values: Vec = column_idents + .iter() + .zip(&self.ignore_attrs) + .map(|(column_ident, ignore)| { + if *ignore { + quote! { + Default::default() + } + } else { + quote! { + row.try_get(pre, sea_orm::IdenStatic::as_str(&<::Entity as sea_orm::entity::EntityTrait>::Column::#column_ident).into())? + } + } + }) + .collect(); quote!( impl sea_orm::FromQueryResult for #ident { fn from_query_result(row: &sea_orm::QueryResult, pre: &str) -> Result { Ok(Self { - #(#field_idents: row.try_get(pre, sea_orm::IdenStatic::as_str(&<::Entity as sea_orm::entity::EntityTrait>::Column::#column_idents).into())?),* + #(#field_idents: #field_values),* }) } } ) } - fn impl_model_trait(&self) -> TokenStream { + fn impl_model_trait<'a>(&'a self) -> TokenStream { let ident = &self.ident; let entity_ident = &self.entity_ident; - let field_idents = &self.field_idents; - let column_idents = &self.column_idents; + let ignore_attrs = &self.ignore_attrs; + let ignore = |(ident, ignore): (&'a Ident, &bool)| -> Option<&'a Ident> { + if *ignore { + None + } else { + Some(ident) + } + }; + let field_idents: Vec<&Ident> = self + .field_idents + .iter() + .zip(ignore_attrs) + .filter_map(ignore) + .collect(); + let column_idents: Vec<&Ident> = self + .column_idents + .iter() + .zip(ignore_attrs) + .filter_map(ignore) + .collect(); let missing_field_msg = format!("field does not exist on {}", ident); diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 879ad5eb..629c5c18 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -5,6 +5,7 @@ use syn::{parse_macro_input, DeriveInput, Error}; mod attributes; mod derives; +mod util; #[proc_macro_derive(DeriveEntity, attributes(sea_orm))] pub fn derive_entity(input: TokenStream) -> TokenStream { @@ -73,7 +74,7 @@ pub fn derive_model(input: TokenStream) -> TokenStream { .into() } -#[proc_macro_derive(DeriveActiveModel)] +#[proc_macro_derive(DeriveActiveModel, attributes(sea_orm))] pub fn derive_active_model(input: TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); diff --git a/sea-orm-macros/src/util.rs b/sea-orm-macros/src/util.rs new file mode 100644 index 00000000..7dda1087 --- /dev/null +++ b/sea-orm-macros/src/util.rs @@ -0,0 +1,26 @@ +use syn::{punctuated::Punctuated, token::Comma, Field, Meta}; + +pub(crate) fn field_not_ignored(field: &Field) -> bool { + 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::Path(path) = meta { + if let Some(name) = path.get_ident() { + if name == "ignore" { + return false; + } + } + } + } + } + } + true +} From 4e7bf8b8360f75364d5e3ea7fccd7611c44e7b52 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 13:11:26 +0800 Subject: [PATCH 2/4] Testing --- src/tests_cfg/cake_filling_price.rs | 2 ++ src/tests_cfg/filling.rs | 2 ++ tests/common/bakery_chain/baker.rs | 2 ++ tests/common/bakery_chain/bakery.rs | 2 ++ tests/common/bakery_chain/cake.rs | 2 ++ tests/common/bakery_chain/cakes_bakers.rs | 2 ++ tests/common/bakery_chain/customer.rs | 2 ++ tests/common/bakery_chain/lineitem.rs | 2 ++ tests/common/bakery_chain/order.rs | 2 ++ 9 files changed, 18 insertions(+) diff --git a/src/tests_cfg/cake_filling_price.rs b/src/tests_cfg/cake_filling_price.rs index e820ae0f..12779d14 100644 --- a/src/tests_cfg/cake_filling_price.rs +++ b/src/tests_cfg/cake_filling_price.rs @@ -19,6 +19,8 @@ pub struct Model { pub cake_id: i32, pub filling_id: i32, pub price: Decimal, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] diff --git a/src/tests_cfg/filling.rs b/src/tests_cfg/filling.rs index 433a89b8..14f7a849 100644 --- a/src/tests_cfg/filling.rs +++ b/src/tests_cfg/filling.rs @@ -9,6 +9,8 @@ pub struct Entity; pub struct Model { pub id: i32, pub name: String, + #[sea_orm(ignore)] + pub ignored_attr: i32, } // If your column names are not in snake-case, derive `DeriveCustomColumn` here. diff --git a/tests/common/bakery_chain/baker.rs b/tests/common/bakery_chain/baker.rs index ec3d3fb5..45b6c64b 100644 --- a/tests/common/bakery_chain/baker.rs +++ b/tests/common/bakery_chain/baker.rs @@ -8,6 +8,8 @@ pub struct Model { pub name: String, pub contact_details: Json, pub bakery_id: Option, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/bakery.rs b/tests/common/bakery_chain/bakery.rs index a168ad1c..5658740d 100644 --- a/tests/common/bakery_chain/bakery.rs +++ b/tests/common/bakery_chain/bakery.rs @@ -7,6 +7,8 @@ pub struct Model { pub id: i32, pub name: String, pub profit_margin: f64, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs index 4730394b..6d025fe7 100644 --- a/tests/common/bakery_chain/cake.rs +++ b/tests/common/bakery_chain/cake.rs @@ -11,6 +11,8 @@ pub struct Model { pub bakery_id: Option, pub gluten_free: bool, pub serial: Uuid, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cakes_bakers.rs b/tests/common/bakery_chain/cakes_bakers.rs index 3582ada0..6a1eeb54 100644 --- a/tests/common/bakery_chain/cakes_bakers.rs +++ b/tests/common/bakery_chain/cakes_bakers.rs @@ -7,6 +7,8 @@ pub struct Model { pub cake_id: i32, #[sea_orm(primary_key)] pub baker_id: i32, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/customer.rs b/tests/common/bakery_chain/customer.rs index 31e41018..1d3563e4 100644 --- a/tests/common/bakery_chain/customer.rs +++ b/tests/common/bakery_chain/customer.rs @@ -8,6 +8,8 @@ pub struct Model { pub name: String, #[sea_orm(column_type = "Text", nullable)] pub notes: Option, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/lineitem.rs b/tests/common/bakery_chain/lineitem.rs index c2d18987..27a79fa3 100644 --- a/tests/common/bakery_chain/lineitem.rs +++ b/tests/common/bakery_chain/lineitem.rs @@ -10,6 +10,8 @@ pub struct Model { pub quantity: i32, pub order_id: i32, pub cake_id: i32, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/order.rs b/tests/common/bakery_chain/order.rs index ed6185cf..e52ba04c 100644 --- a/tests/common/bakery_chain/order.rs +++ b/tests/common/bakery_chain/order.rs @@ -10,6 +10,8 @@ pub struct Model { pub bakery_id: i32, pub customer_id: i32, pub placed_at: DateTime, + #[sea_orm(ignore)] + pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From beca48d48e361e5b79088b416573c738bab1972a Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 16 Sep 2021 14:59:48 +0800 Subject: [PATCH 3/4] Refactor --- sea-orm-macros/src/derives/active_model.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sea-orm-macros/src/derives/active_model.rs b/sea-orm-macros/src/derives/active_model.rs index 4c1b909f..3a96860e 100644 --- a/sea-orm-macros/src/derives/active_model.rs +++ b/sea-orm-macros/src/derives/active_model.rs @@ -15,9 +15,9 @@ pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result compile_error!("you can only derive DeriveActiveModel on structs"); }) } - }; - - let fields = fields.into_iter().filter(field_not_ignored); + } + .into_iter() + .filter(field_not_ignored); let field: Vec = fields .clone() From 5fe8c7c9c4047102a25024b1524fcacc45a57ef1 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 17 Sep 2021 17:08:55 +0800 Subject: [PATCH 4/4] Revert adding `#[sea_orm(ignore)]` to tests entities --- tests/common/bakery_chain/baker.rs | 2 -- tests/common/bakery_chain/bakery.rs | 2 -- tests/common/bakery_chain/cake.rs | 2 -- tests/common/bakery_chain/cakes_bakers.rs | 2 -- tests/common/bakery_chain/customer.rs | 2 -- tests/common/bakery_chain/lineitem.rs | 2 -- tests/common/bakery_chain/order.rs | 2 -- 7 files changed, 14 deletions(-) diff --git a/tests/common/bakery_chain/baker.rs b/tests/common/bakery_chain/baker.rs index 45b6c64b..ec3d3fb5 100644 --- a/tests/common/bakery_chain/baker.rs +++ b/tests/common/bakery_chain/baker.rs @@ -8,8 +8,6 @@ pub struct Model { pub name: String, pub contact_details: Json, pub bakery_id: Option, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/bakery.rs b/tests/common/bakery_chain/bakery.rs index 5658740d..a168ad1c 100644 --- a/tests/common/bakery_chain/bakery.rs +++ b/tests/common/bakery_chain/bakery.rs @@ -7,8 +7,6 @@ pub struct Model { pub id: i32, pub name: String, pub profit_margin: f64, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cake.rs b/tests/common/bakery_chain/cake.rs index 6d025fe7..4730394b 100644 --- a/tests/common/bakery_chain/cake.rs +++ b/tests/common/bakery_chain/cake.rs @@ -11,8 +11,6 @@ pub struct Model { pub bakery_id: Option, pub gluten_free: bool, pub serial: Uuid, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/cakes_bakers.rs b/tests/common/bakery_chain/cakes_bakers.rs index 6a1eeb54..3582ada0 100644 --- a/tests/common/bakery_chain/cakes_bakers.rs +++ b/tests/common/bakery_chain/cakes_bakers.rs @@ -7,8 +7,6 @@ pub struct Model { pub cake_id: i32, #[sea_orm(primary_key)] pub baker_id: i32, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/customer.rs b/tests/common/bakery_chain/customer.rs index 1d3563e4..31e41018 100644 --- a/tests/common/bakery_chain/customer.rs +++ b/tests/common/bakery_chain/customer.rs @@ -8,8 +8,6 @@ pub struct Model { pub name: String, #[sea_orm(column_type = "Text", nullable)] pub notes: Option, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/lineitem.rs b/tests/common/bakery_chain/lineitem.rs index 27a79fa3..c2d18987 100644 --- a/tests/common/bakery_chain/lineitem.rs +++ b/tests/common/bakery_chain/lineitem.rs @@ -10,8 +10,6 @@ pub struct Model { pub quantity: i32, pub order_id: i32, pub cake_id: i32, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/tests/common/bakery_chain/order.rs b/tests/common/bakery_chain/order.rs index e52ba04c..ed6185cf 100644 --- a/tests/common/bakery_chain/order.rs +++ b/tests/common/bakery_chain/order.rs @@ -10,8 +10,6 @@ pub struct Model { pub bakery_id: i32, pub customer_id: i32, pub placed_at: DateTime, - #[sea_orm(ignore)] - pub ignored_attr: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]