mirror of https://github.com/go-redis/redis.git
Refactor scan signature to work with Slice and StringMap cmds
This commit is contained in:
parent
a4144ea98e
commit
f9dfc7a949
28
command.go
28
command.go
|
@ -372,11 +372,12 @@ func (cmd *SliceCmd) String() string {
|
||||||
return cmdString(cmd, cmd.val)
|
return cmdString(cmd, cmd.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan scans the results from a key-value Redis map result set ([]interface{})
|
// Scan scans the results from the map into a destination struct. The map keys
|
||||||
// like HMGET and HGETALL to a destination struct.
|
// are matched in the Redis struct fields by the `redis:"field"` tag.
|
||||||
// The Redis keys are matched to the struct's field with the `redis` tag.
|
func (cmd *SliceCmd) Scan(dest interface{}) error {
|
||||||
func (cmd *SliceCmd) Scan(val interface{}) error {
|
// Pass the list of keys and values. Skip the first to args (command, key),
|
||||||
return hscan.Scan(cmd.val, val)
|
// eg: HMGET map.
|
||||||
|
return hscan.Scan(cmd.args[2:], cmd.val, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
|
func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
|
||||||
|
@ -925,6 +926,23 @@ func (cmd *StringStringMapCmd) String() string {
|
||||||
return cmdString(cmd, cmd.val)
|
return cmdString(cmd, cmd.val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scan scans the results from the map into a destination struct. The map keys
|
||||||
|
// are matched in the Redis struct fields by the `redis:"field"` tag.
|
||||||
|
func (cmd *StringStringMapCmd) Scan(dest interface{}) error {
|
||||||
|
// Pass the list of keys and values. Skip the first to args (command, key),
|
||||||
|
// eg: HGETALL map.
|
||||||
|
var (
|
||||||
|
keys = make([]interface{}, 0, len(cmd.val))
|
||||||
|
vals = make([]interface{}, 0, len(cmd.val))
|
||||||
|
)
|
||||||
|
for k, v := range cmd.val {
|
||||||
|
keys = append(keys, k)
|
||||||
|
vals = append(vals, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hscan.Scan(keys, vals, dest)
|
||||||
|
}
|
||||||
|
|
||||||
func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
|
func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
|
||||||
_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
|
_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
|
||||||
cmd.val = make(map[string]string, n/2)
|
cmd.val = make(map[string]string, n/2)
|
||||||
|
|
|
@ -1375,6 +1375,22 @@ var _ = Describe("Commands", func() {
|
||||||
Expect(m).To(Equal(map[string]string{"key1": "hello1", "key2": "hello2"}))
|
Expect(m).To(Equal(map[string]string{"key1": "hello1", "key2": "hello2"}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should scan", func() {
|
||||||
|
err := client.HMSet(ctx, "hash", "key1", "hello1", "key2", 123).Err()
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
res := client.HGetAll(ctx, "hash")
|
||||||
|
Expect(res.Err()).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
type data struct {
|
||||||
|
Key1 string `redis:"key1"`
|
||||||
|
Key2 int `redis:"key2"`
|
||||||
|
}
|
||||||
|
var d data
|
||||||
|
Expect(res.Scan(&d)).NotTo(HaveOccurred())
|
||||||
|
Expect(d).To(Equal(data{Key1: "hello1", Key2: 123}))
|
||||||
|
})
|
||||||
|
|
||||||
It("should HIncrBy", func() {
|
It("should HIncrBy", func() {
|
||||||
hSet := client.HSet(ctx, "hash", "key", "5")
|
hSet := client.HSet(ctx, "hash", "key", "5")
|
||||||
Expect(hSet.Err()).NotTo(HaveOccurred())
|
Expect(hSet.Err()).NotTo(HaveOccurred())
|
||||||
|
|
|
@ -46,12 +46,11 @@ var (
|
||||||
structSpecs = newStructMap()
|
structSpecs = newStructMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Scan scans the results from a key-value Redis map result set ([]interface{})
|
// Scan scans the results from a key-value Redis map result set to a destination struct.
|
||||||
// to a destination struct. The Redis keys are matched to the struct's field
|
// The Redis keys are matched to the struct's field with the `redis` tag.
|
||||||
// with the `redis` tag.
|
func Scan(keys []interface{}, vals []interface{}, dest interface{}) error {
|
||||||
func Scan(vals []interface{}, dest interface{}) error {
|
if len(keys) != len(vals) {
|
||||||
if len(vals)%2 != 0 {
|
return errors.New("args should have the same number of keys and vals")
|
||||||
return errors.New("args should have an even number of items (key-val)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The destination to scan into should be a struct pointer.
|
// The destination to scan into should be a struct pointer.
|
||||||
|
@ -72,13 +71,13 @@ func Scan(vals []interface{}, dest interface{}) error {
|
||||||
fMap := structSpecs.get(typ)
|
fMap := structSpecs.get(typ)
|
||||||
|
|
||||||
// Iterate through the (key, value) sequence.
|
// Iterate through the (key, value) sequence.
|
||||||
for i := 0; i < len(vals); i += 2 {
|
for i := 0; i < len(vals); i++ {
|
||||||
key, ok := vals[i].(string)
|
key, ok := keys[i].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val, ok := vals[i+1].(string)
|
val, ok := vals[i].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ type data struct {
|
||||||
Bool bool `redis:"bool"`
|
Bool bool `redis:"bool"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type i []interface{}
|
||||||
|
|
||||||
func TestGinkgoSuite(t *testing.T) {
|
func TestGinkgoSuite(t *testing.T) {
|
||||||
RegisterFailHandler(Fail)
|
RegisterFailHandler(Fail)
|
||||||
RunSpecs(t, "hscan")
|
RunSpecs(t, "hscan")
|
||||||
|
@ -26,35 +28,33 @@ func TestGinkgoSuite(t *testing.T) {
|
||||||
|
|
||||||
var _ = Describe("Scan", func() {
|
var _ = Describe("Scan", func() {
|
||||||
It("catches bad args", func() {
|
It("catches bad args", func() {
|
||||||
var d data
|
var (
|
||||||
|
d data
|
||||||
|
)
|
||||||
|
|
||||||
Expect(Scan([]interface{}{}, &d)).NotTo(HaveOccurred())
|
Expect(Scan(i{}, i{}, &d)).NotTo(HaveOccurred())
|
||||||
Expect(d).To(Equal(data{}))
|
Expect(d).To(Equal(data{}))
|
||||||
|
|
||||||
Expect(Scan([]interface{}{"key"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"key"}, i{}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"key", "1", "2"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"key"}, i{"1", "2"}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"key", "1"}, nil)).To(HaveOccurred())
|
Expect(Scan(i{"key", "1"}, i{}, nil)).To(HaveOccurred())
|
||||||
|
|
||||||
var i map[string]interface{}
|
var m map[string]interface{}
|
||||||
Expect(Scan([]interface{}{"key", "1"}, &i)).To(HaveOccurred())
|
Expect(Scan(i{"key"}, i{"1"}, &m)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"key", "1"}, data{})).To(HaveOccurred())
|
Expect(Scan(i{"key"}, i{"1"}, data{})).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"key", nil, "string", nil}, data{})).To(HaveOccurred())
|
Expect(Scan(i{"key", "string"}, i{nil, nil}, data{})).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("scans good values", func() {
|
It("scans good values", func() {
|
||||||
var d data
|
var d data
|
||||||
|
|
||||||
// non-tagged fields.
|
// non-tagged fields.
|
||||||
Expect(Scan([]interface{}{"key", "value"}, &d)).NotTo(HaveOccurred())
|
Expect(Scan(i{"key"}, i{"value"}, &d)).NotTo(HaveOccurred())
|
||||||
Expect(d).To(Equal(data{}))
|
Expect(d).To(Equal(data{}))
|
||||||
|
|
||||||
res := []interface{}{"string", "str!",
|
keys := i{"string", "byte", "int", "uint", "float", "bool"}
|
||||||
"byte", "bytes!",
|
vals := i{"str!", "bytes!", "123", "456", "123.456", "1"}
|
||||||
"int", "123",
|
Expect(Scan(keys, vals, &d)).NotTo(HaveOccurred())
|
||||||
"uint", "456",
|
|
||||||
"float", "123.456",
|
|
||||||
"bool", "1"}
|
|
||||||
Expect(Scan(res, &d)).NotTo(HaveOccurred())
|
|
||||||
Expect(d).To(Equal(data{
|
Expect(d).To(Equal(data{
|
||||||
String: "str!",
|
String: "str!",
|
||||||
Bytes: []byte("bytes!"),
|
Bytes: []byte("bytes!"),
|
||||||
|
@ -75,7 +75,7 @@ var _ = Describe("Scan", func() {
|
||||||
Bool bool `redis:"bool"`
|
Bool bool `redis:"bool"`
|
||||||
}
|
}
|
||||||
var d2 data2
|
var d2 data2
|
||||||
Expect(Scan(res, &d2)).NotTo(HaveOccurred())
|
Expect(Scan(keys, vals, &d2)).NotTo(HaveOccurred())
|
||||||
Expect(d2).To(Equal(data2{
|
Expect(d2).To(Equal(data2{
|
||||||
String: "str!",
|
String: "str!",
|
||||||
Bytes: []byte("bytes!"),
|
Bytes: []byte("bytes!"),
|
||||||
|
@ -85,10 +85,7 @@ var _ = Describe("Scan", func() {
|
||||||
Bool: true,
|
Bool: true,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
Expect(Scan([]interface{}{
|
Expect(Scan(i{"string", "float", "bool"}, i{"", "1", "t"}, &d)).NotTo(HaveOccurred())
|
||||||
"string", "",
|
|
||||||
"float", "1",
|
|
||||||
"bool", "t"}, &d)).NotTo(HaveOccurred())
|
|
||||||
Expect(d).To(Equal(data{
|
Expect(d).To(Equal(data{
|
||||||
String: "",
|
String: "",
|
||||||
Bytes: []byte("bytes!"),
|
Bytes: []byte("bytes!"),
|
||||||
|
@ -102,10 +99,7 @@ var _ = Describe("Scan", func() {
|
||||||
It("omits untagged fields", func() {
|
It("omits untagged fields", func() {
|
||||||
var d data
|
var d data
|
||||||
|
|
||||||
Expect(Scan([]interface{}{
|
Expect(Scan(i{"empty", "omit", "string"}, i{"value", "value", "str!"}, &d)).NotTo(HaveOccurred())
|
||||||
"empty", "value",
|
|
||||||
"omit", "value",
|
|
||||||
"string", "str!"}, &d)).NotTo(HaveOccurred())
|
|
||||||
Expect(d).To(Equal(data{
|
Expect(d).To(Equal(data{
|
||||||
String: "str!",
|
String: "str!",
|
||||||
}))
|
}))
|
||||||
|
@ -114,12 +108,12 @@ var _ = Describe("Scan", func() {
|
||||||
It("catches bad values", func() {
|
It("catches bad values", func() {
|
||||||
var d data
|
var d data
|
||||||
|
|
||||||
Expect(Scan([]interface{}{"int", "a"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"int"}, i{"a"}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"uint", "a"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"uint"}, i{"a"}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"uint", ""}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"uint"}, i{""}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"float", "b"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"float"}, i{"b"}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"bool", "-1"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"bool"}, i{"-1"}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"bool", ""}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"bool"}, i{""}, &d)).To(HaveOccurred())
|
||||||
Expect(Scan([]interface{}{"bool", "123"}, &d)).To(HaveOccurred())
|
Expect(Scan(i{"bool"}, i{"123"}, &d)).To(HaveOccurred())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue