@@ -44,6 +44,25 @@ pub enum MigrationAction {
4444 column : ColumnName ,
4545 new_type : ColumnType ,
4646 } ,
47+ ModifyColumnNullable {
48+ table : TableName ,
49+ column : ColumnName ,
50+ nullable : bool ,
51+ /// Required when changing from nullable to non-nullable to backfill existing NULL values.
52+ fill_with : Option < String > ,
53+ } ,
54+ ModifyColumnDefault {
55+ table : TableName ,
56+ column : ColumnName ,
57+ /// The new default value, or None to remove the default.
58+ new_default : Option < String > ,
59+ } ,
60+ ModifyColumnComment {
61+ table : TableName ,
62+ column : ColumnName ,
63+ /// The new comment, or None to remove the comment.
64+ new_comment : Option < String > ,
65+ } ,
4766 AddConstraint {
4867 table : TableName ,
4968 constraint : TableConstraint ,
@@ -82,6 +101,42 @@ impl fmt::Display for MigrationAction {
82101 MigrationAction :: ModifyColumnType { table, column, .. } => {
83102 write ! ( f, "ModifyColumnType: {}.{}" , table, column)
84103 }
104+ MigrationAction :: ModifyColumnNullable {
105+ table,
106+ column,
107+ nullable,
108+ ..
109+ } => {
110+ let nullability = if * nullable { "NULL" } else { "NOT NULL" } ;
111+ write ! ( f, "ModifyColumnNullable: {}.{} -> {}" , table, column, nullability)
112+ }
113+ MigrationAction :: ModifyColumnDefault {
114+ table,
115+ column,
116+ new_default,
117+ } => {
118+ if let Some ( default) = new_default {
119+ write ! ( f, "ModifyColumnDefault: {}.{} -> {}" , table, column, default )
120+ } else {
121+ write ! ( f, "ModifyColumnDefault: {}.{} -> (none)" , table, column)
122+ }
123+ }
124+ MigrationAction :: ModifyColumnComment {
125+ table,
126+ column,
127+ new_comment,
128+ } => {
129+ if let Some ( comment) = new_comment {
130+ let display = if comment. len ( ) > 30 {
131+ format ! ( "{}..." , & comment[ ..27 ] )
132+ } else {
133+ comment. clone ( )
134+ } ;
135+ write ! ( f, "ModifyColumnComment: {}.{} -> '{}'" , table, column, display)
136+ } else {
137+ write ! ( f, "ModifyColumnComment: {}.{} -> (none)" , table, column)
138+ }
139+ }
85140 MigrationAction :: AddConstraint { table, constraint } => {
86141 let constraint_name = match constraint {
87142 TableConstraint :: PrimaryKey { .. } => "PRIMARY KEY" ,
@@ -438,4 +493,95 @@ mod tests {
438493 assert ! ( result. ends_with( "..." ) ) ;
439494 assert ! ( result. len( ) > 10 ) ;
440495 }
496+
497+ #[ rstest]
498+ #[ case:: modify_column_nullable_to_not_null(
499+ MigrationAction :: ModifyColumnNullable {
500+ table: "users" . into( ) ,
501+ column: "email" . into( ) ,
502+ nullable: false ,
503+ fill_with: None ,
504+ } ,
505+ "ModifyColumnNullable: users.email -> NOT NULL"
506+ ) ]
507+ #[ case:: modify_column_nullable_to_null(
508+ MigrationAction :: ModifyColumnNullable {
509+ table: "users" . into( ) ,
510+ column: "email" . into( ) ,
511+ nullable: true ,
512+ fill_with: None ,
513+ } ,
514+ "ModifyColumnNullable: users.email -> NULL"
515+ ) ]
516+ fn test_display_modify_column_nullable (
517+ #[ case] action : MigrationAction ,
518+ #[ case] expected : & str ,
519+ ) {
520+ assert_eq ! ( action. to_string( ) , expected) ;
521+ }
522+
523+ #[ rstest]
524+ #[ case:: modify_column_default_set(
525+ MigrationAction :: ModifyColumnDefault {
526+ table: "users" . into( ) ,
527+ column: "status" . into( ) ,
528+ new_default: Some ( "'active'" . into( ) ) ,
529+ } ,
530+ "ModifyColumnDefault: users.status -> 'active'"
531+ ) ]
532+ #[ case:: modify_column_default_drop(
533+ MigrationAction :: ModifyColumnDefault {
534+ table: "users" . into( ) ,
535+ column: "status" . into( ) ,
536+ new_default: None ,
537+ } ,
538+ "ModifyColumnDefault: users.status -> (none)"
539+ ) ]
540+ fn test_display_modify_column_default (
541+ #[ case] action : MigrationAction ,
542+ #[ case] expected : & str ,
543+ ) {
544+ assert_eq ! ( action. to_string( ) , expected) ;
545+ }
546+
547+ #[ rstest]
548+ #[ case:: modify_column_comment_set(
549+ MigrationAction :: ModifyColumnComment {
550+ table: "users" . into( ) ,
551+ column: "email" . into( ) ,
552+ new_comment: Some ( "User email address" . into( ) ) ,
553+ } ,
554+ "ModifyColumnComment: users.email -> 'User email address'"
555+ ) ]
556+ #[ case:: modify_column_comment_drop(
557+ MigrationAction :: ModifyColumnComment {
558+ table: "users" . into( ) ,
559+ column: "email" . into( ) ,
560+ new_comment: None ,
561+ } ,
562+ "ModifyColumnComment: users.email -> (none)"
563+ ) ]
564+ fn test_display_modify_column_comment (
565+ #[ case] action : MigrationAction ,
566+ #[ case] expected : & str ,
567+ ) {
568+ assert_eq ! ( action. to_string( ) , expected) ;
569+ }
570+
571+ #[ test]
572+ fn test_display_modify_column_comment_long ( ) {
573+ // Test truncation for long comments (> 30 chars)
574+ let action = MigrationAction :: ModifyColumnComment {
575+ table : "users" . into ( ) ,
576+ column : "email" . into ( ) ,
577+ new_comment : Some (
578+ "This is a very long comment that should be truncated in display" . into ( ) ,
579+ ) ,
580+ } ;
581+ let result = action. to_string ( ) ;
582+ assert ! ( result. contains( "..." ) ) ;
583+ assert ! ( result. contains( "This is a very long comment" ) ) ;
584+ // Should be truncated at 27 chars + "..."
585+ assert ! ( !result. contains( "truncated in display" ) ) ;
586+ }
441587}
0 commit comments