Skip to content
This repository was archived by the owner on Dec 15, 2020. It is now read-only.

Commit abb7b71

Browse files
authored
Adds HasChanged and HasChangedSinceInit (#2)
These two methods return true if a value has changed.
1 parent 5bace2a commit abb7b71

2 files changed

Lines changed: 66 additions & 0 deletions

File tree

viper.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ type Viper struct {
200200
aliases map[string]string
201201
typeByDefValue bool
202202

203+
previousValues map[string]interface{}
204+
203205
// Store read properties on the object so that we can write back in order with comments.
204206
// This will only be used if the configuration read is a properties file.
205207
properties *properties.Properties
@@ -220,6 +222,7 @@ func New() *Viper {
220222
v.override = make(map[string]interface{})
221223
v.defaults = make(map[string]interface{})
222224
v.kvstore = make(map[string]interface{})
225+
v.previousValues = make(map[string]interface{})
223226
v.pflags = make(map[string]FlagValue)
224227
v.env = make(map[string]string)
225228
v.aliases = make(map[string]string)
@@ -685,6 +688,45 @@ func GetViper() *Viper {
685688
return v
686689
}
687690

691+
// HasChanged returns true if a key has changed and the change has not been retrieved yet using `Get()` and all
692+
// casters `GetString()`, `GetDuration()`, ...
693+
//
694+
// If the value has not been retrieved at all this will also return true.
695+
func HasChanged(key string) bool { return v.HasChanged(key) }
696+
func (v *Viper) HasChanged(key string) bool {
697+
lcaseKey := strings.ToLower(key)
698+
v.lock.RLock()
699+
defer v.lock.RUnlock()
700+
701+
value, ok := v.previousValues[lcaseKey]
702+
if !ok {
703+
return IsSet(lcaseKey)
704+
}
705+
706+
// Avoid writing the change
707+
return value != v.find(lcaseKey)
708+
}
709+
710+
// HasChangedSinceInit returns true if a key has changed and the change has not been retrieved yet using `Get()` and all
711+
// casters `GetString()`, `GetDuration()`, ...
712+
//
713+
// If the value has not been retrieved before at all this will return false.
714+
func HasChangedSinceInit(key string) bool { return v.HasChangedSinceInit(key) }
715+
func (v *Viper) HasChangedSinceInit(key string) bool {
716+
lcaseKey := strings.ToLower(key)
717+
v.lock.RLock()
718+
defer v.lock.RUnlock()
719+
720+
value, ok := v.previousValues[lcaseKey]
721+
if !ok {
722+
return false
723+
}
724+
725+
// Avoid writing the change
726+
return value != v.find(lcaseKey)
727+
728+
}
729+
688730
// Get can retrieve any value given the key to use.
689731
// Get is case-insensitive for a key.
690732
// Get has the behavior of returning the value associated with the first
@@ -696,6 +738,11 @@ func Get(key string) interface{} { return v.Get(key) }
696738
func (v *Viper) Get(key string) interface{} {
697739
lcaseKey := strings.ToLower(key)
698740
val := v.find(lcaseKey)
741+
742+
v.lock.Lock()
743+
v.previousValues[lcaseKey] = val
744+
v.lock.Unlock()
745+
699746
if val == nil {
700747
return nil
701748
}

viper_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,25 @@ func TestArrayOfObjects(t *testing.T) {
17611761
require.NoError(t, WriteConfig())
17621762
}
17631763

1764+
func TestHasChanged(t *testing.T) {
1765+
Reset()
1766+
require.False(t, HasChanged("foo"))
1767+
require.False(t, HasChangedSinceInit("foo"))
1768+
1769+
Set("foo", "bar")
1770+
require.False(t, HasChangedSinceInit("foo"))
1771+
require.True(t, HasChanged("foo"))
1772+
require.Equal(t, "bar", Get("foo"))
1773+
require.False(t, HasChanged("foo"))
1774+
1775+
Set("foo", "baz")
1776+
require.True(t, HasChangedSinceInit("foo"))
1777+
require.True(t, HasChanged("foo"))
1778+
require.Equal(t, "baz", Get("foo"))
1779+
require.False(t, HasChanged("foo"))
1780+
require.False(t, HasChangedSinceInit("foo"))
1781+
}
1782+
17641783
func BenchmarkGetBool(b *testing.B) {
17651784
key := "BenchmarkGetBool"
17661785
v = New()

0 commit comments

Comments
 (0)