Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sea-orm-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ path = "src/lib.rs"
proc-macro = true

[dependencies]
bae = { version = "0.2", package = "sea-bae", default-features = false, optional = true }
darling = { version = "0.23", optional = true }
heck = { version = "0.5", default-features = false }
itertools = "0.14"
pluralizer = { version = "0.5" }
Expand All @@ -44,7 +44,7 @@ serde = { version = "1.0", features = ["derive"] }
[features]
async = []
default = ["derive"]
derive = ["bae"]
derive = ["darling"]
entity-registry = []
postgres-array = []
seaography = ["proc-macro-crate"]
Expand Down
10 changes: 5 additions & 5 deletions sea-orm-macros/src/derives/active_model_ex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::util::{
await_token, consume_meta, escape_rust_keyword, is_self_entity, trim_starting_raw_identifier,
};
use heck::ToUpperCamelCase;
use proc_macro2::{Ident, Span, TokenStream};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use syn::{Attribute, Data, LitStr, PathArguments, Type, TypePath, Visibility};

Expand Down Expand Up @@ -620,10 +620,10 @@ impl ActiveModelActionTokens {
if is_unique_relation_target {
RelationLookup::ByRelatedEntity
} else {
RelationLookup::ByRelationVariant(Ident::new(
&infer_relation_name_from_entity(&compound_type.entity)
.to_upper_camel_case(),
Span::call_site(),
RelationLookup::ByRelationVariant(format_ident!(
"{}",
infer_relation_name_from_entity(&compound_type.entity)
.to_upper_camel_case()
))
}
}
Expand Down
169 changes: 126 additions & 43 deletions sea-orm-macros/src/derives/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,166 @@
use darling::{FromAttributes, FromMeta, Result};
use syn::{Attribute, Expr, Ident, Lit};

/// An optional `syn::Ident` attribute value.
///
/// Darling has no `from_word` for `syn::Ident`, so a bare-word usage such as
/// `#[sea_orm(model_ex)]` would be rejected for an `Option<Ident>` field. Several
/// `sea_orm` attributes are emitted both as bare words (e.g. `#[sea_orm(model_ex)]`)
/// and as name-value paths (e.g. `#[sea_orm(model_ex = ModelEx)]`); this wrapper
/// treats the bare-word form as absent so both usages parse cleanly.
#[derive(Debug, Clone, Default)]
pub struct OptionalIdent(pub Option<Ident>);

impl FromMeta for OptionalIdent {
fn from_word() -> Result<Self> {
Ok(Self(None))
}
fn from_value(value: &Lit) -> Result<Self> {
Ident::from_value(value).map(|id| Self(Some(id)))
}
fn from_expr(expr: &Expr) -> Result<Self> {
Ident::from_expr(expr).map(|id| Self(Some(id)))
}
}

fn try_from_attributes<T: FromAttributes>(attrs: &[Attribute]) -> syn::Result<Option<T>> {
if attrs.iter().any(|a| a.path().is_ident("sea_orm")) {
T::from_attributes(attrs)
.map(Some)
.map_err(syn::Error::from)
} else {
Ok(None)
}
}

fn from_attributes<T: FromAttributes>(attrs: &[Attribute]) -> syn::Result<T> {
T::from_attributes(attrs).map_err(syn::Error::from)
}

pub mod derive_attr {
use bae::FromAttributes;
use super::*;
use syn::{Ident, LitStr};

/// Attributes for Models and ActiveModels
#[derive(Default, FromAttributes)]
#[darling(attributes(sea_orm), allow_unknown_fields)]
#[allow(dead_code)]
pub struct SeaOrm {
pub column: Option<syn::Ident>,
pub entity: Option<syn::Ident>,
pub model: Option<syn::Ident>,
pub model_ex: Option<syn::Ident>,
pub active_model: Option<syn::Ident>,
pub active_model_ex: Option<syn::Ident>,
pub primary_key: Option<syn::Ident>,
pub relation: Option<syn::Ident>,
pub schema_name: Option<syn::LitStr>,
pub table_name: Option<syn::LitStr>,
pub comment: Option<syn::LitStr>,
pub column: Option<Ident>,
pub entity: Option<Ident>,
pub model: Option<Ident>,
#[darling(default)]
pub model_ex: OptionalIdent,
pub active_model: Option<Ident>,
pub active_model_ex: Option<Ident>,
pub primary_key: Option<Ident>,
pub relation: Option<Ident>,
pub schema_name: Option<LitStr>,
pub table_name: Option<LitStr>,
pub comment: Option<LitStr>,
pub table_iden: Option<()>,
pub rename_all: Option<syn::LitStr>,
pub rename_all: Option<LitStr>,
}

impl SeaOrm {
pub fn try_from_attributes(attrs: &[Attribute]) -> syn::Result<Option<Self>> {
super::try_from_attributes(attrs)
}
}
}

pub mod relation_attr {
use bae::FromAttributes;
use super::*;
use syn::Lit;

/// Attributes for Relation enum
#[derive(Default, FromAttributes)]
#[darling(attributes(sea_orm), allow_unknown_fields)]
pub struct SeaOrm {
pub belongs_to: Option<syn::Lit>,
pub has_one: Option<syn::Lit>,
pub has_many: Option<syn::Lit>,
pub via_rel: Option<syn::Lit>,
pub on_update: Option<syn::Lit>,
pub on_delete: Option<syn::Lit>,
pub on_condition: Option<syn::Lit>,
pub from: Option<syn::Lit>,
pub to: Option<syn::Lit>,
pub fk_name: Option<syn::Lit>,
pub belongs_to: Option<Lit>,
pub has_one: Option<Lit>,
pub has_many: Option<Lit>,
pub via_rel: Option<Lit>,
pub on_update: Option<Lit>,
pub on_delete: Option<Lit>,
pub on_condition: Option<Lit>,
pub from: Option<Lit>,
pub to: Option<Lit>,
pub fk_name: Option<Lit>,
pub skip_fk: Option<()>,
pub condition_type: Option<syn::Lit>,
pub condition_type: Option<Lit>,
}

impl SeaOrm {
pub fn from_attributes(attrs: &[Attribute]) -> syn::Result<Self> {
super::from_attributes(attrs)
}
}
}

pub mod compound_attr {
use bae::FromAttributes;
use super::*;
use syn::LitStr;

/// Attributes for compound model fields
#[derive(Default, FromAttributes)]
#[darling(attributes(sea_orm), allow_unknown_fields)]
pub struct SeaOrm {
pub has_one: Option<()>,
pub has_many: Option<()>,
pub belongs_to: Option<()>,
pub self_ref: Option<()>,
pub skip_fk: Option<()>,
pub via: Option<syn::LitStr>,
pub via_rel: Option<syn::LitStr>,
pub from: Option<syn::LitStr>,
pub to: Option<syn::LitStr>,
pub relation_enum: Option<syn::LitStr>,
pub relation_reverse: Option<syn::LitStr>,
pub via: Option<LitStr>,
pub via_rel: Option<LitStr>,
pub from: Option<LitStr>,
pub to: Option<LitStr>,
pub relation_enum: Option<LitStr>,
pub relation_reverse: Option<LitStr>,
pub reverse: Option<()>,
pub on_update: Option<syn::LitStr>,
pub on_delete: Option<syn::LitStr>,
pub on_update: Option<LitStr>,
pub on_delete: Option<LitStr>,
}

impl SeaOrm {
pub fn try_from_attributes(attrs: &[Attribute]) -> syn::Result<Option<Self>> {
super::try_from_attributes(attrs)
}
}
}

pub mod value_type_attr {
use bae::FromAttributes;
use super::*;
use syn::LitStr;

/// Attributes for compound model fields
#[derive(Default, FromAttributes)]
#[darling(attributes(sea_orm), allow_unknown_fields)]
pub struct SeaOrm {
pub column_type: Option<syn::LitStr>,
pub array_type: Option<syn::LitStr>,
pub value_type: Option<syn::LitStr>,
pub from_str: Option<syn::LitStr>,
pub to_str: Option<syn::LitStr>,
pub column_type: Option<LitStr>,
pub array_type: Option<LitStr>,
pub value_type: Option<LitStr>,
pub from_str: Option<LitStr>,
pub to_str: Option<LitStr>,
pub try_from_u64: Option<()>,
pub try_getable_array: Option<()>,
}

impl SeaOrm {
pub fn try_from_attributes(attrs: &[Attribute]) -> syn::Result<Option<Self>> {
super::try_from_attributes(attrs)
}
}
}

#[cfg(feature = "seaography")]
pub mod related_attr {
use bae::FromAttributes;
use super::*;
use syn::Lit;

/// Attributes for RelatedEntity enum
#[derive(Default, FromAttributes)]
#[darling(attributes(sea_orm), allow_unknown_fields)]
pub struct SeaOrm {
///
/// Allows to modify target entity
Expand All @@ -96,14 +170,23 @@ pub mod related_attr {
/// If used on enumeration attributes
/// it allows to specify different
/// Entity ident
pub entity: Option<syn::Lit>,
pub entity: Option<Lit>,
///
/// Allows to specify RelationDef
///
/// Optional
///
/// If not supplied the generated code
/// will utilize `impl Related` trait
pub def: Option<syn::Lit>,
pub def: Option<Lit>,
}

impl SeaOrm {
pub fn try_from_attributes(attrs: &[Attribute]) -> syn::Result<Option<Self>> {
super::try_from_attributes(attrs)
}
pub fn from_attributes(attrs: &[Attribute]) -> syn::Result<Self> {
super::from_attributes(attrs)
}
}
}
2 changes: 1 addition & 1 deletion sea-orm-macros/src/derives/case_style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ impl TryFrom<&ParseNestedMeta<'_>> for CaseStyle {

#[test]
fn test_convert_case() {
let id = Ident::new("test_me", proc_macro2::Span::call_site());
let id = quote::format_ident!("test_me");
assert_eq!("testMe", id.convert_case(Some(CaseStyle::CamelCase)));
assert_eq!("TestMe", id.convert_case(Some(CaseStyle::PascalCase)));
}
5 changes: 4 additions & 1 deletion sea-orm-macros/src/derives/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ impl DeriveEntity {
let ident = input.ident;
let column_ident = sea_attr.column.unwrap_or_else(|| format_ident!("Column"));
let model_ident = sea_attr.model.unwrap_or_else(|| format_ident!("Model"));
let model_ex_ident = sea_attr.model_ex.unwrap_or_else(|| format_ident!("Model"));
let model_ex_ident = sea_attr
.model_ex
.0
.unwrap_or_else(|| format_ident!("Model"));
let active_model_ident = sea_attr
.active_model
.unwrap_or_else(|| format_ident!("ActiveModel"));
Expand Down
29 changes: 14 additions & 15 deletions sea-orm-macros/src/derives/entity_loader.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use proc_macro2::Span;
use proc_macro2::TokenStream;
use quote::quote;
use std::collections::{HashMap, HashSet};
Expand All @@ -20,6 +21,16 @@ pub enum EntityLoaderFieldKind {
},
}

/// Ident for the `LoadTarget` variant used by a self-referential many-to-many
/// junction: `TableRef` for the forward direction, `TableRefRev` for the reverse.
fn table_ref_ident(reverse: bool, span: Span) -> Ident {
if reverse {
Ident::new("TableRefRev", span)
} else {
Ident::new("TableRef", span)
}
}

pub struct EntityLoaderField {
pub field: Ident,
/// super::bakery::Entity
Expand Down Expand Up @@ -115,11 +126,7 @@ impl EntityLoaderField {
junction_module: &Ident,
reverse: bool,
) {
let target_type = if !reverse {
Ident::new("TableRef", junction_module.span())
} else {
Ident::new("TableRefRev", junction_module.span())
};
let target_type = table_ref_ident(reverse, junction_module.span());

let target_entity = if !reverse {
quote!(super::#junction_module::Entity)
Expand Down Expand Up @@ -195,11 +202,7 @@ impl EntityLoaderField {
reverse,
} = &self.kind
{
let target_type = if !reverse {
Ident::new("TableRef", junction_module.span())
} else {
Ident::new("TableRefRev", junction_module.span())
};
let target_type = table_ref_ident(*reverse, junction_module.span());

output.loader_with_set_impl.extend(quote! {
if target == sea_orm::compound::LoadTarget::#target_type(super::#junction_module::Entity.table_ref()) {
Expand Down Expand Up @@ -248,11 +251,7 @@ impl EntityLoaderField {
junction_module,
reverse,
} => {
let target_type = if !reverse {
Ident::new("TableRef", junction_module.span())
} else {
Ident::new("TableRefRev", junction_module.span())
};
let target_type = table_ref_ident(*reverse, junction_module.span());

output.loader_with_2_impl.extend(quote! {
if left == sea_orm::compound::LoadTarget::#target_type(super::#junction_module::Entity.table_ref()) {
Expand Down
6 changes: 3 additions & 3 deletions sea-orm-macros/src/derives/entity_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use super::util::{consume_meta, escape_rust_keyword, trim_starting_raw_identifie
use heck::{
ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToTitleCase, ToUpperCamelCase,
};
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use std::str::FromStr;
use syn::{
Attribute, Data, Fields, Lit, LitStr, Visibility, punctuated::Punctuated, spanned::Spanned,
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn expand_derive_entity_model(

if table_iden {
if let Some(table_name) = &table_name {
let table_field_name = Ident::new("Table", Span::call_site());
let table_field_name = format_ident!("Table");
columns_enum.push(quote! {
#[doc = " Generated by sea-orm-macros"]
#[sea_orm(table_name=#table_name)]
Expand Down
2 changes: 1 addition & 1 deletion sea-orm-macros/src/derives/into_active_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl DeriveIntoActiveModel {

let mut active_model_ident = active_model
.clone()
.unwrap_or_else(|| syn::parse_str::<syn::Type>("ActiveModel").unwrap());
.unwrap_or_else(|| syn::parse_quote!(ActiveModel));

// Create a type alias for qualified types
let type_alias_definition = if is_qualified_type(&active_model_ident) {
Expand Down
Loading