diff --git a/schema/relationship_test.go b/schema/relationship_test.go index e237af36..ea1cabac 100644 --- a/schema/relationship_test.go +++ b/schema/relationship_test.go @@ -1,6 +1,8 @@ package schema -import "testing" +import ( + "testing" +) func TestBelongsToRel(t *testing.T) { type BelongsTo struct { @@ -89,7 +91,7 @@ func TestSelfReferenceBelongsToRel(t *testing.T) { {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, {DBName: "name", Name: "Name", BindNames: []string{"Name"}, IsNormal: true}, {DBName: "belongs_to_key", Name: "BelongsToKey", BindNames: []string{"BelongsToKey"}, IsNormal: true, IsForeignKey: true}, - {DBName: "belongs_to", Name: "BelongsTo", BindNames: []string{"BelongsTo"}, Relationship: &Relationship{Kind: "belongs_to", ForeignKey: []string{"belongs_to_key"}, AssociationForeignKey: []string{"id"}}, TagSettings: map[string]string{"FOREIGNKEY": "BelongsToKey"}}, + {DBName: "belongs_to", Name: "BelongsTo", BindNames: []string{"BelongsTo"}, Relationship: &Relationship{Kind: "belongs_to", ForeignKey: []string{"belongs_to_key"}, AssociationForeignKey: []string{"id"}}, TagSettings: map[string]string{"FOREIGNKEY": "BelongsToKey", "REL": "belongs_to"}}, }, t) type MyStruct3 struct { @@ -341,10 +343,48 @@ func TestManyToManyRel(t *testing.T) { } type MyStruct struct { - ID int - Name string - Many2Many []Many2Many + ID int + Name string + ManyTOMany []Many2Many `gorm:"many2many:m2m"` } - Parse(&MyStruct{}) + schema := Parse(&MyStruct{}) + compareFields(schema.Fields, []*Field{ + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, + {DBName: "name", Name: "Name", BindNames: []string{"Name"}, IsNormal: true}, + {DBName: "many_to_many", Name: "ManyTOMany", BindNames: []string{"ManyTOMany"}, Relationship: &Relationship{Kind: "many_to_many", PolymorphicType: "", PolymorphicDBName: "", PolymorphicValue: "", ForeignKey: []string{"id"}, AssociationForeignKey: []string{"id"}, JointableForeignkey: []string{"my_struct_id"}, AssociationJointableForeignkey: []string{"many2_many_id"}}, TagSettings: map[string]string{"MANY2MANY": "m2m"}}, + }, t) + + type Many2Many2 struct { + ID int `gorm:"column:rel_id"` + Name string + } + + type MyStruct2 struct { + ID int `gorm:"column:my_id"` + Name string + ManyTOMany []Many2Many2 `gorm:"many2many:m2m"` + } + + schema2 := Parse(&MyStruct2{}) + compareFields(schema2.Fields, []*Field{ + {DBName: "my_id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"COLUMN": "my_id"}}, + {DBName: "name", Name: "Name", BindNames: []string{"Name"}, IsNormal: true}, + {DBName: "many_to_many", Name: "ManyTOMany", BindNames: []string{"ManyTOMany"}, Relationship: &Relationship{Kind: "many_to_many", PolymorphicType: "", PolymorphicDBName: "", PolymorphicValue: "", ForeignKey: []string{"my_id"}, AssociationForeignKey: []string{"rel_id"}, JointableForeignkey: []string{"my_struct2_my_id"}, AssociationJointableForeignkey: []string{"many2_many2_rel_id"}}, TagSettings: map[string]string{"MANY2MANY": "m2m"}}, + }, t) +} + +func TestSelfReferenceManyToManyRel(t *testing.T) { + type MyStruct struct { + ID int + Name string + ManyTOMany []MyStruct `gorm:"many2many:m2m;association_jointable_foreignkey:rel_id"` + } + + schema := Parse(&MyStruct{}) + compareFields(schema.Fields, []*Field{ + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, + {DBName: "name", Name: "Name", BindNames: []string{"Name"}, IsNormal: true}, + {DBName: "many_to_many", Name: "ManyTOMany", BindNames: []string{"ManyTOMany"}, Relationship: &Relationship{Kind: "many_to_many", PolymorphicType: "", PolymorphicDBName: "", PolymorphicValue: "", ForeignKey: []string{"id"}, AssociationForeignKey: []string{"id"}, JointableForeignkey: []string{"my_struct_id"}, AssociationJointableForeignkey: []string{"rel_id"}}, TagSettings: map[string]string{"MANY2MANY": "m2m", "ASSOCIATION_JOINTABLE_FOREIGNKEY": "rel_id"}}, + }, t) } diff --git a/schema/schema_test.go b/schema/schema_test.go index 405a0070..36aeda77 100644 --- a/schema/schema_test.go +++ b/schema/schema_test.go @@ -44,7 +44,7 @@ func TestCustomizePrimaryKey(t *testing.T) { schema := Parse(&MyStruct{}) expectedFields := []*Field{ - {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"PRIMARY_KEY": "PRIMARY_KEY"}}, + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, } compareFields(schema.PrimaryFields, expectedFields, t) @@ -77,8 +77,8 @@ func TestEmbeddedStruct(t *testing.T) { expectedFields := []*Field{ {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, {DBName: "name", Name: "Name", BindNames: []string{"EmbedStruct", "Name"}, IsNormal: true}, - {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"COLUMN": "Age"}}, - {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"COLUMN": "Role"}}, + {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"COLUMN": "my_age"}}, + {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"DEFAULT": "guest"}}, } compareFields(schema.Fields, expectedFields, t) @@ -90,25 +90,31 @@ func TestEmbeddedStruct(t *testing.T) { schema2 := Parse(&MyStruct2{}) expectedFields2 := []*Field{ - {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED"}}, + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, {DBName: "name", Name: "Name", BindNames: []string{"EmbedStruct", "Name"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED"}}, - {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "COLUMN": "Age"}}, - {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "COLUMN": "Role"}}, + {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "COLUMN": "my_age"}}, + {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "DEFAULT": "guest"}}, } compareFields(schema2.Fields, expectedFields2, t) // Embedded with prefix + type EmbedStruct2 struct { + Name string + Age string `gorm:"column:my_age"` + Role string `gorm:"default:guest"` + } + type MyStruct3 struct { - ID string - EmbedStruct `gorm:"EMBEDDED_PREFIX:my_"` + ID string + EmbedStruct2 `gorm:"EMBEDDED_PREFIX:my_"` } schema3 := Parse(&MyStruct3{}) expectedFields3 := []*Field{ - {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_"}}, - {DBName: "my_name", Name: "Name", BindNames: []string{"EmbedStruct", "Name"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_"}}, - {DBName: "my_my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_", "COLUMN": "Age"}}, - {DBName: "my_role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_", "COLUMN": "Role"}}, + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, + {DBName: "my_name", Name: "Name", BindNames: []string{"EmbedStruct2", "Name"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_"}}, + {DBName: "my_my_age", Name: "Age", BindNames: []string{"EmbedStruct2", "Age"}, IsNormal: true, TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_", "COLUMN": "my_age"}}, + {DBName: "my_role", Name: "Role", BindNames: []string{"EmbedStruct2", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"EMBEDDED_PREFIX": "my_", "DEFAULT": "guest"}}, } compareFields(schema3.Fields, expectedFields3, t) } @@ -129,8 +135,8 @@ func TestEmbeddedStructWithPrimaryKey(t *testing.T) { expectedFields := []*Field{ {DBName: "id", Name: "ID", BindNames: []string{"EmbedStruct", "ID"}, IsNormal: true, IsPrimaryKey: true}, {DBName: "name", Name: "Name", BindNames: []string{"Name"}, IsNormal: true}, - {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"COLUMN": "Age"}}, - {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"COLUMN": "Role"}}, + {DBName: "my_age", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"COLUMN": "my_age"}}, + {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"DEFAULT": "guest"}}, } compareFields(schema.Fields, expectedFields, t) } @@ -155,7 +161,7 @@ func TestOverwriteEmbeddedStructFields(t *testing.T) { {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, {DBName: "name", Name: "Name", BindNames: []string{"EmbedStruct", "Name"}, IsNormal: true}, {DBName: "my_age2", Name: "Age", BindNames: []string{"Age"}, IsNormal: true, TagSettings: map[string]string{"ON_EMBEDDED_CONFLICT": "replace", "COLUMN": "my_age2"}}, - {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"COLUMN": "Role"}}, + {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"DEFAULT": "guest"}}, } compareFields(schema.Fields, expectedFields, t) @@ -173,7 +179,7 @@ func TestOverwriteEmbeddedStructFields(t *testing.T) { {DBName: "name", Name: "Name", BindNames: []string{"EmbedStruct", "Name"}, IsNormal: true}, {DBName: "my_name2", Name: "Name2", BindNames: []string{"Name2"}, IsNormal: true, TagSettings: map[string]string{"ON_EMBEDDED_CONFLICT": "ignore", "COLUMN": "my_name2"}}, {DBName: "my_age2", Name: "Age", BindNames: []string{"EmbedStruct", "Age"}, IsNormal: true, TagSettings: map[string]string{"ON_EMBEDDED_CONFLICT": "update", "COLUMN": "my_age2"}}, - {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"COLUMN": "Role"}}, + {DBName: "role", Name: "Role", BindNames: []string{"EmbedStruct", "Role"}, IsNormal: true, HasDefaultValue: true, DefaultValue: "guest", TagSettings: map[string]string{"DEFAULT": "guest"}}, } compareFields(schema2.Fields, expectedFields2, t) } @@ -194,7 +200,7 @@ func TestOverwriteEmbeddedStructPrimaryFields(t *testing.T) { schema := Parse(&MyStruct{}) expectedFields := []*Field{ - {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"PRIMARY_KEY": "PRIMARY_KEY"}}, + {DBName: "id", Name: "ID", BindNames: []string{"ID"}, IsNormal: true, IsPrimaryKey: true}, } compareFields(schema.PrimaryFields, expectedFields, t) @@ -223,7 +229,7 @@ func TestOverwriteEmbeddedStructPrimaryFields(t *testing.T) { schema3 := Parse(&MyStruct3{}) expectedFields3 := []*Field{ - {DBName: "email", Name: "Email", BindNames: []string{"Email"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"PRIMARY_KEY": "PRIMARY_KEY", "ON_EMBEDDED_CONFLICT": "update"}}, + {DBName: "email", Name: "Email", BindNames: []string{"Email"}, IsNormal: true, IsPrimaryKey: true, TagSettings: map[string]string{"PRIMARY_KEY": "PRIMARY_KEY", "ON_EMBEDDED_CONFLICT": "replace"}}, } compareFields(schema3.PrimaryFields, expectedFields3, t) } @@ -266,7 +272,7 @@ func fieldEqual(got, expected *Field) error { return fmt.Errorf("field BindNames should be %#v, got %#v", expected.BindNames, got.BindNames) } - if (expected.TagSettings == nil && len(got.TagSettings) != 0) && !reflect.DeepEqual(expected.TagSettings, got.TagSettings) { + if (expected.TagSettings == nil && len(got.TagSettings) != 0) || (expected.TagSettings != nil && !reflect.DeepEqual(expected.TagSettings, got.TagSettings)) { return fmt.Errorf("field TagSettings should be %#v, got %#v", expected.TagSettings, got.TagSettings) } diff --git a/schema/utils.go b/schema/utils.go index b75f5ad6..1e11a516 100644 --- a/schema/utils.go +++ b/schema/utils.go @@ -86,9 +86,9 @@ func getPrimaryPrimaryField(fields []*Field) *Field { func parseTagSetting(tags reflect.StructTag) map[string]string { setting := map[string]string{} for _, str := range []string{tags.Get("sql"), tags.Get("gorm")} { - if str != "" { - tags := strings.Split(str, ";") - for _, value := range tags { + tags := strings.Split(str, ";") + for _, value := range tags { + if value != "" { v := strings.Split(value, ":") k := strings.TrimSpace(strings.ToUpper(v[0])) if len(v) >= 2 {