mirror of https://github.com/go-gorm/gorm.git
feature: bring custom type and id column name to polymorphism (#6716)
* feature: bring custom type and id column name to polymorphism * relationship: better returns for hasPolymorphicRelation * fix: tests
This commit is contained in:
parent
b9ebdb13c7
commit
a2cac75218
|
@ -76,8 +76,8 @@ func (schema *Schema) parseRelation(field *Field) *Relationship {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {
|
if hasPolymorphicRelation(field.TagSettings) {
|
||||||
schema.buildPolymorphicRelation(relation, field, polymorphic)
|
schema.buildPolymorphicRelation(relation, field)
|
||||||
} else if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
|
} else if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
|
||||||
schema.buildMany2ManyRelation(relation, field, many2many)
|
schema.buildMany2ManyRelation(relation, field, many2many)
|
||||||
} else if belongsTo := field.TagSettings["BELONGSTO"]; belongsTo != "" {
|
} else if belongsTo := field.TagSettings["BELONGSTO"]; belongsTo != "" {
|
||||||
|
@ -89,7 +89,8 @@ func (schema *Schema) parseRelation(field *Field) *Relationship {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
schema.guessRelation(relation, field, guessHas)
|
schema.guessRelation(relation, field, guessHas)
|
||||||
default:
|
default:
|
||||||
schema.err = fmt.Errorf("unsupported data type %v for %v on field %s", relation.FieldSchema, schema, field.Name)
|
schema.err = fmt.Errorf("unsupported data type %v for %v on field %s", relation.FieldSchema, schema,
|
||||||
|
field.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +125,20 @@ func (schema *Schema) parseRelation(field *Field) *Relationship {
|
||||||
return relation
|
return relation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hasPolymorphicRelation check if has polymorphic relation
|
||||||
|
// 1. `POLYMORPHIC` tag
|
||||||
|
// 2. `POLYMORPHICTYPE` and `POLYMORPHICID` tag
|
||||||
|
func hasPolymorphicRelation(tagSettings map[string]string) bool {
|
||||||
|
if _, ok := tagSettings["POLYMORPHIC"]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hasType := tagSettings["POLYMORPHICTYPE"]
|
||||||
|
_, hasId := tagSettings["POLYMORPHICID"]
|
||||||
|
|
||||||
|
return hasType && hasId
|
||||||
|
}
|
||||||
|
|
||||||
func (schema *Schema) setRelation(relation *Relationship) {
|
func (schema *Schema) setRelation(relation *Relationship) {
|
||||||
// set non-embedded relation
|
// set non-embedded relation
|
||||||
if rel := schema.Relationships.Relations[relation.Name]; rel != nil {
|
if rel := schema.Relationships.Relations[relation.Name]; rel != nil {
|
||||||
|
@ -169,23 +184,41 @@ func (schema *Schema) setRelation(relation *Relationship) {
|
||||||
// OwnerID int
|
// OwnerID int
|
||||||
// OwnerType string
|
// OwnerType string
|
||||||
// }
|
// }
|
||||||
func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Field, polymorphic string) {
|
func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Field) {
|
||||||
|
polymorphic := field.TagSettings["POLYMORPHIC"]
|
||||||
|
|
||||||
relation.Polymorphic = &Polymorphic{
|
relation.Polymorphic = &Polymorphic{
|
||||||
Value: schema.Table,
|
Value: schema.Table,
|
||||||
PolymorphicType: relation.FieldSchema.FieldsByName[polymorphic+"Type"],
|
|
||||||
PolymorphicID: relation.FieldSchema.FieldsByName[polymorphic+"ID"],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeName = polymorphic + "Type"
|
||||||
|
typeId = polymorphic + "ID"
|
||||||
|
)
|
||||||
|
|
||||||
|
if value, ok := field.TagSettings["POLYMORPHICTYPE"]; ok {
|
||||||
|
typeName = strings.TrimSpace(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := field.TagSettings["POLYMORPHICID"]; ok {
|
||||||
|
typeId = strings.TrimSpace(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
relation.Polymorphic.PolymorphicType = relation.FieldSchema.FieldsByName[typeName]
|
||||||
|
relation.Polymorphic.PolymorphicID = relation.FieldSchema.FieldsByName[typeId]
|
||||||
|
|
||||||
if value, ok := field.TagSettings["POLYMORPHICVALUE"]; ok {
|
if value, ok := field.TagSettings["POLYMORPHICVALUE"]; ok {
|
||||||
relation.Polymorphic.Value = strings.TrimSpace(value)
|
relation.Polymorphic.Value = strings.TrimSpace(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
if relation.Polymorphic.PolymorphicType == nil {
|
if relation.Polymorphic.PolymorphicType == nil {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s", relation.FieldSchema, schema, field.Name, polymorphic+"Type")
|
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s",
|
||||||
|
relation.FieldSchema, schema, field.Name, polymorphic+"Type")
|
||||||
}
|
}
|
||||||
|
|
||||||
if relation.Polymorphic.PolymorphicID == nil {
|
if relation.Polymorphic.PolymorphicID == nil {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s", relation.FieldSchema, schema, field.Name, polymorphic+"ID")
|
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing field %s",
|
||||||
|
relation.FieldSchema, schema, field.Name, polymorphic+"ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
if schema.err == nil {
|
if schema.err == nil {
|
||||||
|
@ -197,12 +230,14 @@ func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Fi
|
||||||
primaryKeyField := schema.PrioritizedPrimaryField
|
primaryKeyField := schema.PrioritizedPrimaryField
|
||||||
if len(relation.foreignKeys) > 0 {
|
if len(relation.foreignKeys) > 0 {
|
||||||
if primaryKeyField = schema.LookUpField(relation.foreignKeys[0]); primaryKeyField == nil || len(relation.foreignKeys) > 1 {
|
if primaryKeyField = schema.LookUpField(relation.foreignKeys[0]); primaryKeyField == nil || len(relation.foreignKeys) > 1 {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic foreign keys %+v for %v on field %s", relation.foreignKeys, schema, field.Name)
|
schema.err = fmt.Errorf("invalid polymorphic foreign keys %+v for %v on field %s", relation.foreignKeys,
|
||||||
|
schema, field.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if primaryKeyField == nil {
|
if primaryKeyField == nil {
|
||||||
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing primaryKey field", relation.FieldSchema, schema, field.Name)
|
schema.err = fmt.Errorf("invalid polymorphic type %v for %v on field %s, missing primaryKey field",
|
||||||
|
relation.FieldSchema, schema, field.Name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +352,8 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
Tag: `gorm:"-"`,
|
Tag: `gorm:"-"`,
|
||||||
})
|
})
|
||||||
|
|
||||||
if relation.JoinTable, err = Parse(reflect.New(reflect.StructOf(joinTableFields)).Interface(), schema.cacheStore, schema.namer); err != nil {
|
if relation.JoinTable, err = Parse(reflect.New(reflect.StructOf(joinTableFields)).Interface(), schema.cacheStore,
|
||||||
|
schema.namer); err != nil {
|
||||||
schema.err = err
|
schema.err = err
|
||||||
}
|
}
|
||||||
relation.JoinTable.Name = many2many
|
relation.JoinTable.Name = many2many
|
||||||
|
@ -436,7 +472,8 @@ func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl gu
|
||||||
schema.guessRelation(relation, field, guessEmbeddedHas)
|
schema.guessRelation(relation, field, guessEmbeddedHas)
|
||||||
// case guessEmbeddedHas:
|
// case guessEmbeddedHas:
|
||||||
default:
|
default:
|
||||||
schema.err = fmt.Errorf("invalid field found for struct %v's field %s: define a valid foreign key for relations or implement the Valuer/Scanner interface", schema, field.Name)
|
schema.err = fmt.Errorf("invalid field found for struct %v's field %s: define a valid foreign key for relations or implement the Valuer/Scanner interface",
|
||||||
|
schema, field.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +529,9 @@ func (schema *Schema) guessRelation(relation *Relationship, field *Field, cgl gu
|
||||||
|
|
||||||
lookUpNames := []string{lookUpName}
|
lookUpNames := []string{lookUpName}
|
||||||
if len(primaryFields) == 1 {
|
if len(primaryFields) == 1 {
|
||||||
lookUpNames = append(lookUpNames, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID", strings.TrimSuffix(lookUpName, primaryField.Name)+"Id", schema.namer.ColumnName(foreignSchema.Table, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID"))
|
lookUpNames = append(lookUpNames, strings.TrimSuffix(lookUpName, primaryField.Name)+"ID",
|
||||||
|
strings.TrimSuffix(lookUpName, primaryField.Name)+"Id", schema.namer.ColumnName(foreignSchema.Table,
|
||||||
|
strings.TrimSuffix(lookUpName, primaryField.Name)+"ID"))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range lookUpNames {
|
for _, name := range lookUpNames {
|
||||||
|
|
|
@ -577,6 +577,193 @@ func TestEmbeddedHas(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPolymorphic(t *testing.T) {
|
||||||
|
t.Run("has one", func(t *testing.T) {
|
||||||
|
type Toy struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
OwnerID int
|
||||||
|
OwnerType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cat struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Toy Toy `gorm:"polymorphic:Owner;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := schema.Parse(&Cat{}, &sync.Map{}, schema.NamingStrategy{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse schema, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmbeddedRelations(t, s.Relationships.EmbeddedRelations, map[string]EmbeddedRelations{
|
||||||
|
"Cat": {
|
||||||
|
Relations: map[string]Relation{
|
||||||
|
"Toy": {
|
||||||
|
Name: "Toy",
|
||||||
|
Type: schema.HasOne,
|
||||||
|
Schema: "User",
|
||||||
|
FieldSchema: "Toy",
|
||||||
|
Polymorphic: Polymorphic{ID: "OwnerID", Type: "OwnerType", Value: "users"},
|
||||||
|
References: []Reference{
|
||||||
|
{ForeignKey: "OwnerType", ForeignSchema: "Toy", PrimaryValue: "users"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("has one with custom polymorphic type and id", func(t *testing.T) {
|
||||||
|
type Toy struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
RefId int
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cat struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Toy Toy `gorm:"polymorphic:Owner;polymorphicType:Type;polymorphicId:RefId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := schema.Parse(&Cat{}, &sync.Map{}, schema.NamingStrategy{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse schema, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmbeddedRelations(t, s.Relationships.EmbeddedRelations, map[string]EmbeddedRelations{
|
||||||
|
"Cat": {
|
||||||
|
Relations: map[string]Relation{
|
||||||
|
"Toy": {
|
||||||
|
Name: "Toy",
|
||||||
|
Type: schema.HasOne,
|
||||||
|
Schema: "User",
|
||||||
|
FieldSchema: "Toy",
|
||||||
|
Polymorphic: Polymorphic{ID: "ref_id", Type: "Type", Value: "users"},
|
||||||
|
References: []Reference{
|
||||||
|
{ForeignKey: "Type", ForeignSchema: "Toy", PrimaryValue: "users"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("has one with only polymorphic type", func(t *testing.T) {
|
||||||
|
type Toy struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
OwnerID int
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cat struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Toy Toy `gorm:"polymorphic:Owner;polymorphicType:Type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := schema.Parse(&Cat{}, &sync.Map{}, schema.NamingStrategy{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse schema, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmbeddedRelations(t, s.Relationships.EmbeddedRelations, map[string]EmbeddedRelations{
|
||||||
|
"Cat": {
|
||||||
|
Relations: map[string]Relation{
|
||||||
|
"Toy": {
|
||||||
|
Name: "Toy",
|
||||||
|
Type: schema.HasOne,
|
||||||
|
Schema: "User",
|
||||||
|
FieldSchema: "Toy",
|
||||||
|
Polymorphic: Polymorphic{ID: "owner_id", Type: "Type", Value: "users"},
|
||||||
|
References: []Reference{
|
||||||
|
{ForeignKey: "Type", ForeignSchema: "Toy", PrimaryValue: "users"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("has many", func(t *testing.T) {
|
||||||
|
type Toy struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
OwnerID int
|
||||||
|
OwnerType string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cat struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Toys []Toy `gorm:"polymorphic:Owner;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := schema.Parse(&Cat{}, &sync.Map{}, schema.NamingStrategy{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse schema, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmbeddedRelations(t, s.Relationships.EmbeddedRelations, map[string]EmbeddedRelations{
|
||||||
|
"Cat": {
|
||||||
|
Relations: map[string]Relation{
|
||||||
|
"Toys": {
|
||||||
|
Name: "Toys",
|
||||||
|
Type: schema.HasMany,
|
||||||
|
Schema: "User",
|
||||||
|
FieldSchema: "Toy",
|
||||||
|
Polymorphic: Polymorphic{ID: "OwnerID", Type: "OwnerType", Value: "users"},
|
||||||
|
References: []Reference{
|
||||||
|
{ForeignKey: "OwnerType", ForeignSchema: "Toy", PrimaryValue: "users"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("has many with custom polymorphic type and id", func(t *testing.T) {
|
||||||
|
type Toy struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
RefId int
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cat struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
Toys []Toy `gorm:"polymorphicType:Type;polymorphicId:RefId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := schema.Parse(&Cat{}, &sync.Map{}, schema.NamingStrategy{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to parse schema, got error %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkEmbeddedRelations(t, s.Relationships.EmbeddedRelations, map[string]EmbeddedRelations{
|
||||||
|
"Cat": {
|
||||||
|
Relations: map[string]Relation{
|
||||||
|
"Toys": {
|
||||||
|
Name: "Toys",
|
||||||
|
Type: schema.HasMany,
|
||||||
|
Schema: "User",
|
||||||
|
FieldSchema: "Toy",
|
||||||
|
Polymorphic: Polymorphic{ID: "ref_id", Type: "Type", Value: "users"},
|
||||||
|
References: []Reference{
|
||||||
|
{ForeignKey: "Type", ForeignSchema: "Toy", PrimaryValue: "users"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestEmbeddedBelongsTo(t *testing.T) {
|
func TestEmbeddedBelongsTo(t *testing.T) {
|
||||||
type Country struct {
|
type Country struct {
|
||||||
ID int `gorm:"primaryKey"`
|
ID int `gorm:"primaryKey"`
|
||||||
|
|
|
@ -422,7 +422,7 @@ func TestPolymorphicHasManyAssociation(t *testing.T) {
|
||||||
func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
|
func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
|
||||||
users := []User{
|
users := []User{
|
||||||
*GetUser("slice-hasmany-1", Config{Toys: 2}),
|
*GetUser("slice-hasmany-1", Config{Toys: 2}),
|
||||||
*GetUser("slice-hasmany-2", Config{Toys: 0}),
|
*GetUser("slice-hasmany-2", Config{Toys: 0, Tools: 2}),
|
||||||
*GetUser("slice-hasmany-3", Config{Toys: 4}),
|
*GetUser("slice-hasmany-3", Config{Toys: 4}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +430,7 @@ func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
AssertAssociationCount(t, users, "Toys", 6, "")
|
AssertAssociationCount(t, users, "Toys", 6, "")
|
||||||
|
AssertAssociationCount(t, users, "Tools", 2, "")
|
||||||
|
|
||||||
// Find
|
// Find
|
||||||
var toys []Toy
|
var toys []Toy
|
||||||
|
@ -437,6 +438,14 @@ func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
|
||||||
t.Errorf("toys count should be %v, but got %v", 6, len(toys))
|
t.Errorf("toys count should be %v, but got %v", 6, len(toys))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find Tools (polymorphic with custom type and id)
|
||||||
|
var tools []Tools
|
||||||
|
DB.Model(&users).Association("Tools").Find(&tools)
|
||||||
|
|
||||||
|
if len(tools) != 2 {
|
||||||
|
t.Errorf("tools count should be %v, but got %v", 2, len(tools))
|
||||||
|
}
|
||||||
|
|
||||||
// Append
|
// Append
|
||||||
DB.Model(&users).Association("Toys").Append(
|
DB.Model(&users).Association("Toys").Append(
|
||||||
&Toy{Name: "toy-slice-append-1"},
|
&Toy{Name: "toy-slice-append-1"},
|
||||||
|
|
|
@ -23,6 +23,7 @@ type Config struct {
|
||||||
Languages int
|
Languages int
|
||||||
Friends int
|
Friends int
|
||||||
NamedPet bool
|
NamedPet bool
|
||||||
|
Tools int
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUser(name string, config Config) *User {
|
func GetUser(name string, config Config) *User {
|
||||||
|
@ -47,6 +48,10 @@ func GetUser(name string, config Config) *User {
|
||||||
user.Toys = append(user.Toys, Toy{Name: name + "_toy_" + strconv.Itoa(i+1)})
|
user.Toys = append(user.Toys, Toy{Name: name + "_toy_" + strconv.Itoa(i+1)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i := 0; i < config.Tools; i++ {
|
||||||
|
user.Tools = append(user.Tools, Tools{Name: name + "_tool_" + strconv.Itoa(i+1)})
|
||||||
|
}
|
||||||
|
|
||||||
if config.Company {
|
if config.Company {
|
||||||
user.Company = Company{Name: "company-" + name}
|
user.Company = Company{Name: "company-" + name}
|
||||||
}
|
}
|
||||||
|
@ -118,11 +123,13 @@ func doCheckUser(t *testing.T, user User, expect User, unscoped bool) {
|
||||||
if err := db(unscoped).Where("id = ?", user.ID).First(&newUser).Error; err != nil {
|
if err := db(unscoped).Where("id = ?", user.ID).First(&newUser).Error; err != nil {
|
||||||
t.Fatalf("errors happened when query: %v", err)
|
t.Fatalf("errors happened when query: %v", err)
|
||||||
} else {
|
} else {
|
||||||
AssertObjEqual(t, newUser, user, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
AssertObjEqual(t, newUser, user, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday",
|
||||||
|
"CompanyID", "ManagerID", "Active")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertObjEqual(t, user, expect, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
AssertObjEqual(t, user, expect, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID",
|
||||||
|
"ManagerID", "Active")
|
||||||
|
|
||||||
t.Run("Account", func(t *testing.T) {
|
t.Run("Account", func(t *testing.T) {
|
||||||
AssertObjEqual(t, user.Account, expect.Account, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "UserID", "Number")
|
AssertObjEqual(t, user.Account, expect.Account, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "UserID", "Number")
|
||||||
|
@ -133,7 +140,8 @@ func doCheckUser(t *testing.T, user User, expect User, unscoped bool) {
|
||||||
} else {
|
} else {
|
||||||
var account Account
|
var account Account
|
||||||
db(unscoped).First(&account, "user_id = ?", user.ID)
|
db(unscoped).First(&account, "user_id = ?", user.ID)
|
||||||
AssertObjEqual(t, account, user.Account, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "UserID", "Number")
|
AssertObjEqual(t, account, user.Account, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "UserID",
|
||||||
|
"Number")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -193,8 +201,10 @@ func doCheckUser(t *testing.T, user User, expect User, unscoped bool) {
|
||||||
} else {
|
} else {
|
||||||
var manager User
|
var manager User
|
||||||
db(unscoped).First(&manager, "id = ?", *user.ManagerID)
|
db(unscoped).First(&manager, "id = ?", *user.ManagerID)
|
||||||
AssertObjEqual(t, manager, user.Manager, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
AssertObjEqual(t, manager, user.Manager, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age",
|
||||||
AssertObjEqual(t, manager, expect.Manager, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
"Birthday", "CompanyID", "ManagerID", "Active")
|
||||||
|
AssertObjEqual(t, manager, expect.Manager, "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age",
|
||||||
|
"Birthday", "CompanyID", "ManagerID", "Active")
|
||||||
}
|
}
|
||||||
} else if user.ManagerID != nil {
|
} else if user.ManagerID != nil {
|
||||||
t.Errorf("Manager should not be created for zero value, got: %+v", user.ManagerID)
|
t.Errorf("Manager should not be created for zero value, got: %+v", user.ManagerID)
|
||||||
|
@ -215,7 +225,8 @@ func doCheckUser(t *testing.T, user User, expect User, unscoped bool) {
|
||||||
})
|
})
|
||||||
|
|
||||||
for idx, team := range user.Team {
|
for idx, team := range user.Team {
|
||||||
AssertObjEqual(t, team, expect.Team[idx], "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
AssertObjEqual(t, team, expect.Team[idx], "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age",
|
||||||
|
"Birthday", "CompanyID", "ManagerID", "Active")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -250,7 +261,8 @@ func doCheckUser(t *testing.T, user User, expect User, unscoped bool) {
|
||||||
})
|
})
|
||||||
|
|
||||||
for idx, friend := range user.Friends {
|
for idx, friend := range user.Friends {
|
||||||
AssertObjEqual(t, friend, expect.Friends[idx], "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age", "Birthday", "CompanyID", "ManagerID", "Active")
|
AssertObjEqual(t, friend, expect.Friends[idx], "ID", "CreatedAt", "UpdatedAt", "DeletedAt", "Name", "Age",
|
||||||
|
"Birthday", "CompanyID", "ManagerID", "Active")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMigrate(t *testing.T) {
|
func TestMigrate(t *testing.T) {
|
||||||
allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}}
|
allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Tools{}}
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] })
|
rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] })
|
||||||
DB.Migrator().DropTable("user_speaks", "user_friends", "ccc")
|
DB.Migrator().DropTable("user_speaks", "user_friends", "ccc")
|
||||||
|
@ -34,7 +34,7 @@ func TestMigrate(t *testing.T) {
|
||||||
if tables, err := DB.Migrator().GetTables(); err != nil {
|
if tables, err := DB.Migrator().GetTables(); err != nil {
|
||||||
t.Fatalf("Failed to get database all tables, but got error %v", err)
|
t.Fatalf("Failed to get database all tables, but got error %v", err)
|
||||||
} else {
|
} else {
|
||||||
for _, t1 := range []string{"users", "accounts", "pets", "companies", "toys", "languages"} {
|
for _, t1 := range []string{"users", "accounts", "pets", "companies", "toys", "languages", "tools"} {
|
||||||
hasTable := false
|
hasTable := false
|
||||||
for _, t2 := range tables {
|
for _, t2 := range tables {
|
||||||
if t2 == t1 {
|
if t2 == t1 {
|
||||||
|
@ -93,7 +93,8 @@ func TestAutoMigrateInt8PG(t *testing.T) {
|
||||||
Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
||||||
sql, _ := fc()
|
sql, _ := fc()
|
||||||
if strings.HasPrefix(sql, "ALTER TABLE \"migrate_ints\" ALTER COLUMN \"int8\" TYPE smallint") {
|
if strings.HasPrefix(sql, "ALTER TABLE \"migrate_ints\" ALTER COLUMN \"int8\" TYPE smallint") {
|
||||||
t.Fatalf("shouldn't execute ALTER COLUMN TYPE if such type is already existed in DB schema: sql: %s", sql)
|
t.Fatalf("shouldn't execute ALTER COLUMN TYPE if such type is already existed in DB schema: sql: %s",
|
||||||
|
sql)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -432,40 +433,50 @@ func TestTiDBMigrateColumns(t *testing.T) {
|
||||||
switch columnType.Name() {
|
switch columnType.Name() {
|
||||||
case "id":
|
case "id":
|
||||||
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
||||||
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "name":
|
case "name":
|
||||||
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
||||||
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
||||||
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
||||||
}
|
}
|
||||||
if length, ok := columnType.Length(); !ok || length != 100 {
|
if length, ok := columnType.Length(); !ok || length != 100 {
|
||||||
t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), length, 100, columnType)
|
t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), length, 100, columnType)
|
||||||
}
|
}
|
||||||
case "age":
|
case "age":
|
||||||
if v, ok := columnType.DefaultValue(); !ok || v != "18" {
|
if v, ok := columnType.DefaultValue(); !ok || v != "18" {
|
||||||
t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.Comment(); !ok || v != "my age" {
|
if v, ok := columnType.Comment(); !ok || v != "my age" {
|
||||||
t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "code":
|
case "code":
|
||||||
if v, ok := columnType.Unique(); !ok || !v {
|
if v, ok := columnType.Unique(); !ok || !v {
|
||||||
t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.DefaultValue(); !ok || v != "hello" {
|
if v, ok := columnType.DefaultValue(); !ok || v != "hello" {
|
||||||
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v", columnType.Name(), columnType, v)
|
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v",
|
||||||
|
columnType.Name(), columnType, v)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.Comment(); !ok || v != "my code2" {
|
if v, ok := columnType.Comment(); !ok || v != "my code2" {
|
||||||
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "code2":
|
case "code2":
|
||||||
// Code2 string `gorm:"comment:my code2;default:hello"`
|
// Code2 string `gorm:"comment:my code2;default:hello"`
|
||||||
if v, ok := columnType.DefaultValue(); !ok || v != "hello" {
|
if v, ok := columnType.DefaultValue(); !ok || v != "hello" {
|
||||||
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v", columnType.Name(), columnType, v)
|
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v",
|
||||||
|
columnType.Name(), columnType, v)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.Comment(); !ok || v != "my code2" {
|
if v, ok := columnType.Comment(); !ok || v != "my code2" {
|
||||||
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,7 +508,8 @@ func TestTiDBMigrateColumns(t *testing.T) {
|
||||||
t.Fatalf("Failed to add column, got %v", err)
|
t.Fatalf("Failed to add column, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := DB.Table("column_structs").Migrator().RenameColumn(&NewColumnStruct{}, "NewName", "new_new_name"); err != nil {
|
if err := DB.Table("column_structs").Migrator().RenameColumn(&NewColumnStruct{}, "NewName",
|
||||||
|
"new_new_name"); err != nil {
|
||||||
t.Fatalf("Failed to add column, got %v", err)
|
t.Fatalf("Failed to add column, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,36 +573,45 @@ func TestMigrateColumns(t *testing.T) {
|
||||||
switch columnType.Name() {
|
switch columnType.Name() {
|
||||||
case "id":
|
case "id":
|
||||||
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
||||||
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "name":
|
case "name":
|
||||||
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
||||||
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
||||||
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
||||||
}
|
}
|
||||||
if length, ok := columnType.Length(); !sqlite && (!ok || length != 100) {
|
if length, ok := columnType.Length(); !sqlite && (!ok || length != 100) {
|
||||||
t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), length, 100, columnType)
|
t.Fatalf("column name length should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), length, 100, columnType)
|
||||||
}
|
}
|
||||||
case "age":
|
case "age":
|
||||||
if v, ok := columnType.DefaultValue(); !ok || v != "18" {
|
if v, ok := columnType.DefaultValue(); !ok || v != "18" {
|
||||||
t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column age default value should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my age") {
|
if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my age") {
|
||||||
t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column age comment should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "code":
|
case "code":
|
||||||
if v, ok := columnType.Unique(); !ok || !v {
|
if v, ok := columnType.Unique(); !ok || !v {
|
||||||
t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code unique should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.DefaultValue(); !sqlserver && (!ok || v != "hello") {
|
if v, ok := columnType.DefaultValue(); !sqlserver && (!ok || v != "hello") {
|
||||||
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v", columnType.Name(), columnType, v)
|
t.Fatalf("column code default value should be correct, name: %v, column: %#v, default value: %v",
|
||||||
|
columnType.Name(), columnType, v)
|
||||||
}
|
}
|
||||||
if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my code2") {
|
if v, ok := columnType.Comment(); !sqlite && !sqlserver && (!ok || v != "my code2") {
|
||||||
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code comment should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "code2":
|
case "code2":
|
||||||
if v, ok := columnType.Unique(); !sqlserver && (!ok || !v) {
|
if v, ok := columnType.Unique(); !sqlserver && (!ok || !v) {
|
||||||
t.Fatalf("column code2 unique should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column code2 unique should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "code3":
|
case "code3":
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -627,7 +648,8 @@ func TestMigrateColumns(t *testing.T) {
|
||||||
t.Fatalf("Failed to add column, got %v", err)
|
t.Fatalf("Failed to add column, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := DB.Table("column_structs").Migrator().RenameColumn(&NewColumnStruct{}, "NewName", "new_new_name"); err != nil {
|
if err := DB.Table("column_structs").Migrator().RenameColumn(&NewColumnStruct{}, "NewName",
|
||||||
|
"new_new_name"); err != nil {
|
||||||
t.Fatalf("Failed to add column, got %v", err)
|
t.Fatalf("Failed to add column, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1555,7 +1577,8 @@ func TestMigrateIgnoreRelations(t *testing.T) {
|
||||||
func TestMigrateView(t *testing.T) {
|
func TestMigrateView(t *testing.T) {
|
||||||
DB.Save(GetUser("joins-args-db", Config{Pets: 2}))
|
DB.Save(GetUser("joins-args-db", Config{Pets: 2}))
|
||||||
|
|
||||||
if err := DB.Migrator().CreateView("invalid_users_pets", gorm.ViewOption{Query: nil}); err != gorm.ErrSubQueryRequired {
|
if err := DB.Migrator().CreateView("invalid_users_pets",
|
||||||
|
gorm.ViewOption{Query: nil}); err != gorm.ErrSubQueryRequired {
|
||||||
t.Fatalf("no view should be created, got %v", err)
|
t.Fatalf("no view should be created, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1624,17 +1647,20 @@ func TestMigrateExistingBoolColumnPG(t *testing.T) {
|
||||||
switch columnType.Name() {
|
switch columnType.Name() {
|
||||||
case "id":
|
case "id":
|
||||||
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
if v, ok := columnType.PrimaryKey(); !ok || !v {
|
||||||
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(), columnType)
|
t.Fatalf("column id primary key should be correct, name: %v, column: %#v", columnType.Name(),
|
||||||
|
columnType)
|
||||||
}
|
}
|
||||||
case "string_bool":
|
case "string_bool":
|
||||||
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
||||||
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
||||||
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
||||||
}
|
}
|
||||||
case "smallint_bool":
|
case "smallint_bool":
|
||||||
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
dataType := DB.Dialector.DataTypeOf(stmt.Schema.LookUpField(columnType.Name()))
|
||||||
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
if !strings.Contains(strings.ToUpper(dataType), strings.ToUpper(columnType.DatabaseTypeName())) {
|
||||||
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v", columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
t.Fatalf("column name type should be correct, name: %v, length: %v, expects: %v, column: %#v",
|
||||||
|
columnType.Name(), columnType.DatabaseTypeName(), dataType, columnType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1659,7 +1685,8 @@ func TestTableType(t *testing.T) {
|
||||||
|
|
||||||
DB.Migrator().DropTable(&City{})
|
DB.Migrator().DropTable(&City{})
|
||||||
|
|
||||||
if err := DB.Set("gorm:table_options", fmt.Sprintf("ENGINE InnoDB COMMENT '%s'", tblComment)).AutoMigrate(&City{}); err != nil {
|
if err := DB.Set("gorm:table_options",
|
||||||
|
fmt.Sprintf("ENGINE InnoDB COMMENT '%s'", tblComment)).AutoMigrate(&City{}); err != nil {
|
||||||
t.Fatalf("failed to migrate cities tables, got error: %v", err)
|
t.Fatalf("failed to migrate cities tables, got error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ func OpenTestConnection(cfg *gorm.Config) (db *gorm.DB, err error) {
|
||||||
|
|
||||||
func RunMigrations() {
|
func RunMigrations() {
|
||||||
var err error
|
var err error
|
||||||
allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}, &Order{}, &Parent{}, &Child{}}
|
allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}, &Order{}, &Parent{}, &Child{}, &Tools{}}
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] })
|
rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] })
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ type User struct {
|
||||||
Account Account
|
Account Account
|
||||||
Pets []*Pet
|
Pets []*Pet
|
||||||
NamedPet *Pet
|
NamedPet *Pet
|
||||||
Toys []Toy `gorm:"polymorphic:Owner"`
|
Toys []Toy `gorm:"polymorphic:Owner"`
|
||||||
|
Tools []Tools `gorm:"polymorphicType:Type;polymorphicId:CustomID"`
|
||||||
CompanyID *int
|
CompanyID *int
|
||||||
Company Company
|
Company Company
|
||||||
ManagerID *uint
|
ManagerID *uint
|
||||||
|
@ -51,6 +52,13 @@ type Toy struct {
|
||||||
OwnerType string
|
OwnerType string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tools struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string
|
||||||
|
CustomID string
|
||||||
|
Type string
|
||||||
|
}
|
||||||
|
|
||||||
type Company struct {
|
type Company struct {
|
||||||
ID int
|
ID int
|
||||||
Name string
|
Name string
|
||||||
|
|
Loading…
Reference in New Issue