-
-
Notifications
You must be signed in to change notification settings - Fork 277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Times are being overwritten even when src is empty #52
Comments
Updated: I understood wrongly your issue and my assumptions were also wrong. I'm checking this.
|
Ok, I understand what is happening. As per MergeWithOverwrite's documentation:
As I said in my previous comment, time.Time can be semantically empty (as in IsZero() returns true) but it is a struct. Structs in Go don't have a zero value by themselves, as described in the official documentation about zero value:
So the overwriting behavior works as expected. It overrides one struct by another one. The only way to solve this is using transformers, as I also said in my previous comment. I wrote some tests showing how to use transformers in your case, with Merge and MergeWithOverwrite: type structWithTime struct {
Birth time.Time
}
type timeTransfomer struct {
overwrite bool
}
func (t timeTransfomer) Transformer(typ reflect.Type) func (dst, src reflect.Value) error {
if typ == reflect.TypeOf(time.Time{}) {
return func (dst, src reflect.Value) error {
if dst.CanSet() {
if t.overwrite {
isZero := src.MethodByName("IsZero")
result := isZero.Call([]reflect.Value{})
if !result[0].Bool() {
dst.Set(src)
}
} else {
isZero := dst.MethodByName("IsZero")
result := isZero.Call([]reflect.Value{})
if result[0].Bool() {
dst.Set(src)
}
}
}
return nil
}
}
return nil
}
// Expected standard behavior: ruthless overwrite.
func TestOverwriteZeroSrcTime(t *testing.T) {
now := time.Now()
dst := structWithTime{now}
src := structWithTime{}
if err := MergeWithOverwrite(&dst, src); err != nil {
t.FailNow()
}
if !dst.Birth.IsZero() {
t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
}
}
// Non standard behavior for MergeWithOverwrite: src.IsZero() == true then we don't overwrite dst.
func TestOverwriteZeroSrcTimeWithTransformer(t *testing.T) {
now := time.Now()
dst := structWithTime{now}
src := structWithTime{}
if err := MergeWithOverwrite(&dst, src, WithTransformers(timeTransfomer{true})); err != nil {
t.FailNow()
}
if dst.Birth.IsZero() {
t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
}
}
// Expected standard behavior: ruthless overwrite.
func TestOverwriteZeroDstTime(t *testing.T) {
now := time.Now()
dst := structWithTime{}
src := structWithTime{now}
if err := MergeWithOverwrite(&dst, src); err != nil {
t.FailNow()
}
if dst.Birth.IsZero() {
t.Fatalf("dst should have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
}
}
// Expected standard behavior: dst is a struct and structs doesn't have a zero value, so we don't overwrite it.
func TestZeroDstTime(t *testing.T) {
now := time.Now()
dst := structWithTime{}
src := structWithTime{now}
if err := Merge(&dst, src); err != nil {
t.FailNow()
}
if !dst.Birth.IsZero() {
t.Fatalf("dst should not have been overwritten: dst.Birth(%v) != zero(%v)", dst.Birth, time.Time{})
}
}
// Non standard behavior for Merge: dst.IsZero() == true then we overwrite dst.
func TestZeroDstTimeWithTransformer(t *testing.T) {
now := time.Now()
dst := structWithTime{}
src := structWithTime{now}
if err := Merge(&dst, src, WithTransformers(timeTransfomer{})); err != nil {
t.FailNow()
}
if dst.Birth.IsZero() {
t.Fatalf("dst should have been overwritten: dst.Birth(%v) != now(%v)", dst.Birth, now)
}
} |
Thank you so much @imdario for the explanation. I'm gonna use the Transformer approach. |
I'm using mergo with structs that can have empty times. I expected it not to overwrite times in destination when the value in source is empty (
time.IsEmpty()
returnstrue
).Sample failing test:
Output:
Is this expected behavior or can I go ahead fork & change it?
The text was updated successfully, but these errors were encountered: