42Atomys/webhooked

View on GitHub
pkg/factory/mapstructure_decode.go

Summary

Maintainability
A
0 mins
Test Coverage
package factory

import (
    "fmt"
    "reflect"

    "atomys.codes/webhooked/internal/valuable"
)

// DecodeHook is a mapstructure.DecodeHook that serializes
// the given data into a InputConfig with a name and a Valuable object.
// mapstructure cannot nested objects, so we need to serialize the
// data into a map[string]interface{} and then deserialize it into
// a InputConfig.
//
// @see https://pkg.go.dev/github.com/mitchellh/mapstructure#DecodeHookFunc for more details.
func DecodeHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
    if t != reflect.TypeOf(InputConfig{}) {
        return data, nil
    }

    v, err := valuable.SerializeValuable(data)
    if err != nil {
        return nil, err
    }

    var name = ""
    for k, v2 := range rangeOverInterfaceMap(data) {
        if fmt.Sprintf("%v", k) == "name" {
            name = fmt.Sprintf("%s", v2)
            break
        }
    }

    if err != nil {
        return nil, err
    }

    return &InputConfig{
        Valuable: *v,
        Name:     name,
    }, nil
}

// rangeOverInterfaceMap iterates over the given interface map to convert it
// into a map[string]interface{}. This is needed because mapstructure cannot
// handle objects that are not of type map[string]interface{} for obscure reasons.
func rangeOverInterfaceMap(data interface{}) map[string]interface{} {
    transformedData, ok := data.(map[string]interface{})
    if !ok {
        transformedData = make(map[string]interface{})
        for k, v := range data.(map[interface{}]interface{}) {
            transformedData[fmt.Sprintf("%v", k)] = v
        }
    }

    return transformedData
}