From c48e3a07a22c9f6cbf2933eb1cd391a49f808e90 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 9 Jan 2025 11:43:39 +0800 Subject: [PATCH 1/4] DeriveRelatedEntity use `async-graphql` re-exported by `seaography` --- sea-orm-macros/Cargo.toml | 1 + sea-orm-macros/src/derives/related_entity.rs | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 1b8ed548d..4d6595f36 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -23,6 +23,7 @@ syn = { version = "2", default-features = false, features = ["parsing", "proc-ma quote = { version = "1", default-features = false } heck = { version = "0.4", default-features = false } proc-macro2 = { version = "1", default-features = false } +proc-macro-crate = { version = "3.2.0" } unicode-ident = { version = "1" } [dev-dependencies] diff --git a/sea-orm-macros/src/derives/related_entity.rs b/sea-orm-macros/src/derives/related_entity.rs index bf74a48cc..0f4c20178 100644 --- a/sea-orm-macros/src/derives/related_entity.rs +++ b/sea-orm-macros/src/derives/related_entity.rs @@ -1,5 +1,6 @@ use heck::ToLowerCamelCase; -use proc_macro2::TokenStream; +use proc_macro2::{Ident, Span, TokenStream}; +use proc_macro_crate::{crate_name, FoundCrate}; use quote::{quote, quote_spanned}; use crate::derives::attributes::related_attr; @@ -82,9 +83,21 @@ impl DeriveRelatedEntity { }) .collect::, _>>()?; + // Get the path of the `async-graphql` on the application's Cargo.toml + let async_graphql_crate = match crate_name("async-graphql") { + // if found, use application's `async-graphql` + Ok(FoundCrate::Name(name)) => { + let ident = Ident::new(&name, Span::call_site()); + quote! { #ident } + } + Ok(FoundCrate::Itself) => quote! { async_graphql }, + // if not, then use the `async-graphql` re-exported by `seaography` + Err(_) => quote! { seaography::async_graphql }, + }; + Ok(quote! { impl seaography::RelationBuilder for #ident { - fn get_relation(&self, context: & 'static seaography::BuilderContext) -> async_graphql::dynamic::Field { + fn get_relation(&self, context: & 'static seaography::BuilderContext) -> #async_graphql_crate::dynamic::Field { let builder = seaography::EntityObjectRelationBuilder { context }; let via_builder = seaography::EntityObjectViaRelationBuilder { context }; match self { From 565c9056011a264d0737caba606786944f0d01de Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Jan 2025 21:12:56 +0800 Subject: [PATCH 2/4] Optionally compile related_entity --- sea-orm-macros/Cargo.toml | 4 ++-- sea-orm-macros/src/derives/attributes.rs | 1 + sea-orm-macros/src/derives/mod.rs | 8 ++++++-- sea-orm-macros/src/lib.rs | 20 +++++++++++++------- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 4d6595f36..8e2e7d7c4 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -23,7 +23,7 @@ syn = { version = "2", default-features = false, features = ["parsing", "proc-ma quote = { version = "1", default-features = false } heck = { version = "0.4", default-features = false } proc-macro2 = { version = "1", default-features = false } -proc-macro-crate = { version = "3.2.0" } +proc-macro-crate = { version = "3.2.0", optional = true } unicode-ident = { version = "1" } [dev-dependencies] @@ -35,4 +35,4 @@ default = ["derive"] postgres-array = [] derive = ["bae"] strum = [] -seaography = [] +seaography = ["proc-macro-crate"] diff --git a/sea-orm-macros/src/derives/attributes.rs b/sea-orm-macros/src/derives/attributes.rs index 4f46f55ac..708fe3714 100644 --- a/sea-orm-macros/src/derives/attributes.rs +++ b/sea-orm-macros/src/derives/attributes.rs @@ -38,6 +38,7 @@ pub mod field_attr { } } +#[cfg(feature = "seaography")] pub mod related_attr { use bae::FromAttributes; diff --git a/sea-orm-macros/src/derives/mod.rs b/sea-orm-macros/src/derives/mod.rs index 2bb44ee1f..ad093cee0 100644 --- a/sea-orm-macros/src/derives/mod.rs +++ b/sea-orm-macros/src/derives/mod.rs @@ -14,13 +14,15 @@ mod migration; mod model; mod partial_model; mod primary_key; -mod related_entity; mod relation; mod sql_type_match; mod try_getable_from_json; mod util; mod value_type; +#[cfg(feature = "seaography")] +mod related_entity; + pub use active_enum::*; pub use active_enum_display::*; pub use active_model::*; @@ -35,7 +37,9 @@ pub use migration::*; pub use model::*; pub use partial_model::*; pub use primary_key::*; -pub use related_entity::*; pub use relation::*; pub use try_getable_from_json::*; pub use value_type::*; + +#[cfg(feature = "seaography")] +pub use related_entity::*; diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 708958495..0b85a2f19 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -674,14 +674,20 @@ pub fn derive_relation(input: TokenStream) -> TokenStream { #[cfg(feature = "derive")] #[proc_macro_derive(DeriveRelatedEntity, attributes(sea_orm))] pub fn derive_related_entity(input: TokenStream) -> TokenStream { + derive_related_entity_inner(input) +} + +#[cfg(feature = "seaography")] +fn derive_related_entity_inner(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); - if cfg!(feature = "seaography") { - derives::expand_derive_related_entity(input) - .unwrap_or_else(Error::into_compile_error) - .into() - } else { - TokenStream::new() - } + derives::expand_derive_related_entity(input) + .unwrap_or_else(Error::into_compile_error) + .into() +} + +#[cfg(not(feature = "seaography"))] +fn derive_related_entity_inner(_: TokenStream) -> TokenStream { + TokenStream::new() } /// The DeriveMigrationName derive macro will implement `sea_orm_migration::MigrationName` for a migration. From 543d31fed203aaeff454ce7ef8a042e0dc4a6380 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 10 Jan 2025 14:23:43 +0000 Subject: [PATCH 3/4] Update mod.rs --- sea-orm-macros/src/derives/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sea-orm-macros/src/derives/mod.rs b/sea-orm-macros/src/derives/mod.rs index ad093cee0..2bb44ee1f 100644 --- a/sea-orm-macros/src/derives/mod.rs +++ b/sea-orm-macros/src/derives/mod.rs @@ -14,15 +14,13 @@ mod migration; mod model; mod partial_model; mod primary_key; +mod related_entity; mod relation; mod sql_type_match; mod try_getable_from_json; mod util; mod value_type; -#[cfg(feature = "seaography")] -mod related_entity; - pub use active_enum::*; pub use active_enum_display::*; pub use active_model::*; @@ -37,9 +35,7 @@ pub use migration::*; pub use model::*; pub use partial_model::*; pub use primary_key::*; +pub use related_entity::*; pub use relation::*; pub use try_getable_from_json::*; pub use value_type::*; - -#[cfg(feature = "seaography")] -pub use related_entity::*; From 492a64a410e8801bc57ef6759e1657f9bd41102e Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 10 Jan 2025 22:58:33 +0800 Subject: [PATCH 4/4] private --- sea-orm-macros/src/derives/related_entity.rs | 254 ++++++++++--------- sea-orm-macros/src/lib.rs | 10 - 2 files changed, 134 insertions(+), 130 deletions(-) diff --git a/sea-orm-macros/src/derives/related_entity.rs b/sea-orm-macros/src/derives/related_entity.rs index 0f4c20178..9db8b531d 100644 --- a/sea-orm-macros/src/derives/related_entity.rs +++ b/sea-orm-macros/src/derives/related_entity.rs @@ -1,138 +1,152 @@ -use heck::ToLowerCamelCase; -use proc_macro2::{Ident, Span, TokenStream}; -use proc_macro_crate::{crate_name, FoundCrate}; -use quote::{quote, quote_spanned}; +#[cfg(feature = "seaography")] +mod private { + use heck::ToLowerCamelCase; + use proc_macro2::{Ident, Span, TokenStream}; + use proc_macro_crate::{crate_name, FoundCrate}; + use quote::{quote, quote_spanned}; + + use crate::derives::attributes::related_attr; + + enum Error { + InputNotEnum, + InvalidEntityPath, + Syn(syn::Error), + } -use crate::derives::attributes::related_attr; + struct DeriveRelatedEntity { + entity_ident: TokenStream, + ident: syn::Ident, + variants: syn::punctuated::Punctuated, + } -enum Error { - InputNotEnum, - InvalidEntityPath, - Syn(syn::Error), -} + impl DeriveRelatedEntity { + fn new(input: syn::DeriveInput) -> Result { + let sea_attr = related_attr::SeaOrm::try_from_attributes(&input.attrs) + .map_err(Error::Syn)? + .unwrap_or_default(); + + let ident = input.ident; + let entity_ident = match sea_attr.entity.as_ref().map(Self::parse_lit_string) { + Some(entity_ident) => entity_ident.map_err(|_| Error::InvalidEntityPath)?, + None => quote! { Entity }, + }; + + let variants = match input.data { + syn::Data::Enum(syn::DataEnum { variants, .. }) => variants, + _ => return Err(Error::InputNotEnum), + }; + + Ok(DeriveRelatedEntity { + entity_ident, + ident, + variants, + }) + } -struct DeriveRelatedEntity { - entity_ident: TokenStream, - ident: syn::Ident, - variants: syn::punctuated::Punctuated, -} + fn expand(&self) -> syn::Result { + let ident = &self.ident; + let entity_ident = &self.entity_ident; + + let variant_implementations: Vec = self + .variants + .iter() + .map(|variant| { + let attr = related_attr::SeaOrm::from_attributes(&variant.attrs)?; + + let enum_name = &variant.ident; + + let target_entity = attr + .entity + .as_ref() + .map(Self::parse_lit_string) + .ok_or_else(|| { + syn::Error::new_spanned(variant, "Missing value for 'entity'") + })??; + + let def = match attr.def { + Some(def) => Some(Self::parse_lit_string(&def).map_err(|_| { + syn::Error::new_spanned(variant, "Missing value for 'def'") + })?), + None => None, + }; + + let name = enum_name.to_string().to_lower_camel_case(); + + if let Some(def) = def { + Result::<_, syn::Error>::Ok(quote! { + Self::#enum_name => builder.get_relation::<#entity_ident, #target_entity>(#name, #def) + }) + } else { + Result::<_, syn::Error>::Ok(quote! { + Self::#enum_name => via_builder.get_relation::<#entity_ident, #target_entity>(#name) + }) + } -impl DeriveRelatedEntity { - fn new(input: syn::DeriveInput) -> Result { - let sea_attr = related_attr::SeaOrm::try_from_attributes(&input.attrs) - .map_err(Error::Syn)? - .unwrap_or_default(); - - let ident = input.ident; - let entity_ident = match sea_attr.entity.as_ref().map(Self::parse_lit_string) { - Some(entity_ident) => entity_ident.map_err(|_| Error::InvalidEntityPath)?, - None => quote! { Entity }, - }; - - let variants = match input.data { - syn::Data::Enum(syn::DataEnum { variants, .. }) => variants, - _ => return Err(Error::InputNotEnum), - }; - - Ok(DeriveRelatedEntity { - entity_ident, - ident, - variants, - }) - } + }) + .collect::, _>>()?; - fn expand(&self) -> syn::Result { - let ident = &self.ident; - let entity_ident = &self.entity_ident; - - let variant_implementations: Vec = self - .variants - .iter() - .map(|variant| { - let attr = related_attr::SeaOrm::from_attributes(&variant.attrs)?; - - let enum_name = &variant.ident; - - let target_entity = attr - .entity - .as_ref() - .map(Self::parse_lit_string) - .ok_or_else(|| { - syn::Error::new_spanned(variant, "Missing value for 'entity'") - })??; - - let def = match attr.def { - Some(def) => Some(Self::parse_lit_string(&def).map_err(|_| { - syn::Error::new_spanned(variant, "Missing value for 'def'") - })?), - None => None, - }; - - let name = enum_name.to_string().to_lower_camel_case(); - - if let Some(def) = def { - Result::<_, syn::Error>::Ok(quote! { - Self::#enum_name => builder.get_relation::<#entity_ident, #target_entity>(#name, #def) - }) - } else { - Result::<_, syn::Error>::Ok(quote! { - Self::#enum_name => via_builder.get_relation::<#entity_ident, #target_entity>(#name) - }) + // Get the path of the `async-graphql` on the application's Cargo.toml + let async_graphql_crate = match crate_name("async-graphql") { + // if found, use application's `async-graphql` + Ok(FoundCrate::Name(name)) => { + let ident = Ident::new(&name, Span::call_site()); + quote! { #ident } } - - }) - .collect::, _>>()?; - - // Get the path of the `async-graphql` on the application's Cargo.toml - let async_graphql_crate = match crate_name("async-graphql") { - // if found, use application's `async-graphql` - Ok(FoundCrate::Name(name)) => { - let ident = Ident::new(&name, Span::call_site()); - quote! { #ident } - } - Ok(FoundCrate::Itself) => quote! { async_graphql }, - // if not, then use the `async-graphql` re-exported by `seaography` - Err(_) => quote! { seaography::async_graphql }, - }; - - Ok(quote! { - impl seaography::RelationBuilder for #ident { - fn get_relation(&self, context: & 'static seaography::BuilderContext) -> #async_graphql_crate::dynamic::Field { - let builder = seaography::EntityObjectRelationBuilder { context }; - let via_builder = seaography::EntityObjectViaRelationBuilder { context }; - match self { - #(#variant_implementations,)* - _ => panic!("No relations for this entity"), + Ok(FoundCrate::Itself) => quote! { async_graphql }, + // if not, then use the `async-graphql` re-exported by `seaography` + Err(_) => quote! { seaography::async_graphql }, + }; + + Ok(quote! { + impl seaography::RelationBuilder for #ident { + fn get_relation(&self, context: & 'static seaography::BuilderContext) -> #async_graphql_crate::dynamic::Field { + let builder = seaography::EntityObjectRelationBuilder { context }; + let via_builder = seaography::EntityObjectViaRelationBuilder { context }; + match self { + #(#variant_implementations,)* + _ => panic!("No relations for this entity"), + } } + } + }) + } + fn parse_lit_string(lit: &syn::Lit) -> syn::Result { + match lit { + syn::Lit::Str(lit_str) => lit_str + .value() + .parse() + .map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")), + _ => Err(syn::Error::new_spanned(lit, "attribute must be a string")), } - }) + } } - fn parse_lit_string(lit: &syn::Lit) -> syn::Result { - match lit { - syn::Lit::Str(lit_str) => lit_str - .value() - .parse() - .map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")), - _ => Err(syn::Error::new_spanned(lit, "attribute must be a string")), + /// Method to derive a Related enumeration + pub fn expand_derive_related_entity(input: syn::DeriveInput) -> syn::Result { + let ident_span = input.ident.span(); + + match DeriveRelatedEntity::new(input) { + Ok(model) => model.expand(), + Err(Error::InputNotEnum) => Ok(quote_spanned! { + ident_span => compile_error!("you can only derive DeriveRelation on enums"); + }), + Err(Error::InvalidEntityPath) => Ok(quote_spanned! { + ident_span => compile_error!("invalid attribute value for 'entity'"); + }), + Err(Error::Syn(err)) => Err(err), } } } -/// Method to derive a Related enumeration -pub fn expand_derive_related_entity(input: syn::DeriveInput) -> syn::Result { - let ident_span = input.ident.span(); - - match DeriveRelatedEntity::new(input) { - Ok(model) => model.expand(), - Err(Error::InputNotEnum) => Ok(quote_spanned! { - ident_span => compile_error!("you can only derive DeriveRelation on enums"); - }), - Err(Error::InvalidEntityPath) => Ok(quote_spanned! { - ident_span => compile_error!("invalid attribute value for 'entity'"); - }), - Err(Error::Syn(err)) => Err(err), +#[cfg(not(feature = "seaography"))] +mod private { + use proc_macro2::TokenStream; + + pub fn expand_derive_related_entity(_: syn::DeriveInput) -> syn::Result { + Ok(TokenStream::new()) } } + +pub use private::*; diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 0b85a2f19..536165c0f 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -674,22 +674,12 @@ pub fn derive_relation(input: TokenStream) -> TokenStream { #[cfg(feature = "derive")] #[proc_macro_derive(DeriveRelatedEntity, attributes(sea_orm))] pub fn derive_related_entity(input: TokenStream) -> TokenStream { - derive_related_entity_inner(input) -} - -#[cfg(feature = "seaography")] -fn derive_related_entity_inner(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); derives::expand_derive_related_entity(input) .unwrap_or_else(Error::into_compile_error) .into() } -#[cfg(not(feature = "seaography"))] -fn derive_related_entity_inner(_: TokenStream) -> TokenStream { - TokenStream::new() -} - /// The DeriveMigrationName derive macro will implement `sea_orm_migration::MigrationName` for a migration. /// /// ### Usage