Skip to content

Commit d4c5594

Browse files
author
Bogdan Dinu
authored
Fix for #2383 (#3004)
1 parent 78fa10a commit d4c5594

File tree

5 files changed

+98
-0
lines changed

5 files changed

+98
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"id": "adfe779a-b5b4-44bd-8e23-5cdb4db5aef8",
3+
"type": "bugfix",
4+
"collapse": false,
5+
"description": "DynamoDB AttributeValue's MarshallMap() Does Not Support time.Time Correctly #2383",
6+
"modules": [
7+
"feature/dynamodb",
8+
"feature/dynamodbstreams"
9+
]
10+
}

feature/dynamodb/attributevalue/encode.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ type EncoderOptions struct {
399399
// NULL attribute values returned from the standard marshaling routine will
400400
// always respect omitempty regardless of this setting.
401401
OmitNullAttributeValues bool
402+
403+
// When enabled, the encoder will omit empty time attribute values
404+
OmitEmptyTime bool
402405
}
403406

404407
// An Encoder provides marshaling Go value types to AttributeValues.
@@ -499,6 +502,11 @@ func (e *Encoder) encodeStruct(v reflect.Value, fieldTag tag) (types.AttributeVa
499502
if v.Type().ConvertibleTo(timeType) {
500503
var t time.Time
501504
t = v.Convert(timeType).Interface().(time.Time)
505+
506+
if e.options.OmitEmptyTime && fieldTag.OmitEmpty && t.IsZero() {
507+
return nil, nil
508+
}
509+
502510
if fieldTag.AsUnixTime {
503511
return UnixTime(t).MarshalDynamoDBAttributeValue()
504512
}

feature/dynamodb/attributevalue/encode_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,39 @@ func TestMarshalMap_keyTypes(t *testing.T) {
830830
})
831831
}
832832
}
833+
834+
func TestEncodeEmptyTime(t *testing.T) {
835+
type A struct {
836+
Created time.Time `dynamodbav:"created,omitempty"`
837+
}
838+
839+
a := A{Created: time.Time{}}
840+
841+
actual, err := MarshalWithOptions(a, func(o *EncoderOptions) {
842+
o.OmitEmptyTime = true
843+
})
844+
if err != nil {
845+
t.Errorf("expect nil, got %v", err)
846+
}
847+
848+
expect := &types.AttributeValueMemberM{
849+
Value: map[string]types.AttributeValue{},
850+
}
851+
852+
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
853+
t.Errorf("expect %v, got %v", e, a)
854+
}
855+
856+
actual2, err := MarshalMapWithOptions(a, func(o *EncoderOptions) {
857+
o.OmitEmptyTime = true
858+
})
859+
if err != nil {
860+
t.Errorf("expect nil, got %v", err)
861+
}
862+
863+
expect2 := map[string]types.AttributeValue{}
864+
865+
if e, a := expect2, actual2; !reflect.DeepEqual(e, a) {
866+
t.Errorf("expect %v, got %v", e, a)
867+
}
868+
}

feature/dynamodbstreams/attributevalue/encode.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,9 @@ type EncoderOptions struct {
399399
// NULL attribute values returned from the standard marshaling routine will
400400
// always respect omitempty regardless of this setting.
401401
OmitNullAttributeValues bool
402+
403+
// When enabled, the encoder will omit empty time attribute values
404+
OmitEmptyTime bool
402405
}
403406

404407
// An Encoder provides marshaling Go value types to AttributeValues.
@@ -499,6 +502,11 @@ func (e *Encoder) encodeStruct(v reflect.Value, fieldTag tag) (types.AttributeVa
499502
if v.Type().ConvertibleTo(timeType) {
500503
var t time.Time
501504
t = v.Convert(timeType).Interface().(time.Time)
505+
506+
if e.options.OmitEmptyTime && fieldTag.OmitEmpty && t.IsZero() {
507+
return nil, nil
508+
}
509+
502510
if fieldTag.AsUnixTime {
503511
return UnixTime(t).MarshalDynamoDBStreamsAttributeValue()
504512
}

feature/dynamodbstreams/attributevalue/encode_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,3 +830,39 @@ func TestMarshalMap_keyTypes(t *testing.T) {
830830
})
831831
}
832832
}
833+
834+
func TestEncodeEmptyTime(t *testing.T) {
835+
type A struct {
836+
Created time.Time `dynamodbav:"created,omitempty"`
837+
}
838+
839+
a := A{Created: time.Time{}}
840+
841+
actual, err := MarshalWithOptions(a, func(o *EncoderOptions) {
842+
o.OmitEmptyTime = true
843+
})
844+
if err != nil {
845+
t.Errorf("expect nil, got %v", err)
846+
}
847+
848+
expect := &types.AttributeValueMemberM{
849+
Value: map[string]types.AttributeValue{},
850+
}
851+
852+
if e, a := expect, actual; !reflect.DeepEqual(e, a) {
853+
t.Errorf("expect %v, got %v", e, a)
854+
}
855+
856+
actual2, err := MarshalMapWithOptions(a, func(o *EncoderOptions) {
857+
o.OmitEmptyTime = true
858+
})
859+
if err != nil {
860+
t.Errorf("expect nil, got %v", err)
861+
}
862+
863+
expect2 := map[string]types.AttributeValue{}
864+
865+
if e, a := expect2, actual2; !reflect.DeepEqual(e, a) {
866+
t.Errorf("expect %v, got %v", e, a)
867+
}
868+
}

0 commit comments

Comments
 (0)