Skip to content

Commit

Permalink
Merge branch 'redis:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
SoulPancake authored Jan 28, 2025
2 parents ac5c7ad + 94b88f5 commit 41c8b3a
Show file tree
Hide file tree
Showing 59 changed files with 9,580 additions and 2,502 deletions.
6 changes: 6 additions & 0 deletions .github/wordlist.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ACLs
APIs
autoload
autoloader
autoloading
Expand Down Expand Up @@ -46,11 +47,14 @@ runtime
SHA
sharding
SETNAME
SpellCheck
SSL
struct
stunnel
SynDump
TCP
TLS
UnstableResp
uri
URI
url
Expand All @@ -59,3 +63,5 @@ RedisStack
RedisGears
RedisTimeseries
RediSearch
RawResult
RawVal
47 changes: 45 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,50 @@ jobs:
run: make test

- name: Upload to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v5
with:
files: coverage.txt
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}

test-redis-ce:
name: test-redis-ce
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
redis_version:
- "8.0-M01"
- "7.4.1"
- "7.2.6"
- "6.2.16"
go-version:
- "1.19.x"
- "1.20.x"
- "1.21.x"

steps:
- name: Set up ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}

- name: Checkout code
uses: actions/checkout@v4

# Set up Docker Compose environment
- name: Set up Docker Compose environment
run: |
docker compose --profile all up -d
- name: Run tests
env:
USE_CONTAINERIZED_REDIS: "true"
RE_CLUSTER: "true"
run: |
go test \
--ginkgo.skip-file="ring_test.go" \
--ginkgo.skip-file="sentinel_test.go" \
--ginkgo.skip-file="osscluster_test.go" \
--ginkgo.skip-file="pubsub_test.go" \
--ginkgo.skip-file="gears_commands_test.go" \
--ginkgo.label-filter='!NonRedisEnterprise'
2 changes: 1 addition & 1 deletion .github/workflows/spellcheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Check Spelling
uses: rojopolis/spellcheck-github-actions@0.40.0
uses: rojopolis/spellcheck-github-actions@0.45.0
with:
config_path: .github/spellcheck-settings.yml
task_name: Markdown
1 change: 1 addition & 0 deletions .github/workflows/test-redis-enterprise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
- name: Test
env:
RE_CLUSTER: "1"
USE_CONTAINERIZED_REDIS: "1"
run: |
go test \
--ginkgo.skip-file="ring_test.go" \
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dockers/
*.rdb
testdata/*
.idea/
.DS_Store
*.tar.gz
*.dic
*.dic
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,24 @@ rdb := redis.NewClient(&redis.Options{
})
```

#### Unstable RESP3 Structures for RediSearch Commands
When integrating Redis with application functionalities using RESP3, it's important to note that some response structures aren't final yet. This is especially true for more complex structures like search and query results. We recommend using RESP2 when using the search and query capabilities, but we plan to stabilize the RESP3-based API-s in the coming versions. You can find more guidance in the upcoming release notes.

To enable unstable RESP3, set the option in your client configuration:

```go
redis.NewClient(&redis.Options{
UnstableResp3: true,
})
```
**Note:** When UnstableResp3 mode is enabled, it's necessary to use RawResult() and RawVal() to retrieve a raw data.
Since, raw response is the only option for unstable search commands Val() and Result() calls wouldn't have any affect on them:

```go
res1, err := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawResult()
val1 := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawVal()
```

## Contributing

Please see [out contributing guidelines](CONTRIBUTING.md) to help us improve this library!
Expand Down
76 changes: 61 additions & 15 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type Cmder interface {

readTimeout() *time.Duration
readReply(rd *proto.Reader) error

readRawReply(rd *proto.Reader) error
SetErr(error)
Err() error
}
Expand Down Expand Up @@ -122,11 +122,11 @@ func cmdString(cmd Cmder, val interface{}) string {
//------------------------------------------------------------------------------

type baseCmd struct {
ctx context.Context
args []interface{}
err error
keyPos int8

ctx context.Context
args []interface{}
err error
keyPos int8
rawVal interface{}
_readTimeout *time.Duration
}

Expand Down Expand Up @@ -167,6 +167,8 @@ func (cmd *baseCmd) stringArg(pos int) string {
switch v := arg.(type) {
case string:
return v
case []byte:
return string(v)
default:
// TODO: consider using appendArg
return fmt.Sprint(v)
Expand Down Expand Up @@ -197,6 +199,11 @@ func (cmd *baseCmd) setReadTimeout(d time.Duration) {
cmd._readTimeout = &d
}

func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) {
cmd.rawVal, err = rd.ReadReply()
return err
}

//------------------------------------------------------------------------------

type Cmd struct {
Expand Down Expand Up @@ -1398,27 +1405,63 @@ func (cmd *MapStringSliceInterfaceCmd) Val() map[string][]interface{} {
}

func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
n, err := rd.ReadMapLen()
readType, err := rd.PeekReplyType()
if err != nil {
return err
}
cmd.val = make(map[string][]interface{}, n)
for i := 0; i < n; i++ {
k, err := rd.ReadString()

cmd.val = make(map[string][]interface{})

if readType == proto.RespMap {
n, err := rd.ReadMapLen()
if err != nil {
return err
}
nn, err := rd.ReadArrayLen()
for i := 0; i < n; i++ {
k, err := rd.ReadString()
if err != nil {
return err
}
nn, err := rd.ReadArrayLen()
if err != nil {
return err
}
cmd.val[k] = make([]interface{}, nn)
for j := 0; j < nn; j++ {
value, err := rd.ReadReply()
if err != nil {
return err
}
cmd.val[k][j] = value
}
}
} else if readType == proto.RespArray {
// RESP2 response
n, err := rd.ReadArrayLen()
if err != nil {
return err
}
cmd.val[k] = make([]interface{}, nn)
for j := 0; j < nn; j++ {
value, err := rd.ReadReply()

for i := 0; i < n; i++ {
// Each entry in this array is itself an array with key details
itemLen, err := rd.ReadArrayLen()
if err != nil {
return err
}
cmd.val[k][j] = value

key, err := rd.ReadString()
if err != nil {
return err
}
cmd.val[key] = make([]interface{}, 0, itemLen-1)
for j := 1; j < itemLen; j++ {
// Read the inner array for timestamp-value pairs
data, err := rd.ReadReply()
if err != nil {
return err
}
cmd.val[key] = append(cmd.val[key], data)
}
}
}

Expand Down Expand Up @@ -5071,6 +5114,7 @@ type ClientInfo struct {
OutputListLength int // oll, output list length (replies are queued in this list when the buffer is full)
OutputMemory int // omem, output buffer memory usage
TotalMemory int // tot-mem, total memory consumed by this client in its various buffers
IoThread int // io-thread id
Events string // file descriptor events (see below)
LastCmd string // cmd, last command played
User string // the authenticated username of the client
Expand Down Expand Up @@ -5249,6 +5293,8 @@ func parseClientInfo(txt string) (info *ClientInfo, err error) {
info.LibName = val
case "lib-ver":
info.LibVer = val
case "io-thread":
info.IoThread, err = strconv.Atoi(val)
default:
return nil, fmt.Errorf("redis: unexpected client info key(%s)", key)
}
Expand Down
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---

services:

redis-stanalone:
image: redislabs/client-libs-test:8.0-M02
container_name: redis-standalone
environment:
- REDIS_CLUSTER=no
- PORT=6379
- TLS_PORT=6666

ports:
- 6379:6379
- 6380:6379
- 6666:6666 # TLS port
volumes:
- "./dockers/redis-standalone:/redis/work"
profiles:
- standalone
- all
83 changes: 83 additions & 0 deletions doctests/bf_tutorial_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// EXAMPLE: bf_tutorial
// HIDE_START
package example_commands_test

import (
"context"
"fmt"

"github.com/redis/go-redis/v9"
)

// HIDE_END

func ExampleClient_bloom() {
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password docs
DB: 0, // use default DB
})

// REMOVE_START
rdb.Del(ctx, "bikes:models")
// REMOVE_END

// STEP_START bloom
res1, err := rdb.BFReserve(ctx, "bikes:models", 0.01, 1000).Result()

if err != nil {
panic(err)
}

fmt.Println(res1) // >>> OK

res2, err := rdb.BFAdd(ctx, "bikes:models", "Smoky Mountain Striker").Result()

if err != nil {
panic(err)
}

fmt.Println(res2) // >>> true

res3, err := rdb.BFExists(ctx, "bikes:models", "Smoky Mountain Striker").Result()

if err != nil {
panic(err)
}

fmt.Println(res3) // >>> true

res4, err := rdb.BFMAdd(ctx, "bikes:models",
"Rocky Mountain Racer",
"Cloudy City Cruiser",
"Windy City Wippet",
).Result()

if err != nil {
panic(err)
}

fmt.Println(res4) // >>> [true true true]

res5, err := rdb.BFMExists(ctx, "bikes:models",
"Rocky Mountain Racer",
"Cloudy City Cruiser",
"Windy City Wippet",
).Result()

if err != nil {
panic(err)
}

fmt.Println(res5) // >>> [true true true]
// STEP_END

// Output:
// OK
// true
// true
// [true true true]
// [true true true]
}
Loading

0 comments on commit 41c8b3a

Please sign in to comment.