Skip to content

Commit

Permalink
Merge pull request #147 from modopayments/master
Browse files Browse the repository at this point in the history
merge struct fields of type interface{} that contain data with the same concrete type
  • Loading branch information
darccio authored Jul 16, 2020
2 parents 9d33180 + 524f5a3 commit a0c19e4
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 16 deletions.
38 changes: 22 additions & 16 deletions merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,20 +291,6 @@ func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int,
break
}

if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
if dst.IsNil() || overwrite {
if overwrite || isEmptyValue(dst) {
if dst.CanSet() {
dst.Set(src)
} else {
dst = src
}
}
}

break
}

if src.Kind() != reflect.Interface {
if dst.IsNil() || (src.Kind() != reflect.Ptr && overwrite) {
if dst.CanSet() && (overwrite || isEmptyValue(dst)) {
Expand Down Expand Up @@ -335,8 +321,28 @@ func deepMerge(dstIn, src reflect.Value, visited map[uintptr]*visit, depth int,
dst = src
}
}
} else if _, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
return
break
}

if dst.Elem().Kind() == src.Elem().Kind() {
if dst, err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil {
return
}
break
}

if dst.Kind() != reflect.Ptr && src.Type().AssignableTo(dst.Type()) {
if dst.IsNil() || overwrite {
if overwrite || isEmptyValue(dst) {
if dst.CanSet() {
dst.Set(src)
} else {
dst = src
}
}
}

break
}
default:
mustSet := (!isEmptyValue(src) || overwriteWithEmptySrc) && (overwrite || isEmptyValue(dst))
Expand Down
34 changes: 34 additions & 0 deletions merge_interface_concrete_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,37 @@ func TestMergeInterfaceWithDifferentConcreteTypes(t *testing.T) {
t.Errorf("Handler not merged in properly: got %q header value %q, want %q", "Test", got, want)
}
}

func TestMergeInterfaceWithSameConcreteTypes(t *testing.T) {
type testStruct struct {
Name string
Value string
}
type interfaceStruct struct {
Field interface{}
}
dst := interfaceStruct{
Field: testStruct{
Value: "keepMe",
},
}

src := interfaceStruct{
Field: testStruct{
Name: t.Name(),
},
}

if err := Merge(&dst, src); err != nil {
t.Errorf("Error while merging %s", err)
}

dstData := dst.Field.(testStruct)
srcData := src.Field.(testStruct)
if dstData.Name != srcData.Name {
t.Errorf("dst name was not updated: got %s, want %s", dstData.Name, srcData.Name)
}
if dstData.Value != "keepMe" {
t.Errorf("dst value was not preserved: got %s, want %s", dstData.Value, "keepMe")
}
}

0 comments on commit a0c19e4

Please sign in to comment.