From 6b830ffc3df09a6f22aafd7dfbf5f02d0da2ee22 Mon Sep 17 00:00:00 2001 From: vova Date: Wed, 5 Jun 2024 14:19:42 -0400 Subject: [PATCH 1/4] fixes issue #187 --- map.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/map.go b/map.go index b50d5c2..f7461e5 100644 --- a/map.go +++ b/map.go @@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf } fieldName := field.Name fieldName = changeInitialCase(fieldName, unicode.ToLower) - if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) { + if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) && overwrite) { dstMap[fieldName] = src.Field(i).Interface() } } From a13a1175be733af04b175c9fe616f594c5e8dfa9 Mon Sep 17 00:00:00 2001 From: vsemichev Date: Wed, 5 Jun 2024 14:57:24 -0400 Subject: [PATCH 2/4] fixes issue #187. attempt #2 --- map.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/map.go b/map.go index f7461e5..9e6a2db 100644 --- a/map.go +++ b/map.go @@ -32,6 +32,7 @@ func isExported(field reflect.StructField) bool { // The map argument tracks comparisons that have already been seen, which allows // short circuiting on recursive types. func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { + fmt.Println("In deepMap") overwrite := config.Overwrite if dst.CanAddr() { addr := dst.UnsafeAddr() @@ -58,7 +59,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf } fieldName := field.Name fieldName = changeInitialCase(fieldName, unicode.ToLower) - if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) && overwrite) { + if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) { dstMap[fieldName] = src.Field(i).Interface() } } From 4da170b81eef59e84cfa68070a73aea40f98ddbd Mon Sep 17 00:00:00 2001 From: vsemichev Date: Wed, 5 Jun 2024 14:59:24 -0400 Subject: [PATCH 3/4] fixes issue #187. attempt #3 --- map.go | 1 - 1 file changed, 1 deletion(-) diff --git a/map.go b/map.go index 9e6a2db..95ccd12 100644 --- a/map.go +++ b/map.go @@ -32,7 +32,6 @@ func isExported(field reflect.StructField) bool { // The map argument tracks comparisons that have already been seen, which allows // short circuiting on recursive types. func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, config *Config) (err error) { - fmt.Println("In deepMap") overwrite := config.Overwrite if dst.CanAddr() { addr := dst.UnsafeAddr() From 2f1a6156ce0c8b8a6291926b75bc27b9b8fc2bfe Mon Sep 17 00:00:00 2001 From: vsemichev Date: Thu, 8 Aug 2024 17:01:49 -0400 Subject: [PATCH 4/4] fixes issue #187. adds test to verify the fix. --- issue187_test.go | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ map.go | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 issue187_test.go diff --git a/issue187_test.go b/issue187_test.go new file mode 100644 index 0000000..49aabfc --- /dev/null +++ b/issue187_test.go @@ -0,0 +1,71 @@ +package mergo_test + +import ( + "dario.cat/mergo" + "testing" +) + +func TestIssue187MergeStructToMap(t *testing.T) { + dst := map[string]interface{}{ + "empty": "data", + } + + src := struct { + Foo string + Bar int + Empty string + }{ + Foo: "hello", + Bar: 42, + } + if err := mergo.Map(&dst, src); err != nil { + t.Error(err) + } + if dst["foo"] != "hello" || dst["bar"] != 42 || dst["empty"] != "data" { + t.Errorf("expected dst to be {foo: hello, bar: 42, empty: data}, got {foo: %v, bar: %v, empty: %v}", dst["foo"], dst["bar"], dst["empty"]) + } +} + +func TestIssue187MergeStructToMapWithOverwrite(t *testing.T) { + dst := map[string]interface{}{ + "foo": "initial", + "bar": 1, + "empty": "data", + } + src := struct { + Foo string + Bar int + Empty string + }{ + Foo: "hello", + Bar: 42, + } + if err := mergo.Map(&dst, src, mergo.WithOverride); err != nil { + t.Error(err) + } + if dst["foo"] != "hello" || dst["bar"] != 42 || dst["empty"] != "data" { + t.Errorf("expected dst to be {foo: hello, bar: 42, empty: data}, got {foo: %v, bar: %v, empty: %v}", dst["foo"], dst["bar"], dst["empty"]) + } +} + +func TestIssue187MergeStructToMapWithOverwriteWithEmptyValue(t *testing.T) { + dst := map[string]interface{}{ + "foo": "initial", + "bar": 1, + "empty": "data", + } + src := struct { + Foo string + Bar int + Empty string + }{ + Foo: "hello", + Bar: 42, + } + if err := mergo.Map(&dst, src, mergo.WithOverwriteWithEmptyValue); err != nil { + t.Error(err) + } + if dst["foo"] != "hello" || dst["bar"] != 42 || dst["empty"] != "" { + t.Errorf("expected dst to be {foo: hello, bar: 42, empty: }, got {foo: %v, bar: %v, empty: %v}", dst["foo"], dst["bar"], dst["empty"]) + } +} diff --git a/map.go b/map.go index 95ccd12..759b4f7 100644 --- a/map.go +++ b/map.go @@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf } fieldName := field.Name fieldName = changeInitialCase(fieldName, unicode.ToLower) - if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) { + if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue { dstMap[fieldName] = src.Field(i).Interface() } }