This commit is contained in:
Mike Schwörer 2023-06-11 16:35:20 +02:00
parent 7977c0e59c
commit ee262a94fb
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
3 changed files with 138 additions and 57 deletions

View File

@ -1,5 +1,5 @@
package goext package goext
const GoextVersion = "0.0.159" const GoextVersion = "0.0.161"
const GoextVersionTimestamp = "2023-06-10T18:35:56+0200" const GoextVersionTimestamp = "2023-06-11T16:35:20+0200"

View File

@ -1,6 +1,7 @@
package wmo package wmo
import ( import (
"errors"
"gogs.mikescher.com/BlackForestBytes/goext/langext" "gogs.mikescher.com/BlackForestBytes/goext/langext"
"gogs.mikescher.com/BlackForestBytes/goext/reflectext" "gogs.mikescher.com/BlackForestBytes/goext/reflectext"
"reflect" "reflect"
@ -14,7 +15,6 @@ func (c *Coll[TData]) EnsureInitializedReflection(v TData) {
} }
rval := reflect.ValueOf(v) rval := reflect.ValueOf(v)
for rval.Type().Kind() == reflect.Pointer { for rval.Type().Kind() == reflect.Pointer {
rval = rval.Elem() rval = rval.Elem()
} }
@ -69,50 +69,65 @@ func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, m map[string
continue continue
} }
bsontags := make([]string, 0)
bsonkey, found := rsfield.Tag.Lookup("bson") bsonkey, found := rsfield.Tag.Lookup("bson")
if !found { if !found {
continue continue
} }
if strings.Contains(bsonkey, ",") { if strings.Contains(bsonkey, ",") {
bsonkey = bsonkey[:strings.Index(bsonkey, ",")] bsonkey = bsonkey[:strings.Index(bsonkey, ",")]
bsontags = strings.Split(bsonkey[strings.Index(bsonkey, ",")+1:], ",")
} }
if bsonkey == "-" { if bsonkey == "-" {
continue continue
} }
if bsonkey == "" {
bsonkey = rsfield.Name
}
fullKey := prefix + bsonkey fullKey := prefix + bsonkey
newIdxArr := langext.ArrCopy(idxarr) newIdxArr := langext.ArrCopy(idxarr)
newIdxArr = append(newIdxArr, i) newIdxArr = append(newIdxArr, i)
if rvfield.Type().Kind() == reflect.Pointer { if langext.InArray("inline", bsontags) && rvfield.Kind() == reflect.Struct {
m[fullKey] = fullTypeRef{ // pass-through field
IsPointer: true, c.initFields(prefix, rvfield, m, newIdxArr)
RealType: rvfield.Type(),
Kind: rvfield.Type().Elem().Kind(),
Type: rvfield.Type().Elem(),
UnderlyingType: reflectext.Underlying(rvfield.Type().Elem()),
Name: rsfield.Name,
Index: newIdxArr,
}
} else { } else {
m[fullKey] = fullTypeRef{ if rvfield.Type().Kind() == reflect.Pointer {
IsPointer: false,
RealType: rvfield.Type(), m[fullKey] = fullTypeRef{
Kind: rvfield.Type().Kind(), IsPointer: true,
Type: rvfield.Type(), RealType: rvfield.Type(),
UnderlyingType: reflectext.Underlying(rvfield.Type()), Kind: rvfield.Type().Elem().Kind(),
Name: rsfield.Name, Type: rvfield.Type().Elem(),
Index: newIdxArr, UnderlyingType: reflectext.Underlying(rvfield.Type().Elem()),
Name: rsfield.Name,
Index: newIdxArr,
}
} else {
m[fullKey] = fullTypeRef{
IsPointer: false,
RealType: rvfield.Type(),
Kind: rvfield.Type().Kind(),
Type: rvfield.Type(),
UnderlyingType: reflectext.Underlying(rvfield.Type()),
Name: rsfield.Name,
Index: newIdxArr,
}
} }
} if rvfield.Kind() == reflect.Struct {
c.initFields(fullKey+".", rvfield, m, newIdxArr)
}
if rvfield.Kind() == reflect.Struct {
c.initFields(fullKey+".", rvfield, m, newIdxArr)
} }
} }
@ -121,7 +136,10 @@ func (c *Coll[TData]) initFields(prefix string, rval reflect.Value, m map[string
func (c *Coll[TData]) getTokenValueAsMongoType(value string, fieldName string) (any, error) { func (c *Coll[TData]) getTokenValueAsMongoType(value string, fieldName string) (any, error) {
fref := c.dataTypeMap[fieldName] fref, err := c.getFieldType(fieldName)
if err != nil {
return nil, err
}
pss := reflectext.PrimitiveStringSerializer{} pss := reflectext.PrimitiveStringSerializer{}
@ -131,7 +149,10 @@ func (c *Coll[TData]) getTokenValueAsMongoType(value string, fieldName string) (
func (c *Coll[TData]) getFieldValueAsTokenString(entity TData, fieldName string) (string, error) { func (c *Coll[TData]) getFieldValueAsTokenString(entity TData, fieldName string) (string, error) {
realValue := c.getFieldValue(entity, fieldName) realValue, err := c.getFieldValue(entity, fieldName)
if err != nil {
return "", err
}
pss := reflectext.PrimitiveStringSerializer{} pss := reflectext.PrimitiveStringSerializer{}
@ -139,12 +160,56 @@ func (c *Coll[TData]) getFieldValueAsTokenString(entity TData, fieldName string)
} }
func (c *Coll[TData]) getFieldType(fieldName string) fullTypeRef { func (c *Coll[TData]) getFieldType(fieldName string) (fullTypeRef, error) {
return c.dataTypeMap[fieldName] if c.isInterfaceDataType {
for _, m := range c.implDataTypeMap {
if r, ok := m[fieldName]; ok {
return r, nil
}
}
return fullTypeRef{}, errors.New("unknown field: '" + fieldName + "' (in any impl)")
} else {
if r, ok := c.dataTypeMap[fieldName]; ok {
return r, nil
} else {
return fullTypeRef{}, errors.New("unknown field: '" + fieldName + "'")
}
}
} }
func (c *Coll[TData]) getFieldValue(data TData, fieldName string) any { func (c *Coll[TData]) getFieldValue(data TData, fieldName string) (any, error) {
fref := c.dataTypeMap[fieldName] if c.isInterfaceDataType {
rval := reflect.ValueOf(data)
return rval.FieldByIndex(fref.Index).Interface() rval := reflect.ValueOf(data)
for rval.Type().Kind() == reflect.Pointer {
rval = rval.Elem()
}
if m, ok := c.implDataTypeMap[rval.Type()]; ok {
if fref, ok := m[fieldName]; ok {
rval := reflect.ValueOf(data)
return rval.FieldByIndex(fref.Index).Interface(), nil
} else {
return nil, errors.New("unknown bson field '" + fieldName + "' in type '" + rval.Type().String() + "'")
}
} else {
return nil, errors.New("unknown TData type: '" + rval.Type().String() + "'")
}
} else {
if fref, ok := c.dataTypeMap[fieldName]; ok {
rval := reflect.ValueOf(data)
return rval.FieldByIndex(fref.Index).Interface(), nil
} else {
return nil, errors.New("unknown bson field '" + fieldName + "'")
}
}
} }

View File

@ -48,35 +48,51 @@ func TestReflectionGetFieldType(t *testing.T) {
MDate: t1, MDate: t1,
} }
tst.AssertEqual(t, coll.getFieldType("_id").Kind.String(), "string") gft := func(k string) fullTypeRef {
tst.AssertEqual(t, coll.getFieldType("_id").Type.String(), "wmo.IDType") v, err := coll.getFieldType(k)
tst.AssertEqual(t, coll.getFieldType("_id").Name, "ID") if err != nil {
tst.AssertEqual(t, coll.getFieldType("_id").IsPointer, false) t.Errorf("%s: %v", "failed to getFieldType", err)
tst.AssertEqual(t, coll.getFieldValue(d, "_id").(IDType), "1") }
return v
}
tst.AssertEqual(t, coll.getFieldType("cdate").Kind.String(), "struct") gfv := func(k string) any {
tst.AssertEqual(t, coll.getFieldType("cdate").Type.String(), "time.Time") v, err := coll.getFieldValue(d, k)
tst.AssertEqual(t, coll.getFieldType("cdate").Name, "CDate") if err != nil {
tst.AssertEqual(t, coll.getFieldType("cdate").IsPointer, false) t.Errorf("%s: %v", "failed to getFieldType", err)
tst.AssertEqual(t, coll.getFieldValue(d, "cdate").(time.Time), t0) }
return v
}
tst.AssertEqual(t, coll.getFieldType("sub.a").Kind.String(), "string") tst.AssertEqual(t, gft("_id").Kind.String(), "string")
tst.AssertEqual(t, coll.getFieldType("sub.a").Type.String(), "string") tst.AssertEqual(t, gft("_id").Type.String(), "wmo.IDType")
tst.AssertEqual(t, coll.getFieldType("sub.a").Name, "A") tst.AssertEqual(t, gft("_id").Name, "ID")
tst.AssertEqual(t, coll.getFieldType("sub.a").IsPointer, false) tst.AssertEqual(t, gft("_id").IsPointer, false)
tst.AssertEqual(t, coll.getFieldValue(d, "sub.a").(string), "2") tst.AssertEqual(t, gfv("_id").(IDType), "1")
tst.AssertEqual(t, coll.getFieldType("str").Kind.String(), "string") tst.AssertEqual(t, gft("cdate").Kind.String(), "struct")
tst.AssertEqual(t, coll.getFieldType("str").Type.String(), "string") tst.AssertEqual(t, gft("cdate").Type.String(), "time.Time")
tst.AssertEqual(t, coll.getFieldType("str").Name, "Str") tst.AssertEqual(t, gft("cdate").Name, "CDate")
tst.AssertEqual(t, coll.getFieldType("str").IsPointer, false) tst.AssertEqual(t, gft("cdate").IsPointer, false)
tst.AssertEqual(t, coll.getFieldValue(d, "str").(string), "3") tst.AssertEqual(t, gfv("cdate").(time.Time), t0)
tst.AssertEqual(t, coll.getFieldType("ptr").Kind.String(), "int") tst.AssertEqual(t, gft("sub.a").Kind.String(), "string")
tst.AssertEqual(t, coll.getFieldType("ptr").Type.String(), "int") tst.AssertEqual(t, gft("sub.a").Type.String(), "string")
tst.AssertEqual(t, coll.getFieldType("ptr").Name, "Ptr") tst.AssertEqual(t, gft("sub.a").Name, "A")
tst.AssertEqual(t, coll.getFieldType("ptr").IsPointer, true) tst.AssertEqual(t, gft("sub.a").IsPointer, false)
tst.AssertEqual(t, *coll.getFieldValue(d, "ptr").(*int), 4) tst.AssertEqual(t, gfv("sub.a").(string), "2")
tst.AssertEqual(t, gft("str").Kind.String(), "string")
tst.AssertEqual(t, gft("str").Type.String(), "string")
tst.AssertEqual(t, gft("str").Name, "Str")
tst.AssertEqual(t, gft("str").IsPointer, false)
tst.AssertEqual(t, gfv("str").(string), "3")
tst.AssertEqual(t, gft("ptr").Kind.String(), "int")
tst.AssertEqual(t, gft("ptr").Type.String(), "int")
tst.AssertEqual(t, gft("ptr").Name, "Ptr")
tst.AssertEqual(t, gft("ptr").IsPointer, true)
tst.AssertEqual(t, *gfv("ptr").(*int), 4)
} }
func TestReflectionGetTokenValueAsMongoType(t *testing.T) { func TestReflectionGetTokenValueAsMongoType(t *testing.T) {