Skip to content

Commit

Permalink
fix: migrate column default value (#5359)
Browse files Browse the repository at this point in the history
Co-authored-by: Jinzhu <wosmvp@gmail.com>
  • Loading branch information
a631807682 and jinzhu committed May 28, 2022
1 parent dc1ae39 commit 93986de
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 3 deletions.
16 changes: 13 additions & 3 deletions migrator/migrator.go
Expand Up @@ -448,10 +448,20 @@ func (m Migrator) MigrateColumn(value interface{}, field *schema.Field, columnTy
}

// check default value
if v, ok := columnType.DefaultValue(); ok && v != field.DefaultValue {
// not primary key
if !field.PrimaryKey {
if !field.PrimaryKey {
dv, dvNotNull := columnType.DefaultValue()
if dvNotNull && field.DefaultValueInterface == nil {
// defalut value -> null
alterColumn = true
} else if !dvNotNull && field.DefaultValueInterface != nil {
// null -> default value
alterColumn = true
} else if dv != field.DefaultValue {
// default value not equal
// not both null
if !(field.DefaultValueInterface == nil && !dvNotNull) {
alterColumn = true
}
}
}

Expand Down
136 changes: 136 additions & 0 deletions tests/migrate_test.go
@@ -1,6 +1,7 @@
package tests_test

import (
"fmt"
"math/rand"
"reflect"
"strings"
Expand Down Expand Up @@ -714,6 +715,141 @@ func TestPrimarykeyID(t *testing.T) {
}
}

func TestUniqueColumn(t *testing.T) {
if DB.Dialector.Name() != "mysql" {
return
}

type UniqueTest struct {
ID string `gorm:"primary_key"`
Name string `gorm:"unique"`
}

type UniqueTest2 struct {
ID string `gorm:"primary_key"`
Name string `gorm:"unique;default:NULL"`
}

type UniqueTest3 struct {
ID string `gorm:"primary_key"`
Name string `gorm:"unique;default:''"`
}

type UniqueTest4 struct {
ID string `gorm:"primary_key"`
Name string `gorm:"unique;default:'123'"`
}

var err error
err = DB.Migrator().DropTable(&UniqueTest{})
if err != nil {
t.Errorf("DropTable err:%v", err)
}

err = DB.AutoMigrate(&UniqueTest{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

// null -> null
err = DB.AutoMigrate(&UniqueTest{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

ct, err := findColumnType(&UniqueTest{}, "name")
if err != nil {
t.Fatalf("findColumnType err:%v", err)
}

value, ok := ct.DefaultValue()
AssertEqual(t, "", value)
AssertEqual(t, false, ok)

// null -> null
err = DB.Table("unique_tests").AutoMigrate(&UniqueTest2{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

// not trigger alert column
AssertEqual(t, true, DB.Migrator().HasIndex(&UniqueTest{}, "name"))
AssertEqual(t, false, DB.Migrator().HasIndex(&UniqueTest{}, "name_1"))
AssertEqual(t, false, DB.Migrator().HasIndex(&UniqueTest{}, "name_2"))

ct, err = findColumnType(&UniqueTest{}, "name")
if err != nil {
t.Fatalf("findColumnType err:%v", err)
}

value, ok = ct.DefaultValue()
AssertEqual(t, "", value)
AssertEqual(t, false, ok)

// null -> empty string
err = DB.Table("unique_tests").AutoMigrate(&UniqueTest3{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

ct, err = findColumnType(&UniqueTest{}, "name")
if err != nil {
t.Fatalf("findColumnType err:%v", err)
}

value, ok = ct.DefaultValue()
AssertEqual(t, "", value)
AssertEqual(t, true, ok)

// empty string -> 123
err = DB.Table("unique_tests").AutoMigrate(&UniqueTest4{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

ct, err = findColumnType(&UniqueTest{}, "name")
if err != nil {
t.Fatalf("findColumnType err:%v", err)
}

value, ok = ct.DefaultValue()
AssertEqual(t, "123", value)
AssertEqual(t, true, ok)

// 123 -> null
err = DB.Table("unique_tests").AutoMigrate(&UniqueTest2{})
if err != nil {
t.Fatalf("AutoMigrate err:%v", err)
}

ct, err = findColumnType(&UniqueTest{}, "name")
if err != nil {
t.Fatalf("findColumnType err:%v", err)
}

value, ok = ct.DefaultValue()
AssertEqual(t, "", value)
AssertEqual(t, false, ok)

}

func findColumnType(dest interface{}, columnName string) (
foundColumn gorm.ColumnType, err error) {
columnTypes, err := DB.Migrator().ColumnTypes(dest)
if err != nil {
err = fmt.Errorf("ColumnTypes err:%v", err)
return
}

for _, c := range columnTypes {
if c.Name() == columnName {
foundColumn = c
break
}
}
return
}

func TestInvalidCachedPlan(t *testing.T) {
if DB.Dialector.Name() != "postgres" {
return
Expand Down

0 comments on commit 93986de

Please sign in to comment.