Skip to content

Commit

Permalink
Added FlattenMap
Browse files Browse the repository at this point in the history
  • Loading branch information
sonnes committed Aug 3, 2023
1 parent e93ac80 commit b5b5c52
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 38 deletions.
14 changes: 0 additions & 14 deletions xload/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,6 @@ func PrefixLoader(prefix string, loader Loader) Loader {
})
}

// MapLoader loads values from a map.
// Mostly used for testing.
type MapLoader map[string]string

// Load fetches the value from the map.
func (m MapLoader) Load(ctx context.Context, key string) (string, error) {
value, ok := m[key]
if !ok {
return "", nil
}

return value, nil
}

// OSLoader loads values from the OS environment.
func OSLoader() Loader {
return LoaderFunc(func(ctx context.Context, key string) (string, error) {
Expand Down
46 changes: 46 additions & 0 deletions xload/maps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package xload

import (
"context"

"github.com/spf13/cast"
)

// MapLoader loads values from a map.
//
// Can be used with xload.FlattenMap as an intermediate format
// when loading from various sources.
type MapLoader map[string]string

// Load fetches the value from the map.
func (m MapLoader) Load(ctx context.Context, key string) (string, error) {
value, ok := m[key]
if !ok {
return "", nil
}

return value, nil
}

// FlattenMap flattens a map[string]interface{} into a map[string]string.
// Nested maps are flattened using given separator.
func FlattenMap(m map[string]interface{}, sep string) map[string]string {
return flatten(m, "", sep)
}

func flatten(m map[string]interface{}, prefix string, sep string) map[string]string {
flattened := make(map[string]string)

for key, value := range m {
switch value := value.(type) {
case map[string]interface{}:
for k, v := range flatten(value, key+sep, sep) {
flattened[prefix+k] = v
}
default:
flattened[prefix+key] = cast.ToString(value)
}
}

return flattened
}
32 changes: 32 additions & 0 deletions xload/maps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package xload

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestFlattenMap(t *testing.T) {
input := map[string]interface{}{
"NAME": "xload",
"VERSION": 1.1,
"AUTHOR": map[string]interface{}{
"NAME": "gojek",
"EMAIL": "[email protected]",
"ADDRESS": map[string]interface{}{
"CITY": "Bombay",
},
},
}

want := map[string]string{
"NAME": "xload",
"VERSION": "1.1",
"AUTHOR_NAME": "gojek",
"AUTHOR_EMAIL": "[email protected]",
"AUTHOR_ADDRESS_CITY": "Bombay",
}

got := FlattenMap(input, "_")
assert.EqualValues(t, want, got)
}
6 changes: 2 additions & 4 deletions xload/providers/yaml/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/spf13/cast v1.5.1
github.com/stretchr/testify v1.8.4
)
require github.com/stretchr/testify v1.8.4

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
)
22 changes: 2 additions & 20 deletions xload/providers/yaml/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ package yaml
import (
"io"

"github.com/spf13/cast"
"gopkg.in/yaml.v3"

"github.com/gojekfarm/xtools/xload"
)

// NewLoader reads YAML from the given io.Reader and returns a xload.Loader
func NewLoader(r io.Reader, delim string) (xload.Loader, error) {
func NewLoader(r io.Reader, sep string) (xload.Loader, error) {
b, err := io.ReadAll(r)
if err != nil {
return nil, err
Expand All @@ -24,22 +23,5 @@ func NewLoader(r io.Reader, delim string) (xload.Loader, error) {
return nil, err
}

return xload.MapLoader(flatten("", delim, out)), nil
}

func flatten(prefix, delim string, data map[string]interface{}) map[string]string {
flattened := make(map[string]string)

for key, value := range data {
switch value := value.(type) {
case map[string]interface{}:
for k, v := range flatten(key+delim, delim, value) {
flattened[prefix+k] = v
}
default:
flattened[prefix+key] = cast.ToString(value)
}
}

return flattened
return xload.MapLoader(xload.FlattenMap(out, sep)), nil
}

0 comments on commit b5b5c52

Please sign in to comment.