From 1124d83ab83f584f368c14c3e9511e9f365b2333 Mon Sep 17 00:00:00 2001 From: Nomango Date: Tue, 27 Dec 2022 14:20:53 +0800 Subject: [PATCH] fix(migrator): ignore relationships when migrating #5913 --- gorm.go | 2 ++ migrator/migrator.go | 18 ++++++++---- tests/migrate_test.go | 64 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/gorm.go b/gorm.go index 65c9e2280e..37595ddd78 100644 --- a/gorm.go +++ b/gorm.go @@ -37,6 +37,8 @@ type Config struct { DisableAutomaticPing bool // DisableForeignKeyConstraintWhenMigrating DisableForeignKeyConstraintWhenMigrating bool + // IgnoreRelationshipsWhenMigrating + IgnoreRelationshipsWhenMigrating bool // DisableNestedTransaction disable nested transaction DisableNestedTransaction bool // AllowGlobalUpdate allow global update diff --git a/migrator/migrator.go b/migrator/migrator.go index eafe7bb298..af89e9d683 100644 --- a/migrator/migrator.go +++ b/migrator/migrator.go @@ -103,7 +103,7 @@ func (m Migrator) FullDataTypeOf(field *schema.Field) (expr clause.Expr) { // AutoMigrate auto migrate values func (m Migrator) AutoMigrate(values ...interface{}) error { - for _, value := range m.ReorderModels(values, true) { + for _, value := range m.ReorderModels(values, !m.DB.IgnoreRelationshipsWhenMigrating, true) { queryTx := m.DB.Session(&gorm.Session{}) execTx := queryTx if m.DB.DryRun { @@ -789,13 +789,14 @@ func (m Migrator) CurrentDatabase() (name string) { } // ReorderModels reorder models according to constraint dependencies -func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []interface{}) { +func (m Migrator) ReorderModels(values []interface{}, autoAdd bool, isMigrations ...bool) (results []interface{}) { type Dependency struct { *gorm.Statement Depends []*schema.Schema } var ( + isMigration bool modelNames, orderedModelNames []string orderedModelNamesMap = map[string]bool{} parsedSchemas = map[*schema.Schema]bool{} @@ -804,6 +805,10 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i parseDependence func(value interface{}, addToList bool) ) + if len(isMigrations) > 0 { + isMigration = isMigrations[0] + } + parseDependence = func(value interface{}, addToList bool) { dep := Dependency{ Statement: &gorm.Statement{DB: m.DB, Dest: value}, @@ -819,15 +824,18 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i parsedSchemas[dep.Statement.Schema] = true for _, rel := range dep.Schema.Relationships.Relations { - if c := rel.ParseConstraint(); c != nil && c.Schema == dep.Statement.Schema && c.Schema != c.ReferenceSchema { - dep.Depends = append(dep.Depends, c.ReferenceSchema) + ignoreRel := isMigration && rel.Field.IgnoreMigration + if !ignoreRel { + if c := rel.ParseConstraint(); c != nil && c.Schema == dep.Statement.Schema && c.Schema != c.ReferenceSchema { + dep.Depends = append(dep.Depends, c.ReferenceSchema) + } } if rel.Type == schema.HasOne || rel.Type == schema.HasMany { beDependedOn[rel.FieldSchema] = true } - if rel.JoinTable != nil { + if !ignoreRel && rel.JoinTable != nil { // append join value defer func(rel *schema.Relationship, joinValue interface{}) { if !beDependedOn[rel.FieldSchema] { diff --git a/tests/migrate_test.go b/tests/migrate_test.go index 9df626fd27..60dc1626f1 100644 --- a/tests/migrate_test.go +++ b/tests/migrate_test.go @@ -1203,3 +1203,67 @@ func TestMigrateSameEmbeddedFieldName(t *testing.T) { _, err = findColumnType(&GameUser{}, "rate_ground_rb_ground_destory_count") AssertEqual(t, nil, err) } + +func TestMigrateIgnoreRelations(t *testing.T) { + type RelationModel1 struct { + ID uint + } + type RelationModel2 struct { + ID uint + } + type RelationModel3 struct { + ID uint + RelationModel1ID uint + RelationModel1 *RelationModel1 + RelationModel2ID uint + RelationModel2 *RelationModel2 `gorm:"-:migration"` + } + + var err error + DB.Migrator().DropTable(&RelationModel1{}, &RelationModel2{}, &RelationModel3{}) + + tx := DB.Session(&gorm.Session{}) + tx.IgnoreRelationshipsWhenMigrating = true + + err = tx.AutoMigrate(&RelationModel3{}) + if err != nil { + t.Errorf("AutoMigrate err:%v", err) + } + + // RelationModel3 should be existed + _, err = findColumnType(&RelationModel3{}, "id") + AssertEqual(t, nil, err) + + // RelationModel1 should not be existed + _, err = findColumnType(&RelationModel1{}, "id") + if err == nil { + t.Errorf("RelationModel1 should not be migrated") + } + + // RelationModel2 should not be existed + _, err = findColumnType(&RelationModel2{}, "id") + if err == nil { + t.Errorf("RelationModel2 should not be migrated") + } + + tx.IgnoreRelationshipsWhenMigrating = false + + err = tx.AutoMigrate(&RelationModel3{}) + if err != nil { + t.Errorf("AutoMigrate err:%v", err) + } + + // RelationModel3 should be existed + _, err = findColumnType(&RelationModel3{}, "id") + AssertEqual(t, nil, err) + + // RelationModel1 should be existed + _, err = findColumnType(&RelationModel1{}, "id") + AssertEqual(t, nil, err) + + // RelationModel2 should not be existed + _, err = findColumnType(&RelationModel2{}, "id") + if err == nil { + t.Errorf("RelationModel2 should not be migrated") + } +}