From c04db4aefa48d3a3bf0541b01ff0589b3d860d93 Mon Sep 17 00:00:00 2001 From: Yan Zhu Date: Wed, 5 Jan 2022 17:04:02 +0800 Subject: [PATCH] fix: auto migration column order unpredictable --- migrator/migrator.go | 7 +++-- tests/migrate_test.go | 72 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/migrator/migrator.go b/migrator/migrator.go index 18212dbb3f..9e15b0291b 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -97,11 +97,12 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) { 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 for _, columnType := range columnTypes { - if columnType.Name() == field.DBName { + if columnType.Name() == dbName { foundColumn = columnType break } @@ -109,7 +110,7 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { if foundColumn == nil { // 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 } } else if err := m.DB.Migrator().MigrateColumn(value, field, foundColumn); err != nil { diff --git a/tests/migrate_test.go b/tests/migrate_test.go index 3d15bf2c7b..5b37cae764 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -1,7 +1,9 @@ package tests_test import ( + "gorm.io/gorm/schema" "math/rand" + "reflect" "strings" "testing" "time" @@ -455,3 +457,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) + } + } +}