Name conflict of foreign key constraints when two entities have more than one foreign keys (#417)

* fix: name conflict of foreign key constraints when two entities have more than one fk

* test: update test case's foreign keys

* feat: override default name of foreign key constraint
This commit is contained in:
Billy Chan 2022-01-28 01:03:24 +08:00 committed by GitHub
parent 946a03b426
commit 76c0d7fff5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 59 additions and 29 deletions

View File

@ -28,5 +28,6 @@ pub mod field_attr {
pub on_delete: Option<syn::Lit>, pub on_delete: Option<syn::Lit>,
pub from: Option<syn::Lit>, pub from: Option<syn::Lit>,
pub to: Option<syn::Lit>, pub to: Option<syn::Lit>,
pub fk_name: Option<syn::Lit>,
} }
} }

View File

@ -136,6 +136,22 @@ impl DeriveRelation {
result = quote! { #result.on_delete(sea_orm::prelude::ForeignKeyAction::#on_delete) }; 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 = quote! { #result.into() };
Result::<_, syn::Error>::Ok(result) Result::<_, syn::Error>::Ok(result)

View File

@ -62,6 +62,8 @@ pub struct RelationDef {
/// Defines an operation to be performed on a Foreign Key when a /// Defines an operation to be performed on a Foreign Key when a
/// `UPDATE` Operation is performed /// `UPDATE` Operation is performed
pub on_update: Option<ForeignKeyAction>, pub on_update: Option<ForeignKeyAction>,
/// The name of foreign key constraint
pub fk_name: Option<String>,
} }
/// Defines a helper to build a relation /// Defines a helper to build a relation
@ -80,6 +82,7 @@ where
is_owner: bool, is_owner: bool,
on_delete: Option<ForeignKeyAction>, on_delete: Option<ForeignKeyAction>,
on_update: Option<ForeignKeyAction>, on_update: Option<ForeignKeyAction>,
fk_name: Option<String>,
} }
impl RelationDef { impl RelationDef {
@ -94,6 +97,7 @@ impl RelationDef {
is_owner: !self.is_owner, is_owner: !self.is_owner,
on_delete: self.on_delete, on_delete: self.on_delete,
on_update: self.on_update, on_update: self.on_update,
fk_name: None,
} }
} }
} }
@ -114,6 +118,7 @@ where
is_owner, is_owner,
on_delete: None, on_delete: None,
on_update: None, on_update: None,
fk_name: None,
} }
} }
@ -128,6 +133,7 @@ where
is_owner, is_owner,
on_delete: None, on_delete: None,
on_update: None, on_update: None,
fk_name: None,
} }
} }
@ -160,6 +166,12 @@ where
self.on_update = Some(action); self.on_update = Some(action);
self 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<E, R> From<RelationBuilder<E, R>> for RelationDef impl<E, R> From<RelationBuilder<E, R>> for RelationDef
@ -177,6 +189,7 @@ where
is_owner: b.is_owner, is_owner: b.is_owner,
on_delete: b.on_delete, on_delete: b.on_delete,
on_update: b.on_update, on_update: b.on_update,
fk_name: b.fk_name,
} }
} }
} }

View File

@ -144,20 +144,18 @@ where
let mut foreign_key_stmt = ForeignKeyCreateStatement::new(); let mut foreign_key_stmt = ForeignKeyCreateStatement::new();
let from_tbl = unpack_table_ref(&relation.from_tbl); let from_tbl = unpack_table_ref(&relation.from_tbl);
let to_tbl = unpack_table_ref(&relation.to_tbl); let to_tbl = unpack_table_ref(&relation.to_tbl);
match relation.from_col { let from_cols: Vec<String> = match relation.from_col {
Identity::Unary(o1) => { Identity::Unary(o1) => vec![o1],
foreign_key_stmt.from_col(o1); Identity::Binary(o1, o2) => vec![o1, o2],
} Identity::Ternary(o1, o2, o3) => vec![o1, o2, o3],
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);
}
} }
.into_iter()
.map(|col| {
let col_name = col.to_string();
foreign_key_stmt.from_col(col);
col_name
})
.collect();
match relation.to_col { match relation.to_col {
Identity::Unary(o1) => { Identity::Unary(o1) => {
foreign_key_stmt.to_col(o1); foreign_key_stmt.to_col(o1);
@ -166,7 +164,7 @@ where
foreign_key_stmt.to_col(o1); foreign_key_stmt.to_col(o1);
foreign_key_stmt.to_col(o2); 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(o1);
foreign_key_stmt.to_col(o2); foreign_key_stmt.to_col(o2);
foreign_key_stmt.to_col(o3); foreign_key_stmt.to_col(o3);
@ -178,13 +176,14 @@ where
if let Some(action) = relation.on_update { if let Some(action) = relation.on_update {
foreign_key_stmt.on_update(action); 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( stmt.foreign_key(
foreign_key_stmt foreign_key_stmt
.name(&format!( .name(&name)
"fk-{}-{}",
from_tbl.to_string(),
to_tbl.to_string()
))
.from_tbl(from_tbl) .from_tbl(from_tbl)
.to_tbl(to_tbl), .to_tbl(to_tbl),
); );
@ -235,7 +234,7 @@ mod tests {
) )
.foreign_key( .foreign_key(
ForeignKeyCreateStatement::new() ForeignKeyCreateStatement::new()
.name("fk-cake_filling_price-cake_filling") .name("fk-cake_filling_price-cake_id-filling_id")
.from_tbl(CakeFillingPrice) .from_tbl(CakeFillingPrice)
.from_col(cake_filling_price::Column::CakeId) .from_col(cake_filling_price::Column::CakeId)
.from_col(cake_filling_price::Column::FillingId) .from_col(cake_filling_price::Column::FillingId)

View File

@ -55,7 +55,7 @@ pub async fn create_baker_table(db: &DbConn) -> Result<ExecResult, DbErr> {
.col(ColumnDef::new(baker::Column::BakeryId).integer()) .col(ColumnDef::new(baker::Column::BakeryId).integer())
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-baker-bakery") .name("fk-baker-bakery_id")
.from(baker::Entity, baker::Column::BakeryId) .from(baker::Entity, baker::Column::BakeryId)
.to(bakery::Entity, bakery::Column::Id) .to(bakery::Entity, bakery::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -111,7 +111,7 @@ pub async fn create_order_table(db: &DbConn) -> Result<ExecResult, DbErr> {
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-order-bakery") .name("fk-order-bakery_id")
.from(order::Entity, order::Column::BakeryId) .from(order::Entity, order::Column::BakeryId)
.to(bakery::Entity, bakery::Column::Id) .to(bakery::Entity, bakery::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -119,7 +119,7 @@ pub async fn create_order_table(db: &DbConn) -> Result<ExecResult, DbErr> {
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-order-customer") .name("fk-order-customer_id")
.from(order::Entity, order::Column::CustomerId) .from(order::Entity, order::Column::CustomerId)
.to(customer::Entity, customer::Column::Id) .to(customer::Entity, customer::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -162,7 +162,7 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result<ExecResult, DbErr> {
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-lineitem-order") .name("fk-lineitem-order_id")
.from(lineitem::Entity, lineitem::Column::OrderId) .from(lineitem::Entity, lineitem::Column::OrderId)
.to(order::Entity, order::Column::Id) .to(order::Entity, order::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -170,7 +170,7 @@ pub async fn create_lineitem_table(db: &DbConn) -> Result<ExecResult, DbErr> {
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-lineitem-cake") .name("fk-lineitem-cake_id")
.from(lineitem::Entity, lineitem::Column::CakeId) .from(lineitem::Entity, lineitem::Column::CakeId)
.to(cake::Entity, cake::Column::Id) .to(cake::Entity, cake::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -202,7 +202,7 @@ pub async fn create_cakes_bakers_table(db: &DbConn) -> Result<ExecResult, DbErr>
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-cakes_bakers-cake") .name("fk-cakes_bakers-cake_id")
.from(cakes_bakers::Entity, cakes_bakers::Column::CakeId) .from(cakes_bakers::Entity, cakes_bakers::Column::CakeId)
.to(cake::Entity, cake::Column::Id) .to(cake::Entity, cake::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -210,7 +210,7 @@ pub async fn create_cakes_bakers_table(db: &DbConn) -> Result<ExecResult, DbErr>
) )
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-cakes_bakers-baker") .name("fk-cakes_bakers-baker_id")
.from(cakes_bakers::Entity, cakes_bakers::Column::BakerId) .from(cakes_bakers::Entity, cakes_bakers::Column::BakerId)
.to(baker::Entity, baker::Column::Id) .to(baker::Entity, baker::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)
@ -240,7 +240,7 @@ pub async fn create_cake_table(db: &DbConn) -> Result<ExecResult, DbErr> {
.col(ColumnDef::new(cake::Column::BakeryId).integer()) .col(ColumnDef::new(cake::Column::BakeryId).integer())
.foreign_key( .foreign_key(
ForeignKey::create() ForeignKey::create()
.name("fk-cake-bakery") .name("fk-cake-bakery_id")
.from(cake::Entity, cake::Column::BakeryId) .from(cake::Entity, cake::Column::BakeryId)
.to(bakery::Entity, bakery::Column::Id) .to(bakery::Entity, bakery::Column::Id)
.on_delete(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade)

View File

@ -16,6 +16,7 @@ pub struct Model {
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation { pub enum Relation {
#[sea_orm( #[sea_orm(
fk_name = "fk-active_enum_child-active_enum",
belongs_to = "super::active_enum::Entity", belongs_to = "super::active_enum::Entity",
from = "Column::ParentId", from = "Column::ParentId",
to = "super::active_enum::Column::Id" to = "super::active_enum::Column::Id"

View File

@ -116,7 +116,7 @@ pub async fn create_self_join_table(db: &DbConn) -> Result<ExecResult, DbErr> {
.col(ColumnDef::new(self_join::Column::Time).time()) .col(ColumnDef::new(self_join::Column::Time).time())
.foreign_key( .foreign_key(
ForeignKeyCreateStatement::new() ForeignKeyCreateStatement::new()
.name("fk-self_join-self_join") .name("fk-self_join-uuid_ref")
.from_tbl(SelfJoin) .from_tbl(SelfJoin)
.from_col(self_join::Column::UuidRef) .from_col(self_join::Column::UuidRef)
.to_tbl(SelfJoin) .to_tbl(SelfJoin)