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

View File

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