diff --git a/command.go b/command.go index bea76c22..da044caa 100644 --- a/command.go +++ b/command.go @@ -3690,3 +3690,65 @@ func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error { } return nil } + +//------------------------------------------------------------------------------ + +type ListElementCmd struct { + baseCmd + + key string + val []string +} + +var _ Cmder = (*ListElementCmd)(nil) + +func NewListElementCmd(ctx context.Context, args ...interface{}) *ListElementCmd { + return &ListElementCmd{ + baseCmd: baseCmd{ + ctx: ctx, + args: args, + }, + } +} + +func (cmd *ListElementCmd) SetVal(key string, val []string) { + cmd.key = key + cmd.val = val +} + +func (cmd *ListElementCmd) Val() (string, []string) { + return cmd.key, cmd.val +} + +func (cmd *ListElementCmd) Result() (string, []string, error) { + return cmd.key, cmd.val, cmd.err +} + +func (cmd *ListElementCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *ListElementCmd) readReply(rd *proto.Reader) (err error) { + if err = rd.ReadFixedArrayLen(2); err != nil { + return err + } + + cmd.key, err = rd.ReadString() + if err != nil { + return err + } + + n, err := rd.ReadArrayLen() + if err != nil { + return err + } + cmd.val = make([]string, n) + for i := 0; i < n; i++ { + cmd.val[i], err = rd.ReadString() + if err != nil { + return err + } + } + + return nil +} diff --git a/commands.go b/commands.go index a8d0b56e..61b1bac3 100644 --- a/commands.go +++ b/commands.go @@ -225,6 +225,7 @@ type Cmdable interface { LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd LLen(ctx context.Context, key string) *IntCmd + LMPop(ctx context.Context, direction string, count int64, keys ...string) *ListElementCmd LPop(ctx context.Context, key string) *StringCmd LPopCount(ctx context.Context, key string, count int) *StringSliceCmd LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd @@ -1463,6 +1464,22 @@ func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd return cmd } +// LMPop Pops one or more elements from the first non-empty list key from the list of provided key names. +// direction: left or right, count: > 0 +// example: client.LMPop(ctx, "left", 3, "key1", "key2") +func (c cmdable) LMPop(ctx context.Context, direction string, count int64, keys ...string) *ListElementCmd { + args := make([]interface{}, 2+len(keys), 5+len(keys)) + args[0] = "lmpop" + args[1] = len(keys) + for i, key := range keys { + args[2+i] = key + } + args = append(args, strings.ToLower(direction), "count", count) + cmd := NewListElementCmd(ctx, args...) + _ = c(ctx, cmd) + return cmd +} + func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd { cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value) _ = c(ctx, cmd) diff --git a/commands_test.go b/commands_test.go index fdc3452c..95fb2146 100644 --- a/commands_test.go +++ b/commands_test.go @@ -2272,6 +2272,46 @@ var _ = Describe("Commands", func() { Expect(lRange.Val()).To(Equal([]string{"Hello", "There", "World"})) }) + It("should LMPop", func() { + err := client.LPush(ctx, "list1", "one", "two", "three", "four", "five").Err() + Expect(err).NotTo(HaveOccurred()) + + err = client.LPush(ctx, "list2", "a", "b", "c", "d", "e").Err() + Expect(err).NotTo(HaveOccurred()) + + key, elems, err := client.LMPop(ctx, "left", 3, "list1", "list2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(key).To(Equal("list1")) + Expect(elems).To(Equal([]string{"five", "four", "three"})) + + key, elems, err = client.LMPop(ctx, "right", 3, "list1", "list2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(key).To(Equal("list1")) + Expect(elems).To(Equal([]string{"one", "two"})) + + key, elems, err = client.LMPop(ctx, "left", 1, "list1", "list2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(key).To(Equal("list2")) + Expect(elems).To(Equal([]string{"e"})) + + key, elems, err = client.LMPop(ctx, "right", 10, "list1", "list2").Result() + Expect(err).NotTo(HaveOccurred()) + Expect(key).To(Equal("list2")) + Expect(elems).To(Equal([]string{"a", "b", "c", "d"})) + + err = client.LMPop(ctx, "left", 10, "list1", "list2").Err() + Expect(err).To(Equal(redis.Nil)) + + err = client.Set(ctx, "list3", 1024, 0).Err() + Expect(err).NotTo(HaveOccurred()) + + err = client.LMPop(ctx, "left", 10, "list1", "list2", "list3").Err() + Expect(err.Error()).To(Equal("WRONGTYPE Operation against a key holding the wrong kind of value")) + + err = client.LMPop(ctx, "right", 0, "list1", "list2").Err() + Expect(err).To(HaveOccurred()) + }) + It("should LLen", func() { lPush := client.LPush(ctx, "list", "World") Expect(lPush.Err()).NotTo(HaveOccurred())