From e2e57d36fb9728db20fa64ed1f97058cccddb401 Mon Sep 17 00:00:00 2001 From: Melody Ruch <396921921@qq.com> Date: Sun, 20 Sep 2026 19:11:10 +0800 Subject: [PATCH] fix(sqlserver): merge composite foreign keys in exported ddl --- crates/dbx-core/src/schema/mod.rs | 50 +++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/crates/dbx-core/src/schema/mod.rs b/crates/dbx-core/src/schema/mod.rs index 87060045c5..407ce04a1a 100644 --- a/crates/dbx-core/src/schema/mod.rs +++ b/crates/dbx-core/src/schema/mod.rs @@ -11819,6 +11819,41 @@ mod ddl_tests { assert!(ddl.contains("[FIDS] int IDENTITY(1,1) NOT NULL"), "ddl: {ddl}"); } + #[test] + fn sqlserver_table_ddl_groups_composite_foreign_key_columns() { + let fk = |name: &str, column: &str, ref_table: &str, ref_column: &str| db::ForeignKeyInfo { + name: name.to_string(), + column: column.to_string(), + ref_schema: Some("dbo".to_string()), + ref_table: ref_table.to_string(), + ref_column: ref_column.to_string(), + on_update: None, + on_delete: None, + }; + let fkeys = [ + fk("FK_TRIGGERS_JOB", "sched_name", "JOB_DETAILS", "sched_name"), + fk("FK_TRIGGERS_JOB", "job_name", "JOB_DETAILS", "job_name"), + fk("FK_TRIGGERS_JOB", "job_group", "JOB_DETAILS", "job_group"), + fk("FK_TRIGGERS_CAL", "calendar_name", "CALENDARS", "calendar_name"), + ]; + + let ddl = render_sqlserver_table_ddl("dbo", "TRIGGERS", &[column("sched_name", "nvarchar")], &[], &fkeys, None); + + assert!( + ddl.contains( + "CONSTRAINT [FK_TRIGGERS_JOB] FOREIGN KEY ([sched_name], [job_name], [job_group]) REFERENCES [JOB_DETAILS]([sched_name], [job_name], [job_group])" + ), + "ddl: {ddl}" + ); + assert_eq!(ddl.matches("CONSTRAINT [FK_TRIGGERS_JOB]").count(), 1, "ddl: {ddl}"); + assert!( + ddl.contains( + "CONSTRAINT [FK_TRIGGERS_CAL] FOREIGN KEY ([calendar_name]) REFERENCES [CALENDARS]([calendar_name])" + ), + "ddl: {ddl}" + ); + } + #[test] fn opengauss_table_ddl_uses_native_tabledef_function() { assert_eq!( @@ -13498,13 +13533,18 @@ pub fn render_sqlserver_table_ddl( pks.iter().map(|k| sqlserver_ident(k)).collect::>().join(", ") )); } - for fk in fkeys { + for fk_group in group_foreign_keys_by_name(fkeys) { + let Some(first_fk) = fk_group.first() else { + continue; + }; + let columns = fk_group.iter().map(|fk| sqlserver_ident(&fk.column)).collect::>().join(", "); + let ref_columns = fk_group.iter().map(|fk| sqlserver_ident(&fk.ref_column)).collect::>().join(", "); ddl.push_str(&format!( ",\n CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {}({})", - sqlserver_ident(&fk.name), - sqlserver_ident(&fk.column), - sqlserver_ident(&fk.ref_table), - sqlserver_ident(&fk.ref_column) + sqlserver_ident(&first_fk.name), + columns, + sqlserver_ident(&first_fk.ref_table), + ref_columns )); } ddl.push_str("\n);\n");