From ad131f49b0210b3252648b880921b9f6d2fe452e Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Thu, 26 Sep 2024 13:14:30 +0300 Subject: [PATCH 1/7] Updated package version (#3134) * Updated package version * Changed version format according to specification * Updated submodule versions --- .github/workflows/build.yml | 4 ++-- example/del-keys-without-ttl/go.mod | 2 +- example/hll/go.mod | 2 +- example/lua-scripting/go.mod | 2 +- example/otel/go.mod | 6 +++--- example/redis-bloom/go.mod | 2 +- example/scan-struct/go.mod | 2 +- extra/rediscensus/go.mod | 4 ++-- extra/rediscmd/go.mod | 2 +- extra/redisotel/go.mod | 8 +++----- extra/redisprometheus/go.mod | 2 +- version.go | 2 +- 12 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5007423a..eb0c20ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Go on: push: - branches: [master, v9] + branches: [master, v9, v9.7] pull_request: - branches: [master, v9] + branches: [master, v9, v9.7] permissions: contents: read diff --git a/example/del-keys-without-ttl/go.mod b/example/del-keys-without-ttl/go.mod index 715454c6..47e3e865 100644 --- a/example/del-keys-without-ttl/go.mod +++ b/example/del-keys-without-ttl/go.mod @@ -5,7 +5,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. require ( - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 go.uber.org/zap v1.24.0 ) diff --git a/example/hll/go.mod b/example/hll/go.mod index f68ff25d..1d69d427 100644 --- a/example/hll/go.mod +++ b/example/hll/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.6.1 +require github.com/redis/go-redis/v9 v9.7.0-beta.1 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/lua-scripting/go.mod b/example/lua-scripting/go.mod index 176e03d0..c0506b78 100644 --- a/example/lua-scripting/go.mod +++ b/example/lua-scripting/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.6.1 +require github.com/redis/go-redis/v9 v9.7.0-beta.1 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/otel/go.mod b/example/otel/go.mod index 2b5030ab..fa9c4871 100644 --- a/example/otel/go.mod +++ b/example/otel/go.mod @@ -9,8 +9,8 @@ replace github.com/redis/go-redis/extra/redisotel/v9 => ../../extra/redisotel replace github.com/redis/go-redis/extra/rediscmd/v9 => ../../extra/rediscmd require ( - github.com/redis/go-redis/extra/redisotel/v9 v9.6.1 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/extra/redisotel/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 github.com/uptrace/uptrace-go v1.21.0 go.opentelemetry.io/otel v1.22.0 ) @@ -23,7 +23,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect - github.com/redis/go-redis/extra/rediscmd/v9 v9.6.1 // indirect + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.46.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect diff --git a/example/redis-bloom/go.mod b/example/redis-bloom/go.mod index d8e9bfff..820d173f 100644 --- a/example/redis-bloom/go.mod +++ b/example/redis-bloom/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.6.1 +require github.com/redis/go-redis/v9 v9.7.0-beta.1 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/scan-struct/go.mod b/example/scan-struct/go.mod index 45423ec5..b2dcdcb2 100644 --- a/example/scan-struct/go.mod +++ b/example/scan-struct/go.mod @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/davecgh/go-spew v1.1.1 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 ) require ( diff --git a/extra/rediscensus/go.mod b/extra/rediscensus/go.mod index 33221d20..00ef6e43 100644 --- a/extra/rediscensus/go.mod +++ b/extra/rediscensus/go.mod @@ -7,8 +7,8 @@ replace github.com/redis/go-redis/v9 => ../.. replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd require ( - github.com/redis/go-redis/extra/rediscmd/v9 v9.6.1 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 go.opencensus.io v0.24.0 ) diff --git a/extra/rediscmd/go.mod b/extra/rediscmd/go.mod index 7bc65f9e..a5139f27 100644 --- a/extra/rediscmd/go.mod +++ b/extra/rediscmd/go.mod @@ -7,7 +7,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/bsm/ginkgo/v2 v2.12.0 github.com/bsm/gomega v1.27.10 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 ) require ( diff --git a/extra/redisotel/go.mod b/extra/redisotel/go.mod index 3a95b56e..1adda6f6 100644 --- a/extra/redisotel/go.mod +++ b/extra/redisotel/go.mod @@ -7,8 +7,8 @@ replace github.com/redis/go-redis/v9 => ../.. replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd require ( - github.com/redis/go-redis/extra/rediscmd/v9 v9.6.1 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 go.opentelemetry.io/otel v1.22.0 go.opentelemetry.io/otel/metric v1.22.0 go.opentelemetry.io/otel/sdk v1.22.0 @@ -23,6 +23,4 @@ require ( golang.org/x/sys v0.16.0 // indirect ) -retract ( - v9.5.3 // This version was accidentally released. -) +retract v9.5.3 // This version was accidentally released. diff --git a/extra/redisprometheus/go.mod b/extra/redisprometheus/go.mod index 34283600..5e0aa645 100644 --- a/extra/redisprometheus/go.mod +++ b/extra/redisprometheus/go.mod @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/prometheus/client_golang v1.14.0 - github.com/redis/go-redis/v9 v9.6.1 + github.com/redis/go-redis/v9 v9.7.0-beta.1 ) require ( diff --git a/version.go b/version.go index b1234dac..3194f313 100644 --- a/version.go +++ b/version.go @@ -2,5 +2,5 @@ package redis // Version is the current release version. func Version() string { - return "9.6.1" + return "9.7.0-beta.1" } From ec680aec142159539c2594584a5dd31a416a4683 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:55:45 +0300 Subject: [PATCH 2/7] Remove direct read from TLS underlying conn (#3138) (#3154) Co-authored-by: Francesco Renzi --- internal/pool/conn_check.go | 5 ----- internal/pool/conn_check_test.go | 18 ------------------ 2 files changed, 23 deletions(-) diff --git a/internal/pool/conn_check.go b/internal/pool/conn_check.go index 07c261c2..83190d39 100644 --- a/internal/pool/conn_check.go +++ b/internal/pool/conn_check.go @@ -3,7 +3,6 @@ package pool import ( - "crypto/tls" "errors" "io" "net" @@ -17,10 +16,6 @@ func connCheck(conn net.Conn) error { // Reset previous timeout. _ = conn.SetDeadline(time.Time{}) - // Check if tls.Conn. - if c, ok := conn.(*tls.Conn); ok { - conn = c.NetConn() - } sysConn, ok := conn.(syscall.Conn) if !ok { return nil diff --git a/internal/pool/conn_check_test.go b/internal/pool/conn_check_test.go index 21499333..2ade8a0b 100644 --- a/internal/pool/conn_check_test.go +++ b/internal/pool/conn_check_test.go @@ -3,7 +3,6 @@ package pool import ( - "crypto/tls" "net" "net/http/httptest" "time" @@ -15,17 +14,12 @@ import ( var _ = Describe("tests conn_check with real conns", func() { var ts *httptest.Server var conn net.Conn - var tlsConn *tls.Conn var err error BeforeEach(func() { ts = httptest.NewServer(nil) conn, err = net.DialTimeout(ts.Listener.Addr().Network(), ts.Listener.Addr().String(), time.Second) Expect(err).NotTo(HaveOccurred()) - tlsTestServer := httptest.NewUnstartedServer(nil) - tlsTestServer.StartTLS() - tlsConn, err = tls.DialWithDialer(&net.Dialer{Timeout: time.Second}, tlsTestServer.Listener.Addr().Network(), tlsTestServer.Listener.Addr().String(), &tls.Config{InsecureSkipVerify: true}) - Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { @@ -39,23 +33,11 @@ var _ = Describe("tests conn_check with real conns", func() { Expect(connCheck(conn)).To(HaveOccurred()) }) - It("good tls conn check", func() { - Expect(connCheck(tlsConn)).NotTo(HaveOccurred()) - - Expect(tlsConn.Close()).NotTo(HaveOccurred()) - Expect(connCheck(tlsConn)).To(HaveOccurred()) - }) - It("bad conn check", func() { Expect(conn.Close()).NotTo(HaveOccurred()) Expect(connCheck(conn)).To(HaveOccurred()) }) - It("bad tls conn check", func() { - Expect(tlsConn.Close()).NotTo(HaveOccurred()) - Expect(connCheck(tlsConn)).To(HaveOccurred()) - }) - It("check conn deadline", func() { Expect(conn.SetDeadline(time.Now())).NotTo(HaveOccurred()) time.Sleep(time.Millisecond * 10) From ac2e91d9d9ccabefd9a158d5ab294345d2368707 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:59:45 +0300 Subject: [PATCH 3/7] Support Json with Resp 2 (#3146) (#3155) * Support ReJSON resp 2 && Test ReJSON against RESP 2 and 3 && Add complex search and json test * Remove comments * Remove unnecessary changes Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- json.go | 8 +- json_test.go | 1378 ++++++++++++++++++++++++++++---------------------- 2 files changed, 772 insertions(+), 614 deletions(-) diff --git a/json.go b/json.go index ca731db3..b3cadf4b 100644 --- a/json.go +++ b/json.go @@ -60,7 +60,7 @@ type JSONArrTrimArgs struct { type JSONCmd struct { baseCmd val string - expanded []interface{} + expanded interface{} } var _ Cmder = (*JSONCmd)(nil) @@ -100,11 +100,11 @@ func (cmd *JSONCmd) Result() (string, error) { return cmd.Val(), cmd.Err() } -func (cmd JSONCmd) Expanded() (interface{}, 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 { - return "", err + return nil, err } } @@ -494,7 +494,7 @@ func (c cmdable) JSONMSet(ctx context.Context, params ...interface{}) *StatusCmd } // JSONNumIncrBy increments the number value stored at the specified path by the provided number. -// For more information, see https://redis.io/commands/json.numincreby +// For more information, see https://redis.io/docs/latest/commands/json.numincrby/ func (c cmdable) JSONNumIncrBy(ctx context.Context, key, path string, value float64) *JSONCmd { args := []interface{}{"JSON.NUMINCRBY", key, path, value} cmd := newJSONCmd(ctx, args...) diff --git a/json_test.go b/json_test.go index d1ea2429..9139be3a 100644 --- a/json_test.go +++ b/json_test.go @@ -2,6 +2,8 @@ package redis_test import ( "context" + "encoding/json" + "time" . "github.com/bsm/ginkgo/v2" . "github.com/bsm/gomega" @@ -17,644 +19,800 @@ var _ = Describe("JSON Commands", Label("json"), func() { ctx := context.TODO() var client *redis.Client - BeforeEach(func() { - client = redis.NewClient(&redis.Options{Addr: ":6379"}) - Expect(client.FlushAll(ctx).Err()).NotTo(HaveOccurred()) - }) + setupRedisClient := func(protocolVersion int) *redis.Client { + return redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + DB: 0, + Protocol: protocolVersion, + UnstableResp3: true, + }) + } AfterEach(func() { - Expect(client.Close()).NotTo(HaveOccurred()) + if client != nil { + client.FlushDB(ctx) + client.Close() + } }) - 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()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONArrAppend(ctx, "append2", "$..a", 10) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal([]int64{2, 3})) + protocols := []int{2, 3} + for _, protocol := range protocols { + BeforeEach(func() { + client = setupRedisClient(protocol) + Expect(client.FlushAll(ctx).Err()).NotTo(HaveOccurred()) }) - It("should JSONArrIndex and JSONArrIndexWithArgs", Label("json.arrindex", "json"), func() { - cmd1, err := client.JSONSet(ctx, "index1", "$", `{"a": [10], "b": {"a": [12, 10]}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd1).To(Equal("OK")) + 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()) + Expect(cmd1.Val()).To(Equal("OK")) - cmd2, err := client.JSONArrIndex(ctx, "index1", "$.b.a", 10).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd2).To(Equal([]int64{1})) + cmd2 := client.JSONArrAppend(ctx, "append2", "$..a", 10) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal([]int64{2, 3})) + }) - cmd3, err := client.JSONSet(ctx, "index2", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd3).To(Equal("OK")) + It("should JSONArrIndex and JSONArrIndexWithArgs", Label("json.arrindex", "json"), func() { + cmd1, err := client.JSONSet(ctx, "index1", "$", `{"a": [10], "b": {"a": [12, 10]}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd1).To(Equal("OK")) - res, err := client.JSONArrIndex(ctx, "index2", "$", 1).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(1))) + cmd2, err := client.JSONArrIndex(ctx, "index1", "$.b.a", 10).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd2).To(Equal([]int64{1})) - res, err = client.JSONArrIndex(ctx, "index2", "$", 1, 2).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(-1))) + cmd3, err := client.JSONSet(ctx, "index2", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd3).To(Equal("OK")) - res, err = client.JSONArrIndex(ctx, "index2", "$", 4).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(4))) + res, err := client.JSONArrIndex(ctx, "index2", "$", 1).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal(int64(1))) - res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{}, 4).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(4))) + res, err = client.JSONArrIndex(ctx, "index2", "$", 1, 2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal(int64(-1))) - stop := 5000 - res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(4))) + res, err = client.JSONArrIndex(ctx, "index2", "$", 4).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal(int64(4))) - stop = -1 - res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res[0]).To(Equal(int64(-1))) + res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{}, 4).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal(int64(4))) + + stop := 5000 + res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res[0]).To(Equal(int64(4))) + + stop = -1 + 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() { + doc := `{ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95, + "size": [10, 20, 30, 40] + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99, + "size": [50, 60, 70, 80] + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99, + "size": [5, 10, 20, 30] + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99, + "size": [5, 6, 7, 8] + } + ], + "bicycle": {"color": "red", "price": 19.95} + } + }` + res, err := client.JSONSet(ctx, "doc1", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + resGet, err := client.JSONGet(ctx, "doc1", "$.store.book[?(@.price<10)].size").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal("[[10,20,30,40],[5,10,20,30]]")) + + resArr, err := client.JSONArrIndex(ctx, "doc1", "$.store.book[?(@.price<10)].size", 20).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resArr).To(Equal([]int64{1, 2})) + }) + + It("should JSONArrInsert", Label("json.arrinsert", "json"), func() { + cmd1 := client.JSONSet(ctx, "insert2", "$", `[100, 200, 300, 200]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONArrInsert(ctx, "insert2", "$", -1, 1, 2) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal([]int64{6})) + + cmd3 := client.JSONGet(ctx, "insert2") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + // RESP2 vs RESP3 + Expect(cmd3.Val()).To(Or( + Equal(`[100,200,300,1,2,200]`), + Equal(`[[100,200,300,1,2,200]]`))) + }) + + It("should JSONArrLen", Label("json.arrlen", "json"), func() { + cmd1 := client.JSONSet(ctx, "length2", "$", `{"a": [10], "b": {"a": [12, 10, 20, 12, 90, 10]}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONArrLen(ctx, "length2", "$..a") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal([]int64{1, 6})) + }) + + It("should JSONArrPop", Label("json.arrpop"), func() { + cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal([]string{"300"})) + + cmd3 := client.JSONGet(ctx, "pop4", "$") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + Expect(cmd3.Val()).To(Equal("[[100,200,200]]")) + }) + + It("should JSONArrTrim", Label("json.arrtrim", "json"), func() { + cmd1, err := client.JSONSet(ctx, "trim1", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd1).To(Equal("OK")) + + stop := 3 + cmd2, err := client.JSONArrTrimWithArgs(ctx, "trim1", "$", &redis.JSONArrTrimArgs{Start: 1, Stop: &stop}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd2).To(Equal([]int64{3})) + + res, err := client.JSONGet(ctx, "trim1", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`[[1,2,3]]`)) + + cmd3, err := client.JSONSet(ctx, "trim2", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd3).To(Equal("OK")) + + stop = 3 + cmd4, err := client.JSONArrTrimWithArgs(ctx, "trim2", "$", &redis.JSONArrTrimArgs{Start: -1, Stop: &stop}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd4).To(Equal([]int64{0})) + + cmd5, err := client.JSONSet(ctx, "trim3", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd5).To(Equal("OK")) + + stop = 99 + cmd6, err := client.JSONArrTrimWithArgs(ctx, "trim3", "$", &redis.JSONArrTrimArgs{Start: 3, Stop: &stop}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd6).To(Equal([]int64{2})) + + cmd7, err := client.JSONSet(ctx, "trim4", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd7).To(Equal("OK")) + + stop = 1 + cmd8, err := client.JSONArrTrimWithArgs(ctx, "trim4", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd8).To(Equal([]int64{0})) + + cmd9, err := client.JSONSet(ctx, "trim5", "$", `[0,1,2,3,4]`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd9).To(Equal("OK")) + + stop = 11 + cmd10, err := client.JSONArrTrimWithArgs(ctx, "trim5", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd10).To(Equal([]int64{0})) + }) + + It("should JSONArrPop", Label("json.arrpop", "json"), func() { + cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal([]string{"300"})) + + cmd3 := client.JSONGet(ctx, "pop4", "$") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + Expect(cmd3.Val()).To(Equal("[[100,200,200]]")) + }) }) - It("should JSONArrIndex and JSONArrIndexWithArgs with $", Label("json.arrindex", "json"), func() { - doc := `{ - "store": { - "book": [ - { - "category": "reference", - "author": "Nigel Rees", - "title": "Sayings of the Century", - "price": 8.95, - "size": [10, 20, 30, 40] - }, - { - "category": "fiction", - "author": "Evelyn Waugh", - "title": "Sword of Honour", - "price": 12.99, - "size": [50, 60, 70, 80] - }, - { - "category": "fiction", - "author": "Herman Melville", - "title": "Moby Dick", - "isbn": "0-553-21311-3", - "price": 8.99, - "size": [5, 10, 20, 30] - }, - { - "category": "fiction", - "author": "J. R. R. Tolkien", - "title": "The Lord of the Rings", - "isbn": "0-395-19395-8", - "price": 22.99, - "size": [5, 6, 7, 8] - } - ], - "bicycle": {"color": "red", "price": 19.95} - } - }` - res, err := client.JSONSet(ctx, "doc1", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) + Describe("get/set", Label("getset"), func() { + It("should JSONSet", Label("json.set", "json"), func() { + cmd := client.JSONSet(ctx, "set1", "$", `{"a": 1, "b": 2, "hello": "world"}`) + Expect(cmd.Err()).NotTo(HaveOccurred()) + Expect(cmd.Val()).To(Equal("OK")) + }) - resGet, err := client.JSONGet(ctx, "doc1", "$.store.book[?(@.price<10)].size").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal("[[10,20,30,40],[5,10,20,30]]")) + It("should JSONGet", Label("json.get", "json", "NonRedisEnterprise"), func() { + res, err := client.JSONSet(ctx, "get3", "$", `{"a": 1, "b": 2}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) - resArr, err := client.JSONArrIndex(ctx, "doc1", "$.store.book[?(@.price<10)].size", 20).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resArr).To(Equal([]int64{1, 2})) + res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-"}).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`{-"a":1,-"b":2}`)) + + 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() { + res, err := client.JSONSet(ctx, "merge1", "$", `{"a": 1, "b": 2}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + res, err = client.JSONMerge(ctx, "merge1", "$", `{"b": 3, "c": 4}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + res, err = client.JSONGet(ctx, "merge1", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`[{"a":1,"b":3,"c":4}]`)) + }) + + It("should JSONMSet", Label("json.mset", "json", "NonRedisEnterprise"), func() { + doc1 := redis.JSONSetArgs{Key: "mset1", Path: "$", Value: `{"a": 1}`} + doc2 := redis.JSONSetArgs{Key: "mset2", Path: "$", Value: 2} + docs := []redis.JSONSetArgs{doc1, doc2} + + mSetResult, err := client.JSONMSetArgs(ctx, docs).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(mSetResult).To(Equal("OK")) + + res, err := client.JSONMGet(ctx, "$", "mset1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal([]interface{}{`[{"a":1}]`})) + + res, err = client.JSONMGet(ctx, "$", "mset1", "mset2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal([]interface{}{`[{"a":1}]`, "[2]"})) + + _, err = client.JSONMSet(ctx, "mset1", "$.a", 2, "mset3", "$", `[1]`).Result() + Expect(err).NotTo(HaveOccurred()) + }) + + It("should JSONMGet", Label("json.mget", "json", "NonRedisEnterprise"), func() { + cmd1 := client.JSONSet(ctx, "mget2a", "$", `{"a": ["aa", "ab", "ac", "ad"], "b": {"a": ["ba", "bb", "bc", "bd"]}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + cmd2 := client.JSONSet(ctx, "mget2b", "$", `{"a": [100, 200, 300, 200], "b": {"a": [100, 200, 300, 200]}}`) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal("OK")) + + cmd3 := client.JSONMGet(ctx, "$..a", "mget2a", "mget2b") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + Expect(cmd3.Val()).To(HaveLen(2)) + Expect(cmd3.Val()[0]).To(Equal(`[["aa","ab","ac","ad"],["ba","bb","bc","bd"]]`)) + Expect(cmd3.Val()[1]).To(Equal(`[[100,200,300,200],[100,200,300,200]]`)) + }) + + It("should JSONMget with $", Label("json.mget", "json", "NonRedisEnterprise"), func() { + res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "b": 2, "nested": {"a": 3}, "c": "", "nested2": {"a": ""}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + res, err = client.JSONSet(ctx, "doc2", "$", `{"a": 4, "b": 5, "nested": {"a": 6}, "c": "", "nested2": {"a": [""]}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err := client.JSONMGet(ctx, "$..a", "doc1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal([]interface{}{`[1,3,""]`})) + + iRes, err = client.JSONMGet(ctx, "$..a", "doc1", "doc2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal([]interface{}{`[1,3,""]`, `[4,6,[""]]`})) + + iRes, err = client.JSONMGet(ctx, "$..a", "non_existing_doc", "non_existing_doc1").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal([]interface{}{nil, nil})) + }) }) - It("should JSONArrInsert", Label("json.arrinsert", "json"), func() { - cmd1 := client.JSONSet(ctx, "insert2", "$", `[100, 200, 300, 200]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) + Describe("Misc", Label("misc"), func() { + It("should JSONClear", Label("json.clear", "json"), func() { + cmd1 := client.JSONSet(ctx, "clear1", "$", `[1]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) - cmd2 := client.JSONArrInsert(ctx, "insert2", "$", -1, 1, 2) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal([]int64{6})) + cmd2 := client.JSONClear(ctx, "clear1", "$") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal(int64(1))) - cmd3 := client.JSONGet(ctx, "insert2") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - // RESP2 vs RESP3 - Expect(cmd3.Val()).To(Or( - Equal(`[100,200,300,1,2,200]`), - Equal(`[[100,200,300,1,2,200]]`))) + cmd3 := client.JSONGet(ctx, "clear1", "$") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + Expect(cmd3.Val()).To(Equal(`[[]]`)) + }) + + It("should JSONClear with $", Label("json.clear", "json"), func() { + doc := `{ + "nested1": {"a": {"foo": 10, "bar": 20}}, + "a": ["foo"], + "nested2": {"a": "claro"}, + "nested3": {"a": {"baz": 50}} + }` + res, err := client.JSONSet(ctx, "doc1", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err := client.JSONClear(ctx, "doc1", "$..a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(3))) + + resGet, err := client.JSONGet(ctx, "doc1", `$`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":[],"nested2":{"a":"claro"},"nested3":{"a":{}}}]`)) + + res, err = client.JSONSet(ctx, "doc1", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err = client.JSONClear(ctx, "doc1", "$.nested1.a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(1))) + + resGet, err = client.JSONGet(ctx, "doc1", `$`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":["foo"],"nested2":{"a":"claro"},"nested3":{"a":{"baz":50}}}]`)) + }) + + It("should JSONDel", Label("json.del", "json"), func() { + cmd1 := client.JSONSet(ctx, "del1", "$", `[1]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONDel(ctx, "del1", "$") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal(int64(1))) + + cmd3 := client.JSONGet(ctx, "del1", "$") + Expect(cmd3.Err()).NotTo(HaveOccurred()) + Expect(cmd3.Val()).To(HaveLen(0)) + }) + + It("should JSONDel with $", Label("json.del", "json"), func() { + res, err := client.JSONSet(ctx, "del1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err := client.JSONDel(ctx, "del1", "$..a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(2))) + + resGet, err := client.JSONGet(ctx, "del1", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`)) + + res, err = client.JSONSet(ctx, "del2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err = client.JSONDel(ctx, "del2", "$..a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(1))) + + resGet, err = client.JSONGet(ctx, "del2", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`)) + + doc := `[ + { + "ciao": ["non ancora"], + "nested": [ + {"ciao": [1, "a"]}, + {"ciao": [2, "a"]}, + {"ciaoc": [3, "non", "ciao"]}, + {"ciao": [4, "a"]}, + {"e": [5, "non", "ciao"]} + ] + } + ]` + res, err = client.JSONSet(ctx, "del3", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err = client.JSONDel(ctx, "del3", `$.[0]["nested"]..ciao`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(3))) + + resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]` + resGet, err = client.JSONGet(ctx, "del3", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(resVal)) + }) + + It("should JSONForget", Label("json.forget", "json"), func() { + cmd1 := client.JSONSet(ctx, "forget3", "$", `{"a": [1,2,3], "b": {"a": [1,2,3], "b": "annie"}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONForget(ctx, "forget3", "$..a") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal(int64(2))) + + 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() { + res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err := client.JSONForget(ctx, "doc1", "$..a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(2))) + + resGet, err := client.JSONGet(ctx, "doc1", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`)) + + res, err = client.JSONSet(ctx, "doc2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err = client.JSONForget(ctx, "doc2", "$..a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(1))) + + resGet, err = client.JSONGet(ctx, "doc2", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`)) + + doc := `[ + { + "ciao": ["non ancora"], + "nested": [ + {"ciao": [1, "a"]}, + {"ciao": [2, "a"]}, + {"ciaoc": [3, "non", "ciao"]}, + {"ciao": [4, "a"]}, + {"e": [5, "non", "ciao"]} + ] + } + ]` + res, err = client.JSONSet(ctx, "doc3", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + iRes, err = client.JSONForget(ctx, "doc3", `$.[0]["nested"]..ciao`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(iRes).To(Equal(int64(3))) + + resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]` + resGet, err = client.JSONGet(ctx, "doc3", "$").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(resGet).To(Equal(resVal)) + }) + + It("should JSONNumIncrBy", Label("json.numincrby", "json"), func() { + cmd1 := client.JSONSet(ctx, "incr3", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONNumIncrBy(ctx, "incr3", "$..a[1]", float64(1)) + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(Equal(`[3,0]`)) + }) + + It("should JSONNumIncrBy with $", Label("json.numincrby", "json"), func() { + res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 2).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`[7]`)) + + res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 3.5).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`[10.5]`)) + + res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + res, err = client.JSONNumIncrBy(ctx, "doc2", "$.b[0].a", 3).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal(`[5]`)) + }) + + It("should JSONObjKeys", Label("json.objkeys", "json"), func() { + cmd1 := client.JSONSet(ctx, "objkeys1", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONObjKeys(ctx, "objkeys1", "$..*") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(HaveLen(7)) + Expect(cmd2.Val()).To(Equal([]interface{}{nil, []interface{}{"a"}, nil, nil, nil, nil, nil})) + }) + + It("should JSONObjKeys with $", Label("json.objkeys", "json"), func() { + doc := `{ + "nested1": {"a": {"foo": 10, "bar": 20}}, + "a": ["foo"], + "nested2": {"a": {"baz": 50}} + }` + cmd1, err := client.JSONSet(ctx, "objkeys1", "$", doc).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd1).To(Equal("OK")) + + cmd2, err := client.JSONObjKeys(ctx, "objkeys1", "$.nested1.a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd2).To(Equal([]interface{}{[]interface{}{"foo", "bar"}})) + + cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".*.a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd2).To(Equal([]interface{}{"foo", "bar"})) + + cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".nested2.a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd2).To(Equal([]interface{}{"baz"})) + + _, err = client.JSONObjKeys(ctx, "non_existing_doc", "..a").Result() + Expect(err).To(HaveOccurred()) + }) + + It("should JSONObjLen", Label("json.objlen", "json"), func() { + cmd1 := client.JSONSet(ctx, "objlen2", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONObjLen(ctx, "objlen2", "$..*") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(HaveLen(7)) + Expect(cmd2.Val()[0]).To(BeNil()) + Expect(*cmd2.Val()[1]).To(Equal(int64(1))) + }) + + It("should JSONStrLen", Label("json.strlen", "json"), func() { + cmd1 := client.JSONSet(ctx, "strlen2", "$", `{"a": "alice", "b": "bob", "c": {"a": "alice", "b": "bob"}}`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONStrLen(ctx, "strlen2", "$..*") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(HaveLen(5)) + var tmp int64 = 20 + Expect(cmd2.Val()[0]).To(BeAssignableToTypeOf(&tmp)) + Expect(*cmd2.Val()[0]).To(Equal(int64(5))) + Expect(*cmd2.Val()[1]).To(Equal(int64(3))) + Expect(cmd2.Val()[2]).To(BeNil()) + Expect(*cmd2.Val()[3]).To(Equal(int64(5))) + Expect(*cmd2.Val()[4]).To(Equal(int64(3))) + }) + + It("should JSONStrAppend", Label("json.strappend", "json"), func() { + cmd1, err := client.JSONSet(ctx, "strapp1", "$", `"foo"`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(cmd1).To(Equal("OK")) + cmd2, err := client.JSONStrAppend(ctx, "strapp1", "$", `"bar"`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(*cmd2[0]).To(Equal(int64(6))) + 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() { + res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + intArrayResult, err := client.JSONStrAppend(ctx, "doc1", "$.nested1.a", `"baz"`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(*intArrayResult[0]).To(Equal(int64(8))) + + res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(res).To(Equal("OK")) + + intResult, err := client.JSONStrLen(ctx, "doc2", "$.nested1.a").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(*intResult[0]).To(Equal(int64(5))) + }) + + It("should JSONToggle", Label("json.toggle", "json"), func() { + cmd1 := client.JSONSet(ctx, "toggle1", "$", `[true]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONToggle(ctx, "toggle1", "$[0]") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(HaveLen(1)) + Expect(*cmd2.Val()[0]).To(Equal(int64(0))) + }) + + It("should JSONType", Label("json.type", "json"), func() { + cmd1 := client.JSONSet(ctx, "type1", "$", `[true]`) + Expect(cmd1.Err()).NotTo(HaveOccurred()) + Expect(cmd1.Val()).To(Equal("OK")) + + cmd2 := client.JSONType(ctx, "type1", "$[0]") + Expect(cmd2.Err()).NotTo(HaveOccurred()) + Expect(cmd2.Val()).To(HaveLen(1)) + // RESP2 v RESP3 + Expect(cmd2.Val()[0]).To(Or(Equal([]interface{}{"boolean"}), Equal("boolean"))) + }) }) + } +}) - It("should JSONArrLen", Label("json.arrlen", "json"), func() { - cmd1 := client.JSONSet(ctx, "length2", "$", `{"a": [10], "b": {"a": [12, 10, 20, 12, 90, 10]}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) +var _ = Describe("Go-Redis Advanced JSON and RediSearch Tests", func() { + var client *redis.Client + var ctx = context.Background() - cmd2 := client.JSONArrLen(ctx, "length2", "$..a") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal([]int64{1, 6})) + setupRedisClient := func(protocolVersion int) *redis.Client { + return redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + DB: 0, + Protocol: protocolVersion, // Setting RESP2 or RESP3 protocol + UnstableResp3: true, // Enable RESP3 features }) + } - It("should JSONArrPop", Label("json.arrpop"), func() { - cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal([]string{"300"})) - - cmd3 := client.JSONGet(ctx, "pop4", "$") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - Expect(cmd3.Val()).To(Equal("[[100,200,200]]")) - }) - - It("should JSONArrTrim", Label("json.arrtrim", "json"), func() { - cmd1, err := client.JSONSet(ctx, "trim1", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd1).To(Equal("OK")) - - stop := 3 - cmd2, err := client.JSONArrTrimWithArgs(ctx, "trim1", "$", &redis.JSONArrTrimArgs{Start: 1, Stop: &stop}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd2).To(Equal([]int64{3})) - - res, err := client.JSONGet(ctx, "trim1", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`[[1,2,3]]`)) - - cmd3, err := client.JSONSet(ctx, "trim2", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd3).To(Equal("OK")) - - stop = 3 - cmd4, err := client.JSONArrTrimWithArgs(ctx, "trim2", "$", &redis.JSONArrTrimArgs{Start: -1, Stop: &stop}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd4).To(Equal([]int64{0})) - - cmd5, err := client.JSONSet(ctx, "trim3", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd5).To(Equal("OK")) - - stop = 99 - cmd6, err := client.JSONArrTrimWithArgs(ctx, "trim3", "$", &redis.JSONArrTrimArgs{Start: 3, Stop: &stop}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd6).To(Equal([]int64{2})) - - cmd7, err := client.JSONSet(ctx, "trim4", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd7).To(Equal("OK")) - - stop = 1 - cmd8, err := client.JSONArrTrimWithArgs(ctx, "trim4", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd8).To(Equal([]int64{0})) - - cmd9, err := client.JSONSet(ctx, "trim5", "$", `[0,1,2,3,4]`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd9).To(Equal("OK")) - - stop = 11 - cmd10, err := client.JSONArrTrimWithArgs(ctx, "trim5", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd10).To(Equal([]int64{0})) - }) - - It("should JSONArrPop", Label("json.arrpop", "json"), func() { - cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal([]string{"300"})) - - cmd3 := client.JSONGet(ctx, "pop4", "$") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - Expect(cmd3.Val()).To(Equal("[[100,200,200]]")) - }) + AfterEach(func() { + if client != nil { + client.FlushDB(ctx) + client.Close() + } }) - Describe("get/set", Label("getset"), func() { - It("should JSONSet", Label("json.set", "json"), func() { - cmd := client.JSONSet(ctx, "set1", "$", `{"a": 1, "b": 2, "hello": "world"}`) - Expect(cmd.Err()).NotTo(HaveOccurred()) - Expect(cmd.Val()).To(Equal("OK")) - }) - - It("should JSONGet", Label("json.get", "json", "NonRedisEnterprise"), func() { - res, err := client.JSONSet(ctx, "get3", "$", `{"a": 1, "b": 2}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-"}).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`{-"a":1,-"b":2}`)) - - 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() { - res, err := client.JSONSet(ctx, "merge1", "$", `{"a": 1, "b": 2}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONMerge(ctx, "merge1", "$", `{"b": 3, "c": 4}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONGet(ctx, "merge1", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`[{"a":1,"b":3,"c":4}]`)) - }) - - It("should JSONMSet", Label("json.mset", "json", "NonRedisEnterprise"), func() { - doc1 := redis.JSONSetArgs{Key: "mset1", Path: "$", Value: `{"a": 1}`} - doc2 := redis.JSONSetArgs{Key: "mset2", Path: "$", Value: 2} - docs := []redis.JSONSetArgs{doc1, doc2} - - mSetResult, err := client.JSONMSetArgs(ctx, docs).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(mSetResult).To(Equal("OK")) - - res, err := client.JSONMGet(ctx, "$", "mset1").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal([]interface{}{`[{"a":1}]`})) - - res, err = client.JSONMGet(ctx, "$", "mset1", "mset2").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal([]interface{}{`[{"a":1}]`, "[2]"})) - - _, err = client.JSONMSet(ctx, "mset1", "$.a", 2, "mset3", "$", `[1]`).Result() - Expect(err).NotTo(HaveOccurred()) - }) - - It("should JSONMGet", Label("json.mget", "json", "NonRedisEnterprise"), func() { - cmd1 := client.JSONSet(ctx, "mget2a", "$", `{"a": ["aa", "ab", "ac", "ad"], "b": {"a": ["ba", "bb", "bc", "bd"]}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - cmd2 := client.JSONSet(ctx, "mget2b", "$", `{"a": [100, 200, 300, 200], "b": {"a": [100, 200, 300, 200]}}`) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal("OK")) - - cmd3 := client.JSONMGet(ctx, "$..a", "mget2a", "mget2b") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - Expect(cmd3.Val()).To(HaveLen(2)) - Expect(cmd3.Val()[0]).To(Equal(`[["aa","ab","ac","ad"],["ba","bb","bc","bd"]]`)) - Expect(cmd3.Val()[1]).To(Equal(`[[100,200,300,200],[100,200,300,200]]`)) - }) - - It("should JSONMget with $", Label("json.mget", "json", "NonRedisEnterprise"), func() { - res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "b": 2, "nested": {"a": 3}, "c": "", "nested2": {"a": ""}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONSet(ctx, "doc2", "$", `{"a": 4, "b": 5, "nested": {"a": 6}, "c": "", "nested2": {"a": [""]}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err := client.JSONMGet(ctx, "$..a", "doc1").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal([]interface{}{`[1,3,""]`})) - - iRes, err = client.JSONMGet(ctx, "$..a", "doc1", "doc2").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal([]interface{}{`[1,3,""]`, `[4,6,[""]]`})) - - 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()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONClear(ctx, "clear1", "$") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal(int64(1))) - - cmd3 := client.JSONGet(ctx, "clear1", "$") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - Expect(cmd3.Val()).To(Equal(`[[]]`)) - }) - - It("should JSONClear with $", Label("json.clear", "json"), func() { - doc := `{ - "nested1": {"a": {"foo": 10, "bar": 20}}, - "a": ["foo"], - "nested2": {"a": "claro"}, - "nested3": {"a": {"baz": 50}} - }` - res, err := client.JSONSet(ctx, "doc1", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err := client.JSONClear(ctx, "doc1", "$..a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(3))) - - resGet, err := client.JSONGet(ctx, "doc1", `$`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":[],"nested2":{"a":"claro"},"nested3":{"a":{}}}]`)) - - res, err = client.JSONSet(ctx, "doc1", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err = client.JSONClear(ctx, "doc1", "$.nested1.a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(1))) - - resGet, err = client.JSONGet(ctx, "doc1", `$`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":["foo"],"nested2":{"a":"claro"},"nested3":{"a":{"baz":50}}}]`)) - }) - - It("should JSONDel", Label("json.del", "json"), func() { - cmd1 := client.JSONSet(ctx, "del1", "$", `[1]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONDel(ctx, "del1", "$") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal(int64(1))) - - cmd3 := client.JSONGet(ctx, "del1", "$") - Expect(cmd3.Err()).NotTo(HaveOccurred()) - Expect(cmd3.Val()).To(HaveLen(0)) - }) - - It("should JSONDel with $", Label("json.del", "json"), func() { - res, err := client.JSONSet(ctx, "del1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err := client.JSONDel(ctx, "del1", "$..a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(2))) - - resGet, err := client.JSONGet(ctx, "del1", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`)) - - res, err = client.JSONSet(ctx, "del2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err = client.JSONDel(ctx, "del2", "$..a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(1))) - - resGet, err = client.JSONGet(ctx, "del2", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`)) - - doc := `[ - { - "ciao": ["non ancora"], - "nested": [ - {"ciao": [1, "a"]}, - {"ciao": [2, "a"]}, - {"ciaoc": [3, "non", "ciao"]}, - {"ciao": [4, "a"]}, - {"e": [5, "non", "ciao"]} - ] - } - ]` - res, err = client.JSONSet(ctx, "del3", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err = client.JSONDel(ctx, "del3", `$.[0]["nested"]..ciao`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(3))) - - resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]` - resGet, err = client.JSONGet(ctx, "del3", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(resVal)) - }) - - It("should JSONForget", Label("json.forget", "json"), func() { - cmd1 := client.JSONSet(ctx, "forget3", "$", `{"a": [1,2,3], "b": {"a": [1,2,3], "b": "annie"}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONForget(ctx, "forget3", "$..a") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal(int64(2))) - - 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() { - res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err := client.JSONForget(ctx, "doc1", "$..a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(2))) - - resGet, err := client.JSONGet(ctx, "doc1", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`)) - - res, err = client.JSONSet(ctx, "doc2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err = client.JSONForget(ctx, "doc2", "$..a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(1))) - - resGet, err = client.JSONGet(ctx, "doc2", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`)) - - doc := `[ - { - "ciao": ["non ancora"], - "nested": [ - {"ciao": [1, "a"]}, - {"ciao": [2, "a"]}, - {"ciaoc": [3, "non", "ciao"]}, - {"ciao": [4, "a"]}, - {"e": [5, "non", "ciao"]} - ] - } - ]` - res, err = client.JSONSet(ctx, "doc3", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - iRes, err = client.JSONForget(ctx, "doc3", `$.[0]["nested"]..ciao`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(iRes).To(Equal(int64(3))) - - resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]` - resGet, err = client.JSONGet(ctx, "doc3", "$").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(resGet).To(Equal(resVal)) - }) - - It("should JSONNumIncrBy", Label("json.numincrby", "json"), func() { - cmd1 := client.JSONSet(ctx, "incr3", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONNumIncrBy(ctx, "incr3", "$..a[1]", float64(1)) - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(Equal(`[3,0]`)) - }) - - It("should JSONNumIncrBy with $", Label("json.numincrby", "json"), func() { - res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 2).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`[7]`)) - - res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 3.5).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`[10.5]`)) - - res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - res, err = client.JSONNumIncrBy(ctx, "doc2", "$.b[0].a", 3).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal(`[5]`)) - }) - - It("should JSONObjKeys", Label("json.objkeys", "json"), func() { - cmd1 := client.JSONSet(ctx, "objkeys1", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONObjKeys(ctx, "objkeys1", "$..*") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(HaveLen(7)) - Expect(cmd2.Val()).To(Equal([]interface{}{nil, []interface{}{"a"}, nil, nil, nil, nil, nil})) - }) - - It("should JSONObjKeys with $", Label("json.objkeys", "json"), func() { - doc := `{ - "nested1": {"a": {"foo": 10, "bar": 20}}, - "a": ["foo"], - "nested2": {"a": {"baz": 50}} - }` - cmd1, err := client.JSONSet(ctx, "objkeys1", "$", doc).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd1).To(Equal("OK")) - - cmd2, err := client.JSONObjKeys(ctx, "objkeys1", "$.nested1.a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd2).To(Equal([]interface{}{[]interface{}{"foo", "bar"}})) - - cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".*.a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd2).To(Equal([]interface{}{"foo", "bar"})) - - cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".nested2.a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd2).To(Equal([]interface{}{"baz"})) - - _, err = client.JSONObjKeys(ctx, "non_existing_doc", "..a").Result() - Expect(err).To(HaveOccurred()) - }) - - It("should JSONObjLen", Label("json.objlen", "json"), func() { - cmd1 := client.JSONSet(ctx, "objlen2", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONObjLen(ctx, "objlen2", "$..*") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(HaveLen(7)) - Expect(cmd2.Val()[0]).To(BeNil()) - Expect(*cmd2.Val()[1]).To(Equal(int64(1))) - }) - - It("should JSONStrLen", Label("json.strlen", "json"), func() { - cmd1 := client.JSONSet(ctx, "strlen2", "$", `{"a": "alice", "b": "bob", "c": {"a": "alice", "b": "bob"}}`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONStrLen(ctx, "strlen2", "$..*") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(HaveLen(5)) - var tmp int64 = 20 - Expect(cmd2.Val()[0]).To(BeAssignableToTypeOf(&tmp)) - Expect(*cmd2.Val()[0]).To(Equal(int64(5))) - Expect(*cmd2.Val()[1]).To(Equal(int64(3))) - Expect(cmd2.Val()[2]).To(BeNil()) - Expect(*cmd2.Val()[3]).To(Equal(int64(5))) - Expect(*cmd2.Val()[4]).To(Equal(int64(3))) - }) - - It("should JSONStrAppend", Label("json.strappend", "json"), func() { - cmd1, err := client.JSONSet(ctx, "strapp1", "$", `"foo"`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(cmd1).To(Equal("OK")) - cmd2, err := client.JSONStrAppend(ctx, "strapp1", "$", `"bar"`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(*cmd2[0]).To(Equal(int64(6))) - 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() { - res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - intArrayResult, err := client.JSONStrAppend(ctx, "doc1", "$.nested1.a", `"baz"`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(*intArrayResult[0]).To(Equal(int64(8))) - - res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result() - Expect(err).NotTo(HaveOccurred()) - Expect(res).To(Equal("OK")) - - intResult, err := client.JSONStrLen(ctx, "doc2", "$.nested1.a").Result() - Expect(err).NotTo(HaveOccurred()) - Expect(*intResult[0]).To(Equal(int64(5))) - }) - - It("should JSONToggle", Label("json.toggle", "json"), func() { - cmd1 := client.JSONSet(ctx, "toggle1", "$", `[true]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONToggle(ctx, "toggle1", "$[0]") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(HaveLen(1)) - Expect(*cmd2.Val()[0]).To(Equal(int64(0))) - }) - - It("should JSONType", Label("json.type", "json"), func() { - cmd1 := client.JSONSet(ctx, "type1", "$", `[true]`) - Expect(cmd1.Err()).NotTo(HaveOccurred()) - Expect(cmd1.Val()).To(Equal("OK")) - - cmd2 := client.JSONType(ctx, "type1", "$[0]") - Expect(cmd2.Err()).NotTo(HaveOccurred()) - Expect(cmd2.Val()).To(HaveLen(1)) - // RESP2 v RESP3 - Expect(cmd2.Val()[0]).To(Or(Equal([]interface{}{"boolean"}), Equal("boolean"))) - }) + Context("when testing with RESP2 and RESP3", func() { + protocols := []int{2, 3} + + for _, protocol := range protocols { + When("using protocol version", func() { + BeforeEach(func() { + client = setupRedisClient(protocol) + }) + + It("should perform complex JSON and RediSearch operations", func() { + jsonDoc := map[string]interface{}{ + "person": map[string]interface{}{ + "name": "Alice", + "age": 30, + "status": true, + "address": map[string]interface{}{ + "city": "Wonderland", + "postcode": "12345", + }, + "contacts": []map[string]interface{}{ + {"type": "email", "value": "alice@example.com"}, + {"type": "phone", "value": "+123456789"}, + {"type": "fax", "value": "+987654321"}, + }, + "friends": []map[string]interface{}{ + {"name": "Bob", "age": 35, "status": true}, + {"name": "Charlie", "age": 28, "status": false}, + }, + }, + "settings": map[string]interface{}{ + "notifications": map[string]interface{}{ + "email": true, + "sms": false, + "alerts": []string{"low battery", "door open"}, + }, + "theme": "dark", + }, + } + + setCmd := client.JSONSet(ctx, "person:1", ".", jsonDoc) + Expect(setCmd.Err()).NotTo(HaveOccurred(), "JSON.SET failed") + + getCmdRaw := client.JSONGet(ctx, "person:1", ".") + rawJSON, err := getCmdRaw.Result() + Expect(err).NotTo(HaveOccurred(), "JSON.GET (raw) failed") + GinkgoWriter.Printf("Raw JSON: %s\n", rawJSON) + + getCmdExpanded := client.JSONGet(ctx, "person:1", ".") + expandedJSON, err := getCmdExpanded.Expanded() + Expect(err).NotTo(HaveOccurred(), "JSON.GET (expanded) failed") + GinkgoWriter.Printf("Expanded JSON: %+v\n", expandedJSON) + + Expect(rawJSON).To(MatchJSON(jsonMustMarshal(expandedJSON))) + + arrAppendCmd := client.JSONArrAppend(ctx, "person:1", "$.person.contacts", `{"type": "social", "value": "@alice_wonder"}`) + Expect(arrAppendCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRAPPEND failed") + arrLenCmd := client.JSONArrLen(ctx, "person:1", "$.person.contacts") + arrLen, err := arrLenCmd.Result() + Expect(err).NotTo(HaveOccurred(), "JSON.ARRLEN failed") + Expect(arrLen).To(Equal([]int64{4}), "Array length mismatch after append") + + arrInsertCmd := client.JSONArrInsert(ctx, "person:1", "$.person.friends", 1, `{"name": "Diana", "age": 25, "status": true}`) + Expect(arrInsertCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRINSERT failed") + + start := 0 + stop := 1 + arrTrimCmd := client.JSONArrTrimWithArgs(ctx, "person:1", "$.person.friends", &redis.JSONArrTrimArgs{Start: start, Stop: &stop}) + Expect(arrTrimCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRTRIM failed") + + mergeData := map[string]interface{}{ + "status": false, + "nickname": "WonderAlice", + "lastLogin": time.Now().Format(time.RFC3339), + } + mergeCmd := client.JSONMerge(ctx, "person:1", "$.person", jsonMustMarshal(mergeData)) + Expect(mergeCmd.Err()).NotTo(HaveOccurred(), "JSON.MERGE failed") + + typeCmd := client.JSONType(ctx, "person:1", "$.person.nickname") + nicknameType, err := typeCmd.Result() + Expect(err).NotTo(HaveOccurred(), "JSON.TYPE failed") + Expect(nicknameType[0]).To(Equal([]interface{}{"string"}), "JSON.TYPE mismatch for nickname") + + createIndexCmd := client.Do(ctx, "FT.CREATE", "person_idx", "ON", "JSON", + "PREFIX", "1", "person:", "SCHEMA", + "$.person.name", "AS", "name", "TEXT", + "$.person.age", "AS", "age", "NUMERIC", + "$.person.address.city", "AS", "city", "TEXT", + "$.person.contacts[*].value", "AS", "contact_value", "TEXT", + ) + Expect(createIndexCmd.Err()).NotTo(HaveOccurred(), "FT.CREATE failed") + + searchCmd := client.FTSearchWithArgs(ctx, "person_idx", "@contact_value:(alice\\@example\\.com alice_wonder)", &redis.FTSearchOptions{Return: []redis.FTSearchReturn{{FieldName: "$.person.name"}, {FieldName: "$.person.age"}, {FieldName: "$.person.address.city"}}}) + searchResult, err := searchCmd.Result() + Expect(err).NotTo(HaveOccurred(), "FT.SEARCH failed") + GinkgoWriter.Printf("Advanced Search result: %+v\n", searchResult) + + incrCmd := client.JSONNumIncrBy(ctx, "person:1", "$.person.age", 5) + incrResult, err := incrCmd.Result() + Expect(err).NotTo(HaveOccurred(), "JSON.NUMINCRBY failed") + Expect(incrResult).To(Equal("[35]"), "Age increment mismatch") + + delCmd := client.JSONDel(ctx, "person:1", "$.settings.notifications.email") + Expect(delCmd.Err()).NotTo(HaveOccurred(), "JSON.DEL failed") + + typeCmd = client.JSONType(ctx, "person:1", "$.settings.notifications.email") + typeResult, err := typeCmd.Result() + Expect(err).ToNot(HaveOccurred()) + Expect(typeResult[0]).To(BeEmpty(), "Expected JSON.TYPE to be empty for deleted field") + }) + }) + } }) }) + +// Helper function to marshal data into JSON for comparisons +func jsonMustMarshal(v interface{}) string { + bytes, err := json.Marshal(v) + Expect(err).NotTo(HaveOccurred()) + return string(bytes) +} From 135f8e3b12d7dce2ed41fd9e428ce90b085f52d0 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:13:57 +0300 Subject: [PATCH 4/7] Fix field name spellings (#3132) (#3156) Co-authored-by: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com> --- search_commands.go | 24 ++++++++++++------------ search_test.go | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/search_commands.go b/search_commands.go index 1a8a4cfe..e4df0b6f 100644 --- a/search_commands.go +++ b/search_commands.go @@ -16,7 +16,7 @@ type SearchCmdable interface { FTAliasAdd(ctx context.Context, index string, alias string) *StatusCmd FTAliasDel(ctx context.Context, alias string) *StatusCmd FTAliasUpdate(ctx context.Context, index string, alias string) *StatusCmd - FTAlter(ctx context.Context, index string, skipInitalScan bool, definition []interface{}) *StatusCmd + FTAlter(ctx context.Context, index string, skipInitialScan bool, definition []interface{}) *StatusCmd FTConfigGet(ctx context.Context, option string) *MapMapStringInterfaceCmd FTConfigSet(ctx context.Context, option string, value interface{}) *StatusCmd FTCreate(ctx context.Context, index string, options *FTCreateOptions, schema ...*FieldSchema) *StatusCmd @@ -57,7 +57,7 @@ type FTCreateOptions struct { NoFields bool NoFreqs bool StopWords []interface{} - SkipInitalScan bool + SkipInitialScan bool } type FieldSchema struct { @@ -70,7 +70,7 @@ type FieldSchema struct { NoIndex bool PhoneticMatcher string Weight float64 - Seperator string + Separator string CaseSensitive bool WithSuffixtrie bool VectorArgs *FTVectorArgs @@ -285,7 +285,7 @@ type FTSearchSortBy struct { type FTSearchOptions struct { NoContent bool Verbatim bool - NoStopWrods bool + NoStopWords bool WithScores bool WithPayloads bool WithSortKeys bool @@ -808,13 +808,13 @@ func (c cmdable) FTAliasUpdate(ctx context.Context, index string, alias string) } // FTAlter - Alters the definition of an existing index. -// The 'index' parameter specifies the index to alter, and the 'skipInitalScan' parameter specifies whether to skip the initial scan. +// The 'index' parameter specifies the index to alter, and the 'skipInitialScan' parameter specifies whether to skip the initial scan. // The 'definition' parameter specifies the new definition for the index. // For more information, please refer to the Redis documentation: // [FT.ALTER]: (https://redis.io/commands/ft.alter/) -func (c cmdable) FTAlter(ctx context.Context, index string, skipInitalScan bool, definition []interface{}) *StatusCmd { +func (c cmdable) FTAlter(ctx context.Context, index string, skipInitialScan bool, definition []interface{}) *StatusCmd { args := []interface{}{"FT.ALTER", index} - if skipInitalScan { + if skipInitialScan { args = append(args, "SKIPINITIALSCAN") } args = append(args, "SCHEMA", "ADD") @@ -907,7 +907,7 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp args = append(args, "STOPWORDS", len(options.StopWords)) args = append(args, options.StopWords...) } - if options.SkipInitalScan { + if options.SkipInitialScan { args = append(args, "SKIPINITIALSCAN") } } @@ -1003,8 +1003,8 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp if schema.Weight > 0 { args = append(args, "WEIGHT", schema.Weight) } - if schema.Seperator != "" { - args = append(args, "SEPERATOR", schema.Seperator) + if schema.Separator != "" { + args = append(args, "SEPARATOR", schema.Separator) } if schema.CaseSensitive { args = append(args, "CASESENSITIVE") @@ -1694,7 +1694,7 @@ func FTSearchQuery(query string, options *FTSearchOptions) SearchQuery { if options.Verbatim { queryArgs = append(queryArgs, "VERBATIM") } - if options.NoStopWrods { + if options.NoStopWords { queryArgs = append(queryArgs, "NOSTOPWORDS") } if options.WithScores { @@ -1808,7 +1808,7 @@ func (c cmdable) FTSearchWithArgs(ctx context.Context, index string, query strin if options.Verbatim { args = append(args, "VERBATIM") } - if options.NoStopWrods { + if options.NoStopWords { args = append(args, "NOSTOPWORDS") } if options.WithScores { diff --git a/search_test.go b/search_test.go index efdc6bb1..48b9aa39 100644 --- a/search_test.go +++ b/search_test.go @@ -637,11 +637,11 @@ var _ = Describe("RediSearch commands Resp 2", Label("search"), func() { }) - It("should FTSearch SkipInitalScan", Label("search", "ftsearch"), func() { + It("should FTSearch SkipInitialScan", Label("search", "ftsearch"), func() { client.HSet(ctx, "doc1", "foo", "bar") text1 := &redis.FieldSchema{FieldName: "foo", FieldType: redis.SearchFieldTypeText} - val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{SkipInitalScan: true}, text1).Result() + val, err := client.FTCreate(ctx, "idx1", &redis.FTCreateOptions{SkipInitialScan: true}, text1).Result() Expect(err).NotTo(HaveOccurred()) Expect(val).To(BeEquivalentTo("OK")) WaitForIndexing(client, "idx1") From ed37c33a9037483ad2a6b1042e5eb6df89009a1c Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Wed, 16 Oct 2024 10:01:32 +0300 Subject: [PATCH 5/7] Updated package version [9.7] (#3159) --- example/del-keys-without-ttl/go.mod | 2 +- example/hll/go.mod | 2 +- example/lua-scripting/go.mod | 2 +- example/otel/go.mod | 6 +++--- example/redis-bloom/go.mod | 2 +- example/scan-struct/go.mod | 2 +- extra/rediscensus/go.mod | 4 ++-- extra/rediscmd/go.mod | 2 +- extra/redisotel/go.mod | 4 ++-- extra/redisprometheus/go.mod | 2 +- version.go | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/example/del-keys-without-ttl/go.mod b/example/del-keys-without-ttl/go.mod index 47e3e865..6b59a87a 100644 --- a/example/del-keys-without-ttl/go.mod +++ b/example/del-keys-without-ttl/go.mod @@ -5,7 +5,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. require ( - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0 go.uber.org/zap v1.24.0 ) diff --git a/example/hll/go.mod b/example/hll/go.mod index 1d69d427..5bff57e6 100644 --- a/example/hll/go.mod +++ b/example/hll/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.7.0-beta.1 +require github.com/redis/go-redis/v9 v9.7.0 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/lua-scripting/go.mod b/example/lua-scripting/go.mod index c0506b78..8ca0910e 100644 --- a/example/lua-scripting/go.mod +++ b/example/lua-scripting/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.7.0-beta.1 +require github.com/redis/go-redis/v9 v9.7.0 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/otel/go.mod b/example/otel/go.mod index fa9c4871..28b791e1 100644 --- a/example/otel/go.mod +++ b/example/otel/go.mod @@ -9,8 +9,8 @@ replace github.com/redis/go-redis/extra/redisotel/v9 => ../../extra/redisotel replace github.com/redis/go-redis/extra/rediscmd/v9 => ../../extra/rediscmd require ( - github.com/redis/go-redis/extra/redisotel/v9 v9.7.0-beta.1 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/extra/redisotel/v9 v9.7.0 + github.com/redis/go-redis/v9 v9.7.0 github.com/uptrace/uptrace-go v1.21.0 go.opentelemetry.io/otel v1.22.0 ) @@ -23,7 +23,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect - github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 // indirect + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.46.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect diff --git a/example/redis-bloom/go.mod b/example/redis-bloom/go.mod index 820d173f..e968e60f 100644 --- a/example/redis-bloom/go.mod +++ b/example/redis-bloom/go.mod @@ -4,7 +4,7 @@ go 1.18 replace github.com/redis/go-redis/v9 => ../.. -require github.com/redis/go-redis/v9 v9.7.0-beta.1 +require github.com/redis/go-redis/v9 v9.7.0 require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect diff --git a/example/scan-struct/go.mod b/example/scan-struct/go.mod index b2dcdcb2..b850ef6f 100644 --- a/example/scan-struct/go.mod +++ b/example/scan-struct/go.mod @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/davecgh/go-spew v1.1.1 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0 ) require ( diff --git a/extra/rediscensus/go.mod b/extra/rediscensus/go.mod index 00ef6e43..b9d65195 100644 --- a/extra/rediscensus/go.mod +++ b/extra/rediscensus/go.mod @@ -7,8 +7,8 @@ replace github.com/redis/go-redis/v9 => ../.. replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd require ( - github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 + github.com/redis/go-redis/v9 v9.7.0 go.opencensus.io v0.24.0 ) diff --git a/extra/rediscmd/go.mod b/extra/rediscmd/go.mod index a5139f27..794985bb 100644 --- a/extra/rediscmd/go.mod +++ b/extra/rediscmd/go.mod @@ -7,7 +7,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/bsm/ginkgo/v2 v2.12.0 github.com/bsm/gomega v1.27.10 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0 ) require ( diff --git a/extra/redisotel/go.mod b/extra/redisotel/go.mod index 1adda6f6..e40bd207 100644 --- a/extra/redisotel/go.mod +++ b/extra/redisotel/go.mod @@ -7,8 +7,8 @@ replace github.com/redis/go-redis/v9 => ../.. replace github.com/redis/go-redis/extra/rediscmd/v9 => ../rediscmd require ( - github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0-beta.1 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/extra/rediscmd/v9 v9.7.0 + github.com/redis/go-redis/v9 v9.7.0 go.opentelemetry.io/otel v1.22.0 go.opentelemetry.io/otel/metric v1.22.0 go.opentelemetry.io/otel/sdk v1.22.0 diff --git a/extra/redisprometheus/go.mod b/extra/redisprometheus/go.mod index 5e0aa645..33d8a6a4 100644 --- a/extra/redisprometheus/go.mod +++ b/extra/redisprometheus/go.mod @@ -6,7 +6,7 @@ replace github.com/redis/go-redis/v9 => ../.. require ( github.com/prometheus/client_golang v1.14.0 - github.com/redis/go-redis/v9 v9.7.0-beta.1 + github.com/redis/go-redis/v9 v9.7.0 ) require ( diff --git a/version.go b/version.go index 3194f313..2b9926ea 100644 --- a/version.go +++ b/version.go @@ -2,5 +2,5 @@ package redis // Version is the current release version. func Version() string { - return "9.7.0-beta.1" + return "9.7.0" } From 76d12b4cc41e9c6db2cb0ecfa7bbcbc7e9f416cb Mon Sep 17 00:00:00 2001 From: vladvildanov Date: Thu, 17 Oct 2024 13:33:18 +0300 Subject: [PATCH 6/7] Removed branch setup --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb0c20ba..5007423a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Go on: push: - branches: [master, v9, v9.7] + branches: [master, v9] pull_request: - branches: [master, v9, v9.7] + branches: [master, v9] permissions: contents: read From 9c0b623d20cb28aed2abee51612956b4979990ed Mon Sep 17 00:00:00 2001 From: vladvildanov Date: Thu, 17 Oct 2024 13:35:34 +0300 Subject: [PATCH 7/7] Proper retract --- extra/redisotel/go.mod | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extra/redisotel/go.mod b/extra/redisotel/go.mod index e40bd207..9ccaee80 100644 --- a/extra/redisotel/go.mod +++ b/extra/redisotel/go.mod @@ -23,4 +23,6 @@ require ( golang.org/x/sys v0.16.0 // indirect ) -retract v9.5.3 // This version was accidentally released. +retract ( + v9.5.3 // This version was accidentally released. +)