Refactor the structInfo struct so it can accept more information

pull/2/head
Vinícius Garcia 2021-02-28 12:25:42 -03:00
parent 933ded26f4
commit f5b7ab8028
3 changed files with 54 additions and 18 deletions

View File

@ -228,3 +228,7 @@ ok github.com/vingarcia/kissorm 21.740s
- Implement support for nested objects with prefixed table names - Implement support for nested objects with prefixed table names
- Improve error messages - Improve error messages
- Add tests for tables using composite keys - Add tests for tables using composite keys
### Optimizations Oportunities
- Test if using a pointer on the field info is faster or not

View File

@ -381,7 +381,7 @@ func (c DB) insertWithReturningID(
for _, id := range idNames { for _, id := range idNames {
scanFields = append( scanFields = append(
scanFields, scanFields,
v.Elem().Field(info.Index[id]).Addr().Interface(), v.Elem().Field(info.ByName(id).Index).Addr().Interface(),
) )
} }
err = rows.Scan(scanFields...) err = rows.Scan(scanFields...)
@ -420,7 +420,7 @@ func (c DB) insertWithLastInsertID(
vID := reflect.ValueOf(id) vID := reflect.ValueOf(id)
tID := vID.Type() tID := vID.Type()
fieldAddr := v.Elem().Field(info.Index[idName]).Addr() fieldAddr := v.Elem().Field(info.ByName(idName).Index).Addr()
fieldType := fieldAddr.Type().Elem() fieldType := fieldAddr.Type().Elem()
if !tID.ConvertibleTo(fieldType) { if !tID.ConvertibleTo(fieldType) {
@ -753,10 +753,11 @@ func scanRows(rows *sql.Rows, record interface{}) error {
scanArgs := []interface{}{} scanArgs := []interface{}{}
for _, name := range names { for _, name := range names {
idx, found := info.Index[name] fieldInfo := info.ByName(name)
valueScanner := v.Field(idx).Addr()
if !found { valueScanner := nopScannerValue
valueScanner = nopScannerValue if fieldInfo.Valid {
valueScanner = v.Field(fieldInfo.Index).Addr()
} }
scanArgs = append(scanArgs, valueScanner.Interface()) scanArgs = append(scanArgs, valueScanner.Interface())

View File

@ -8,8 +8,36 @@ import (
) )
type structInfo struct { type structInfo struct {
Names map[int]string byIndex map[int]*fieldInfo
Index map[string]int byName map[string]*fieldInfo
}
type fieldInfo struct {
Name string
Index int
Valid bool
}
func (s structInfo) ByIndex(idx int) *fieldInfo {
field, found := s.byIndex[idx]
if !found {
return &fieldInfo{}
}
return field
}
func (s structInfo) ByName(name string) *fieldInfo {
field, found := s.byName[name]
if !found {
return &fieldInfo{}
}
return field
}
func (s structInfo) Add(field fieldInfo) {
field.Valid = true
s.byIndex[field.Index] = &field
s.byName[field.Name] = &field
} }
// This cache is kept as a pkg variable // This cache is kept as a pkg variable
@ -72,7 +100,7 @@ func StructToMap(obj interface{}) (map[string]interface{}, error) {
field = field.Elem() field = field.Elem()
} }
m[info.Names[i]] = field.Interface() m[info.ByIndex(i).Name] = field.Interface()
} }
return m, nil return m, nil
@ -107,15 +135,15 @@ func FillStructWith(record interface{}, dbRow map[string]interface{}) error {
info := getCachedTagInfo(tagInfoCache, t) info := getCachedTagInfo(tagInfoCache, t)
for colName, rawSrc := range dbRow { for colName, rawSrc := range dbRow {
fieldIdx, found := info.Index[colName] fieldInfo := info.ByName(colName)
if !found { if !fieldInfo.Valid {
// Ignore columns not tagged with `kissorm:""` // Ignore columns not tagged with `kissorm:"..."`
continue continue
} }
src := NewPtrConverter(rawSrc) src := NewPtrConverter(rawSrc)
dest := v.Field(fieldIdx) dest := v.Field(fieldInfo.Index)
destType := t.Field(info.Index[colName]).Type destType := t.Field(fieldInfo.Index).Type
destValue, err := src.Convert(destType) destValue, err := src.Convert(destType)
if err != nil { if err != nil {
@ -259,16 +287,19 @@ func FillSliceWith(entities interface{}, dbRows []map[string]interface{}) error
// which improves performance by a lot. // which improves performance by a lot.
func getTagNames(t reflect.Type) structInfo { func getTagNames(t reflect.Type) structInfo {
info := structInfo{ info := structInfo{
Names: map[int]string{}, byIndex: map[int]*fieldInfo{},
Index: map[string]int{}, byName: map[string]*fieldInfo{},
} }
for i := 0; i < t.NumField(); i++ { for i := 0; i < t.NumField(); i++ {
name := t.Field(i).Tag.Get("kissorm") name := t.Field(i).Tag.Get("kissorm")
if name == "" { if name == "" {
continue continue
} }
info.Names[i] = name
info.Index[name] = i info.Add(fieldInfo{
Name: name,
Index: i,
})
} }
return info return info