Skip to content

Commit 4376a29

Browse files
billy1624tyt2y3
andauthored
DeriveRelatedEntity use async-graphql re-exported by seaography (#2469)
* DeriveRelatedEntity use `async-graphql` re-exported by `seaography` * Optionally compile related_entity * Update mod.rs * private --------- Co-authored-by: Chris Tsang <[email protected]>
1 parent 1c0bf23 commit 4376a29

File tree

4 files changed

+140
-115
lines changed

4 files changed

+140
-115
lines changed

sea-orm-macros/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ syn = { version = "2", default-features = false, features = ["parsing", "proc-ma
2323
quote = { version = "1", default-features = false }
2424
heck = { version = "0.4", default-features = false }
2525
proc-macro2 = { version = "1", default-features = false }
26+
proc-macro-crate = { version = "3.2.0", optional = true }
2627
unicode-ident = { version = "1" }
2728

2829
[dev-dependencies]
@@ -34,4 +35,4 @@ default = ["derive"]
3435
postgres-array = []
3536
derive = ["bae"]
3637
strum = []
37-
seaography = []
38+
seaography = ["proc-macro-crate"]

sea-orm-macros/src/derives/attributes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub mod field_attr {
3838
}
3939
}
4040

41+
#[cfg(feature = "seaography")]
4142
pub mod related_attr {
4243
use bae::FromAttributes;
4344

+134-107
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,152 @@
1-
use heck::ToLowerCamelCase;
2-
use proc_macro2::TokenStream;
3-
use quote::{quote, quote_spanned};
1+
#[cfg(feature = "seaography")]
2+
mod private {
3+
use heck::ToLowerCamelCase;
4+
use proc_macro2::{Ident, Span, TokenStream};
5+
use proc_macro_crate::{crate_name, FoundCrate};
6+
use quote::{quote, quote_spanned};
7+
8+
use crate::derives::attributes::related_attr;
9+
10+
enum Error {
11+
InputNotEnum,
12+
InvalidEntityPath,
13+
Syn(syn::Error),
14+
}
415

5-
use crate::derives::attributes::related_attr;
16+
struct DeriveRelatedEntity {
17+
entity_ident: TokenStream,
18+
ident: syn::Ident,
19+
variants: syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>,
20+
}
621

7-
enum Error {
8-
InputNotEnum,
9-
InvalidEntityPath,
10-
Syn(syn::Error),
11-
}
22+
impl DeriveRelatedEntity {
23+
fn new(input: syn::DeriveInput) -> Result<Self, Error> {
24+
let sea_attr = related_attr::SeaOrm::try_from_attributes(&input.attrs)
25+
.map_err(Error::Syn)?
26+
.unwrap_or_default();
27+
28+
let ident = input.ident;
29+
let entity_ident = match sea_attr.entity.as_ref().map(Self::parse_lit_string) {
30+
Some(entity_ident) => entity_ident.map_err(|_| Error::InvalidEntityPath)?,
31+
None => quote! { Entity },
32+
};
33+
34+
let variants = match input.data {
35+
syn::Data::Enum(syn::DataEnum { variants, .. }) => variants,
36+
_ => return Err(Error::InputNotEnum),
37+
};
38+
39+
Ok(DeriveRelatedEntity {
40+
entity_ident,
41+
ident,
42+
variants,
43+
})
44+
}
1245

13-
struct DeriveRelatedEntity {
14-
entity_ident: TokenStream,
15-
ident: syn::Ident,
16-
variants: syn::punctuated::Punctuated<syn::Variant, syn::token::Comma>,
17-
}
46+
fn expand(&self) -> syn::Result<TokenStream> {
47+
let ident = &self.ident;
48+
let entity_ident = &self.entity_ident;
49+
50+
let variant_implementations: Vec<TokenStream> = self
51+
.variants
52+
.iter()
53+
.map(|variant| {
54+
let attr = related_attr::SeaOrm::from_attributes(&variant.attrs)?;
55+
56+
let enum_name = &variant.ident;
57+
58+
let target_entity = attr
59+
.entity
60+
.as_ref()
61+
.map(Self::parse_lit_string)
62+
.ok_or_else(|| {
63+
syn::Error::new_spanned(variant, "Missing value for 'entity'")
64+
})??;
65+
66+
let def = match attr.def {
67+
Some(def) => Some(Self::parse_lit_string(&def).map_err(|_| {
68+
syn::Error::new_spanned(variant, "Missing value for 'def'")
69+
})?),
70+
None => None,
71+
};
72+
73+
let name = enum_name.to_string().to_lower_camel_case();
74+
75+
if let Some(def) = def {
76+
Result::<_, syn::Error>::Ok(quote! {
77+
Self::#enum_name => builder.get_relation::<#entity_ident, #target_entity>(#name, #def)
78+
})
79+
} else {
80+
Result::<_, syn::Error>::Ok(quote! {
81+
Self::#enum_name => via_builder.get_relation::<#entity_ident, #target_entity>(#name)
82+
})
83+
}
1884

19-
impl DeriveRelatedEntity {
20-
fn new(input: syn::DeriveInput) -> Result<Self, Error> {
21-
let sea_attr = related_attr::SeaOrm::try_from_attributes(&input.attrs)
22-
.map_err(Error::Syn)?
23-
.unwrap_or_default();
24-
25-
let ident = input.ident;
26-
let entity_ident = match sea_attr.entity.as_ref().map(Self::parse_lit_string) {
27-
Some(entity_ident) => entity_ident.map_err(|_| Error::InvalidEntityPath)?,
28-
None => quote! { Entity },
29-
};
30-
31-
let variants = match input.data {
32-
syn::Data::Enum(syn::DataEnum { variants, .. }) => variants,
33-
_ => return Err(Error::InputNotEnum),
34-
};
35-
36-
Ok(DeriveRelatedEntity {
37-
entity_ident,
38-
ident,
39-
variants,
40-
})
41-
}
85+
})
86+
.collect::<Result<Vec<_>, _>>()?;
4287

43-
fn expand(&self) -> syn::Result<TokenStream> {
44-
let ident = &self.ident;
45-
let entity_ident = &self.entity_ident;
46-
47-
let variant_implementations: Vec<TokenStream> = self
48-
.variants
49-
.iter()
50-
.map(|variant| {
51-
let attr = related_attr::SeaOrm::from_attributes(&variant.attrs)?;
52-
53-
let enum_name = &variant.ident;
54-
55-
let target_entity = attr
56-
.entity
57-
.as_ref()
58-
.map(Self::parse_lit_string)
59-
.ok_or_else(|| {
60-
syn::Error::new_spanned(variant, "Missing value for 'entity'")
61-
})??;
62-
63-
let def = match attr.def {
64-
Some(def) => Some(Self::parse_lit_string(&def).map_err(|_| {
65-
syn::Error::new_spanned(variant, "Missing value for 'def'")
66-
})?),
67-
None => None,
68-
};
69-
70-
let name = enum_name.to_string().to_lower_camel_case();
71-
72-
if let Some(def) = def {
73-
Result::<_, syn::Error>::Ok(quote! {
74-
Self::#enum_name => builder.get_relation::<#entity_ident, #target_entity>(#name, #def)
75-
})
76-
} else {
77-
Result::<_, syn::Error>::Ok(quote! {
78-
Self::#enum_name => via_builder.get_relation::<#entity_ident, #target_entity>(#name)
79-
})
88+
// Get the path of the `async-graphql` on the application's Cargo.toml
89+
let async_graphql_crate = match crate_name("async-graphql") {
90+
// if found, use application's `async-graphql`
91+
Ok(FoundCrate::Name(name)) => {
92+
let ident = Ident::new(&name, Span::call_site());
93+
quote! { #ident }
8094
}
81-
82-
})
83-
.collect::<Result<Vec<_>, _>>()?;
84-
85-
Ok(quote! {
86-
impl seaography::RelationBuilder for #ident {
87-
fn get_relation(&self, context: & 'static seaography::BuilderContext) -> async_graphql::dynamic::Field {
88-
let builder = seaography::EntityObjectRelationBuilder { context };
89-
let via_builder = seaography::EntityObjectViaRelationBuilder { context };
90-
match self {
91-
#(#variant_implementations,)*
92-
_ => panic!("No relations for this entity"),
95+
Ok(FoundCrate::Itself) => quote! { async_graphql },
96+
// if not, then use the `async-graphql` re-exported by `seaography`
97+
Err(_) => quote! { seaography::async_graphql },
98+
};
99+
100+
Ok(quote! {
101+
impl seaography::RelationBuilder for #ident {
102+
fn get_relation(&self, context: & 'static seaography::BuilderContext) -> #async_graphql_crate::dynamic::Field {
103+
let builder = seaography::EntityObjectRelationBuilder { context };
104+
let via_builder = seaography::EntityObjectViaRelationBuilder { context };
105+
match self {
106+
#(#variant_implementations,)*
107+
_ => panic!("No relations for this entity"),
108+
}
93109
}
110+
94111
}
112+
})
113+
}
95114

115+
fn parse_lit_string(lit: &syn::Lit) -> syn::Result<TokenStream> {
116+
match lit {
117+
syn::Lit::Str(lit_str) => lit_str
118+
.value()
119+
.parse()
120+
.map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")),
121+
_ => Err(syn::Error::new_spanned(lit, "attribute must be a string")),
96122
}
97-
})
123+
}
98124
}
99125

100-
fn parse_lit_string(lit: &syn::Lit) -> syn::Result<TokenStream> {
101-
match lit {
102-
syn::Lit::Str(lit_str) => lit_str
103-
.value()
104-
.parse()
105-
.map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")),
106-
_ => Err(syn::Error::new_spanned(lit, "attribute must be a string")),
126+
/// Method to derive a Related enumeration
127+
pub fn expand_derive_related_entity(input: syn::DeriveInput) -> syn::Result<TokenStream> {
128+
let ident_span = input.ident.span();
129+
130+
match DeriveRelatedEntity::new(input) {
131+
Ok(model) => model.expand(),
132+
Err(Error::InputNotEnum) => Ok(quote_spanned! {
133+
ident_span => compile_error!("you can only derive DeriveRelation on enums");
134+
}),
135+
Err(Error::InvalidEntityPath) => Ok(quote_spanned! {
136+
ident_span => compile_error!("invalid attribute value for 'entity'");
137+
}),
138+
Err(Error::Syn(err)) => Err(err),
107139
}
108140
}
109141
}
110142

111-
/// Method to derive a Related enumeration
112-
pub fn expand_derive_related_entity(input: syn::DeriveInput) -> syn::Result<TokenStream> {
113-
let ident_span = input.ident.span();
114-
115-
match DeriveRelatedEntity::new(input) {
116-
Ok(model) => model.expand(),
117-
Err(Error::InputNotEnum) => Ok(quote_spanned! {
118-
ident_span => compile_error!("you can only derive DeriveRelation on enums");
119-
}),
120-
Err(Error::InvalidEntityPath) => Ok(quote_spanned! {
121-
ident_span => compile_error!("invalid attribute value for 'entity'");
122-
}),
123-
Err(Error::Syn(err)) => Err(err),
143+
#[cfg(not(feature = "seaography"))]
144+
mod private {
145+
use proc_macro2::TokenStream;
146+
147+
pub fn expand_derive_related_entity(_: syn::DeriveInput) -> syn::Result<TokenStream> {
148+
Ok(TokenStream::new())
124149
}
125150
}
151+
152+
pub use private::*;

sea-orm-macros/src/lib.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -675,13 +675,9 @@ pub fn derive_relation(input: TokenStream) -> TokenStream {
675675
#[proc_macro_derive(DeriveRelatedEntity, attributes(sea_orm))]
676676
pub fn derive_related_entity(input: TokenStream) -> TokenStream {
677677
let input = parse_macro_input!(input as DeriveInput);
678-
if cfg!(feature = "seaography") {
679-
derives::expand_derive_related_entity(input)
680-
.unwrap_or_else(Error::into_compile_error)
681-
.into()
682-
} else {
683-
TokenStream::new()
684-
}
678+
derives::expand_derive_related_entity(input)
679+
.unwrap_or_else(Error::into_compile_error)
680+
.into()
685681
}
686682

687683
/// The DeriveMigrationName derive macro will implement `sea_orm_migration::MigrationName` for a migration.

0 commit comments

Comments
 (0)