diamond-orm/scan.go

86 lines
2.3 KiB
Go

package orm
import (
"github.com/jackc/pgx/v5"
"reflect"
)
func rowsToMaps(rows pgx.Rows) ([]map[string]any, error) {
var result []map[string]any
fieldDescs := rows.FieldDescriptions()
for rows.Next() {
m := make(map[string]any)
scanArgs := make([]any, len(fieldDescs))
for i := range fieldDescs {
var v any
scanArgs[i] = &v
}
if err := rows.Scan(scanArgs...); err != nil {
return nil, err
}
for i, fd := range fieldDescs {
name := fd.Name
m[name] = *(scanArgs[i].(*any))
}
result = append(result, m)
}
return result, rows.Err()
}
func fillNested(row map[string]any, t reflect.Type, mm *ModelMap, depth, maxDepth int) any {
cm := mm.Map[t.Name()]
pp := reflect.New(cm.Type).Elem()
for _, field := range cm.Fields {
_, alias := field.alias()
if v, ok := row[alias]; ok && !field.isForeignKey {
reflectSet(pp.Field(field.Index), v)
}
}
for _, rel := range cm.Relationships {
if rel.Idx > -1 && rel.Idx < pp.NumField() {
relType := rel.RelatedModel.Type
for relType.Kind() == reflect.Pointer {
relType = relType.Elem()
}
nv := reflect.New(relType)
if rel.Kind == reflect.Struct || rel.Kind == reflect.Pointer {
if depth < maxDepth {
nv = reflect.ValueOf(fillNested(row, relType, mm, depth+1, maxDepth))
}
if rel.Kind != reflect.Pointer && nv.Kind() == reflect.Pointer {
nv = nv.Elem()
}
reflectSet(pp.Field(rel.Idx), nv)
} else if rel.Kind == reflect.Slice || rel.Kind == reflect.Array {
relType2 := relType
for relType2.Kind() == reflect.Slice || relType2.Kind() == reflect.Array {
relType2 = relType2.Elem()
}
if depth < maxDepth {
nv = reflect.ValueOf(fillNested(row, relType2, mm, depth+1, maxDepth))
}
if nv.Kind() == reflect.Pointer {
nv = nv.Elem()
}
reflectSet(pp.Field(rel.Idx), reflect.Append(pp.Field(rel.Idx), nv))
}
}
}
return pp.Interface()
}
// fillSlice - note that it's the caller's responsibility to indirect
// the type in `t`.
func fillSlice(rows []map[string]any, t reflect.Type, mm *ModelMap) any {
pslice := reflect.MakeSlice(reflect.SliceOf(t), 0, 0)
rt := t
for rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
for _, row := range rows {
pp := fillNested(row, rt, mm, 0, 10)
pslice = reflect.Append(pslice, reflect.ValueOf(pp))
}
return pslice.Interface()
}