Skip to content

Commit

Permalink
Merge pull request #88 from splitio/SDKS-7838-scan-cmd
Browse files Browse the repository at this point in the history
SDKS-7838 Adding Scan cmd for redis
  • Loading branch information
sanzmauro authored Jan 10, 2024
2 parents ffbc706 + f918a1d commit 5de0602
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
5.4.0 (Jan 10, 2024)
- Added `Scan` operation to Redis

5.3.2 (Nov 29, 2023)
- Added Set, SAdd, SMembers, SRem, Incr, Decr, Del methods into Redis Pipeline.
- Updated mocks SAdd, SRem to accept members parameters.
Expand Down
6 changes: 6 additions & 0 deletions redis/mocks/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ type MockClient struct {
HSetCall func(key string, hashKey string, value interface{}) redis.Result
TypeCall func(key string) redis.Result
PipelineCall func() redis.Pipeline
ScanCall func(cursor uint64, match string, count int64) redis.Result
}

func (m *MockClient) ClusterMode() bool {
Expand Down Expand Up @@ -318,3 +319,8 @@ func (m *MockClient) Type(key string) redis.Result {
func (m *MockClient) Pipeline() redis.Pipeline {
return m.PipelineCall()
}

// Scan mock
func (m *MockClient) Scan(cursor uint64, match string, count int64) redis.Result {
return m.ScanCall(cursor, match, count)
}
22 changes: 22 additions & 0 deletions redis/prefixedclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,28 @@ func (p *PrefixedRedisClient) Type(key string) (string, error) {
return p.client.Type(withPrefix(p.prefix, key)).ResultString()
}

func (p *PrefixedRedisClient) Scan(cursor uint64, match string, count int64) ([]string, uint64, error) {
toReturn := make([]string, 0)

res := p.client.Scan(cursor, withPrefix(p.prefix, match), count)
if res.Err() != nil {
return nil, 0, res.Err()
}

cursor = uint64(res.Int())

keys, err := res.Multi()
if err != nil {
return nil, 0, err
}

for _, key := range keys {
toReturn = append(toReturn, withoutPrefix(p.prefix, key))
}

return toReturn, cursor, nil
}

// Pipeline wrapper
func (p *PrefixedRedisClient) Pipeline() Pipeline {
return &PrefixedPipeline{wrapped: p.client.Pipeline(), prefix: p.prefix}
Expand Down
14 changes: 14 additions & 0 deletions redis/wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ type Client interface {
HGetAll(key string) Result
Type(key string) Result
Pipeline() Pipeline
Scan(cursor uint64, match string, count int64) Result
}

// ClientImpl wrapps redis client
Expand Down Expand Up @@ -406,6 +407,12 @@ func (c *ClientImpl) Pipeline() Pipeline {
return &PipelineImpl{wrapped: res}
}

// Scan implements Scan wrapper for redis
func (c *ClientImpl) Scan(cursor uint64, match string, count int64) Result {
res := c.wrapped.Scan(context.TODO(), cursor, match, count)
return wrapResult(res)
}

// NewClient returns new client implementation
func NewClient(options *UniversalOptions) (Client, error) {
if options.ForceClusterMode {
Expand Down Expand Up @@ -468,6 +475,13 @@ func wrapResult(result interface{}) Result {
err: v.Err(),
mapStringString: v.Val(),
}
case *redis.ScanCmd:
keys, cursor := v.Val()
return &ResultImpl{
err: v.Err(),
multi: keys,
value: int64(cursor),
}
default:
return nil
}
Expand Down
49 changes: 49 additions & 0 deletions redis/wrapper_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,62 @@
package redis

import (
"fmt"
"testing"
"time"

"github.com/redis/go-redis/v9"
"github.com/splitio/go-toolkit/v5/testhelpers"
)

func TestRedisWrapperKeysAndScan(t *testing.T) {
rc := redis.NewUniversalClient(&redis.UniversalOptions{})
client := &ClientImpl{wrapped: rc}

for i := 0; i < 10; i++ {
client.Set(fmt.Sprintf("utest.key-del%d", i), 0, 1*time.Hour)
}

keys, err := client.Keys("utest*").Multi()
if err != nil {
t.Error("there should not be any error. Got: ", err)
}

if len(keys) != 10 {
t.Error("should be 10 keys. Got: ", len(keys))
}

var cursor uint64
scanKeys := make([]string, 0)
for {
result := client.Scan(cursor, "utest*", 10)
if result.Err() != nil {
t.Error("there should not be any error. Got: ", result.Err())
}

cursor = uint64(result.Int())

keys, err := result.Multi()
if err != nil {
t.Error("there should not be any error. Got: ", err)
}

scanKeys = append(scanKeys, keys...)

if cursor == 0 {
break
}
}

if len(scanKeys) != 10 {
t.Error("should be 10 keys. Got: ", len(scanKeys))
}

for i := 0; i < 10; i++ {
client.Del(fmt.Sprintf("utest.key-del%d", i))
}
}

func TestRedisWrapperPipeline(t *testing.T) {
rc := redis.NewUniversalClient(&redis.UniversalOptions{})
client := &ClientImpl{wrapped: rc}
Expand Down

0 comments on commit 5de0602

Please sign in to comment.