v0.0.351 sq value converter
All checks were successful
Build Docker and Deploy / Run goext test-suite (push) Successful in 2m30s

This commit is contained in:
2023-12-29 19:25:36 +01:00
parent 6e90239fef
commit f9ccafb976
12 changed files with 280 additions and 111 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/jmoiron/sqlx"
"github.com/jmoiron/sqlx/reflectx"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"reflect"
)
@@ -15,9 +16,10 @@ type StructScanner struct {
Mapper *reflectx.Mapper
unsafe bool
fields [][]int
values []any
columns []string
fields [][]int
values []any
converter []DBTypeConverter
columns []string
}
func NewStructScanner(rows *sqlx.Rows, unsafe bool) *StructScanner {
@@ -47,13 +49,15 @@ func (r *StructScanner) Start(dest any) error {
return fmt.Errorf("missing destination name %s in %T", columns[f], dest)
}
r.values = make([]interface{}, len(columns))
r.converter = make([]DBTypeConverter, len(columns))
return nil
}
// StructScanExt forked from github.com/jmoiron/sqlx@v1.3.5/sqlx.go
// does also wok with nullabel structs (from LEFT JOIN's)
func (r *StructScanner) StructScanExt(dest any) error {
// does also work with nullabel structs (from LEFT JOIN's)
// does also work with custom value converters
func (r *StructScanner) StructScanExt(q Queryable, dest any) error {
v := reflect.ValueOf(dest)
if v.Kind() != reflect.Ptr {
@@ -64,7 +68,7 @@ func (r *StructScanner) StructScanExt(dest any) error {
v = v.Elem()
err := fieldsByTraversalExtended(v, r.fields, r.values)
err := fieldsByTraversalExtended(q, v, r.fields, r.values, r.converter)
if err != nil {
return err
}
@@ -131,7 +135,6 @@ func (r *StructScanner) StructScanExt(dest any) error {
val1 := reflect.ValueOf(r.values[i])
val2 := val1.Elem()
val3 := val2.Elem()
if val2.IsNil() {
if f.Kind() != reflect.Pointer {
@@ -140,7 +143,16 @@ func (r *StructScanner) StructScanExt(dest any) error {
f.Set(reflect.Zero(f.Type())) // set to nil
} else {
f.Set(val3)
if r.converter[i] != nil {
val3 := val2.Elem().Interface()
conv3, err := r.converter[i].DBToModel(val3)
if err != nil {
return err
}
f.Set(reflect.ValueOf(conv3))
} else {
f.Set(val2.Elem())
}
}
}
@@ -172,7 +184,7 @@ func (r *StructScanner) StructScanBase(dest any) error {
}
// fieldsByTraversal forked from github.com/jmoiron/sqlx@v1.3.5/sqlx.go
func fieldsByTraversalExtended(v reflect.Value, traversals [][]int, values []interface{}) error {
func fieldsByTraversalExtended(q Queryable, v reflect.Value, traversals [][]int, values []interface{}, converter []DBTypeConverter) error {
v = reflect.Indirect(v)
if v.Kind() != reflect.Struct {
return errors.New("argument not a struct")
@@ -185,7 +197,23 @@ func fieldsByTraversalExtended(v reflect.Value, traversals [][]int, values []int
}
f := reflectx.FieldByIndexes(v, traversal)
values[i] = reflect.New(reflect.PointerTo(f.Type())).Interface()
typeStr := f.Type().String()
foundConverter := false
for _, conv := range q.ListConverter() {
if conv.ModelTypeString() == typeStr {
_v := langext.Ptr[any](nil)
values[i] = _v
foundConverter = true
converter[i] = conv
break
}
}
if !foundConverter {
values[i] = reflect.New(reflect.PointerTo(f.Type())).Interface()
converter[i] = nil
}
}
return nil
}