Skip to content

Commit

Permalink
Add WithNoOverrideEmptyStructValues
Browse files Browse the repository at this point in the history
Add option to not overwrite empty fields in destination structs if the
structs are not empty.
  • Loading branch information
cwarden committed Feb 26, 2021
1 parent cd55aea commit 9ddaab6
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 9 deletions.
49 changes: 49 additions & 0 deletions emptyStructValues_test.go
@@ -0,0 +1,49 @@
package mergo_test

import (
"testing"

"github.com/imdario/mergo"
)

type parent struct {
S string
Child *child
}

type child struct {
S string
}

func TestDoNotOverwriteEmptyValueWithinStruct(t *testing.T) {
src := parent{
Child: &child{S: "src"},
S: "src",
}
dest := parent{
Child: &child{S: ""},
S: "dest",
}
if err := mergo.Merge(&dest, src, mergo.WithNoOverrideEmptyStructValues); err != nil {
t.Error(err)
}
if dest.Child.S != "" {
t.Errorf("dest.Child.S overwritten")
}
}

func TestOverwriteEmptyStruct(t *testing.T) {
src := parent{
Child: &child{S: "src"},
S: "src",
}
dest := parent{
S: "dest",
}
if err := mergo.Merge(&dest, src, mergo.WithNoOverrideEmptyStructValues); err != nil {
t.Error(err)
}
if dest.Child.S != "src" {
t.Errorf("dest.Child.S not overwritten")
}
}
27 changes: 18 additions & 9 deletions merge.go
Expand Up @@ -38,14 +38,15 @@ func isExportedComponent(field *reflect.StructField) bool {
}

type Config struct {
Overwrite bool
AppendSlice bool
TypeCheck bool
Transformers Transformers
overwriteWithEmptyValue bool
overwriteSliceWithEmptyValue bool
sliceDeepCopy bool
debug bool
Overwrite bool
AppendSlice bool
TypeCheck bool
Transformers Transformers
overwriteWithEmptyValue bool
overwriteSliceWithEmptyValue bool
doNotOverwriteEmptyStructValuesInDst bool
sliceDeepCopy bool
debug bool
}

type Transformers interface {
Expand All @@ -60,6 +61,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
typeCheck := config.TypeCheck
overwriteWithEmptySrc := config.overwriteWithEmptyValue
overwriteSliceWithEmptySrc := config.overwriteSliceWithEmptyValue
doNotOverwriteEmptyStructValuesInDst := config.doNotOverwriteEmptyStructValuesInDst
sliceDeepCopy := config.sliceDeepCopy

if !src.IsValid() {
Expand All @@ -86,9 +88,11 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
}
}

overwriteStructValues := depth == 0 || !doNotOverwriteEmptyStructValuesInDst

switch dst.Kind() {
case reflect.Struct:
if hasMergeableFields(dst) {
if overwriteStructValues && hasMergeableFields(dst) {
for i, n := 0, dst.NumField(); i < n; i++ {
if err = deepMerge(dst.Field(i), src.Field(i), visited, depth+1, config); err != nil {
return
Expand Down Expand Up @@ -321,6 +325,11 @@ func WithOverrideEmptySlice(config *Config) {
config.overwriteSliceWithEmptyValue = true
}

// WithNoOverrideEmptyStruct will make merge not overwrite the empty values within non-empty structs in dst
func WithNoOverrideEmptyStructValues(config *Config) {
config.doNotOverwriteEmptyStructValuesInDst = true
}

// WithAppendSlice will make merge append slices instead of overwriting it.
func WithAppendSlice(config *Config) {
config.AppendSlice = true
Expand Down

0 comments on commit 9ddaab6

Please sign in to comment.