Allow scanning redis values into pointer fields (#2787)

* Allow scanning redis values into pointer fields

* Formatting

---------

Co-authored-by: Ilia Personal <iliapersonal@Ilyas-MBP.station>
Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com>
This commit is contained in:
Ilia Kuznetcov 2023-12-17 15:42:45 +00:00 committed by GitHub
parent 716906adda
commit c828764336
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 14 additions and 22 deletions

View File

@ -5378,7 +5378,6 @@ func (cmd *InfoCmd) readReply(rd *proto.Reader) error {
} }
return nil return nil
} }
func (cmd *InfoCmd) Item(section, key string) string { func (cmd *InfoCmd) Item(section, key string) string {

View File

@ -8,6 +8,8 @@ import (
. "github.com/bsm/ginkgo/v2" . "github.com/bsm/ginkgo/v2"
. "github.com/bsm/gomega" . "github.com/bsm/gomega"
"github.com/redis/go-redis/v9/internal/util"
) )
type data struct { type data struct {
@ -29,6 +31,7 @@ type data struct {
Float float32 `redis:"float"` Float float32 `redis:"float"`
Float64 float64 `redis:"float64"` Float64 float64 `redis:"float64"`
Bool bool `redis:"bool"` Bool bool `redis:"bool"`
BoolRef *bool `redis:"boolRef"`
} }
type TimeRFC3339Nano struct { type TimeRFC3339Nano struct {
@ -117,10 +120,10 @@ var _ = Describe("Scan", func() {
Expect(Scan(&d, i{"key"}, i{"value"})).NotTo(HaveOccurred()) Expect(Scan(&d, i{"key"}, i{"value"})).NotTo(HaveOccurred())
Expect(d).To(Equal(data{})) Expect(d).To(Equal(data{}))
keys := i{"string", "byte", "int", "int64", "uint", "uint64", "float", "float64", "bool"} keys := i{"string", "byte", "int", "int64", "uint", "uint64", "float", "float64", "bool", "boolRef"}
vals := i{ vals := i{
"str!", "bytes!", "123", "123456789123456789", "456", "987654321987654321", "str!", "bytes!", "123", "123456789123456789", "456", "987654321987654321",
"123.456", "123456789123456789.987654321987654321", "1", "123.456", "123456789123456789.987654321987654321", "1", "1",
} }
Expect(Scan(&d, keys, vals)).NotTo(HaveOccurred()) Expect(Scan(&d, keys, vals)).NotTo(HaveOccurred())
Expect(d).To(Equal(data{ Expect(d).To(Equal(data{
@ -133,6 +136,7 @@ var _ = Describe("Scan", func() {
Float: 123.456, Float: 123.456,
Float64: 1.2345678912345678e+17, Float64: 1.2345678912345678e+17,
Bool: true, Bool: true,
BoolRef: util.ToPtr(true),
})) }))
// Scan a different type with the same values to test that // Scan a different type with the same values to test that
@ -167,6 +171,7 @@ var _ = Describe("Scan", func() {
Float: 1.0, Float: 1.0,
Float64: 1.2345678912345678e+17, Float64: 1.2345678912345678e+17,
Bool: true, Bool: true,
BoolRef: util.ToPtr(true),
})) }))
}) })

View File

@ -61,7 +61,11 @@ func newStructSpec(t reflect.Type, fieldTag string) *structSpec {
} }
// Use the built-in decoder. // Use the built-in decoder.
out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]}) kind := f.Type.Kind()
if kind == reflect.Pointer {
kind = f.Type.Elem().Kind()
}
out.set(tag, &structField{index: i, fn: decoders[kind]})
} }
return out return out

View File

@ -66,7 +66,6 @@ type JSONCmd struct {
var _ Cmder = (*JSONCmd)(nil) var _ Cmder = (*JSONCmd)(nil)
func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd { func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd {
return &JSONCmd{ return &JSONCmd{
baseCmd: baseCmd{ baseCmd: baseCmd{
ctx: ctx, ctx: ctx,
@ -95,7 +94,6 @@ func (cmd *JSONCmd) Val() string {
} else { } else {
return cmd.val return cmd.val
} }
} }
func (cmd *JSONCmd) Result() (string, error) { func (cmd *JSONCmd) Result() (string, error) {
@ -103,7 +101,6 @@ func (cmd *JSONCmd) Result() (string, error) {
} }
func (cmd JSONCmd) Expanded() (interface{}, error) { func (cmd JSONCmd) Expanded() (interface{}, error) {
if len(cmd.val) != 0 && cmd.expanded == nil { if len(cmd.val) != 0 && cmd.expanded == nil {
err := json.Unmarshal([]byte(cmd.val), &cmd.expanded) err := json.Unmarshal([]byte(cmd.val), &cmd.expanded)
if err != nil { if err != nil {
@ -115,7 +112,6 @@ func (cmd JSONCmd) Expanded() (interface{}, error) {
} }
func (cmd *JSONCmd) readReply(rd *proto.Reader) error { func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
// nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil") // nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil")
if cmd.baseCmd.Err() == Nil { if cmd.baseCmd.Err() == Nil {
cmd.val = "" cmd.val = ""
@ -131,7 +127,7 @@ func (cmd *JSONCmd) readReply(rd *proto.Reader) error {
return err return err
} }
var expanded = make([]interface{}, size) expanded := make([]interface{}, size)
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
if expanded[i], err = rd.ReadReply(); err != nil { if expanded[i], err = rd.ReadReply(); err != nil {
@ -186,7 +182,6 @@ func (cmd *JSONSliceCmd) Result() ([]interface{}, error) {
} }
func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error { func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
if cmd.baseCmd.Err() == Nil { if cmd.baseCmd.Err() == Nil {
cmd.val = nil cmd.val = nil
return Nil return Nil
@ -220,7 +215,6 @@ func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error {
} }
} }
return nil return nil
} }
/******************************************************************************* /*******************************************************************************
@ -262,7 +256,6 @@ func (cmd *IntPointerSliceCmd) Result() ([]*int64, error) {
} }
func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error { func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error {
n, err := rd.ReadArrayLen() n, err := rd.ReadArrayLen()
if err != nil { if err != nil {
return err return err

View File

@ -5,6 +5,7 @@ import (
. "github.com/bsm/ginkgo/v2" . "github.com/bsm/ginkgo/v2"
. "github.com/bsm/gomega" . "github.com/bsm/gomega"
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
) )
@ -13,7 +14,6 @@ type JSONGetTestStruct struct {
} }
var _ = Describe("JSON Commands", Label("json"), func() { var _ = Describe("JSON Commands", Label("json"), func() {
ctx := context.TODO() ctx := context.TODO()
var client *redis.Client var client *redis.Client
@ -27,7 +27,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
}) })
Describe("arrays", Label("arrays"), func() { Describe("arrays", Label("arrays"), func() {
It("should JSONArrAppend", Label("json.arrappend", "json"), func() { It("should JSONArrAppend", Label("json.arrappend", "json"), func() {
cmd1 := client.JSONSet(ctx, "append2", "$", `{"a": [10], "b": {"a": [12, 13]}}`) cmd1 := client.JSONSet(ctx, "append2", "$", `{"a": [10], "b": {"a": [12, 13]}}`)
Expect(cmd1.Err()).NotTo(HaveOccurred()) Expect(cmd1.Err()).NotTo(HaveOccurred())
@ -76,7 +75,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result() res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(res[0]).To(Equal(int64(-1))) Expect(res[0]).To(Equal(int64(-1)))
}) })
It("should JSONArrIndex and JSONArrIndexWithArgs with $", Label("json.arrindex", "json"), func() { It("should JSONArrIndex and JSONArrIndexWithArgs with $", Label("json.arrindex", "json"), func() {
@ -235,7 +233,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
Expect(cmd3.Err()).NotTo(HaveOccurred()) Expect(cmd3.Err()).NotTo(HaveOccurred())
Expect(cmd3.Val()).To(Equal("[[100,200,200]]")) Expect(cmd3.Val()).To(Equal("[[100,200,200]]"))
}) })
}) })
Describe("get/set", Label("getset"), func() { Describe("get/set", Label("getset"), func() {
@ -257,7 +254,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-", Newline: `~`, Space: `!`}).Result() res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-", Newline: `~`, Space: `!`}).Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(res).To(Equal(`[~-{~--"a":!1,~--"b":!2~-}~]`)) Expect(res).To(Equal(`[~-{~--"a":!1,~--"b":!2~-}~]`))
}) })
It("should JSONMerge", Label("json.merge", "json"), func() { It("should JSONMerge", Label("json.merge", "json"), func() {
@ -330,13 +326,10 @@ var _ = Describe("JSON Commands", Label("json"), func() {
iRes, err = client.JSONMGet(ctx, "$..a", "non_existing_doc", "non_existing_doc1").Result() iRes, err = client.JSONMGet(ctx, "$..a", "non_existing_doc", "non_existing_doc1").Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(iRes).To(Equal([]interface{}{nil, nil})) Expect(iRes).To(Equal([]interface{}{nil, nil}))
}) })
}) })
Describe("Misc", Label("misc"), func() { Describe("Misc", Label("misc"), func() {
It("should JSONClear", Label("json.clear", "json"), func() { It("should JSONClear", Label("json.clear", "json"), func() {
cmd1 := client.JSONSet(ctx, "clear1", "$", `[1]`) cmd1 := client.JSONSet(ctx, "clear1", "$", `[1]`)
Expect(cmd1.Err()).NotTo(HaveOccurred()) Expect(cmd1.Err()).NotTo(HaveOccurred())
@ -460,7 +453,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
cmd3 := client.JSONGet(ctx, "forget3", "$") cmd3 := client.JSONGet(ctx, "forget3", "$")
Expect(cmd3.Err()).NotTo(HaveOccurred()) Expect(cmd3.Err()).NotTo(HaveOccurred())
Expect(cmd3.Val()).To(Equal(`[{"b":{"b":"annie"}}]`)) Expect(cmd3.Val()).To(Equal(`[{"b":{"b":"annie"}}]`))
}) })
It("should JSONForget with $", Label("json.forget", "json"), func() { It("should JSONForget with $", Label("json.forget", "json"), func() {
@ -622,7 +614,6 @@ var _ = Describe("JSON Commands", Label("json"), func() {
cmd3, err := client.JSONGet(ctx, "strapp1", "$").Result() cmd3, err := client.JSONGet(ctx, "strapp1", "$").Result()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(cmd3).To(Equal(`["foobar"]`)) Expect(cmd3).To(Equal(`["foobar"]`))
}) })
It("should JSONStrAppend and JSONStrLen with $", Label("json.strappend", "json.strlen", "json"), func() { It("should JSONStrAppend and JSONStrLen with $", Label("json.strappend", "json.strlen", "json"), func() {