Skip to content

Adding support for ZMPOP command #2408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
21f56df
feat: add ZMPOP command
SoulPancake Jan 31, 2023
d1e3851
Merge branch 'master' into ab/support-for-ZMPOP
SoulPancake Jan 31, 2023
2fd3ec4
Merge branch 'master' into ab/support-for-ZMPOP
chayim Feb 1, 2023
7140b31
Merge branch 'master' into ab/support-for-ZMPOP
SoulPancake Feb 1, 2023
82efba8
fix: reply reading string
SoulPancake Feb 1, 2023
84659b4
Merge branch 'ab/support-for-ZMPOP' of https://github.com/SoulPancake…
SoulPancake Feb 1, 2023
7ab89ad
fix: evaluating a test tweak
SoulPancake Feb 1, 2023
1294cc1
fix: test fix
SoulPancake Feb 1, 2023
85ec45b
fix: reverting to debug
SoulPancake Feb 1, 2023
61e54ac
fix: test fix
SoulPancake Feb 1, 2023
a8ba6de
Merge branch 'redis:master' into ab/support-for-ZMPOP
SoulPancake Feb 13, 2023
94b90b5
fix: remove old implementation
SoulPancake Feb 13, 2023
0d83c51
Merge branch 'master' of https://github.com/SoulPancake/go-redis into…
SoulPancake Feb 13, 2023
f2526c5
Merge branch 'ab/support-for-ZMPOP' of https://github.com/SoulPancake…
SoulPancake Feb 13, 2023
2b045dc
feat: adding ZMPOP and tests
SoulPancake Feb 13, 2023
1f0f603
feat: modifying ZMpopCmd
SoulPancake Feb 14, 2023
6353e86
fix: fix test
SoulPancake Feb 14, 2023
69467cc
fix: test removal check
SoulPancake Feb 14, 2023
82cf405
fix: fix testS
SoulPancake Feb 14, 2023
811fed8
Merge branch 'redis:master' into ab/support-for-ZMPOP
SoulPancake Feb 14, 2023
1de3495
Adding more tests
SoulPancake Feb 14, 2023
1cf62ef
fix: using redis.Nil instead of string
SoulPancake Feb 14, 2023
8a8b1d8
fix: renaming command to ZArrayWithKeyCmd to match the standard
SoulPancake Feb 15, 2023
7bea742
Merge branch 'master' into ab/support-for-ZMPOP
SoulPancake Feb 18, 2023
fc080e8
Merge branch 'redis:master' into ab/support-for-ZMPOP
SoulPancake Feb 21, 2023
c5b1f1c
feat: updated ZArrayWithKeyCmd to ZSliceWithKeyCmd
SoulPancake Feb 21, 2023
53d691e
feat: adding help strings
SoulPancake Feb 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3752,3 +3752,86 @@ func (cmd *KeyValuesCmd) readReply(rd *proto.Reader) (err error) {

return nil
}

//------------------------------------------------------------------------------

type ZSliceWithKeyCmd struct {
baseCmd

key string
val []Z
}

var _ Cmder = (*ZSliceWithKeyCmd)(nil)

func NewZSliceWithKeyCmd(ctx context.Context, args ...interface{}) *ZSliceWithKeyCmd {
return &ZSliceWithKeyCmd{
baseCmd: baseCmd{
ctx: ctx,
args: args,
},
}
}

func (cmd *ZSliceWithKeyCmd) SetVal(key string, val []Z) {
cmd.key = key
cmd.val = val
}

func (cmd *ZSliceWithKeyCmd) Val() (string, []Z) {
return cmd.key, cmd.val
}

func (cmd *ZSliceWithKeyCmd) Result() (string, []Z, error) {
return cmd.key, cmd.val, cmd.err
}

func (cmd *ZSliceWithKeyCmd) String() string {
return cmdString(cmd, cmd.val)
}

func (cmd *ZSliceWithKeyCmd) 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
}

typ, err := rd.PeekReplyType()
if err != nil {
return err
}
array := typ == proto.RespArray

if array {
cmd.val = make([]Z, n)
} else {
cmd.val = make([]Z, n/2)
}

for i := 0; i < len(cmd.val); i++ {
if array {
if err = rd.ReadFixedArrayLen(2); err != nil {
return err
}
}

if cmd.val[i].Member, err = rd.ReadString(); err != nil {
return err
}

if cmd.val[i].Score, err = rd.ReadFloat(); err != nil {
return err
}
}

return nil
}
17 changes: 17 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ type Cmdable interface {
ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd
ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd
ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
Expand Down Expand Up @@ -2473,6 +2474,22 @@ func (c cmdable) ZInterCard(ctx context.Context, limit int64, keys ...string) *I
return cmd
}

// ZMPop Pops one or more elements with the highest or lowest score from the first non-empty sorted set key from the list of provided key names.
// direction: "max" (highest score) or "min" (lowest score), count: > 0
// example: client.ZMPop(ctx, "max", 5, "set1", "set2")
func (c cmdable) ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
args := make([]interface{}, 2+len(keys), 5+len(keys))
args[0] = "zmpop"
args[1] = len(keys)
for i, key := range keys {
args[2+i] = key
}
args = append(args, strings.ToLower(order), "count", count)
cmd := NewZSliceWithKeyCmd(ctx, args...)
_ = c(ctx, cmd)
return cmd
}

func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
args := make([]interface{}, 2+len(members))
args[0] = "zmscore"
Expand Down
79 changes: 79 additions & 0 deletions commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3752,6 +3752,85 @@ var _ = Describe("Commands", func() {
}}))
})

It("should ZMPop", func() {

err := client.ZAdd(ctx, "zset", redis.Z{Score: 1, Member: "one"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "zset", redis.Z{Score: 2, Member: "two"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "zset", redis.Z{Score: 3, Member: "three"}).Err()
Expect(err).NotTo(HaveOccurred())

err = client.ZAdd(ctx, "zset2", redis.Z{Score: 1, Member: "one"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "zset2", redis.Z{Score: 2, Member: "two"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "zset2", redis.Z{Score: 3, Member: "three"}).Err()
Expect(err).NotTo(HaveOccurred())

key, elems, err := client.ZMPop(ctx, "min", 1, "zset").Result()
Expect(err).NotTo(HaveOccurred())
Expect(key).To(Equal("zset"))
Expect(elems).To(Equal([]redis.Z{{
Score: 1,
Member: "one",
}}))

_, _, err = client.ZMPop(ctx, "min", 1, "nosuchkey").Result()
Expect(err).To(Equal(redis.Nil))

err = client.ZAdd(ctx, "myzset", redis.Z{Score: 1, Member: "one"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "myzset", redis.Z{Score: 2, Member: "two"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "myzset", redis.Z{Score: 3, Member: "three"}).Err()
Expect(err).NotTo(HaveOccurred())

key, elems, err = client.ZMPop(ctx, "min", 1, "myzset").Result()
Expect(err).NotTo(HaveOccurred())
Expect(key).To(Equal("myzset"))
Expect(elems).To(Equal([]redis.Z{{
Score:1,
Member:"one",
}}))

key, elems, err = client.ZMPop(ctx, "max", 10, "myzset").Result()
Expect(err).NotTo(HaveOccurred())
Expect(key).To(Equal("myzset"))
Expect(elems).To(Equal([]redis.Z{{
Score:3,
Member:"three",
},{
Score: 2,
Member: "two",
}}))


err = client.ZAdd(ctx, "myzset2", redis.Z{Score: 4, Member: "four"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "myzset2", redis.Z{Score: 5, Member: "five"}).Err()
Expect(err).NotTo(HaveOccurred())
err = client.ZAdd(ctx, "myzset2", redis.Z{Score: 6, Member: "six"}).Err()
Expect(err).NotTo(HaveOccurred())

key, elems, err = client.ZMPop(ctx, "min", 10, "myzset","myzset2").Result()
Expect(err).NotTo(HaveOccurred())
Expect(key).To(Equal("myzset2"))
Expect(elems).To(Equal([]redis.Z{{
Score:4,
Member:"four",
},{
Score: 5,
Member: "five",
},{
Score:6,
Member: "six",
}}))



})

It("should ZMScore", func() {
zmScore := client.ZMScore(ctx, "zset", "one", "three")
Expect(zmScore.Err()).NotTo(HaveOccurred())
Expand Down