Skip to content

Commit

Permalink
fix(migrator): ignore relationships when migrating #5913
Browse files Browse the repository at this point in the history
  • Loading branch information
Nomango committed Dec 27, 2022
1 parent 7da24d1 commit 1124d83
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 5 deletions.
2 changes: 2 additions & 0 deletions gorm.go
Expand Up @@ -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
Expand Down
18 changes: 13 additions & 5 deletions migrator/migrator.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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{}
Expand All @@ -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},
Expand All @@ -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] {
Expand Down
64 changes: 64 additions & 0 deletions tests/migrate_test.go
Expand Up @@ -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")
}
}

0 comments on commit 1124d83

Please sign in to comment.