3
0

Support "final" flag for KV

This enables us to store structure as JSON under a specific
(final) key
This commit is contained in:
Denis Arh
2020-04-19 10:15:15 +02:00
parent b254ebd686
commit 47bb9ab45a
2 changed files with 64 additions and 26 deletions

View File

@@ -48,7 +48,10 @@ func DecodeKV(kv KV, dst interface{}, pp ...string) (err error) {
length := valueOf.NumField()
for i := 0; i < length; i++ {
var structField = valueOf.Field(i)
var (
structField = valueOf.Field(i)
tags = make(map[string]bool)
)
if !structField.CanSet() {
continue
@@ -80,6 +83,7 @@ func DecodeKV(kv KV, dst interface{}, pp ...string) (err error) {
for f := 1; f < len(tagFlags); f++ {
// @todo resolve i18n and other flags...
tags[tagFlags[f]] = true
}
}
@@ -102,36 +106,38 @@ func DecodeKV(kv KV, dst interface{}, pp ...string) (err error) {
}
}
// Handles structs
//
// It calls DecodeKV recursively
if structField.Kind() == reflect.Struct {
if err = DecodeKV(kv.Filter(key), structValue, key); err != nil {
return
}
continue
}
// Handles map values
if structField.Kind() == reflect.Map {
if structField.IsNil() {
// allocate new map
structField.Set(reflect.MakeMap(structField.Type()))
}
// cut KV key prefix and use the rest for the map key
for k, val := range kv.CutPrefix(key + ".") {
mapValue := reflect.New(structField.Type().Elem())
err = val.Unmarshal(mapValue.Interface())
if err != nil {
if !tags["final"] {
// Handles structs
//
// It calls DecodeKV recursively
if structField.Kind() == reflect.Struct {
if err = DecodeKV(kv.Filter(key), structValue, key); err != nil {
return
}
structField.SetMapIndex(reflect.ValueOf(k), mapValue.Elem())
continue
}
continue
// Handles map values
if structField.Kind() == reflect.Map {
if structField.IsNil() {
// allocate new map
structField.Set(reflect.MakeMap(structField.Type()))
}
// cut KV key prefix and use the rest for the map key
for k, val := range kv.CutPrefix(key + ".") {
mapValue := reflect.New(structField.Type().Elem())
err = val.Unmarshal(mapValue.Interface())
if err != nil {
return
}
structField.SetMapIndex(reflect.ValueOf(k), mapValue.Elem())
}
continue
}
}
// Native type

View File

@@ -1,6 +1,7 @@
package settings
import (
"github.com/davecgh/go-spew/spew"
"testing"
"github.com/jmoiron/sqlx/types"
@@ -132,3 +133,34 @@ func TestDecodeHandler(t *testing.T) {
require.Equal(t, 1, aux.Foo.set)
require.Equal(t, 1, aux.Bar.set)
}
func TestDecodeKV_WithFinalTag(t *testing.T) {
type (
dst struct {
NotFinal struct {
Foo string
Sub struct {
SubFoo int
}
}
IsFinal struct {
Foo string
Sub struct {
SubFoo int
}
} `kv:",final"`
}
)
var (
aux = dst{}
kv = KV{
"notFinal.foo": types.JSONText(`"42"`),
"notFinal.sub.subFoo": types.JSONText(`42`),
"isFinal": types.JSONText(`{"Foo":"final42","Sub":{"SubFoo":42}}`),
}
)
spew.Dump(DecodeKV(kv, &aux), aux)
}