86 lines
2.3 KiB
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()
|
|
}
|