@@ -869,4 +869,222 @@ mod tests {
869869 Some ( vespertide_core:: StrOrBoolOrArray :: Bool ( true ) )
870870 ) ;
871871 }
872+
873+ #[ test]
874+ fn remove_unique_constraint_clears_inline_unique_array ( ) {
875+ // Column with inline unique: ["uq_email", "uq_users_email"]
876+ let mut col_with_unique = col ( "email" , ColumnType :: Simple ( SimpleColumnType :: Text ) ) ;
877+ col_with_unique. unique = Some ( vespertide_core:: StrOrBoolOrArray :: Array ( vec ! [
878+ "uq_email" . to_string( ) ,
879+ "uq_users_email" . to_string( ) ,
880+ ] ) ) ;
881+
882+ let mut schema = vec ! [ table(
883+ "users" ,
884+ vec![ col_with_unique] ,
885+ vec![ TableConstraint :: Unique {
886+ name: Some ( "uq_email" . into( ) ) ,
887+ columns: vec![ "email" . into( ) ] ,
888+ } ] ,
889+ ) ] ;
890+
891+ apply_action (
892+ & mut schema,
893+ & MigrationAction :: RemoveConstraint {
894+ table : "users" . into ( ) ,
895+ constraint : TableConstraint :: Unique {
896+ name : Some ( "uq_email" . into ( ) ) ,
897+ columns : vec ! [ "email" . into( ) ] ,
898+ } ,
899+ } ,
900+ )
901+ . unwrap ( ) ;
902+
903+ // Constraint removed
904+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
905+ // "uq_email" removed from array, "uq_users_email" remains
906+ assert_eq ! (
907+ schema[ 0 ] . columns[ 0 ] . unique,
908+ Some ( vespertide_core:: StrOrBoolOrArray :: Array ( vec![
909+ "uq_users_email" . to_string( )
910+ ] ) )
911+ ) ;
912+ }
913+
914+ #[ test]
915+ fn remove_unique_constraint_clears_inline_unique_array_last_item ( ) {
916+ // Column with inline unique: ["uq_email"] (only one item in array)
917+ let mut col_with_unique = col ( "email" , ColumnType :: Simple ( SimpleColumnType :: Text ) ) ;
918+ col_with_unique. unique = Some ( vespertide_core:: StrOrBoolOrArray :: Array ( vec ! [
919+ "uq_email" . to_string( ) ,
920+ ] ) ) ;
921+
922+ let mut schema = vec ! [ table(
923+ "users" ,
924+ vec![ col_with_unique] ,
925+ vec![ TableConstraint :: Unique {
926+ name: Some ( "uq_email" . into( ) ) ,
927+ columns: vec![ "email" . into( ) ] ,
928+ } ] ,
929+ ) ] ;
930+
931+ apply_action (
932+ & mut schema,
933+ & MigrationAction :: RemoveConstraint {
934+ table : "users" . into ( ) ,
935+ constraint : TableConstraint :: Unique {
936+ name : Some ( "uq_email" . into ( ) ) ,
937+ columns : vec ! [ "email" . into( ) ] ,
938+ } ,
939+ } ,
940+ )
941+ . unwrap ( ) ;
942+
943+ // Constraint removed
944+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
945+ // Array becomes empty, so unique should be None
946+ assert ! ( schema[ 0 ] . columns[ 0 ] . unique. is_none( ) ) ;
947+ }
948+
949+ #[ test]
950+ fn remove_unique_constraint_clears_inline_unique_str ( ) {
951+ // Column with inline unique: "uq_email"
952+ let mut col_with_unique = col ( "email" , ColumnType :: Simple ( SimpleColumnType :: Text ) ) ;
953+ col_with_unique. unique = Some ( vespertide_core:: StrOrBoolOrArray :: Str (
954+ "uq_email" . to_string ( ) ,
955+ ) ) ;
956+
957+ let mut schema = vec ! [ table(
958+ "users" ,
959+ vec![ col_with_unique] ,
960+ vec![ TableConstraint :: Unique {
961+ name: Some ( "uq_email" . into( ) ) ,
962+ columns: vec![ "email" . into( ) ] ,
963+ } ] ,
964+ ) ] ;
965+
966+ apply_action (
967+ & mut schema,
968+ & MigrationAction :: RemoveConstraint {
969+ table : "users" . into ( ) ,
970+ constraint : TableConstraint :: Unique {
971+ name : Some ( "uq_email" . into ( ) ) ,
972+ columns : vec ! [ "email" . into( ) ] ,
973+ } ,
974+ } ,
975+ )
976+ . unwrap ( ) ;
977+
978+ // Constraint removed
979+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
980+ // Inline unique cleared
981+ assert ! ( schema[ 0 ] . columns[ 0 ] . unique. is_none( ) ) ;
982+ }
983+
984+ #[ test]
985+ fn remove_foreign_key_constraint_clears_inline_fk ( ) {
986+ use vespertide_core:: schema:: foreign_key:: { ForeignKeyDef , ForeignKeySyntax } ;
987+ // Column with inline foreign_key
988+ let mut col_with_fk = col ( "user_id" , ColumnType :: Simple ( SimpleColumnType :: Integer ) ) ;
989+ col_with_fk. foreign_key = Some ( ForeignKeySyntax :: Object ( ForeignKeyDef {
990+ ref_table : "users" . into ( ) ,
991+ ref_columns : vec ! [ "id" . into( ) ] ,
992+ on_delete : None ,
993+ on_update : None ,
994+ } ) ) ;
995+
996+ let mut schema = vec ! [ table(
997+ "posts" ,
998+ vec![ col_with_fk] ,
999+ vec![ TableConstraint :: ForeignKey {
1000+ name: Some ( "fk_posts_user" . into( ) ) ,
1001+ columns: vec![ "user_id" . into( ) ] ,
1002+ ref_table: "users" . into( ) ,
1003+ ref_columns: vec![ "id" . into( ) ] ,
1004+ on_delete: None ,
1005+ on_update: None ,
1006+ } ] ,
1007+ ) ] ;
1008+
1009+ apply_action (
1010+ & mut schema,
1011+ & MigrationAction :: RemoveConstraint {
1012+ table : "posts" . into ( ) ,
1013+ constraint : TableConstraint :: ForeignKey {
1014+ name : Some ( "fk_posts_user" . into ( ) ) ,
1015+ columns : vec ! [ "user_id" . into( ) ] ,
1016+ ref_table : "users" . into ( ) ,
1017+ ref_columns : vec ! [ "id" . into( ) ] ,
1018+ on_delete : None ,
1019+ on_update : None ,
1020+ } ,
1021+ } ,
1022+ )
1023+ . unwrap ( ) ;
1024+
1025+ // Constraint removed
1026+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
1027+ // Inline foreign_key cleared
1028+ assert ! ( schema[ 0 ] . columns[ 0 ] . foreign_key. is_none( ) ) ;
1029+ }
1030+
1031+ #[ test]
1032+ fn remove_check_constraint ( ) {
1033+ let mut schema = vec ! [ table(
1034+ "users" ,
1035+ vec![ col( "age" , ColumnType :: Simple ( SimpleColumnType :: Integer ) ) ] ,
1036+ vec![ TableConstraint :: Check {
1037+ name: "check_age" . into( ) ,
1038+ expr: "age >= 18" . into( ) ,
1039+ } ] ,
1040+ ) ] ;
1041+
1042+ apply_action (
1043+ & mut schema,
1044+ & MigrationAction :: RemoveConstraint {
1045+ table : "users" . into ( ) ,
1046+ constraint : TableConstraint :: Check {
1047+ name : "check_age" . into ( ) ,
1048+ expr : "age >= 18" . into ( ) ,
1049+ } ,
1050+ } ,
1051+ )
1052+ . unwrap ( ) ;
1053+
1054+ // Constraint removed
1055+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
1056+ }
1057+
1058+ #[ test]
1059+ fn remove_unnamed_index_single_column ( ) {
1060+ // Column with inline index: true
1061+ let mut col_with_index = col ( "email" , ColumnType :: Simple ( SimpleColumnType :: Text ) ) ;
1062+ col_with_index. index = Some ( vespertide_core:: StrOrBoolOrArray :: Bool ( true ) ) ;
1063+
1064+ let mut schema = vec ! [ table(
1065+ "users" ,
1066+ vec![ col_with_index] ,
1067+ vec![ TableConstraint :: Index {
1068+ name: None ,
1069+ columns: vec![ "email" . into( ) ] ,
1070+ } ] ,
1071+ ) ] ;
1072+
1073+ apply_action (
1074+ & mut schema,
1075+ & MigrationAction :: RemoveConstraint {
1076+ table : "users" . into ( ) ,
1077+ constraint : TableConstraint :: Index {
1078+ name : None ,
1079+ columns : vec ! [ "email" . into( ) ] ,
1080+ } ,
1081+ } ,
1082+ )
1083+ . unwrap ( ) ;
1084+
1085+ // Constraint removed
1086+ assert ! ( schema[ 0 ] . constraints. is_empty( ) ) ;
1087+ // Inline index cleared
1088+ assert ! ( schema[ 0 ] . columns[ 0 ] . index. is_none( ) ) ;
1089+ }
8721090}
0 commit comments