Skip to content

Commit

Permalink
add support for maps with as value with primitive types
Browse files Browse the repository at this point in the history
  • Loading branch information
d-enk authored and iamolegga committed Oct 2, 2023
1 parent 66e9666 commit 76a709d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 40 deletions.
83 changes: 43 additions & 40 deletions enviper.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package enviper

import (
"github.com/mitchellh/mapstructure"
"reflect"
"strings"

"github.com/mitchellh/mapstructure"

"github.com/spf13/viper"
)

Expand Down Expand Up @@ -73,53 +74,55 @@ func (e *Enviper) bindEnvs(in interface{}, prev ...string) {
if ifv.Kind() == reflect.Ptr {
ifv = ifv.Elem()
}
for i := 0; i < ifv.NumField(); i++ {
fv := ifv.Field(i)
if fv.Kind() == reflect.Ptr {
if fv.IsZero() {
fv = reflect.New(fv.Type().Elem()).Elem()
} else {
fv = fv.Elem()
}
}
t := ifv.Type().Field(i)
tv, ok := t.Tag.Lookup(e.TagName())
if ok {
if index := strings.Index(tv, ","); index != -1 {
if tv[:index] == "-" {
continue
}

// If "squash" is specified in the tag, we squash the field down.
if strings.Index(tv[index+1:], "squash") != -1 {
e.bindEnvs(fv.Interface(), prev...)
continue
switch ifv.Kind() {
case reflect.Struct:
for i := 0; i < ifv.NumField(); i++ {
fv := ifv.Field(i)
if fv.Kind() == reflect.Ptr {
if fv.IsZero() {
fv = reflect.New(fv.Type().Elem()).Elem()
} else {
fv = fv.Elem()
}

tv = tv[:index]
}
t := ifv.Type().Field(i)
tv, ok := t.Tag.Lookup(e.TagName())
if ok {
if index := strings.Index(tv, ","); index != -1 {
if tv[:index] == "-" {
continue
}

// If "squash" is specified in the tag, we squash the field down.
if strings.Contains(tv[index+1:], "squash") {
e.bindEnvs(fv.Interface(), prev...)
continue
}

if tv == "" {
tv = tv[:index]
}

if tv == "" {
tv = t.Name
}
} else {
tv = t.Name
}
} else {
tv = t.Name
}
switch fv.Kind() {
case reflect.Struct:

e.bindEnvs(fv.Interface(), append(prev, tv)...)
case reflect.Map:
iter := fv.MapRange()
for iter.Next() {
if key, ok := iter.Key().Interface().(string); ok {
e.bindEnvs(iter.Value().Interface(), append(prev, tv, key)...)
}
}
case reflect.Map:
iter := ifv.MapRange()
for iter.Next() {
if key, ok := iter.Key().Interface().(string); ok {
e.bindEnvs(iter.Value().Interface(), append(prev, key)...)
}
default:
env := strings.Join(append(prev, tv), ".")
// Viper.BindEnv will never return error
// because env is always non empty string
_ = e.Viper.BindEnv(env)
}
default:
env := strings.Join(prev, ".")
// Viper.BindEnv will never return error
// because env is always non empty string
_ = e.Viper.BindEnv(env)
}
}
14 changes: 14 additions & 0 deletions enviper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@ func (s *UnmarshalSuite) TestOnlyEnvs() {
//s.Equal(true, c.QuxMap["key1"].Quuux)
}

func (s *UnmarshalSuite) TestPrimitiveMap() {
s.setupFileConfig()

var c Config
e := enviper.New(s.v)
s.Nil(e.Unmarshal(&c))

s.Equal("val1", c.PrimitiveMap["key1"])
s.Equal("val2", c.PrimitiveMap["key2"])
s.Equal("", c.PrimitiveMap[""])
}

func (s *UnmarshalSuite) TestOnlyConfig() {
s.setupFileConfig()

Expand Down Expand Up @@ -180,6 +192,8 @@ type Config struct {
QuxMap map[string]struct {
Quuux bool
}
PrimitiveMap map[string]string

QUX `mapstructure:",squash"`
TagTest string `custom_tag:"TAG_TEST"`
TagValueWithOmitempty string `mapstructure:",omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions fixture.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ QuxMap:
Quuux: false
key2:
Quuux: false
PrimitiveMap:
key1: val1
key2: val2
Quuux: true
quuux_ptr:
Value: testptr2

0 comments on commit 76a709d

Please sign in to comment.