diff --git a/sea-orm-macros/src/attributes.rs b/sea-orm-macros/src/attributes.rs index cb47d0294..3b7ed47b7 100644 --- a/sea-orm-macros/src/attributes.rs +++ b/sea-orm-macros/src/attributes.rs @@ -28,5 +28,6 @@ pub mod field_attr { pub on_delete: Option, pub from: Option, pub to: Option, + pub fk_name: Option, } } diff --git a/sea-orm-macros/src/derives/relation.rs b/sea-orm-macros/src/derives/relation.rs index ee4f332c4..4b6d7d617 100644 --- a/sea-orm-macros/src/derives/relation.rs +++ b/sea-orm-macros/src/derives/relation.rs @@ -136,6 +136,22 @@ impl DeriveRelation { result = quote! { #result.on_delete(sea_orm::prelude::ForeignKeyAction::#on_delete) }; } + if attr.fk_name.is_some() { + let fk_name = attr + .fk_name + .as_ref() + .map(|lit| { + match lit { + syn::Lit::Str(lit_str) => Ok(lit_str.value()), + _ => Err(syn::Error::new_spanned(lit, "attribute must be a string")), + } + }) + .ok_or_else(|| { + syn::Error::new_spanned(variant, "Missing value for 'fk_name'") + })??; + result = quote! { #result.fk_name(#fk_name) }; + } + result = quote! { #result.into() }; Result::<_, syn::Error>::Ok(result) diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 0733c9828..d43c856e8 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -62,6 +62,8 @@ pub struct RelationDef { /// Defines an operation to be performed on a Foreign Key when a /// `UPDATE` Operation is performed pub on_update: Option, + /// The name of foreign key constraint + pub fk_name: Option, } /// Defines a helper to build a relation @@ -80,6 +82,7 @@ where is_owner: bool, on_delete: Option, on_update: Option, + fk_name: Option, } impl RelationDef { @@ -94,6 +97,7 @@ impl RelationDef { is_owner: !self.is_owner, on_delete: self.on_delete, on_update: self.on_update, + fk_name: None, } } } @@ -114,6 +118,7 @@ where is_owner, on_delete: None, on_update: None, + fk_name: None, } } @@ -128,6 +133,7 @@ where is_owner, on_delete: None, on_update: None, + fk_name: None, } } @@ -160,6 +166,12 @@ where self.on_update = Some(action); self } + + /// Set the name of foreign key constraint + pub fn fk_name(mut self, fk_name: &str) -> Self { + self.fk_name = Some(fk_name.to_owned()); + self + } } impl From> for RelationDef @@ -177,6 +189,7 @@ where is_owner: b.is_owner, on_delete: b.on_delete, on_update: b.on_update, + fk_name: b.fk_name, } } } diff --git a/src/schema/entity.rs b/src/schema/entity.rs index 9c422ed34..e937c9ac2 100644 --- a/src/schema/entity.rs +++ b/src/schema/entity.rs @@ -144,20 +144,18 @@ where let mut foreign_key_stmt = ForeignKeyCreateStatement::new(); let from_tbl = unpack_table_ref(&relation.from_tbl); let to_tbl = unpack_table_ref(&relation.to_tbl); - match relation.from_col { - Identity::Unary(o1) => { - foreign_key_stmt.from_col(o1); - } - Identity::Binary(o1, o2) => { - foreign_key_stmt.from_col(o1); - foreign_key_stmt.from_col(o2); - } - Identity::Ternary(o1, o2, o3) => { - foreign_key_stmt.from_col(o1); - foreign_key_stmt.from_col(o2); - foreign_key_stmt.from_col(o3); - } + let from_cols: Vec = match relation.from_col { + Identity::Unary(o1) => vec![o1], + Identity::Binary(o1, o2) => vec![o1, o2], + Identity::Ternary(o1, o2, o3) => vec![o1, o2, o3], } + .into_iter() + .map(|col| { + let col_name = col.to_string(); + foreign_key_stmt.from_col(col); + col_name + }) + .collect(); match relation.to_col { Identity::Unary(o1) => { foreign_key_stmt.to_col(o1); @@ -166,7 +164,7 @@ where foreign_key_stmt.to_col(o1); foreign_key_stmt.to_col(o2); } - crate::Identity::Ternary(o1, o2, o3) => { + Identity::Ternary(o1, o2, o3) => { foreign_key_stmt.to_col(o1); foreign_key_stmt.to_col(o2); foreign_key_stmt.to_col(o3); @@ -178,13 +176,14 @@ where if let Some(action) = relation.on_update { foreign_key_stmt.on_update(action); } + let name = if let Some(name) = relation.fk_name { + name + } else { + format!("fk-{}-{}", from_tbl.to_string(), from_cols.join("-")) + }; stmt.foreign_key( foreign_key_stmt - .name(&format!( - "fk-{}-{}", - from_tbl.to_string(), - to_tbl.to_string() - )) + .name(&name) .from_tbl(from_tbl) .to_tbl(to_tbl), ); @@ -235,7 +234,7 @@ mod tests { ) .foreign_key( ForeignKeyCreateStatement::new() - .name("fk-cake_filling_price-cake_filling") + .name("fk-cake_filling_price-cake_id-filling_id") .from_tbl(CakeFillingPrice) .from_col(cake_filling_price::Column::CakeId) .from_col(cake_filling_price::Column::FillingId) diff --git a/tests/common/bakery_chain/schema.rs b/tests/common/bakery_chain/schema.rs index 0d3e6c2a5..94bbc6498 100644 --- a/tests/common/bakery_chain/schema.rs +++ b/tests/common/bakery_chain/schema.rs @@ -55,7 +55,7 @@ pub async fn create_baker_table(db: &DbConn) -> Result { .col(ColumnDef::new(baker::Column::BakeryId).integer()) .foreign_key( ForeignKey::create() - .name("fk-baker-bakery") + .name("fk-baker-bakery_id") .from(baker::Entity, baker::Column::BakeryId) .to(bakery::Entity, bakery::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -111,7 +111,7 @@ pub async fn create_order_table(db: &DbConn) -> Result { ) .foreign_key( ForeignKey::create() - .name("fk-order-bakery") + .name("fk-order-bakery_id") .from(order::Entity, order::Column::BakeryId) .to(bakery::Entity, bakery::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -119,7 +119,7 @@ pub async fn create_order_table(db: &DbConn) -> Result { ) .foreign_key( ForeignKey::create() - .name("fk-order-customer") + .name("fk-order-customer_id") .from(order::Entity, order::Column::CustomerId) .to(customer::Entity, customer::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -162,7 +162,7 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result { ) .foreign_key( ForeignKey::create() - .name("fk-lineitem-order") + .name("fk-lineitem-order_id") .from(lineitem::Entity, lineitem::Column::OrderId) .to(order::Entity, order::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -170,7 +170,7 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result { ) .foreign_key( ForeignKey::create() - .name("fk-lineitem-cake") + .name("fk-lineitem-cake_id") .from(lineitem::Entity, lineitem::Column::CakeId) .to(cake::Entity, cake::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -202,7 +202,7 @@ pub async fn create_cakes_bakers_table(db: &DbConn) -> Result ) .foreign_key( ForeignKey::create() - .name("fk-cakes_bakers-cake") + .name("fk-cakes_bakers-cake_id") .from(cakes_bakers::Entity, cakes_bakers::Column::CakeId) .to(cake::Entity, cake::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -210,7 +210,7 @@ pub async fn create_cakes_bakers_table(db: &DbConn) -> Result ) .foreign_key( ForeignKey::create() - .name("fk-cakes_bakers-baker") + .name("fk-cakes_bakers-baker_id") .from(cakes_bakers::Entity, cakes_bakers::Column::BakerId) .to(baker::Entity, baker::Column::Id) .on_delete(ForeignKeyAction::Cascade) @@ -240,7 +240,7 @@ pub async fn create_cake_table(db: &DbConn) -> Result { .col(ColumnDef::new(cake::Column::BakeryId).integer()) .foreign_key( ForeignKey::create() - .name("fk-cake-bakery") + .name("fk-cake-bakery_id") .from(cake::Entity, cake::Column::BakeryId) .to(bakery::Entity, bakery::Column::Id) .on_delete(ForeignKeyAction::Cascade) diff --git a/tests/common/features/active_enum_child.rs b/tests/common/features/active_enum_child.rs index 30564a4f2..1a9d0d048 100644 --- a/tests/common/features/active_enum_child.rs +++ b/tests/common/features/active_enum_child.rs @@ -16,6 +16,7 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { #[sea_orm( + fk_name = "fk-active_enum_child-active_enum", belongs_to = "super::active_enum::Entity", from = "Column::ParentId", to = "super::active_enum::Column::Id" diff --git a/tests/common/features/schema.rs b/tests/common/features/schema.rs index c38feb048..89bf959c2 100644 --- a/tests/common/features/schema.rs +++ b/tests/common/features/schema.rs @@ -116,7 +116,7 @@ pub async fn create_self_join_table(db: &DbConn) -> Result { .col(ColumnDef::new(self_join::Column::Time).time()) .foreign_key( ForeignKeyCreateStatement::new() - .name("fk-self_join-self_join") + .name("fk-self_join-uuid_ref") .from_tbl(SelfJoin) .from_col(self_join::Column::UuidRef) .to_tbl(SelfJoin)