mirror of
https://github.com/spf13/viper
synced 2025-05-06 12:17:18 +00:00
Fix: Set() and SetDefault() insert nested values
Set() and SetDefault() fixed, so that they insert (or substitute) correctly "nested values" (= values identified by a complete path, i.e. containing dots; e.g. "foo.bar"). They scan (and create if needed) intermediate maps, so that the value reaches the innermost map. Examples : * v.override = make(map[string]interface{}) v.Set("foo.bar", 10) v.Set("foo.baz", 20) fmt.Println(v.override["foo"]["bar"]) // displays "10" fmt.Println(v.override["foo"]["baz"]) // displays "20" Furthermore, pre-existing non-map value are erased: * v.Set("foo.bar", 10) v.Set("foo.bar.baz", 20) fmt.Println(v.override["foo"]["bar"]) // displays "map["baz": 20]" The low-level work is performed by function deepSearch(), it scans the given map according to a given key path, creating intermediate maps if necessary.
This commit is contained in:
parent
64b6d290f2
commit
4190078ffd
2 changed files with 45 additions and 2 deletions
31
util.go
31
util.go
|
@ -203,3 +203,34 @@ func parseSizeInBytes(sizeStr string) uint {
|
|||
|
||||
return safeMul(uint(size), multiplier)
|
||||
}
|
||||
|
||||
// deepSearch scans deep maps, following the key indexes listed in the
|
||||
// sequence "path".
|
||||
// The last value is expected to be another map, and is returned.
|
||||
//
|
||||
// In case intermediate keys do not exist, or map to a non-map value,
|
||||
// a new map is created and inserted, and the search continues from there:
|
||||
// the initial map "m" may be modified!
|
||||
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
|
||||
for _, k := range path {
|
||||
m2, ok := m[k]
|
||||
if !ok {
|
||||
// intermediate key does not exist
|
||||
// => create it and continue from there
|
||||
m3 := make(map[string]interface{})
|
||||
m[k] = m3
|
||||
m = m3
|
||||
continue
|
||||
}
|
||||
m3, ok := m2.(map[string]interface{})
|
||||
if !ok {
|
||||
// intermediate key is a value
|
||||
// => replace with a new map
|
||||
m3 = make(map[string]interface{})
|
||||
m[k] = m3
|
||||
}
|
||||
// continue search from here
|
||||
m = m3
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
|
16
viper.go
16
viper.go
|
@ -935,7 +935,13 @@ func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
|
|||
func (v *Viper) SetDefault(key string, value interface{}) {
|
||||
// If alias passed in, then set the proper default
|
||||
key = v.realKey(strings.ToLower(key))
|
||||
v.defaults[key] = value
|
||||
|
||||
path := strings.Split(key, v.keyDelim)
|
||||
lastKey := strings.ToLower(path[len(path)-1])
|
||||
deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
|
||||
|
||||
// set innermost value
|
||||
deepestMap[lastKey] = value
|
||||
}
|
||||
|
||||
// Set sets the value for the key in the override regiser.
|
||||
|
@ -945,7 +951,13 @@ func Set(key string, value interface{}) { v.Set(key, value) }
|
|||
func (v *Viper) Set(key string, value interface{}) {
|
||||
// If alias passed in, then set the proper override
|
||||
key = v.realKey(strings.ToLower(key))
|
||||
v.override[key] = value
|
||||
|
||||
path := strings.Split(key, v.keyDelim)
|
||||
lastKey := strings.ToLower(path[len(path)-1])
|
||||
deepestMap := deepSearch(v.override, path[0:len(path)-1])
|
||||
|
||||
// set innermost value
|
||||
deepestMap[lastKey] = value
|
||||
}
|
||||
|
||||
// ReadInConfig will discover and load the configuration file from disk
|
||||
|
|
Loading…
Add table
Reference in a new issue