Fix NamingStrategy with embedded struct, close #3513

This commit is contained in:
Jinzhu 2020-09-24 11:32:38 +08:00
parent 68920449f9
commit 1a526e6802
7 changed files with 107 additions and 3 deletions

View File

@ -326,7 +326,7 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
cacheStore := &sync.Map{}
cacheStore.Store(embeddedCacheKey, true)
if field.EmbeddedSchema, err = Parse(fieldValue.Interface(), cacheStore, schema.namer); err != nil {
if field.EmbeddedSchema, err = Parse(fieldValue.Interface(), cacheStore, embeddedNamer{Table: schema.Table, Namer: schema.namer}); err != nil {
schema.err = err
}

View File

@ -14,7 +14,7 @@ import (
type Namer interface {
TableName(table string) string
ColumnName(table, column string) string
JoinTableName(table string) string
JoinTableName(joinTable string) string
RelationshipFKName(Relationship) string
CheckerName(table, column string) string
IndexName(table, column string) string

View File

@ -1,6 +1,7 @@
package schema
import (
"strings"
"testing"
)
@ -32,3 +33,28 @@ func TestToDBName(t *testing.T) {
}
}
}
type NewNamingStrategy struct {
NamingStrategy
}
func (ns NewNamingStrategy) ColumnName(table, column string) string {
baseColumnName := ns.NamingStrategy.ColumnName(table, column)
if table == "" {
return baseColumnName
}
s := strings.Split(table, "_")
var prefix string
switch len(s) {
case 1:
prefix = s[0][:3]
case 2:
prefix = s[0][:1] + s[1][:2]
default:
prefix = s[0][:1] + s[1][:1] + s[2][:1]
}
return prefix + "_" + baseColumnName
}

View File

@ -97,6 +97,9 @@ func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error)
if tabler, ok := modelValue.Interface().(Tabler); ok {
tableName = tabler.TableName()
}
if en, ok := namer.(embeddedNamer); ok {
tableName = en.Table
}
schema := &Schema{
Name: modelType.Name(),

View File

@ -1,6 +1,7 @@
package schema_test
import (
"strings"
"sync"
"testing"
@ -227,3 +228,72 @@ func TestEmbeddedStruct(t *testing.T) {
})
}
}
type CustomizedNamingStrategy struct {
schema.NamingStrategy
}
func (ns CustomizedNamingStrategy) ColumnName(table, column string) string {
baseColumnName := ns.NamingStrategy.ColumnName(table, column)
if table == "" {
return baseColumnName
}
s := strings.Split(table, "_")
var prefix string
switch len(s) {
case 1:
prefix = s[0][:3]
case 2:
prefix = s[0][:1] + s[1][:2]
default:
prefix = s[0][:1] + s[1][:1] + s[2][:1]
}
return prefix + "_" + baseColumnName
}
func TestEmbeddedStructForCustomizedNamingStrategy(t *testing.T) {
type CorpBase struct {
gorm.Model
OwnerID string
}
type Company struct {
ID int
OwnerID int
Name string
Ignored string `gorm:"-"`
}
type Corp struct {
CorpBase
Base Company `gorm:"embedded;embeddedPrefix:company_"`
}
cropSchema, err := schema.Parse(&Corp{}, &sync.Map{}, CustomizedNamingStrategy{schema.NamingStrategy{}})
if err != nil {
t.Fatalf("failed to parse embedded struct with primary key, got error %v", err)
}
fields := []schema.Field{
{Name: "ID", DBName: "cor_id", BindNames: []string{"CorpBase", "Model", "ID"}, DataType: schema.Uint, PrimaryKey: true, Size: 64, HasDefaultValue: true, AutoIncrement: true, TagSettings: map[string]string{"PRIMARYKEY": "PRIMARYKEY"}},
{Name: "ID", DBName: "company_cor_id", BindNames: []string{"Base", "ID"}, DataType: schema.Int, Size: 64, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "EMBEDDEDPREFIX": "company_"}},
{Name: "Name", DBName: "company_cor_name", BindNames: []string{"Base", "Name"}, DataType: schema.String, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "EMBEDDEDPREFIX": "company_"}},
{Name: "Ignored", BindNames: []string{"Base", "Ignored"}, TagSettings: map[string]string{"-": "-", "EMBEDDED": "EMBEDDED", "EMBEDDEDPREFIX": "company_"}},
{Name: "OwnerID", DBName: "company_cor_owner_id", BindNames: []string{"Base", "OwnerID"}, DataType: schema.Int, Size: 64, TagSettings: map[string]string{"EMBEDDED": "EMBEDDED", "EMBEDDEDPREFIX": "company_"}},
{Name: "OwnerID", DBName: "cor_owner_id", BindNames: []string{"CorpBase", "OwnerID"}, DataType: schema.String},
}
for _, f := range fields {
checkSchemaField(t, cropSchema, &f, func(f *schema.Field) {
if f.Name != "Ignored" {
f.Creatable = true
f.Updatable = true
f.Readable = true
}
})
}
}

View File

@ -190,3 +190,8 @@ func ToQueryValues(table string, foreignKeys []string, foreignValues [][]interfa
return columns, queryValues
}
}
type embeddedNamer struct {
Table string
Namer
}

View File

@ -7,7 +7,7 @@ require (
github.com/jinzhu/now v1.1.1
github.com/lib/pq v1.6.0
gorm.io/driver/mysql v1.0.1
gorm.io/driver/postgres v1.0.0
gorm.io/driver/postgres v1.0.1
gorm.io/driver/sqlite v1.1.3
gorm.io/driver/sqlserver v1.0.4
gorm.io/gorm v1.20.1