Skip to content

Commit

Permalink
Merge pull request #812 from supercaracal/add-zpop-friends
Browse files Browse the repository at this point in the history
Add ZPOP commands support of Redis5
  • Loading branch information
byroot authored Dec 13, 2018
2 parents e036bcd + a904156 commit dde1af7
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 12 deletions.
88 changes: 86 additions & 2 deletions lib/redis.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ def rpoplpush(source, destination)
end
end

def _bpop(cmd, args)
def _bpop(cmd, args, &blk)
options = {}

case args.last
Expand All @@ -1177,7 +1177,7 @@ def _bpop(cmd, args)
synchronize do |client|
command = [cmd, keys, timeout]
timeout += client.timeout if timeout > 0
client.call_with_timeout(command, timeout)
client.call_with_timeout(command, timeout, &blk)
end
end

Expand Down Expand Up @@ -1628,6 +1628,90 @@ def zrem(key, member)
end
end

# Removes and returns up to count members with the highest scores in the sorted set stored at key.
#
# @example Popping a member
# redis.zpopmax('zset')
# #=> ['b', 2.0]
# @example With count option
# redis.zpopmax('zset', 2)
# #=> [['b', 2.0], ['a', 1.0]]
#
# @params key [String] a key of the sorted set
# @params count [Integer] a number of members
#
# @return [Array<String, Float>] element and score pair if count is not specified
# @return [Array<Array<String, Float>>] list of popped elements and scores
def zpopmax(key, count = nil)
synchronize do |client|
members = client.call([:zpopmax, key, count].compact, &FloatifyPairs)
count.to_i > 1 ? members : members.first
end
end

# Removes and returns up to count members with the lowest scores in the sorted set stored at key.
#
# @example Popping a member
# redis.zpopmin('zset')
# #=> ['a', 1.0]
# @example With count option
# redis.zpopmin('zset', 2)
# #=> [['a', 1.0], ['b', 2.0]]
#
# @params key [String] a key of the sorted set
# @params count [Integer] a number of members
#
# @return [Array<String, Float>] element and score pair if count is not specified
# @return [Array<Array<String, Float>>] list of popped elements and scores
def zpopmin(key, count = nil)
synchronize do |client|
members = client.call([:zpopmin, key, count].compact, &FloatifyPairs)
count.to_i > 1 ? members : members.first
end
end

# Removes and returns up to count members with the highest scores in the sorted set stored at keys,
# or block until one is available.
#
# @example Popping a member from a sorted set
# redis.bzpopmax('zset', 1)
# #=> ['zset', 'b', 2.0]
# @example Popping a member from multiple sorted sets
# redis.bzpopmax('zset1', 'zset2', 1)
# #=> ['zset1', 'b', 2.0]
#
# @params keys [Array<String>] one or multiple keys of the sorted sets
# @params timeout [Integer] the maximum number of seconds to block
#
# @return [Array<String, String, Float>] a touple of key, member and score
# @return [nil] when no element could be popped and the timeout expired
def bzpopmax(*args)
_bpop(:bzpopmax, args) do |reply|
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
end
end

# Removes and returns up to count members with the lowest scores in the sorted set stored at keys,
# or block until one is available.
#
# @example Popping a member from a sorted set
# redis.bzpopmin('zset', 1)
# #=> ['zset', 'a', 1.0]
# @example Popping a member from multiple sorted sets
# redis.bzpopmin('zset1', 'zset2', 1)
# #=> ['zset1', 'a', 1.0]
#
# @params keys [Array<String>] one or multiple keys of the sorted sets
# @params timeout [Integer] the maximum number of seconds to block
#
# @return [Array<String, String, Float>] a touple of key, member and score
# @return [nil] when no element could be popped and the timeout expired
def bzpopmin(*args)
_bpop(:bzpopmin, args) do |reply|
reply.is_a?(Array) ? [reply[0], reply[1], Floatify.call(reply[2])] : reply
end
end

# Get the score associated with the given member in a sorted set.
#
# @example Get the score for member "a"
Expand Down
10 changes: 6 additions & 4 deletions test/lint/blocking_commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,16 @@ def test_brpoplpush_timeout_with_old_prototype
end

def test_bzpopmin
target_version('4.9.0') do
assert_equal %w[{szap}foo a 0], r.bzpopmin('{szap}foo', '{szap}bar', 0)
target_version('5.0.0') do
assert_equal ['{szap}foo', 'a', 0.0], r.bzpopmin('{szap}foo', '{szap}bar', 1)
assert_equal nil, r.bzpopmin('{szap}aaa', '{szap}bbb', 1)
end
end

def test_bzpopmax
target_version('4.9.0') do
assert_equal %w[{szap}foo c 2], r.bzpopmax('{szap}foo', '{szap}bar', 0)
target_version('5.0.0') do
assert_equal ['{szap}foo', 'c', 2.0], r.bzpopmax('{szap}foo', '{szap}bar', 1)
assert_equal nil, r.bzpopmax('{szap}aaa', '{szap}bbb', 1)
end
end

Expand Down
16 changes: 10 additions & 6 deletions test/lint/sorted_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -316,16 +316,20 @@ def test_zremrangebyscore
end

def test_zpopmax
target_version('4.9.0') do
r.zadd('foo', %w[0 a 1 b 2 c])
assert_equal %w[c 2], r.zpopmax('foo')
target_version('5.0.0') do
r.zadd('foo', %w[0 a 1 b 2 c 3 d])
assert_equal ['d', 3.0], r.zpopmax('foo')
assert_equal [['c', 2.0], ['b', 1.0]], r.zpopmax('foo', 2)
assert_equal [['a', 0.0]], r.zrange('foo', 0, -1, with_scores: true)
end
end

def test_zpopmin
target_version('4.9.0') do
r.zadd('foo', %w[0 a 1 b 2 c])
assert_equal %w[a 0], r.zpopmin('foo')
target_version('5.0.0') do
r.zadd('foo', %w[0 a 1 b 2 c 3 d])
assert_equal ['a', 0.0], r.zpopmin('foo')
assert_equal [['b', 1.0], ['c', 2.0]], r.zpopmin('foo', 2)
assert_equal [['d', 3.0]], r.zrange('foo', 0, -1, with_scores: true)
end
end

Expand Down

0 comments on commit dde1af7

Please sign in to comment.