From 64431f66e829f51c5b11fc9f6df6e29debc67871 Mon Sep 17 00:00:00 2001 From: Celian Garcia Date: Sun, 2 Aug 2020 13:37:50 +0200 Subject: [PATCH] Support maps in configuration structure --- README.md | 8 ++++++++ enviper.go | 10 ++++++++++ enviper_test.go | 5 +++++ fixture.yaml | 5 +++++ fixture_env | 1 + 5 files changed, 29 insertions(+) diff --git a/README.md b/README.md index 39bb5b2..29a19e2 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ type bazzy struct { type config struct { Foo string Barry barry + Barries map[string]barry Bazzy bazzy `mapstructure:",squash"` } @@ -50,16 +51,23 @@ type config struct { // Barry: // bar: 42 // Baz: true +// Barries: +// key1: +// Bar: 255 +// key2: +// Bar: 256 // // And then it could be overriden by next env variables: // FOO=foo // BARRY_BAR=42 // BAZ=true +// BARRIES_KEY1_BAR=42 // // Or with prefix: // MYAPP_FOO=foo // MYAPP_BARRY_BAR=42 // MYAPP_BAZ=true +// MYAPP_BARRIES_KEY1_BAR=42 func main() { var c config diff --git a/enviper.go b/enviper.go index 2237619..798f319 100644 --- a/enviper.go +++ b/enviper.go @@ -55,6 +55,9 @@ func (e *Enviper) Unmarshal(rawVal interface{}) error { return err } } + // We need to unmarshal before the env binding to make sure that keys of maps are bound just like the struct fields + // We silence errors here because we'll unmarshal a second time + _ = e.Viper.Unmarshal(rawVal) e.readEnvs(rawVal) return e.Viper.Unmarshal(rawVal) } @@ -84,6 +87,13 @@ func (e *Enviper) bindEnvs(in interface{}, prev ...string) { 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)...) + } + } default: env := strings.Join(append(prev, tv), ".") // Viper.BindEnv will never return error diff --git a/enviper_test.go b/enviper_test.go index bc15bc8..64970a8 100644 --- a/enviper_test.go +++ b/enviper_test.go @@ -82,6 +82,8 @@ func (s *UnmarshalSuite) TestWithEnvs() { s.Equal("fooooo", c.Foo) s.Equal(2, c.Bar.BAZ) s.Equal(false, c.QUX.Quuux) + s.Equal(true, c.QuxMap["key1"].Quuux) + s.Equal(false, c.QuxMap["key2"].Quuux) s.tearDownEnvConfig() } @@ -139,6 +141,9 @@ type Config struct { Bar struct { BAZ int `mapstructure:"baz"` } `mapstructure:"bar"` + QuxMap map[string]struct { + Quuux bool + } QUX `mapstructure:",squash"` } diff --git a/fixture.yaml b/fixture.yaml index e6d4d39..4597de3 100644 --- a/fixture.yaml +++ b/fixture.yaml @@ -1,4 +1,9 @@ Foo: foo bar: baz: 1 +QuxMap: + key1: + Quuux: false + key2: + Quuux: false Quuux: true diff --git a/fixture_env b/fixture_env index 98d818e..c3c926d 100644 --- a/fixture_env +++ b/fixture_env @@ -1,3 +1,4 @@ PREF_FOO=fooooo PREF_BAR_BAZ=2 PREF_QUUUX=false +PREF_QUXMAP_KEY1_QUUUX=true