Skip to content

Commit 41c8b3a

Browse files
authored
Merge branch 'redis:master' into master
2 parents ac5c7ad + 94b88f5 commit 41c8b3a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+9580
-2502
lines changed

.github/wordlist.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
ACLs
2+
APIs
23
autoload
34
autoloader
45
autoloading
@@ -46,11 +47,14 @@ runtime
4647
SHA
4748
sharding
4849
SETNAME
50+
SpellCheck
4951
SSL
5052
struct
5153
stunnel
54+
SynDump
5255
TCP
5356
TLS
57+
UnstableResp
5458
uri
5559
URI
5660
url
@@ -59,3 +63,5 @@ RedisStack
5963
RedisGears
6064
RedisTimeseries
6165
RediSearch
66+
RawResult
67+
RawVal

.github/workflows/build.yml

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,50 @@ jobs:
3939
run: make test
4040

4141
- name: Upload to Codecov
42-
uses: codecov/codecov-action@v4
42+
uses: codecov/codecov-action@v5
4343
with:
4444
files: coverage.txt
45-
token: ${{ secrets.CODECOV_TOKEN }}
45+
token: ${{ secrets.CODECOV_TOKEN }}
46+
47+
test-redis-ce:
48+
name: test-redis-ce
49+
runs-on: ubuntu-latest
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
redis_version:
54+
- "8.0-M01"
55+
- "7.4.1"
56+
- "7.2.6"
57+
- "6.2.16"
58+
go-version:
59+
- "1.19.x"
60+
- "1.20.x"
61+
- "1.21.x"
62+
63+
steps:
64+
- name: Set up ${{ matrix.go-version }}
65+
uses: actions/setup-go@v5
66+
with:
67+
go-version: ${{ matrix.go-version }}
68+
69+
- name: Checkout code
70+
uses: actions/checkout@v4
71+
72+
# Set up Docker Compose environment
73+
- name: Set up Docker Compose environment
74+
run: |
75+
docker compose --profile all up -d
76+
77+
- name: Run tests
78+
env:
79+
USE_CONTAINERIZED_REDIS: "true"
80+
RE_CLUSTER: "true"
81+
run: |
82+
go test \
83+
--ginkgo.skip-file="ring_test.go" \
84+
--ginkgo.skip-file="sentinel_test.go" \
85+
--ginkgo.skip-file="osscluster_test.go" \
86+
--ginkgo.skip-file="pubsub_test.go" \
87+
--ginkgo.skip-file="gears_commands_test.go" \
88+
--ginkgo.label-filter='!NonRedisEnterprise'

.github/workflows/spellcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- name: Checkout
99
uses: actions/checkout@v4
1010
- name: Check Spelling
11-
uses: rojopolis/spellcheck-github-actions@0.40.0
11+
uses: rojopolis/spellcheck-github-actions@0.45.0
1212
with:
1313
config_path: .github/spellcheck-settings.yml
1414
task_name: Markdown

.github/workflows/test-redis-enterprise.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ jobs:
4747
- name: Test
4848
env:
4949
RE_CLUSTER: "1"
50+
USE_CONTAINERIZED_REDIS: "1"
5051
run: |
5152
go test \
5253
--ginkgo.skip-file="ring_test.go" \

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
dockers/
12
*.rdb
23
testdata/*
34
.idea/
45
.DS_Store
56
*.tar.gz
6-
*.dic
7+
*.dic

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,24 @@ rdb := redis.NewClient(&redis.Options{
183183
})
184184
```
185185

186+
#### Unstable RESP3 Structures for RediSearch Commands
187+
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.
188+
189+
To enable unstable RESP3, set the option in your client configuration:
190+
191+
```go
192+
redis.NewClient(&redis.Options{
193+
UnstableResp3: true,
194+
})
195+
```
196+
**Note:** When UnstableResp3 mode is enabled, it's necessary to use RawResult() and RawVal() to retrieve a raw data.
197+
Since, raw response is the only option for unstable search commands Val() and Result() calls wouldn't have any affect on them:
198+
199+
```go
200+
res1, err := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawResult()
201+
val1 := client.FTSearchWithArgs(ctx, "txt", "foo bar", &redis.FTSearchOptions{}).RawVal()
202+
```
203+
186204
## Contributing
187205

188206
Please see [out contributing guidelines](CONTRIBUTING.md) to help us improve this library!

command.go

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ type Cmder interface {
4040

4141
readTimeout() *time.Duration
4242
readReply(rd *proto.Reader) error
43-
43+
readRawReply(rd *proto.Reader) error
4444
SetErr(error)
4545
Err() error
4646
}
@@ -122,11 +122,11 @@ func cmdString(cmd Cmder, val interface{}) string {
122122
//------------------------------------------------------------------------------
123123

124124
type baseCmd struct {
125-
ctx context.Context
126-
args []interface{}
127-
err error
128-
keyPos int8
129-
125+
ctx context.Context
126+
args []interface{}
127+
err error
128+
keyPos int8
129+
rawVal interface{}
130130
_readTimeout *time.Duration
131131
}
132132

@@ -167,6 +167,8 @@ func (cmd *baseCmd) stringArg(pos int) string {
167167
switch v := arg.(type) {
168168
case string:
169169
return v
170+
case []byte:
171+
return string(v)
170172
default:
171173
// TODO: consider using appendArg
172174
return fmt.Sprint(v)
@@ -197,6 +199,11 @@ func (cmd *baseCmd) setReadTimeout(d time.Duration) {
197199
cmd._readTimeout = &d
198200
}
199201

202+
func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) {
203+
cmd.rawVal, err = rd.ReadReply()
204+
return err
205+
}
206+
200207
//------------------------------------------------------------------------------
201208

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

14001407
func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
1401-
n, err := rd.ReadMapLen()
1408+
readType, err := rd.PeekReplyType()
14021409
if err != nil {
14031410
return err
14041411
}
1405-
cmd.val = make(map[string][]interface{}, n)
1406-
for i := 0; i < n; i++ {
1407-
k, err := rd.ReadString()
1412+
1413+
cmd.val = make(map[string][]interface{})
1414+
1415+
if readType == proto.RespMap {
1416+
n, err := rd.ReadMapLen()
14081417
if err != nil {
14091418
return err
14101419
}
1411-
nn, err := rd.ReadArrayLen()
1420+
for i := 0; i < n; i++ {
1421+
k, err := rd.ReadString()
1422+
if err != nil {
1423+
return err
1424+
}
1425+
nn, err := rd.ReadArrayLen()
1426+
if err != nil {
1427+
return err
1428+
}
1429+
cmd.val[k] = make([]interface{}, nn)
1430+
for j := 0; j < nn; j++ {
1431+
value, err := rd.ReadReply()
1432+
if err != nil {
1433+
return err
1434+
}
1435+
cmd.val[k][j] = value
1436+
}
1437+
}
1438+
} else if readType == proto.RespArray {
1439+
// RESP2 response
1440+
n, err := rd.ReadArrayLen()
14121441
if err != nil {
14131442
return err
14141443
}
1415-
cmd.val[k] = make([]interface{}, nn)
1416-
for j := 0; j < nn; j++ {
1417-
value, err := rd.ReadReply()
1444+
1445+
for i := 0; i < n; i++ {
1446+
// Each entry in this array is itself an array with key details
1447+
itemLen, err := rd.ReadArrayLen()
14181448
if err != nil {
14191449
return err
14201450
}
1421-
cmd.val[k][j] = value
1451+
1452+
key, err := rd.ReadString()
1453+
if err != nil {
1454+
return err
1455+
}
1456+
cmd.val[key] = make([]interface{}, 0, itemLen-1)
1457+
for j := 1; j < itemLen; j++ {
1458+
// Read the inner array for timestamp-value pairs
1459+
data, err := rd.ReadReply()
1460+
if err != nil {
1461+
return err
1462+
}
1463+
cmd.val[key] = append(cmd.val[key], data)
1464+
}
14221465
}
14231466
}
14241467

@@ -5071,6 +5114,7 @@ type ClientInfo struct {
50715114
OutputListLength int // oll, output list length (replies are queued in this list when the buffer is full)
50725115
OutputMemory int // omem, output buffer memory usage
50735116
TotalMemory int // tot-mem, total memory consumed by this client in its various buffers
5117+
IoThread int // io-thread id
50745118
Events string // file descriptor events (see below)
50755119
LastCmd string // cmd, last command played
50765120
User string // the authenticated username of the client
@@ -5249,6 +5293,8 @@ func parseClientInfo(txt string) (info *ClientInfo, err error) {
52495293
info.LibName = val
52505294
case "lib-ver":
52515295
info.LibVer = val
5296+
case "io-thread":
5297+
info.IoThread, err = strconv.Atoi(val)
52525298
default:
52535299
return nil, fmt.Errorf("redis: unexpected client info key(%s)", key)
52545300
}

docker-compose.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
3+
services:
4+
5+
redis-stanalone:
6+
image: redislabs/client-libs-test:8.0-M02
7+
container_name: redis-standalone
8+
environment:
9+
- REDIS_CLUSTER=no
10+
- PORT=6379
11+
- TLS_PORT=6666
12+
13+
ports:
14+
- 6379:6379
15+
- 6380:6379
16+
- 6666:6666 # TLS port
17+
volumes:
18+
- "./dockers/redis-standalone:/redis/work"
19+
profiles:
20+
- standalone
21+
- all

doctests/bf_tutorial_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// EXAMPLE: bf_tutorial
2+
// HIDE_START
3+
package example_commands_test
4+
5+
import (
6+
"context"
7+
"fmt"
8+
9+
"github.com/redis/go-redis/v9"
10+
)
11+
12+
// HIDE_END
13+
14+
func ExampleClient_bloom() {
15+
ctx := context.Background()
16+
17+
rdb := redis.NewClient(&redis.Options{
18+
Addr: "localhost:6379",
19+
Password: "", // no password docs
20+
DB: 0, // use default DB
21+
})
22+
23+
// REMOVE_START
24+
rdb.Del(ctx, "bikes:models")
25+
// REMOVE_END
26+
27+
// STEP_START bloom
28+
res1, err := rdb.BFReserve(ctx, "bikes:models", 0.01, 1000).Result()
29+
30+
if err != nil {
31+
panic(err)
32+
}
33+
34+
fmt.Println(res1) // >>> OK
35+
36+
res2, err := rdb.BFAdd(ctx, "bikes:models", "Smoky Mountain Striker").Result()
37+
38+
if err != nil {
39+
panic(err)
40+
}
41+
42+
fmt.Println(res2) // >>> true
43+
44+
res3, err := rdb.BFExists(ctx, "bikes:models", "Smoky Mountain Striker").Result()
45+
46+
if err != nil {
47+
panic(err)
48+
}
49+
50+
fmt.Println(res3) // >>> true
51+
52+
res4, err := rdb.BFMAdd(ctx, "bikes:models",
53+
"Rocky Mountain Racer",
54+
"Cloudy City Cruiser",
55+
"Windy City Wippet",
56+
).Result()
57+
58+
if err != nil {
59+
panic(err)
60+
}
61+
62+
fmt.Println(res4) // >>> [true true true]
63+
64+
res5, err := rdb.BFMExists(ctx, "bikes:models",
65+
"Rocky Mountain Racer",
66+
"Cloudy City Cruiser",
67+
"Windy City Wippet",
68+
).Result()
69+
70+
if err != nil {
71+
panic(err)
72+
}
73+
74+
fmt.Println(res5) // >>> [true true true]
75+
// STEP_END
76+
77+
// Output:
78+
// OK
79+
// true
80+
// true
81+
// [true true true]
82+
// [true true true]
83+
}

0 commit comments

Comments
 (0)