Create join table with ReorderModels

This commit is contained in:
Jinzhu 2020-06-24 16:43:53 +08:00
parent 834cfa2c78
commit 4a01d4c263
2 changed files with 33 additions and 31 deletions

View File

@ -116,20 +116,6 @@ func (m Migrator) AutoMigrate(values ...interface{}) error {
} }
} }
} }
// create join table
if rel.JoinTable != nil {
joinValue := reflect.New(rel.JoinTable.ModelType).Interface()
if !tx.Migrator().HasTable(rel.JoinTable.Table) {
defer func(table string, joinValue interface{}) {
errr = tx.Table(table).Migrator().CreateTable(joinValue)
}(rel.JoinTable.Table, joinValue)
} else {
defer func(table string, joinValue interface{}) {
errr = tx.Table(table).Migrator().AutoMigrate(joinValue)
}(rel.JoinTable.Table, joinValue)
}
}
} }
return nil return nil
}); err != nil { }); err != nil {
@ -193,16 +179,6 @@ func (m Migrator) CreateTable(values ...interface{}) error {
} }
} }
} }
// create join table
if rel.JoinTable != nil {
joinValue := reflect.New(rel.JoinTable.ModelType).Interface()
if !tx.Migrator().HasTable(rel.JoinTable.Table) {
defer func(table string, joinValue interface{}) {
errr = tx.Table(table).Migrator().CreateTable(joinValue)
}(rel.JoinTable.Table, joinValue)
}
}
} }
for _, chk := range stmt.Schema.ParseCheckConstraints() { for _, chk := range stmt.Schema.ParseCheckConstraints() {
@ -551,9 +527,10 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i
orderedModelNamesMap = map[string]bool{} orderedModelNamesMap = map[string]bool{}
valuesMap = map[string]Dependency{} valuesMap = map[string]Dependency{}
insertIntoOrderedList func(name string) insertIntoOrderedList func(name string)
parseDependence func(value interface{}, addToList bool)
) )
parseDependence := func(value interface{}, addToList bool) { parseDependence = func(value interface{}, addToList bool) {
dep := Dependency{ dep := Dependency{
Statement: &gorm.Statement{DB: m.DB, Dest: value}, Statement: &gorm.Statement{DB: m.DB, Dest: value},
} }
@ -564,9 +541,15 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i
dep.Depends = append(dep.Depends, c.ReferenceSchema) dep.Depends = append(dep.Depends, c.ReferenceSchema)
} }
if rel.JoinTable != nil && rel.Schema != rel.FieldSchema { if rel.JoinTable != nil {
if rel.Schema != rel.FieldSchema {
dep.Depends = append(dep.Depends, rel.FieldSchema) dep.Depends = append(dep.Depends, rel.FieldSchema)
} }
// append join value
defer func(joinValue interface{}) {
parseDependence(joinValue, autoAdd)
}(reflect.New(rel.JoinTable.ModelType).Interface())
}
} }
valuesMap[dep.Schema.Table] = dep valuesMap[dep.Schema.Table] = dep

View File

@ -4,6 +4,8 @@ import (
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
"gorm.io/gorm"
) )
type Blog struct { type Blog struct {
@ -11,7 +13,7 @@ type Blog struct {
Locale string `gorm:"primary_key"` Locale string `gorm:"primary_key"`
Subject string Subject string
Body string Body string
Tags []Tag `gorm:"many2many:blog_tags;"` Tags []Tag `gorm:"many2many:blogs_tags;"`
SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"` SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"` LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
} }
@ -38,7 +40,16 @@ func TestManyToManyWithMultiPrimaryKeys(t *testing.T) {
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment") t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
} }
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags") if name := DB.Dialector.Name(); name == "postgres" {
stmt := gorm.Statement{DB: DB}
stmt.Parse(&Blog{})
stmt.Schema.LookUpField("ID").Unique = true
stmt.Parse(&Tag{})
stmt.Schema.LookUpField("ID").Unique = true
// postgers only allow unique constraint matching given keys
}
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
t.Fatalf("Failed to auto migrate, got error: %v", err) t.Fatalf("Failed to auto migrate, got error: %v", err)
} }
@ -127,7 +138,11 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment") t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
} }
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags") if name := DB.Dialector.Name(); name == "postgres" {
t.Skip("skip postgers due to it only allow unique constraint matching given keys")
}
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
t.Fatalf("Failed to auto migrate, got error: %v", err) t.Fatalf("Failed to auto migrate, got error: %v", err)
} }
@ -248,7 +263,11 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment") t.Skip("skip sqlite, sqlserver due to it doesn't support multiple primary keys with auto increment")
} }
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags") if name := DB.Dialector.Name(); name == "postgres" {
t.Skip("skip postgers due to it only allow unique constraint matching given keys")
}
DB.Migrator().DropTable(&Blog{}, &Tag{}, "blog_tags", "locale_blog_tags", "shared_blog_tags")
if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil { if err := DB.AutoMigrate(&Blog{}, &Tag{}); err != nil {
t.Fatalf("Failed to auto migrate, got error: %v", err) t.Fatalf("Failed to auto migrate, got error: %v", err)
} }