2022-06-20 21:27:41 +03:00
|
|
|
// Package mapstruct maps struct <-> JSON using came case <-> snake case
|
|
|
|
// also set default values based on struct tags
|
|
|
|
package mapstruct
|
|
|
|
|
|
|
|
// TODO: implement own version as we don't need much?
|
|
|
|
|
|
|
|
import (
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
|
2022-06-01 17:55:55 +03:00
|
|
|
"github.com/creasty/defaults"
|
2022-06-20 21:27:41 +03:00
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
)
|
|
|
|
|
|
|
|
var camelToSnakeRe = regexp.MustCompile(`[[:lower:]][[:upper:]]`)
|
|
|
|
|
|
|
|
// "AaaBbb" -> "aaa_bbb"
|
|
|
|
func CamelToSnake(s string) string {
|
|
|
|
return strings.ToLower(camelToSnakeRe.ReplaceAllStringFunc(s, func(s string) string {
|
|
|
|
return s[0:1] + "_" + s[1:2]
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
func ToStruct(m any, v any) error {
|
2022-06-01 17:55:55 +03:00
|
|
|
_ = defaults.Set(v)
|
2022-06-20 21:27:41 +03:00
|
|
|
ms, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
|
|
|
MatchName: func(mapKey, fieldName string) bool {
|
|
|
|
return CamelToSnake(fieldName) == mapKey
|
|
|
|
},
|
|
|
|
TagName: "mapstruct",
|
|
|
|
Result: v,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := ms.Decode(m); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-07-10 11:49:09 +03:00
|
|
|
func CamelCase(v any) any {
|
|
|
|
switch vv := v.(type) {
|
|
|
|
case map[string]any:
|
|
|
|
n := map[string]any{}
|
|
|
|
for k, v := range vv {
|
|
|
|
n[CamelToSnake(k)] = CamelCase(v)
|
2022-06-20 21:27:41 +03:00
|
|
|
}
|
2022-07-10 11:49:09 +03:00
|
|
|
return n
|
|
|
|
case []any:
|
|
|
|
n := make([]any, len(vv))
|
|
|
|
for i, v := range vv {
|
|
|
|
n[i] = CamelCase(v)
|
|
|
|
}
|
|
|
|
return n
|
2022-06-20 21:27:41 +03:00
|
|
|
}
|
2022-07-10 11:49:09 +03:00
|
|
|
return v
|
2022-06-20 21:27:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func ToMap(v any) (map[string]any, error) {
|
|
|
|
m := map[string]any{}
|
|
|
|
ms, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
|
|
|
Result: &m,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := ms.Decode(v); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-10 11:49:09 +03:00
|
|
|
m, ok := CamelCase(m).(map[string]any)
|
|
|
|
if !ok {
|
|
|
|
panic("not map")
|
|
|
|
}
|
2022-06-20 21:27:41 +03:00
|
|
|
|
2022-07-10 11:49:09 +03:00
|
|
|
return m, nil
|
2022-06-20 21:27:41 +03:00
|
|
|
}
|