mirror of
https://github.com/spf13/viper
synced 2024-12-23 12:07:02 +00:00
#358: access nested array values using get
This commit is contained in:
parent
0967fc9ace
commit
68a8b52d7b
1 changed files with 57 additions and 2 deletions
57
viper.go
57
viper.go
|
@ -28,6 +28,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -492,6 +493,56 @@ func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Viper) searchMapWithArrayPrefix(source map[string]interface{}, path []string) interface{} {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return source
|
||||||
|
}
|
||||||
|
|
||||||
|
next, ok := source[path[0]]
|
||||||
|
if ok {
|
||||||
|
// Immediate Key Value
|
||||||
|
if len(path) == 1 {
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value from Nested key
|
||||||
|
switch next.(type) {
|
||||||
|
case map[interface{}]interface{}:
|
||||||
|
return v.searchMapWithArrayPrefix(cast.ToStringMap(next), path[1:])
|
||||||
|
case map[string]interface{}:
|
||||||
|
// Type assertion is safe here since it is only reached
|
||||||
|
// if the type of `next` is the same as the type being asserted
|
||||||
|
return v.searchMapWithArrayPrefix(next.(map[string]interface{}), path[1:])
|
||||||
|
case []interface{}:
|
||||||
|
v1 := cast.ToSlice(next)
|
||||||
|
for k2, v2 := range v1 {
|
||||||
|
if reflect.TypeOf(v2).Kind() == reflect.Map {
|
||||||
|
if _, err := strconv.ParseInt(path[1], 10, 64); err == nil {
|
||||||
|
if strconv.Itoa(k2) == path[1] {
|
||||||
|
return v.searchMapWithArrayPrefix(cast.ToStringMap(v2), path[1:])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return v.searchMapWithArrayPrefix(cast.ToStringMap(v2), path[1:])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := strconv.ParseInt(path[1], 10, 64); err == nil {
|
||||||
|
if strconv.Itoa(k2) == path[1] {
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := strconv.ParseInt(path[0], 10, 64); err == nil {
|
||||||
|
return v.searchMapWithArrayPrefix(source, path[1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
|
// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
|
||||||
// on its path in the map.
|
// on its path in the map.
|
||||||
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
||||||
|
@ -858,7 +909,6 @@ func (v *Viper) BindEnv(input ...string) error {
|
||||||
// Viper will check to see if an alias exists first.
|
// Viper will check to see if an alias exists first.
|
||||||
// Note: this assumes a lower-cased key given.
|
// Note: this assumes a lower-cased key given.
|
||||||
func (v *Viper) find(lcaseKey string) interface{} {
|
func (v *Viper) find(lcaseKey string) interface{} {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
val interface{}
|
val interface{}
|
||||||
exists bool
|
exists bool
|
||||||
|
@ -932,6 +982,11 @@ func (v *Viper) find(lcaseKey string) interface{} {
|
||||||
if val != nil {
|
if val != nil {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
val = v.searchMapWithArrayPrefix(v.config, path)
|
||||||
|
if val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
|
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue