Skip to content

Commit

Permalink
all: Field 取代 FieldByName (ecodeclub#90)
Browse files Browse the repository at this point in the history
* 用Field取代FieldByName,解决ecodeclub#81

mode.go         添加FieldIndexes字段
mode_test.go    测试FieldIndexes字段
reflect.go      使用自定义fieldByIndex方法(本质reflect.Value.Field)替换reflect.Value.FieldByName方法
reflect_test.go 添加BenchmarkReflectValue_fieldByIndexes_VS_FieldByName测试
unsafe_test.go  添加测试用例NullBoolPtr
.CHANGELOG.md   添加all: Field 取代 FieldByName项

Signed-off-by: longyue0521 <[email protected]>

* 修改.CHANGELOG.md中all: Field 取代 FieldByName的链接地址

Signed-off-by: longyue0521 <[email protected]>
  • Loading branch information
longyue0521 authored Aug 23, 2022
1 parent 935ceb4 commit 2747be0
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 39 deletions.
1 change: 1 addition & 0 deletions .CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- [eorm: transaction API](https://github.com/gotomicro/eorm/pull/78)
- [eorm, internal/valuer: 摒弃中间表达,直接依赖于 Scan](https://github.com/gotomicro/eorm/pull/79)
- [eorm:修改 ErrNoRows 的语义,只有在 Get 才会返回](https://github.com/gotomicro/eorm/pull/80)
- [all: Field 取代 FieldByName](https://github.com/gotomicro/eorm/pull/90)

### 文档, 代码质量以及文档
- [Add examples and docs for Aggregate and Assign](https://github.com/gotomicro/eorm/pull/50)
Expand Down
3 changes: 3 additions & 0 deletions internal/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type ColumnMeta struct {
// IsHolderType 用于表达是否是 Holder 的类型
// 所谓的 Holder,就是指同时实现了 sql.Scanner 和 driver.Valuer 两个接口的类型
IsHolderType bool
// FieldIndexes 用于表达从最外层结构体找到当前ColumnMeta对应的Field所需要的索引集
FieldIndexes []int
}

// TableMetaOption represents options of TableMeta, this options will cover default cover.
Expand Down Expand Up @@ -130,6 +132,7 @@ func (t *tagMetaRegistry) Register(table interface{}, opts ...TableMetaOption) (
IsPrimaryKey: isKey,
Offset: structField.Offset,
IsHolderType: structField.Type.AssignableTo(scannerType) && structField.Type.AssignableTo(driverValuerType),
FieldIndexes: []int{i},
}
columnMetas = append(columnMetas, columnMeta)
fieldMap[columnMeta.FieldName] = columnMeta
Expand Down
84 changes: 48 additions & 36 deletions internal/model/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,28 @@ func TestTagMetaRegistry(t *testing.T) {
Typ: reflect.TypeOf(int64(0)),
IsPrimaryKey: true,
IsAutoIncrement: true,
FieldIndexes: []int{0},
},
{
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
FieldIndexes: []int{1},
},
{
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
FieldIndexes: []int{2},
},
{
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
FieldIndexes: []int{3},
},
},
FieldMap: map[string]*ColumnMeta{
Expand All @@ -69,24 +73,28 @@ func TestTagMetaRegistry(t *testing.T) {
Typ: reflect.TypeOf(int64(0)),
IsPrimaryKey: true,
IsAutoIncrement: true,
FieldIndexes: []int{0},
},
"FirstName": {
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
FieldIndexes: []int{1},
},
"Age": {
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
FieldIndexes: []int{2},
},
"LastName": {
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
FieldIndexes: []int{3},
},
},
ColumnMap: map[string]*ColumnMeta{
Expand All @@ -96,24 +104,28 @@ func TestTagMetaRegistry(t *testing.T) {
Typ: reflect.TypeOf(int64(0)),
IsPrimaryKey: true,
IsAutoIncrement: true,
FieldIndexes: []int{0},
},
"first_name": {
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
ColumnName: "first_name",
FieldName: "FirstName",
Typ: reflect.TypeOf(""),
Offset: 8,
FieldIndexes: []int{1},
},
"age": {
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
ColumnName: "age",
FieldName: "Age",
Typ: reflect.TypeOf(int8(0)),
Offset: 24,
FieldIndexes: []int{2},
},
"last_name": {
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
ColumnName: "last_name",
FieldName: "LastName",
Typ: reflect.TypeOf((*string)(nil)),
Offset: 32,
FieldIndexes: []int{3},
},
},
Typ: reflect.TypeOf(&TestModel{}),
Expand Down
18 changes: 15 additions & 3 deletions internal/valuer/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,25 @@ func NewReflectValue(val interface{}, meta *model.TableMeta) Value {

// Field 返回字段值
func (r reflectValue) Field(name string) (any, error) {
res := r.val.FieldByName(name)
if res == (reflect.Value{}) {
res, ok := r.fieldByIndex(name)
if !ok {
return nil, errs.NewInvalidFieldError(name)
}
return res.Interface(), nil
}

func (r reflectValue) fieldByIndex(name string) (reflect.Value, bool) {
cm, ok := r.meta.FieldMap[name]
if !ok {
return reflect.Value{}, false
}
value := r.val
for _, i := range cm.FieldIndexes {
value = value.Field(i)
}
return value, true
}

func (r reflectValue) SetColumns(rows *sql.Rows) error {
cs, err := rows.Columns()
if err != nil {
Expand Down Expand Up @@ -76,7 +88,7 @@ func (r reflectValue) SetColumns(rows *sql.Rows) error {

for i, c := range cs {
cm := r.meta.ColumnMap[c]
fd := r.val.FieldByName(cm.FieldName)
fd, _ := r.fieldByIndex(cm.FieldName)
fd.Set(colEleValues[i])
}
return nil
Expand Down
36 changes: 36 additions & 0 deletions internal/valuer/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package valuer

import (
"database/sql"
"reflect"
"testing"

"github.com/gotomicro/eorm/internal/errs"
Expand Down Expand Up @@ -109,3 +110,38 @@ func BenchmarkReflectValue_Field(b *testing.B) {
assert.Equal(b, int64(13), val)
}
}

func BenchmarkReflectValue_fieldByIndexes_VS_FieldByName(b *testing.B) {
meta, _ := model.NewMetaRegistry().Get(&test.SimpleStruct{})
ins := NewReflectValue(&test.SimpleStruct{Int64: 13}, meta)
in, ok := ins.(reflectValue)
assert.True(b, ok)
fieldName, unknownFieldName := "Int64", "XXXX"
fieldValue, unknownValue := int64(13), reflect.Value{}
b.Run("fieldByIndex found", func(b *testing.B) {
for i := 0; i < b.N; i++ {
val, ok := in.fieldByIndex(fieldName)
assert.True(b, ok)
assert.Equal(b, fieldValue, val.Interface())
}
})
b.Run("fieldByIndex not found", func(b *testing.B) {
for i := 0; i < b.N; i++ {
val, ok := in.fieldByIndex(unknownFieldName)
assert.False(b, ok)
assert.Equal(b, unknownValue, val)
}
})
b.Run("FieldByName found", func(b *testing.B) {
for i := 0; i < b.N; i++ {
val := in.val.FieldByName(fieldName)
assert.Equal(b, fieldValue, val.Interface())
}
})
b.Run("fieldByIndex not found", func(b *testing.B) {
for i := 0; i < b.N; i++ {
val := in.val.FieldByName(unknownFieldName)
assert.Equal(b, unknownValue, val)
}
})
}
5 changes: 5 additions & 0 deletions internal/valuer/unsafe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,11 @@ func newValueFieldTestCases(entity *test.SimpleStruct) []valueFieldTestCase {
field: "NullInt64Ptr",
wantVal: entity.NullInt64Ptr,
},
{
name: "NullBoolPtr",
field: "NullBoolPtr",
wantVal: entity.NullBoolPtr,
},
{
name: "NullFloat64Ptr",
field: "NullFloat64Ptr",
Expand Down

0 comments on commit 2747be0

Please sign in to comment.