Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: migrate column default value #5359

Merged
merged 2 commits into from May 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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