Skip to content

Commit 7c11c15

Browse files
committed
feat(scan): scan time.Time uses UnmarshalText(RFC3339) interface decoding by default
Signed-off-by: monkey92t <[email protected]>
1 parent a38f75b commit 7c11c15

File tree

4 files changed

+54
-7
lines changed

4 files changed

+54
-7
lines changed

commands_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1841,6 +1841,25 @@ var _ = Describe("Commands", func() {
18411841
Key2: 123,
18421842
Time: TimeValue{Time: time.Time{}},
18431843
}))
1844+
1845+
type data2 struct {
1846+
Key1 string `redis:"key1"`
1847+
Key2 int `redis:"key2"`
1848+
Time time.Time `redis:"time"`
1849+
}
1850+
err = client.HSet(ctx, "hash", &data2{
1851+
Key1: "hello2",
1852+
Key2: 200,
1853+
Time: now,
1854+
}).Err()
1855+
Expect(err).NotTo(HaveOccurred())
1856+
1857+
var d2 data2
1858+
err = client.HMGet(ctx, "hash", "key1", "key2", "time").Scan(&d2)
1859+
Expect(err).NotTo(HaveOccurred())
1860+
Expect(d2.Key1).To(Equal("hello2"))
1861+
Expect(d2.Key2).To(Equal(200))
1862+
Expect(d2.Time.Unix()).To(Equal(now.Unix()))
18441863
})
18451864

18461865
It("should HIncrBy", func() {

internal/hscan/hscan.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"reflect"
77
"strconv"
8+
"time"
89
)
910

1011
// decoderFunc represents decoding functions for default built-in types.
@@ -42,7 +43,7 @@ var (
4243
reflect.Ptr: decodeUnsupported,
4344
reflect.Slice: decodeSlice,
4445
reflect.String: decodeString,
45-
reflect.Struct: decodeUnsupported,
46+
reflect.Struct: decodeStruct,
4647
reflect.UnsafePointer: decodeUnsupported,
4748
}
4849

@@ -202,6 +203,20 @@ func decodeSlice(f reflect.Value, s string) error {
202203
return nil
203204
}
204205

206+
func decodeStruct(f reflect.Value, s string) error {
207+
// handle time.Time here.
208+
// time.Time CanSet() == false
209+
if f.CanAddr() {
210+
p := f.Addr()
211+
if p.CanInterface() {
212+
if v, ok := p.Interface().(*time.Time); ok {
213+
return v.UnmarshalText([]byte(s))
214+
}
215+
}
216+
}
217+
return decodeUnsupported(f, s)
218+
}
219+
205220
func decodeUnsupported(v reflect.Value, s string) error {
206221
return fmt.Errorf("redis.Scan(unsupported %s)", v.Type())
207222
}

internal/hscan/hscan_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,4 +200,16 @@ var _ = Describe("Scan", func() {
200200
Expect(td.Time.UnixNano()).To(Equal(now.UnixNano()))
201201
Expect(td.Time.Format(time.RFC3339Nano)).To(Equal(now.Format(time.RFC3339Nano)))
202202
})
203+
204+
It("should time.Time RFC3339Nano", func() {
205+
type TimeTime struct {
206+
Time time.Time `redis:"time"`
207+
}
208+
209+
now := time.Now()
210+
211+
var tt TimeTime
212+
Expect(Scan(&tt, i{"time"}, i{now.Format(time.RFC3339Nano)})).NotTo(HaveOccurred())
213+
Expect(now.Unix()).To(Equal(tt.Time.Unix()))
214+
})
203215
})

internal/proto/writer.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,16 @@ func (w *Writer) WriteArg(v interface{}) error {
101101
return w.bytes(w.numBuf)
102102
case time.Duration:
103103
return w.int(v.Nanoseconds())
104-
case encoding.BinaryMarshaler:
105-
b, err := v.MarshalBinary()
106-
if err != nil {
107-
return err
108-
}
109-
return w.bytes(b)
110104
case net.IP:
111105
return w.bytes(v)
112106
default:
107+
if m, ok := v.(encoding.BinaryMarshaler); ok {
108+
b, err := m.MarshalBinary()
109+
if err != nil {
110+
return err
111+
}
112+
return w.bytes(b)
113+
}
113114
return fmt.Errorf(
114115
"redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
115116
}

0 commit comments

Comments
 (0)