add map support

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2020-12-04 22:41:46 +03:00
parent 19fefe591c
commit 2868c39a87
2 changed files with 25 additions and 4 deletions

25
env.go
View File

@ -43,9 +43,28 @@ func (c *envConfig) Load(ctx context.Context) error {
func (c *envConfig) fillValue(ctx context.Context, value reflect.Value, val string) error { func (c *envConfig) fillValue(ctx context.Context, value reflect.Value, val string) error {
switch value.Kind() { switch value.Kind() {
case reflect.Map:
t := value.Type()
nvals := strings.FieldsFunc(val, func(c rune) bool { return c == ',' || c == ';' })
if value.IsNil() {
value.Set(reflect.MakeMapWithSize(t, len(nvals)))
}
kt := t.Key()
et := t.Elem()
for _, nval := range nvals {
kv := strings.FieldsFunc(nval, func(c rune) bool { return c == '=' })
mkey := reflect.Indirect(reflect.New(kt))
mval := reflect.Indirect(reflect.New(et))
if err := c.fillValue(ctx, mkey, kv[0]); err != nil {
return err
}
if err := c.fillValue(ctx, mval, kv[1]); err != nil {
return err
}
value.SetMapIndex(mkey, mval)
}
case reflect.Slice, reflect.Array: case reflect.Slice, reflect.Array:
nvals := strings.FieldsFunc(val, func(c rune) bool { return c == ',' || c == ';' }) nvals := strings.FieldsFunc(val, func(c rune) bool { return c == ',' || c == ';' })
// value = value.Elem()
value.Set(reflect.MakeSlice(reflect.SliceOf(value.Type().Elem()), len(nvals), len(nvals))) value.Set(reflect.MakeSlice(reflect.SliceOf(value.Type().Elem()), len(nvals), len(nvals)))
for idx, nval := range nvals { for idx, nval := range nvals {
nvalue := reflect.Indirect(reflect.New(value.Type().Elem())) nvalue := reflect.Indirect(reflect.New(value.Type().Elem()))
@ -53,7 +72,6 @@ func (c *envConfig) fillValue(ctx context.Context, value reflect.Value, val stri
return err return err
} }
value.Index(idx).Set(nvalue) value.Index(idx).Set(nvalue)
//value.Set(reflect.Append(value, nvalue))
} }
case reflect.Bool: case reflect.Bool:
v, err := strconv.ParseBool(val) v, err := strconv.ParseBool(val)
@ -167,7 +185,8 @@ func (c *envConfig) fillValues(ctx context.Context, valueOf reflect.Value) error
if len(field.PkgPath) != 0 { if len(field.PkgPath) != 0 {
continue continue
} }
if value.Kind() == reflect.Ptr { switch value.Kind() {
case reflect.Ptr :
if value.IsNil() { if value.IsNil() {
if value.Type().Elem().Kind() != reflect.Struct { if value.Type().Elem().Kind() != reflect.Struct {
// nil pointer to a non-struct: leave it alone // nil pointer to a non-struct: leave it alone

View File

@ -14,6 +14,7 @@ type Config struct {
BoolValue bool `env:"BOOL_VALUE"` BoolValue bool `env:"BOOL_VALUE"`
StringSlice []string `env:"STRING_SLICE"` StringSlice []string `env:"STRING_SLICE"`
IntSlice []int `env:"INT_SLICE"` IntSlice []int `env:"INT_SLICE"`
MapStringValue map[string]string `env:"MAP_STRING"`
} }
func TestEnv(t *testing.T) { func TestEnv(t *testing.T) {
@ -38,6 +39,7 @@ func TestEnv(t *testing.T) {
os.Setenv("BOOL_VALUE","true") os.Setenv("BOOL_VALUE","true")
os.Setenv("STRING_SLICE", "STRING_SLICE1,STRING_SLICE2;STRING_SLICE3") os.Setenv("STRING_SLICE", "STRING_SLICE1,STRING_SLICE2;STRING_SLICE3")
os.Setenv("INT_SLICE", "1,2,3,4,5") os.Setenv("INT_SLICE", "1,2,3,4,5")
os.Setenv("MAP_STRING", "key1=val1,key2=val2")
if err := cfg.Load(ctx); err !=nil { if err := cfg.Load(ctx); err !=nil {
t.Fatal(err) t.Fatal(err)