How to use mapstructure with google uuid
Hi,
i'm just trying to decode a map into a struct with uuid but it looks like its not working out of the box.
So is there a trick to get mapstructure working with uuid of google?
Here is a small playground. https://play.golang.org/p/Gn08PEr9shS
Thanks
You could create your own hook, something like:
func StringToUUIDHookFunc() DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(uuid.UUID{}) {
return data, nil
}
return uuid.Parse(data.(string))
}
}
ah okay.. how should this be used exactly in the decode function?
You need to set the hook in the configuration, for example:
func decode(input, output interface{}) error {
config := &mapstructure.DecoderConfig{
DecodeHook: mapstructure.ComposeDecodeHookFunc(
stringToUUIDHookFunc(),
),
Result: &output,
}
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
return err
}
return decoder.Decode(input)
}
func stringToUUIDHookFunc() mapstructure.DecodeHookFunc {
return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(uuid.UUID{}) {
return data, nil
}
return uuid.Parse(data.(string))
}
}
@alex-rufo Thanks for the example.
maybe this could be added somewhere as example? i guess UUID is a common use case for a lot of devs?
Hi,
@alex-rufo
Is it possible to use a custom hook when converting (in the other direction) from a struct to a map ?
I am using the shopspring/decimal package and the monetary type is decimal.Decimal - I would like to represent it as either a float or string in my map,
How can I achieve this?
Thank you
https://play.golang.org/p/IVR-c4rGr0Q
Hi,
@alex-rufo
Is it possible to use a custom hook when converting (in the other direction) from a struct to a map ?
I am using the
shopspring/decimalpackage and the monetary type isdecimal.Decimal- I would like to represent it as either a float or string in my map,How can I achieve this?
Thank you
https://play.golang.org/p/IVR-c4rGr0Q
How about this?
func StringToDecimalFunc() mapstructure.DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(decimal.Decimal{}) {
return data, nil
}
return decimal.NewFromString(data.(string))
}
}
func Decode(input interface{}, result interface{}) error {
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Metadata: nil,
DecodeHook: mapstructure.ComposeDecodeHookFunc(
StringToDecimalFunc()),
Result: result,
})
if err != nil {
return err
}
if err := decoder.Decode(input); err != nil {
return err
}
return err
}
You need to set the hook in the configuration, for example:
func decode(input, output interface{}) error { config := &mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( stringToUUIDHookFunc(), ), Result: &output, } decoder, err := mapstructure.NewDecoder(config) if err != nil { return err } return decoder.Decode(input) } func stringToUUIDHookFunc() mapstructure.DecodeHookFunc { return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { if f.Kind() != reflect.String { return data, nil } if t != reflect.TypeOf(uuid.UUID{}) { return data, nil } return uuid.Parse(data.(string)) } }
One issue I've noticed, which is specific to https://github.com/google/uuid, is that it is not possible to have mapstructure decode a *uuid.UUID field to nil. This is because uuid.UUID is a [16]byte array, and mapstructure always populates a zero value UUID for *uuid.UUID since the decode function always evaluates case reflect.Array.
However, it would be nice if mapstructure had the ability to handle nil uuid values, rather than always falling through to
case reflect.Array:
err = d.decodeArray(name, input, outVal)
Hello,
Thank you very much for this issue.
How can we use UUID when u decode from struct to map[string]string and the struct has a UUID field. I am getting
err: cannot assign type 'uuid.UUID' to map value field of type 'string'
I noticed the DecodeHook behaves differently in this case. It's not called for each field but only once, which makes it hard to change the data.
Any help will be appreciated.