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 from: 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) };
}
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)

View File

@ -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<ForeignKeyAction>,
/// The name of foreign key constraint
pub fk_name: Option<String>,
}
/// Defines a helper to build a relation
@ -80,6 +82,7 @@ where
is_owner: bool,
on_delete: Option<ForeignKeyAction>,
on_update: Option<ForeignKeyAction>,
fk_name: Option<String>,
}
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<E, R> From<RelationBuilder<E, R>> 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,
}
}
}

View File

@ -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<String> = 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)

View File

@ -55,7 +55,7 @@ pub async fn create_baker_table(db: &DbConn) -> Result<ExecResult, DbErr> {
.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<ExecResult, DbErr> {
)
.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<ExecResult, DbErr> {
)
.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<ExecResult, DbErr> {
)
.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<ExecResult, DbErr> {
)
.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<ExecResult, DbErr>
)
.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<ExecResult, DbErr>
)
.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<ExecResult, DbErr> {
.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)

View File

@ -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"

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())
.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)