fix: auto migration column order unpredictable (#4980)

This commit is contained in:
halfcrazy 2022-01-06 18:55:20 +08:00 committed by GitHub
parent b47cf57f5e
commit f757b8fdc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 76 additions and 3 deletions

View File

@ -97,11 +97,12 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) { if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) {
columnTypes, _ := m.DB.Migrator().ColumnTypes(value) columnTypes, _ := m.DB.Migrator().ColumnTypes(value)
for _, field := range stmt.Schema.FieldsByDBName { for _, dbName := range stmt.Schema.DBNames {
field := stmt.Schema.FieldsByDBName[dbName]
var foundColumn gorm.ColumnType var foundColumn gorm.ColumnType
for _, columnType := range columnTypes { for _, columnType := range columnTypes {
if columnType.Name() == field.DBName { if columnType.Name() == dbName {
foundColumn = columnType foundColumn = columnType
break break
} }
@ -109,7 +110,7 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
if foundColumn == nil { if foundColumn == nil {
// not found, add column // not found, add column
if err := tx.Migrator().AddColumn(value, field.DBName); err != nil { if err := tx.Migrator().AddColumn(value, dbName); err != nil {
return err return err
} }
} else if err := m.DB.Migrator().MigrateColumn(value, field, foundColumn); err != nil { } else if err := m.DB.Migrator().MigrateColumn(value, field, foundColumn); err != nil {

View File

@ -2,11 +2,13 @@ package tests_test
import ( import (
"math/rand" "math/rand"
"reflect"
"strings" "strings"
"testing" "testing"
"time" "time"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/schema"
. "gorm.io/gorm/utils/tests" . "gorm.io/gorm/utils/tests"
) )
@ -454,3 +456,73 @@ func TestMigrateIndexesWithDynamicTableName(t *testing.T) {
} }
} }
} }
// check column order after migration, flaky test
// https://github.com/go-gorm/gorm/issues/4351
func TestMigrateColumnOrder(t *testing.T) {
type UserMigrateColumn struct {
ID uint
}
DB.Migrator().DropTable(&UserMigrateColumn{})
DB.AutoMigrate(&UserMigrateColumn{})
type UserMigrateColumn2 struct {
ID uint
F1 string
F2 string
F3 string
F4 string
F5 string
F6 string
F7 string
F8 string
F9 string
F10 string
F11 string
F12 string
F13 string
F14 string
F15 string
F16 string
F17 string
F18 string
F19 string
F20 string
F21 string
F22 string
F23 string
F24 string
F25 string
F26 string
F27 string
F28 string
F29 string
F30 string
F31 string
F32 string
F33 string
F34 string
F35 string
}
if err := DB.Table("user_migrate_columns").AutoMigrate(&UserMigrateColumn2{}); err != nil {
t.Fatalf("failed to auto migrate, got error: %v", err)
}
columnTypes, err := DB.Table("user_migrate_columns").Migrator().ColumnTypes(&UserMigrateColumn2{})
if err != nil {
t.Fatalf("failed to get column types, got error: %v", err)
}
typ := reflect.Indirect(reflect.ValueOf(&UserMigrateColumn2{})).Type()
numField := typ.NumField()
if numField != len(columnTypes) {
t.Fatalf("column's number not match struct and ddl, %d != %d", numField, len(columnTypes))
}
namer := schema.NamingStrategy{}
for i := 0; i < numField; i++ {
expectName := namer.ColumnName("", typ.Field(i).Name)
if columnTypes[i].Name() != expectName {
t.Fatalf("column order not match struct and ddl, idx %d: %s != %s",
i, columnTypes[i].Name(), expectName)
}
}
}