diff --git a/core/stores/redis/redis.go b/core/stores/redis/redis.go index 1dec67c7c..a9ab5b4d8 100644 --- a/core/stores/redis/redis.go +++ b/core/stores/redis/redis.go @@ -65,6 +65,7 @@ type ( // RedisNode interface represents a redis node. RedisNode interface { red.Cmdable + Do(ctx context.Context, args ...any) *red.Cmd } // GeoLocation is used with GeoAdd to add geospatial location. @@ -421,6 +422,25 @@ func (s *Redis) EvalCtx(ctx context.Context, script string, keys []string, return conn.Eval(ctx, script, keys, args...).Result() } +// Do executes a generic redis command with given arguments. +func (s *Redis) Do(args ...any) (any, error) { + return s.DoCtx(context.Background(), args...) +} + +// DoCtx executes a generic redis command with given arguments using the provided context. +func (s *Redis) DoCtx(ctx context.Context, args ...any) (any, error) { + if len(args) == 0 { + return nil, errors.New("missing redis command") + } + + conn, err := getRedis(s) + if err != nil { + return nil, err + } + + return conn.Do(ctx, args...).Result() +} + // EvalSha is the implementation of redis evalsha command. func (s *Redis) EvalSha(sha string, keys []string, args ...any) (any, error) { return s.EvalShaCtx(context.Background(), sha, keys, args...) diff --git a/core/stores/redis/redis_test.go b/core/stores/redis/redis_test.go index a84dc585e..5a37f32d3 100644 --- a/core/stores/redis/redis_test.go +++ b/core/stores/redis/redis_test.go @@ -275,6 +275,36 @@ func TestRedis_Eval(t *testing.T) { }) } +func TestRedis_Do(t *testing.T) { + runOnRedis(t, func(client *Redis) { + _, err := newRedis(client.Addr, badType()).Do("PING") + assert.NotNil(t, err) + + pong, err := client.Do("PING") + assert.Nil(t, err) + assert.Equal(t, "PONG", pong) + + ok, err := client.Do("SET", "key1", "value1") + assert.Nil(t, err) + assert.Equal(t, "OK", ok) + + val, err := client.Do("GET", "key1") + assert.Nil(t, err) + assert.Equal(t, "value1", val) + + _, err = client.Do("GET", "not_exist") + assert.Equal(t, Nil, err) + + _, err = client.Do() + assert.NotNil(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + _, err = client.DoCtx(ctx, "PING") + assert.Equal(t, context.Canceled, err) + }) +} + func TestRedis_ScriptRun(t *testing.T) { runOnRedis(t, func(client *Redis) { sc := NewScript(`redis.call("EXISTS", KEYS[1])`)