mirror of
https://github.com/spf13/viper
synced 2025-05-11 06:37:27 +00:00
Processed PR feedback
- renamed searchMapWithPathPrefixes to searchIndexableWithPathPrefixes - moved source type specific search logic to speparate functions - Inverted if statments to avoid the arrow pattern
This commit is contained in:
parent
6a8ee097ff
commit
5fd34c89c0
2 changed files with 91 additions and 48 deletions
137
viper.go
137
viper.go
|
@ -583,7 +583,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
|||
return nil
|
||||
}
|
||||
|
||||
// searchMapWithPathPrefixes recursively searches for a value for path in source map/slice.
|
||||
// searchIndexableWithPathPrefixes recursively searches for a value for path in source map/slice.
|
||||
//
|
||||
// While searchMap() considers each path element as a single map key or slice index, this
|
||||
// function searches for, and prioritizes, merged path elements.
|
||||
|
@ -594,7 +594,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
|||
// in their keys).
|
||||
//
|
||||
// Note: This assumes that the path entries and map keys are lower cased.
|
||||
func (v *Viper) searchMapWithPathPrefixes(source interface{}, path []string) interface{} {
|
||||
func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []string) interface{} {
|
||||
if len(path) == 0 {
|
||||
return source
|
||||
}
|
||||
|
@ -602,52 +602,95 @@ func (v *Viper) searchMapWithPathPrefixes(source interface{}, path []string) int
|
|||
// search for path prefixes, starting from the longest one
|
||||
for i := len(path); i > 0; i-- {
|
||||
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
|
||||
if sourceSlice, ok := source.([]interface{}); ok {
|
||||
//if the prefixKey is a number which is not out of bounds of the slice
|
||||
if index, err := strconv.Atoi(prefixKey); err == nil && len(sourceSlice) > index {
|
||||
next := sourceSlice[index]
|
||||
|
||||
// Fast path
|
||||
if i == len(path) {
|
||||
return next
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
switch n := next.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
|
||||
case map[string]interface{}, []interface{}:
|
||||
val = v.searchMapWithPathPrefixes(n, path[i:])
|
||||
default:
|
||||
// got a value but nested key expected, do nothing and look for next prefix
|
||||
}
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
}
|
||||
} else if sourceMap, ok := source.(map[string]interface{}); ok {
|
||||
next, ok := sourceMap[prefixKey]
|
||||
if ok {
|
||||
// Fast path
|
||||
if i == len(path) {
|
||||
return next
|
||||
}
|
||||
|
||||
// Nested case
|
||||
var val interface{}
|
||||
switch n := next.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
|
||||
case map[string]interface{}, []interface{}:
|
||||
val = v.searchMapWithPathPrefixes(n, path[i:])
|
||||
default:
|
||||
// got a value but nested key expected, do nothing and look for next prefix
|
||||
}
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
}
|
||||
var val interface{}
|
||||
switch sourceIndexable := source.(type) {
|
||||
case []interface{}:
|
||||
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
||||
case map[string]interface{}:
|
||||
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
||||
}
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return nil
|
||||
}
|
||||
|
||||
// searchSliceWithPathPrefixes searches for a value for path in sourceSlice
|
||||
//
|
||||
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
||||
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
||||
func (v *Viper) searchSliceWithPathPrefixes(
|
||||
sourceSlice []interface{},
|
||||
prefixKey string,
|
||||
pathIndex int,
|
||||
path []string,
|
||||
) interface{} {
|
||||
// if the prefixKey is not a number or it is out of bounds of the slice
|
||||
index, err := strconv.Atoi(prefixKey)
|
||||
if err != nil || len(sourceSlice) <= index {
|
||||
return nil
|
||||
}
|
||||
|
||||
next := sourceSlice[index]
|
||||
|
||||
// Fast path
|
||||
if pathIndex == len(path) {
|
||||
return next
|
||||
}
|
||||
|
||||
var val interface{}
|
||||
switch n := next.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
val = v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
||||
case map[string]interface{}, []interface{}:
|
||||
val = v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
||||
default:
|
||||
// got a value but nested key expected, do nothing and look for next prefix
|
||||
}
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
|
||||
// not found
|
||||
return nil
|
||||
}
|
||||
|
||||
// searchMapWithPathPrefixes searches for a value for path in sourceMap
|
||||
//
|
||||
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
||||
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
||||
func (v *Viper) searchMapWithPathPrefixes(
|
||||
sourceMap map[string]interface{},
|
||||
prefixKey string,
|
||||
pathIndex int,
|
||||
path []string,
|
||||
) interface{} {
|
||||
next, ok := sourceMap[prefixKey]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fast path
|
||||
if pathIndex == len(path) {
|
||||
return next
|
||||
}
|
||||
|
||||
// Nested case
|
||||
var val interface{}
|
||||
switch n := next.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
val = v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
||||
case map[string]interface{}, []interface{}:
|
||||
val = v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
||||
default:
|
||||
// got a value but nested key expected, do nothing and look for next prefix
|
||||
}
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
|
||||
// not found
|
||||
|
@ -1157,7 +1200,7 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
|
|||
}
|
||||
|
||||
// Config file next
|
||||
val = v.searchMapWithPathPrefixes(v.config, path)
|
||||
val = v.searchIndexableWithPathPrefixes(v.config, path)
|
||||
if val != nil {
|
||||
return val
|
||||
}
|
||||
|
|
|
@ -2315,7 +2315,7 @@ func TestSliceIndexAccess(t *testing.T) {
|
|||
assert.Equal(t, "Static", v.GetString("tv.0.seasons.1.episodes.2.title"))
|
||||
assert.Equal(t, "December 15, 2015", v.GetString("tv.0.seasons.0.episodes.1.air_date"))
|
||||
|
||||
//Test for index out of bounds
|
||||
// Test for index out of bounds
|
||||
assert.Equal(t, "", v.GetString("tv.0.seasons.2.first_released"))
|
||||
|
||||
// Accessing multidimensional arrays
|
||||
|
|
Loading…
Add table
Reference in a new issue