diff --git a/command.go b/command.go index 3cb9538a..53ba1269 100644 --- a/command.go +++ b/command.go @@ -30,6 +30,9 @@ type Cmder interface { // e.g. "set k v ex 10" -> "[set k v ex 10]". Args() []interface{} + //all keys in command. + Keys() []string + // format request and response string. // e.g. "set k v ex 10" -> "set k v ex 10: OK", "get k" -> "get k: v". String() string @@ -126,6 +129,7 @@ type baseCmd struct { args []interface{} err error keyPos int8 + keys []string rawVal interface{} _readTimeout *time.Duration } @@ -159,6 +163,10 @@ func (cmd *baseCmd) Args() []interface{} { return cmd.args } +func (cmd *baseCmd) Keys() []string { + return cmd.keys +} + func (cmd *baseCmd) stringArg(pos int) string { if pos < 0 || pos >= len(cmd.args) { return "" @@ -204,6 +212,22 @@ func (cmd *baseCmd) readRawReply(rd *proto.Reader) (err error) { return err } +// getInterleavedArguments returns arguments at even indices starting from index 1. +func (cmd *baseCmd) getInterleavedArguments() []string { + return cmd.getInterleavedArgumentsWithOffset(1) +} + +// getInterleavedArgumentsWithOffset returns arguments at even indices starting from the specified offset. +func (cmd *baseCmd) getInterleavedArgumentsWithOffset(offset int) []string { + var matchingArguments []string + for i := offset; i < len(cmd.args); i += 2 { + if arg, ok := cmd.args[i].(string); ok { + matchingArguments = append(matchingArguments, arg) + } + } + return matchingArguments +} + //------------------------------------------------------------------------------ type Cmd struct { diff --git a/commands_test.go b/commands_test.go index 9554bf9a..cf722a9e 100644 --- a/commands_test.go +++ b/commands_test.go @@ -7279,6 +7279,67 @@ var _ = Describe("Commands", func() { }) }) +var _ = Describe("Keys Extraction Tests", func() { + var client *redis.Client + var ctx = context.TODO() + + BeforeEach(func() { + client = redis.NewClient(redisOptions()) + Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred()) + }) + + AfterEach(func() { + Expect(client.Close()).NotTo(HaveOccurred()) + }) + + // STRING COMMANDS + + It("should test Append command", func() { + cmd := client.Append(ctx, "key1", "value") + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test Decr command", func() { + cmd := client.Decr(ctx, "key1") + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test Get command", func() { + cmd := client.Get(ctx, "key1") + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test MGet command", func() { + cmd := client.MGet(ctx, "key1", "key2", "key3") + Expect(cmd.Keys()).To(Equal([]string{"key1", "key2", "key3"})) + }) + + It("should test Set command", func() { + cmd := client.Set(ctx, "key1", "value", time.Second) + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test MSet command", func() { + cmd := client.MSet(ctx, "key1", "value1", "key2", "value2") + Expect(cmd.Keys()).To(Equal([]string{"key1", "key2"})) + }) + + It("should test IncrBy command", func() { + cmd := client.IncrBy(ctx, "key1", 10) + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test SetNX command", func() { + cmd := client.SetNX(ctx, "key1", "value", time.Second) + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) + + It("should test GetDel command", func() { + cmd := client.GetDel(ctx, "key1") + Expect(cmd.Keys()).To(Equal([]string{"key1"})) + }) +}) + type numberStruct struct { Number int } diff --git a/string_commands.go b/string_commands.go index eff5880d..d9d1d90a 100644 --- a/string_commands.go +++ b/string_commands.go @@ -32,18 +32,21 @@ type StringCmdable interface { func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd { cmd := NewIntCmd(ctx, "append", key, value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) Decr(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "decr", key) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd { cmd := NewIntCmd(ctx, "decrby", key, decrement) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -51,18 +54,21 @@ func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCm // Get Redis `GET key` command. It returns redis.Nil error when key does not exist. func (c cmdable) Get(ctx context.Context, key string) *StringCmd { cmd := NewStringCmd(ctx, "get", key) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd { cmd := NewStringCmd(ctx, "getrange", key, start, end) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd { cmd := NewStringCmd(ctx, "getset", key, value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -83,6 +89,7 @@ func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration } cmd := NewStringCmd(ctx, args...) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -90,24 +97,28 @@ func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration // GetDel redis-server version >= 6.2.0. func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd { cmd := NewStringCmd(ctx, "getdel", key) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) Incr(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "incr", key) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd { cmd := NewIntCmd(ctx, "incrby", key, value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd { cmd := NewFloatCmd(ctx, "incrbyfloat", key, value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -125,6 +136,7 @@ func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd { args[1+i] = key } cmd := NewSliceCmd(ctx, args...) + cmd.keys = append(cmd.keys, keys...) _ = c(ctx, cmd) return cmd } @@ -139,6 +151,7 @@ func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd { args[0] = "mset" args = appendArgs(args, values) cmd := NewStatusCmd(ctx, args...) + cmd.keys = append(cmd.keys, cmd.getInterleavedArguments()...) _ = c(ctx, cmd) return cmd } @@ -153,6 +166,7 @@ func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd { args[0] = "msetnx" args = appendArgs(args, values) cmd := NewBoolCmd(ctx, args...) + cmd.keys = append(cmd.keys, cmd.getInterleavedArguments()...) _ = c(ctx, cmd) return cmd } @@ -179,6 +193,7 @@ func (c cmdable) Set(ctx context.Context, key string, value interface{}, expirat } cmd := NewStatusCmd(ctx, args...) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -230,6 +245,7 @@ func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a S } cmd := NewStatusCmd(ctx, args...) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -237,6 +253,7 @@ func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a S // SetEx Redis `SETEx key expiration value` command. func (c cmdable) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd { cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -261,7 +278,7 @@ func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expir cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx") } } - + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } @@ -285,19 +302,21 @@ func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expir cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx") } } - + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd { cmd := NewIntCmd(ctx, "setrange", key, offset, value) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd } func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd { cmd := NewIntCmd(ctx, "strlen", key) + cmd.keys = append(cmd.keys, key) _ = c(ctx, cmd) return cmd }