1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-31 05:04:23 +03:00

feat: appendArgs adds to read the structure field and supplements the test

Signed-off-by: monkey92t <golang@88.com>
This commit is contained in:
monkey92t
2023-01-19 15:31:31 +08:00
parent 684f34d441
commit 0064199323
2 changed files with 122 additions and 24 deletions

View File

@ -5,6 +5,7 @@ import (
"errors"
"io"
"reflect"
"strings"
"time"
"github.com/go-redis/redis/v9/internal"
@ -75,31 +76,44 @@ func appendArg(dst []interface{}, arg interface{}) []interface{} {
}
return dst
default:
// scan struct field
v := reflect.ValueOf(arg)
if v.Type().Kind() == reflect.Ptr {
if v.IsNil() {
// error: arg is not a valid object
return dst
}
v = v.Elem()
}
if v.Type().Kind() == reflect.Struct {
return appendStructField(dst, v)
}
return append(dst, arg)
}
}
func structToMap(items interface{}) map[string]interface{} {
res := map[string]interface{}{}
if items == nil {
return res
}
v := reflect.TypeOf(items)
reflectValue := reflect.Indirect(reflect.ValueOf(items))
// appendStructField appends the field and value held by the structure v to dst, and returns the appended dst.
func appendStructField(dst []interface{}, v reflect.Value) []interface{} {
typ := v.Type()
for i := 0; i < typ.NumField(); i++ {
tag := typ.Field(i).Tag.Get("redis")
if tag == "" || tag == "-" {
continue
}
tag = strings.Split(tag, ",")[0]
if tag == "" {
continue
}
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
tag := v.Field(i).Tag.Get("redis")
if tag != "" && v.Field(i).Type.Kind() != reflect.Struct {
field := reflectValue.Field(i).Interface()
res[tag] = field
field := v.Field(i)
if field.CanInterface() {
dst = append(dst, tag, field.Interface())
}
}
return res
return dst
}
type Cmdable interface {
@ -904,6 +918,7 @@ func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
// - MSet("key1", "value1", "key2", "value2")
// - MSet([]string{"key1", "value1", "key2", "value2"})
// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
// - MSet(struct), For struct types, see HSet description.
func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
args := make([]interface{}, 1, 1+len(values))
args[0] = "mset"
@ -917,6 +932,7 @@ func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
// - MSetNX("key1", "value1", "key2", "value2")
// - MSetNX([]string{"key1", "value1", "key2", "value2"})
// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
// - MSetNX(struct), For struct types, see HSet description.
func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
args := make([]interface{}, 1, 1+len(values))
args[0] = "msetnx"
@ -1319,21 +1335,27 @@ func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *Slice
}
// HSet accepts values in following formats:
//
// - HSet("myhash", "key1", "value1", "key2", "value2")
//
// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
//
// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
//
// Playing struct With "redis" tag
// - type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
// Playing struct With "redis" tag.
// type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
//
// - HSet("myhash", MyHash{"value1", "value2"})
//
// For struct, can be a structure pointer type, we only parse the field whose tag is redis.
// if you don't want the field to be read, you can use the `redis:"-"` flag to ignore it,
// or you don't need to set the redis tag.
// For the type of structure field, we only support simple data types:
// string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ),
// if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface.
//
// Note that it requires Redis v4 for multiple field/value pairs support.
func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
if len(values) == 1 {
if reflect.ValueOf(values[0]).Kind() == reflect.Struct {
values = []interface{}{structToMap(values[0])}
}
}
args := make([]interface{}, 2, 2+len(values))
args[0] = "hset"
args[1] = key