5
5
"errors"
6
6
"io"
7
7
"reflect"
8
+ "strings"
8
9
"time"
9
10
10
11
"github.com/go-redis/redis/v9/internal"
@@ -75,31 +76,44 @@ func appendArg(dst []interface{}, arg interface{}) []interface{} {
75
76
}
76
77
return dst
77
78
default :
79
+ // scan struct field
80
+ v := reflect .ValueOf (arg )
81
+ if v .Type ().Kind () == reflect .Ptr {
82
+ if v .IsNil () {
83
+ // error: arg is not a valid object
84
+ return dst
85
+ }
86
+ v = v .Elem ()
87
+ }
88
+
89
+ if v .Type ().Kind () == reflect .Struct {
90
+ return appendStructField (dst , v )
91
+ }
92
+
78
93
return append (dst , arg )
79
94
}
80
95
}
81
96
82
- func structToMap (items interface {}) map [string ]interface {} {
83
- res := map [string ]interface {}{}
84
- if items == nil {
85
- return res
86
- }
87
- v := reflect .TypeOf (items )
88
- reflectValue := reflect .Indirect (reflect .ValueOf (items ))
89
-
90
- if v .Kind () == reflect .Ptr {
91
- v = v .Elem ()
92
- }
93
- for i := 0 ; i < v .NumField (); i ++ {
94
- tag := v .Field (i ).Tag .Get ("redis" )
97
+ // appendStructField appends the field and value held by the structure v to dst, and returns the appended dst.
98
+ func appendStructField (dst []interface {}, v reflect.Value ) []interface {} {
99
+ typ := v .Type ()
100
+ for i := 0 ; i < typ .NumField (); i ++ {
101
+ tag := typ .Field (i ).Tag .Get ("redis" )
102
+ if tag == "" || tag == "-" {
103
+ continue
104
+ }
105
+ tag = strings .Split (tag , "," )[0 ]
106
+ if tag == "" {
107
+ continue
108
+ }
95
109
96
- if tag != "" && v .Field (i ). Type . Kind () != reflect . Struct {
97
- field := reflectValue . Field ( i ). Interface ()
98
- res [ tag ] = field
110
+ field := v .Field (i )
111
+ if field . CanInterface () {
112
+ dst = append ( dst , tag , field . Interface ())
99
113
}
100
114
}
101
115
102
- return res
116
+ return dst
103
117
}
104
118
105
119
type Cmdable interface {
@@ -904,6 +918,7 @@ func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
904
918
// - MSet("key1", "value1", "key2", "value2")
905
919
// - MSet([]string{"key1", "value1", "key2", "value2"})
906
920
// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
921
+ // - MSet(struct), For struct types, see HSet description.
907
922
func (c cmdable ) MSet (ctx context.Context , values ... interface {}) * StatusCmd {
908
923
args := make ([]interface {}, 1 , 1 + len (values ))
909
924
args [0 ] = "mset"
@@ -917,6 +932,7 @@ func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
917
932
// - MSetNX("key1", "value1", "key2", "value2")
918
933
// - MSetNX([]string{"key1", "value1", "key2", "value2"})
919
934
// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
935
+ // - MSetNX(struct), For struct types, see HSet description.
920
936
func (c cmdable ) MSetNX (ctx context.Context , values ... interface {}) * BoolCmd {
921
937
args := make ([]interface {}, 1 , 1 + len (values ))
922
938
args [0 ] = "msetnx"
@@ -1319,21 +1335,27 @@ func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *Slice
1319
1335
}
1320
1336
1321
1337
// HSet accepts values in following formats:
1338
+ //
1322
1339
// - HSet("myhash", "key1", "value1", "key2", "value2")
1340
+ //
1323
1341
// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
1342
+ //
1324
1343
// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
1325
1344
//
1326
- // Playing struct With "redis" tag
1327
- // - type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
1345
+ // Playing struct With "redis" tag.
1346
+ // type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
1347
+ //
1328
1348
// - HSet("myhash", MyHash{"value1", "value2"})
1329
1349
//
1350
+ // For struct, can be a structure pointer type, we only parse the field whose tag is redis.
1351
+ // if you don't want the field to be read, you can use the `redis:"-"` flag to ignore it,
1352
+ // or you don't need to set the redis tag.
1353
+ // For the type of structure field, we only support simple data types:
1354
+ // string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ),
1355
+ // if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface.
1356
+ //
1330
1357
// Note that it requires Redis v4 for multiple field/value pairs support.
1331
1358
func (c cmdable ) HSet (ctx context.Context , key string , values ... interface {}) * IntCmd {
1332
- if len (values ) == 1 {
1333
- if reflect .ValueOf (values [0 ]).Kind () == reflect .Struct {
1334
- values = []interface {}{structToMap (values [0 ])}
1335
- }
1336
- }
1337
1359
args := make ([]interface {}, 2 , 2 + len (values ))
1338
1360
args [0 ] = "hset"
1339
1361
args [1 ] = key
0 commit comments