2020-05-31 12:42:21 +03:00
|
|
|
package schema_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
|
2020-06-02 04:16:07 +03:00
|
|
|
"gorm.io/gorm"
|
|
|
|
"gorm.io/gorm/schema"
|
2020-05-31 12:42:21 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func checkStructRelation(t *testing.T, data interface{}, relations ...Relation) {
|
|
|
|
if s, err := schema.Parse(data, &sync.Map{}, schema.NamingStrategy{}); err != nil {
|
|
|
|
t.Errorf("Failed to parse schema")
|
|
|
|
} else {
|
|
|
|
for _, rel := range relations {
|
|
|
|
checkSchemaRelation(t, s, rel)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBelongsToOverrideForeignKey(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile Profile `gorm:"ForeignKey:ProfileRefer"`
|
|
|
|
ProfileRefer int
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.BelongsTo, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"ID", "Profile", "ProfileRefer", "User", "", false}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBelongsToOverrideReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile Profile `gorm:"ForeignKey:ProfileID;References:Refer"`
|
|
|
|
ProfileID int
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.BelongsTo, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "Profile", "ProfileID", "User", "", false}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-28 12:58:12 +03:00
|
|
|
func TestBelongsToWithOnlyReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile Profile `gorm:"References:Refer"`
|
|
|
|
ProfileRefer int
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.BelongsTo, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "Profile", "ProfileRefer", "User", "", false}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-28 13:20:42 +03:00
|
|
|
func TestBelongsToWithOnlyReferences2(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile Profile `gorm:"References:Refer"`
|
|
|
|
ProfileID int
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.BelongsTo, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "Profile", "ProfileID", "User", "", false}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-28 06:31:13 +03:00
|
|
|
func TestSelfReferentialBelongsToOverrideReferences(t *testing.T) {
|
|
|
|
type User struct {
|
|
|
|
ID int32 `gorm:"primaryKey"`
|
|
|
|
Name string
|
|
|
|
CreatedBy *int32
|
|
|
|
Creator *User `gorm:"foreignKey:CreatedBy;references:ID"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Creator", Type: schema.BelongsTo, Schema: "User", FieldSchema: "User",
|
|
|
|
References: []Reference{{"ID", "User", "CreatedBy", "User", "", false}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-31 12:42:21 +03:00
|
|
|
func TestHasOneOverrideForeignKey(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile Profile `gorm:"ForeignKey:UserRefer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasOne, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"ID", "User", "UserRefer", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestHasOneOverrideReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserID uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Profile Profile `gorm:"ForeignKey:UserID;References:Refer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasOne, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "User", "UserID", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-28 12:58:12 +03:00
|
|
|
func TestHasOneWithOnlyReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Profile Profile `gorm:"References:Refer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasOne, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "User", "UserRefer", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-28 13:20:42 +03:00
|
|
|
func TestHasOneWithOnlyReferences2(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserID uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Profile Profile `gorm:"References:Refer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasOne, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "User", "UserID", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-31 12:42:21 +03:00
|
|
|
func TestHasManyOverrideForeignKey(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profile []Profile `gorm:"ForeignKey:UserRefer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasMany, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"ID", "User", "UserRefer", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestHasManyOverrideReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserID uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Refer string
|
|
|
|
Profile []Profile `gorm:"ForeignKey:UserID;References:Refer"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profile", Type: schema.HasMany, Schema: "User", FieldSchema: "Profile",
|
|
|
|
References: []Reference{{"Refer", "User", "UserID", "Profile", "", true}},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMany2ManyOverrideForeignKeyAndReferences(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
2020-07-04 02:24:30 +03:00
|
|
|
Profiles []Profile `gorm:"many2many:user_profiles;ForeignKey:Refer;JoinForeignKey:UserReferID;References:UserRefer;JoinReferences:ProfileRefer"`
|
|
|
|
Profiles2 []Profile `gorm:"many2many:user_profiles2;ForeignKey:refer;JoinForeignKey:user_refer_id;References:user_refer;JoinReferences:profile_refer"`
|
|
|
|
Refer uint
|
2020-05-31 12:42:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profiles", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
|
|
|
JoinTable: JoinTable{Name: "user_profiles", Table: "user_profiles"},
|
|
|
|
References: []Reference{
|
|
|
|
{"Refer", "User", "UserReferID", "user_profiles", "", true},
|
|
|
|
{"UserRefer", "Profile", "ProfileRefer", "user_profiles", "", false},
|
|
|
|
},
|
2020-07-04 02:24:30 +03:00
|
|
|
}, Relation{
|
|
|
|
Name: "Profiles2", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
|
|
|
JoinTable: JoinTable{Name: "user_profiles2", Table: "user_profiles2"},
|
|
|
|
References: []Reference{
|
|
|
|
{"Refer", "User", "User_refer_id", "user_profiles2", "", true},
|
|
|
|
{"UserRefer", "Profile", "Profile_refer", "user_profiles2", "", false},
|
|
|
|
},
|
2020-05-31 12:42:21 +03:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMany2ManyOverrideForeignKey(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profiles []Profile `gorm:"many2many:user_profiles;ForeignKey:Refer;References:UserRefer"`
|
|
|
|
Refer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profiles", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
|
|
|
JoinTable: JoinTable{Name: "user_profiles", Table: "user_profiles"},
|
|
|
|
References: []Reference{
|
|
|
|
{"Refer", "User", "UserRefer", "user_profiles", "", true},
|
|
|
|
{"UserRefer", "Profile", "ProfileUserRefer", "user_profiles", "", false},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMany2ManyOverrideJoinForeignKey(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
2020-09-06 05:51:21 +03:00
|
|
|
Profiles []Profile `gorm:"many2many:user_profile;JoinForeignKey:UserReferID;JoinReferences:ProfileRefer"`
|
2020-05-31 12:42:21 +03:00
|
|
|
Refer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profiles", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
2020-09-06 05:51:21 +03:00
|
|
|
JoinTable: JoinTable{Name: "user_profile", Table: "user_profile"},
|
2020-05-31 12:42:21 +03:00
|
|
|
References: []Reference{
|
2020-09-06 05:51:21 +03:00
|
|
|
{"ID", "User", "UserReferID", "user_profile", "", true},
|
|
|
|
{"ID", "Profile", "ProfileRefer", "user_profile", "", false},
|
2020-05-31 12:42:21 +03:00
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
2020-06-01 03:12:44 +03:00
|
|
|
|
2020-09-09 11:32:29 +03:00
|
|
|
func TestBuildReadonlyMany2ManyRelation(t *testing.T) {
|
|
|
|
type Profile struct {
|
|
|
|
gorm.Model
|
|
|
|
Name string
|
|
|
|
UserRefer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
type User struct {
|
|
|
|
gorm.Model
|
|
|
|
Profiles []Profile `gorm:"->;many2many:user_profile;JoinForeignKey:UserReferID;JoinReferences:ProfileRefer"`
|
|
|
|
Refer uint
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &User{}, Relation{
|
|
|
|
Name: "Profiles", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
|
|
|
JoinTable: JoinTable{Name: "user_profile", Table: "user_profile"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "User", "UserReferID", "user_profile", "", true},
|
|
|
|
{"ID", "Profile", "ProfileRefer", "user_profile", "", false},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-01 03:12:44 +03:00
|
|
|
func TestMany2ManyWithMultiPrimaryKeys(t *testing.T) {
|
|
|
|
type Tag struct {
|
|
|
|
ID uint `gorm:"primary_key"`
|
|
|
|
Locale string `gorm:"primary_key"`
|
|
|
|
Value string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Blog struct {
|
|
|
|
ID uint `gorm:"primary_key"`
|
|
|
|
Locale string `gorm:"primary_key"`
|
|
|
|
Subject string
|
|
|
|
Body string
|
|
|
|
Tags []Tag `gorm:"many2many:blog_tags;"`
|
|
|
|
SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
|
|
|
|
LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &Blog{},
|
|
|
|
Relation{
|
|
|
|
Name: "Tags", Type: schema.Many2Many, Schema: "Blog", FieldSchema: "Tag",
|
|
|
|
JoinTable: JoinTable{Name: "blog_tags", Table: "blog_tags"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "Blog", "BlogID", "blog_tags", "", true},
|
|
|
|
{"Locale", "Blog", "BlogLocale", "blog_tags", "", true},
|
|
|
|
{"ID", "Tag", "TagID", "blog_tags", "", false},
|
|
|
|
{"Locale", "Tag", "TagLocale", "blog_tags", "", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Relation{
|
|
|
|
Name: "SharedTags", Type: schema.Many2Many, Schema: "Blog", FieldSchema: "Tag",
|
|
|
|
JoinTable: JoinTable{Name: "shared_blog_tags", Table: "shared_blog_tags"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "Blog", "BlogID", "shared_blog_tags", "", true},
|
|
|
|
{"ID", "Tag", "TagID", "shared_blog_tags", "", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Relation{
|
|
|
|
Name: "LocaleTags", Type: schema.Many2Many, Schema: "Blog", FieldSchema: "Tag",
|
|
|
|
JoinTable: JoinTable{Name: "locale_blog_tags", Table: "locale_blog_tags"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "Blog", "BlogID", "locale_blog_tags", "", true},
|
|
|
|
{"Locale", "Blog", "BlogLocale", "locale_blog_tags", "", true},
|
|
|
|
{"ID", "Tag", "TagID", "locale_blog_tags", "", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2020-09-01 06:30:16 +03:00
|
|
|
|
|
|
|
func TestMultipleMany2Many(t *testing.T) {
|
|
|
|
type Thing struct {
|
|
|
|
ID int
|
|
|
|
}
|
|
|
|
|
|
|
|
type Person struct {
|
|
|
|
ID int
|
|
|
|
Likes []Thing `gorm:"many2many:likes"`
|
|
|
|
Dislikes []Thing `gorm:"many2many:dislikes"`
|
|
|
|
}
|
|
|
|
|
|
|
|
checkStructRelation(t, &Person{},
|
|
|
|
Relation{
|
|
|
|
Name: "Likes", Type: schema.Many2Many, Schema: "Person", FieldSchema: "Thing",
|
|
|
|
JoinTable: JoinTable{Name: "likes", Table: "likes"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "Person", "PersonID", "likes", "", true},
|
|
|
|
{"ID", "Thing", "ThingID", "likes", "", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Relation{
|
|
|
|
Name: "Dislikes", Type: schema.Many2Many, Schema: "Person", FieldSchema: "Thing",
|
|
|
|
JoinTable: JoinTable{Name: "dislikes", Table: "dislikes"},
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "Person", "PersonID", "dislikes", "", true},
|
|
|
|
{"ID", "Thing", "ThingID", "dislikes", "", false},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2021-01-19 10:40:04 +03:00
|
|
|
|
|
|
|
type CreatedByModel struct {
|
|
|
|
CreatedByID uint
|
|
|
|
CreatedBy *CreatedUser
|
|
|
|
}
|
|
|
|
|
|
|
|
type CreatedUser struct {
|
|
|
|
gorm.Model
|
|
|
|
CreatedByModel
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEmbeddedRelation(t *testing.T) {
|
|
|
|
checkStructRelation(t, &CreatedUser{}, Relation{
|
|
|
|
Name: "CreatedBy", Type: schema.BelongsTo, Schema: "CreatedUser", FieldSchema: "CreatedUser",
|
|
|
|
References: []Reference{
|
|
|
|
{"ID", "CreatedUser", "CreatedByID", "CreatedUser", "", false},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
userSchema, err := schema.Parse(&CreatedUser{}, &sync.Map{}, schema.NamingStrategy{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to parse schema, got error %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(userSchema.Relationships.Relations) != 1 {
|
|
|
|
t.Fatalf("expects 1 relations, but got %v", len(userSchema.Relationships.Relations))
|
|
|
|
}
|
|
|
|
|
|
|
|
if createdByRel, ok := userSchema.Relationships.Relations["CreatedBy"]; ok {
|
|
|
|
if createdByRel.FieldSchema != userSchema {
|
|
|
|
t.Fatalf("expects same field schema, but got new %p, old %p", createdByRel.FieldSchema, userSchema)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Fatalf("expects created by relations, but not found")
|
|
|
|
}
|
|
|
|
}
|