Skip to content

Commit dde1af7

Browse files
authored
Merge pull request #812 from supercaracal/add-zpop-friends
Add ZPOP commands support of Redis5
2 parents e036bcd + a904156 commit dde1af7

File tree

3 files changed

+102
-12
lines changed

3 files changed

+102
-12
lines changed

lib/redis.rb

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ def rpoplpush(source, destination)
11561156
end
11571157
end
11581158

1159-
def _bpop(cmd, args)
1159+
def _bpop(cmd, args, &blk)
11601160
options = {}
11611161

11621162
case args.last
@@ -1177,7 +1177,7 @@ def _bpop(cmd, args)
11771177
synchronize do |client|
11781178
command = [cmd, keys, timeout]
11791179
timeout += client.timeout if timeout > 0
1180-
client.call_with_timeout(command, timeout)
1180+
client.call_with_timeout(command, timeout, &blk)
11811181
end
11821182
end
11831183

@@ -1628,6 +1628,90 @@ def zrem(key, member)
16281628
end
16291629
end
16301630

1631+
# Removes and returns up to count members with the highest scores in the sorted set stored at key.
1632+
#
1633+
# @example Popping a member
1634+
# redis.zpopmax('zset')
1635+
# #=> ['b', 2.0]
1636+
# @example With count option
1637+
# redis.zpopmax('zset', 2)
1638+
# #=> [['b', 2.0], ['a', 1.0]]
1639+
#
1640+
# @params key [String] a key of the sorted set
1641+
# @params count [Integer] a number of members
1642+
#
1643+
# @return [Array<String, Float>] element and score pair if count is not specified
1644+
# @return [Array<Array<String, Float>>] list of popped elements and scores
1645+
def zpopmax(key, count = nil)
1646+
synchronize do |client|
1647+
members = client.call([:zpopmax, key, count].compact, &FloatifyPairs)
1648+
count.to_i > 1 ? members : members.first
1649+
end
1650+
end
1651+
1652+
# Removes and returns up to count members with the lowest scores in the sorted set stored at key.
1653+
#
1654+
# @example Popping a member
1655+
# redis.zpopmin('zset')
1656+
# #=> ['a', 1.0]
1657+
# @example With count option
1658+
# redis.zpopmin('zset', 2)
1659+
# #=> [['a', 1.0], ['b', 2.0]]
1660+
#
1661+
# @params key [String] a key of the sorted set
1662+
# @params count [Integer] a number of members
1663+
#
1664+
# @return [Array<String, Float>] element and score pair if count is not specified
1665+
# @return [Array<Array<String, Float>>] list of popped elements and scores
1666+
def zpopmin(key, count = nil)
1667+
synchronize do |client|
1668+
members = client.call([:zpopmin, key, count].compact, &FloatifyPairs)
1669+
count.to_i > 1 ? members : members.first
1670+
end
1671+
end
1672+
1673+
# Removes and returns up to count members with the highest scores in the sorted set stored at keys,
1674+
# or block until one is available.
1675+
#
1676+
# @example Popping a member from a sorted set
1677+
# redis.bzpopmax('zset', 1)
1678+
# #=> ['zset', 'b', 2.0]
1679+
# @example Popping a member from multiple sorted sets
1680+
# redis.bzpopmax('zset1', 'zset2', 1)
1681+
# #=> ['zset1', 'b', 2.0]
1682+
#
1683+
# @params keys [Array<String>] one or multiple keys of the sorted sets
1684+
# @params timeout [Integer] the maximum number of seconds to block
1685+
#
1686+
# @return [Array<String, String, Float>] a touple of key, member and score
1687+
# @return [nil] when no element could be popped and the timeout expired
1688+
def bzpopmax(*args)
1689+
_bpop(:bzpopmax, args) do |reply|
1690+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
1691+
end
1692+
end
1693+
1694+
# Removes and returns up to count members with the lowest scores in the sorted set stored at keys,
1695+
# or block until one is available.
1696+
#
1697+
# @example Popping a member from a sorted set
1698+
# redis.bzpopmin('zset', 1)
1699+
# #=> ['zset', 'a', 1.0]
1700+
# @example Popping a member from multiple sorted sets
1701+
# redis.bzpopmin('zset1', 'zset2', 1)
1702+
# #=> ['zset1', 'a', 1.0]
1703+
#
1704+
# @params keys [Array<String>] one or multiple keys of the sorted sets
1705+
# @params timeout [Integer] the maximum number of seconds to block
1706+
#
1707+
# @return [Array<String, String, Float>] a touple of key, member and score
1708+
# @return [nil] when no element could be popped and the timeout expired
1709+
def bzpopmin(*args)
1710+
_bpop(:bzpopmin, args) do |reply|
1711+
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
1712+
end
1713+
end
1714+
16311715
# Get the score associated with the given member in a sorted set.
16321716
#
16331717
# @example Get the score for member "a"

test/lint/blocking_commands.rb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,16 @@ def test_brpoplpush_timeout_with_old_prototype
134134
end
135135

136136
def test_bzpopmin
137-
target_version('4.9.0') do
138-
assert_equal %w[{szap}foo a 0], r.bzpopmin('{szap}foo', '{szap}bar', 0)
137+
target_version('5.0.0') do
138+
assert_equal ['{szap}foo', 'a', 0.0], r.bzpopmin('{szap}foo', '{szap}bar', 1)
139+
assert_equal nil, r.bzpopmin('{szap}aaa', '{szap}bbb', 1)
139140
end
140141
end
141142

142143
def test_bzpopmax
143-
target_version('4.9.0') do
144-
assert_equal %w[{szap}foo c 2], r.bzpopmax('{szap}foo', '{szap}bar', 0)
144+
target_version('5.0.0') do
145+
assert_equal ['{szap}foo', 'c', 2.0], r.bzpopmax('{szap}foo', '{szap}bar', 1)
146+
assert_equal nil, r.bzpopmax('{szap}aaa', '{szap}bbb', 1)
145147
end
146148
end
147149

test/lint/sorted_sets.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,16 +316,20 @@ def test_zremrangebyscore
316316
end
317317

318318
def test_zpopmax
319-
target_version('4.9.0') do
320-
r.zadd('foo', %w[0 a 1 b 2 c])
321-
assert_equal %w[c 2], r.zpopmax('foo')
319+
target_version('5.0.0') do
320+
r.zadd('foo', %w[0 a 1 b 2 c 3 d])
321+
assert_equal ['d', 3.0], r.zpopmax('foo')
322+
assert_equal [['c', 2.0], ['b', 1.0]], r.zpopmax('foo', 2)
323+
assert_equal [['a', 0.0]], r.zrange('foo', 0, -1, with_scores: true)
322324
end
323325
end
324326

325327
def test_zpopmin
326-
target_version('4.9.0') do
327-
r.zadd('foo', %w[0 a 1 b 2 c])
328-
assert_equal %w[a 0], r.zpopmin('foo')
328+
target_version('5.0.0') do
329+
r.zadd('foo', %w[0 a 1 b 2 c 3 d])
330+
assert_equal ['a', 0.0], r.zpopmin('foo')
331+
assert_equal [['b', 1.0], ['c', 2.0]], r.zpopmin('foo', 2)
332+
assert_equal [['d', 3.0]], r.zrange('foo', 0, -1, with_scores: true)
329333
end
330334
end
331335

0 commit comments

Comments
 (0)