From c82876433698ae24c7a2504a340f535e758af252 Mon Sep 17 00:00:00 2001 From: Ilia Kuznetcov Date: Sun, 17 Dec 2023 15:42:45 +0000 Subject: [PATCH 1/3] Allow scanning redis values into pointer fields (#2787) * Allow scanning redis values into pointer fields * Formatting --------- Co-authored-by: Ilia Personal Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- command.go | 1 - internal/hscan/hscan_test.go | 9 +++++++-- internal/hscan/structmap.go | 6 +++++- json.go | 9 +-------- json_test.go | 11 +---------- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/command.go b/command.go index 1a33cb32..4ef335a9 100644 --- a/command.go +++ b/command.go @@ -5378,7 +5378,6 @@ func (cmd *InfoCmd) readReply(rd *proto.Reader) error { } return nil - } func (cmd *InfoCmd) Item(section, key string) string { diff --git a/internal/hscan/hscan_test.go b/internal/hscan/hscan_test.go index 728ffad0..6c9b3030 100644 --- a/internal/hscan/hscan_test.go +++ b/internal/hscan/hscan_test.go @@ -8,6 +8,8 @@ import ( . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" + + "github.com/redis/go-redis/v9/internal/util" ) type data struct { @@ -29,6 +31,7 @@ type data struct { Float float32 `redis:"float"` Float64 float64 `redis:"float64"` Bool bool `redis:"bool"` + BoolRef *bool `redis:"boolRef"` } type TimeRFC3339Nano struct { @@ -117,10 +120,10 @@ var _ = Describe("Scan", func() { Expect(Scan(&d, i{"key"}, i{"value"})).NotTo(HaveOccurred()) 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{ "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(d).To(Equal(data{ @@ -133,6 +136,7 @@ var _ = Describe("Scan", func() { Float: 123.456, Float64: 1.2345678912345678e+17, Bool: true, + BoolRef: util.ToPtr(true), })) // Scan a different type with the same values to test that @@ -167,6 +171,7 @@ var _ = Describe("Scan", func() { Float: 1.0, Float64: 1.2345678912345678e+17, Bool: true, + BoolRef: util.ToPtr(true), })) }) diff --git a/internal/hscan/structmap.go b/internal/hscan/structmap.go index 234079f0..1a560e4a 100644 --- a/internal/hscan/structmap.go +++ b/internal/hscan/structmap.go @@ -61,7 +61,11 @@ func newStructSpec(t reflect.Type, fieldTag string) *structSpec { } // 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 diff --git a/json.go b/json.go index f9425241..f0d3abbd 100644 --- a/json.go +++ b/json.go @@ -66,7 +66,6 @@ type JSONCmd struct { var _ Cmder = (*JSONCmd)(nil) func newJSONCmd(ctx context.Context, args ...interface{}) *JSONCmd { - return &JSONCmd{ baseCmd: baseCmd{ ctx: ctx, @@ -95,7 +94,6 @@ func (cmd *JSONCmd) Val() string { } else { return cmd.val } - } func (cmd *JSONCmd) Result() (string, error) { @@ -103,7 +101,6 @@ func (cmd *JSONCmd) Result() (string, error) { } func (cmd JSONCmd) Expanded() (interface{}, error) { - if len(cmd.val) != 0 && cmd.expanded == nil { err := json.Unmarshal([]byte(cmd.val), &cmd.expanded) if err != nil { @@ -115,7 +112,6 @@ func (cmd JSONCmd) Expanded() (interface{}, error) { } func (cmd *JSONCmd) readReply(rd *proto.Reader) error { - // nil response from JSON.(M)GET (cmd.baseCmd.err will be "redis: nil") if cmd.baseCmd.Err() == Nil { cmd.val = "" @@ -131,7 +127,7 @@ func (cmd *JSONCmd) readReply(rd *proto.Reader) error { return err } - var expanded = make([]interface{}, size) + expanded := make([]interface{}, size) for i := 0; i < size; i++ { 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 { - if cmd.baseCmd.Err() == Nil { cmd.val = nil return Nil @@ -220,7 +215,6 @@ func (cmd *JSONSliceCmd) readReply(rd *proto.Reader) error { } } return nil - } /******************************************************************************* @@ -262,7 +256,6 @@ func (cmd *IntPointerSliceCmd) Result() ([]*int64, error) { } func (cmd *IntPointerSliceCmd) readReply(rd *proto.Reader) error { - n, err := rd.ReadArrayLen() if err != nil { return err diff --git a/json_test.go b/json_test.go index d527133a..64bf3941 100644 --- a/json_test.go +++ b/json_test.go @@ -5,6 +5,7 @@ import ( . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" + "github.com/redis/go-redis/v9" ) @@ -13,7 +14,6 @@ type JSONGetTestStruct struct { } var _ = Describe("JSON Commands", Label("json"), func() { - ctx := context.TODO() var client *redis.Client @@ -27,7 +27,6 @@ var _ = Describe("JSON Commands", Label("json"), func() { }) Describe("arrays", Label("arrays"), func() { - It("should JSONArrAppend", Label("json.arrappend", "json"), func() { cmd1 := client.JSONSet(ctx, "append2", "$", `{"a": [10], "b": {"a": [12, 13]}}`) 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() Expect(err).NotTo(HaveOccurred()) Expect(res[0]).To(Equal(int64(-1))) - }) 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.Val()).To(Equal("[[100,200,200]]")) }) - }) 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() Expect(err).NotTo(HaveOccurred()) Expect(res).To(Equal(`[~-{~--"a":!1,~--"b":!2~-}~]`)) - }) 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() Expect(err).NotTo(HaveOccurred()) Expect(iRes).To(Equal([]interface{}{nil, nil})) - }) - }) Describe("Misc", Label("misc"), func() { - It("should JSONClear", Label("json.clear", "json"), func() { cmd1 := client.JSONSet(ctx, "clear1", "$", `[1]`) Expect(cmd1.Err()).NotTo(HaveOccurred()) @@ -460,7 +453,6 @@ var _ = Describe("JSON Commands", Label("json"), func() { cmd3 := client.JSONGet(ctx, "forget3", "$") Expect(cmd3.Err()).NotTo(HaveOccurred()) Expect(cmd3.Val()).To(Equal(`[{"b":{"b":"annie"}}]`)) - }) 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() Expect(err).NotTo(HaveOccurred()) Expect(cmd3).To(Equal(`["foobar"]`)) - }) It("should JSONStrAppend and JSONStrLen with $", Label("json.strappend", "json.strlen", "json"), func() { From 9073e4056de44fe547b4a84840f868165f2f414a Mon Sep 17 00:00:00 2001 From: rouzier Date: Sun, 17 Dec 2023 10:43:21 -0500 Subject: [PATCH 2/3] Update docs and examples (#2806) * Fix example 'Connecting via a redis url' and make it compile * Fix name of example --------- Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- README.md | 9 +++++---- example/lua-scripting/go.mod | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b08330df..98edbe21 100644 --- a/README.md +++ b/README.md @@ -149,15 +149,16 @@ import ( "github.com/redis/go-redis/v9" ) -var ctx = context.Background() - -func ExampleClient() { +func ExampleClient() *redis.Client { url := "redis://user:password@localhost:6379/0?protocol=3" opts, err := redis.ParseURL(url) if err != nil { panic(err) } - rdb := redis.NewClient(opts) + + return redis.NewClient(opts) +} + ``` ## Contributing diff --git a/example/lua-scripting/go.mod b/example/lua-scripting/go.mod index 97416d41..a19f0ab1 100644 --- a/example/lua-scripting/go.mod +++ b/example/lua-scripting/go.mod @@ -1,4 +1,4 @@ -module github.com/redis/go-redis/example/redis-bloom +module github.com/redis/go-redis/example/lua-scripting go 1.18 From 5665b0f7ea26298a8c7ff45323348e7b04b8d491 Mon Sep 17 00:00:00 2001 From: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> Date: Sun, 17 Dec 2023 17:45:00 +0200 Subject: [PATCH 3/3] Clarify TSMadd ktvSlices usage in docstring (#2827) * Clarify TSMadd ktvSlices usage in docstring * change syntax --- timeseries_commands.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/timeseries_commands.go b/timeseries_commands.go index 61cc3a5b..6f1b2fa4 100644 --- a/timeseries_commands.go +++ b/timeseries_commands.go @@ -531,6 +531,8 @@ func (c cmdable) TSInfoWithArgs(ctx context.Context, key string, options *TSInfo } // TSMAdd - Adds multiple samples to multiple time-series keys. +// It accepts a slice of 'ktv' slices, each containing exactly three elements: key, timestamp, and value. +// This struct must be provided for this command to work. // For more information - https://redis.io/commands/ts.madd/ func (c cmdable) TSMAdd(ctx context.Context, ktvSlices [][]interface{}) *IntSliceCmd { args := []interface{}{"TS.MADD"}