Skip to content

Commit

Permalink
MergeStrict returns the first error
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Gront <grount1@gmail.com>
  • Loading branch information
grount committed Mar 26, 2021
1 parent 5c66566 commit a05e2d5
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 44 deletions.
10 changes: 0 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -564,16 +564,6 @@ func main() {
jsonPath := "mock/mock.json"
if err := k.Load(file.Provider(jsonPath), json.Parser()); err != nil {
// go version <= v1.12
if strictErr := err.(*maps.MergeStrictError); strictErr != nil {
log.Fatalf("error merging config %v: %v", jsonPath, err)
}
// go version > v1.12
var strictErr *maps.MergeStrictError
if errors.As(err, &strictErr) {
log.Fatalf("error merging config %v: %v", jsonPath, err)
}
log.Fatalf("error loading config: %v", err)
}
}
Expand Down
16 changes: 5 additions & 11 deletions koanf.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,10 @@ type UnmarshalConf struct {
// when specifying config key paths, for instance a . for `parent.child.key`
// or a / for `parent/child/key`.
func New(delim string) *Koanf {
return &Koanf{
confMap: make(map[string]interface{}),
confMapFlat: make(map[string]interface{}),
keyMap: make(KeyMap),
conf: Conf{
Delim: delim,
StrictMerge: false,
},
}
return NewWithConf(Conf{
Delim: delim,
StrictMerge: false,
})
}

// NewWithConf returns a new instance of Koanf based on the Conf.
Expand Down Expand Up @@ -393,8 +388,7 @@ func (ko *Koanf) MapKeys(path string) []string {
func (ko *Koanf) merge(c map[string]interface{}) error{
maps.IntfaceKeysToStrings(c)
if ko.conf.StrictMerge {
err := maps.MergeStrict(c, ko.confMap)
if err != nil {
if err := maps.MergeStrict(c, ko.confMap); err != nil {
return err
}
} else {
Expand Down
2 changes: 0 additions & 2 deletions koanf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"time"

"github.com/knadh/koanf"
"github.com/knadh/koanf/maps"
"github.com/knadh/koanf/parsers/dotenv"
"github.com/knadh/koanf/parsers/hcl"
"github.com/knadh/koanf/parsers/json"
Expand Down Expand Up @@ -735,7 +734,6 @@ func TestMergeStrictError(t *testing.T) {

err := ks.Load(file.Provider(mockYAML), yaml.Parser())
assert.Error(err)
assert.IsType(&maps.MergeStrictError{}, err)
assert.True(strings.HasPrefix(err.Error(), "incorrect types at key parent2.child2.grandchild2"))
}

Expand Down
34 changes: 13 additions & 21 deletions maps/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ import (
"strings"
)

type MergeStrictError struct {
Errors []error
}

func (m *MergeStrictError) Error() string {
var msg string
for _, err := range m.Errors {
msg += fmt.Sprintf("%v\n", err.Error())
}
return msg
}

// Flatten takes a map[string]interface{} and traverses it and flattens
// nested children into keys delimited by delim.
Expand Down Expand Up @@ -145,16 +134,19 @@ func Merge(a, b map[string]interface{}) {
}
}

// MergeStrict recursively merges map a into b (left to right), mutating
// and expanding map b. Note that there's no copying involved, so
// map b will retain references to map a.
// If an equal key in either of the maps has a different value type, it will return the first error.
//
// It's important to note that all nested maps should be
// map[string]interface{} and not map[interface{}]interface{}.
// Use IntfaceKeysToStrings() to convert if necessary.
func MergeStrict(a, b map[string]interface{}) error {
mergeError := MergeStrictError{Errors: []error{}}
mergeStrict(a, b, &mergeError, "")
if len(mergeError.Errors) > 0 {
return &mergeError
}
return nil
return mergeStrict(a, b, "")
}

func mergeStrict(a, b map[string]interface{}, mergeError *MergeStrictError, fullKey string) {
func mergeStrict(a, b map[string]interface{}, fullKey string) error {
for key, val := range a {
// Does the key exist in the target map?
// If no, add it and move on.
Expand All @@ -174,20 +166,20 @@ func mergeStrict(a, b map[string]interface{}, mergeError *MergeStrictError, full
if reflect.TypeOf(b[key]) == reflect.TypeOf(val) {
b[key] = val
} else {
err := fmt.Errorf("incorrect types at key %v, type %T != %T", fullKey, b[key], val)
mergeError.Errors = append(mergeError.Errors, err)
return fmt.Errorf("incorrect types at key %v, type %T != %T", fullKey, b[key], val)
}
continue
}

// The source key and target keys are both maps. Merge them.
switch v := bVal.(type) {
case map[string]interface{}:
mergeStrict(val.(map[string]interface{}), v, mergeError, newFullKey)
return mergeStrict(val.(map[string]interface{}), v, newFullKey)
default:
b[key] = val
}
}
return nil
}

// Delete removes the entry present at a given path, from the map. The path
Expand Down

0 comments on commit a05e2d5

Please sign in to comment.