Skip to content

Commit

Permalink
✨ Add BLMPOP (#1199)
Browse files Browse the repository at this point in the history
* ✨ Add BLMPOP

* 🚨 Fix rubocop error
  • Loading branch information
JerrodCarpenter committed Jun 12, 2023
1 parent fde7873 commit ff4399b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
28 changes: 28 additions & 0 deletions lib/redis/commands/lists.rb
Expand Up @@ -183,6 +183,34 @@ def brpoplpush(source, destination, timeout: 0)
send_blocking_command(command, timeout)
end

# Pops one or more elements from the first non-empty list key from the list
# of provided key names. If lists are empty, blocks until timeout has passed.
#
# @example Popping a element
# redis.blmpop(1.0, 'list')
# #=> ['list', ['a']]
# @example With count option
# redis.blmpop(1.0, 'list', count: 2)
# #=> ['list', ['a', 'b']]
#
# @params timeout [Float] a float value specifying the maximum number of seconds to block) elapses.
# A timeout of zero can be used to block indefinitely.
# @params key [String, Array<String>] one or more keys with lists
# @params modifier [String]
# - when `"LEFT"` - the elements popped are those from the left of the list
# - when `"RIGHT"` - the elements popped are those from the right of the list
# @params count [Integer] a number of elements to pop
#
# @return [Array<String, Array<String, Float>>] list of popped elements or nil
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
raise ArgumentError, "Pick either LEFT or RIGHT" unless modifier == "LEFT" || modifier == "RIGHT"

args = [:lmpop, keys.size, *keys, modifier]
args << "COUNT" << Integer(count) if count

send_blocking_command(args, timeout)
end

# Pops one or more elements from the first non-empty list key from the list
# of provided key names.
#
Expand Down
9 changes: 8 additions & 1 deletion lib/redis/distributed.rb
Expand Up @@ -542,7 +542,14 @@ def ltrim(key, start, stop)
node_for(key).ltrim(key, start, stop)
end

# Iterate over keys, removing elements from the first non list set found.
# Iterate over keys, blocking and removing elements from the first non empty liist found.
def blmpop(timeout, *keys, modifier: "LEFT", count: nil)
ensure_same_node(:blmpop, keys) do |node|
node.blmpop(timeout, *keys, modifier: modifier, count: count)
end
end

# Iterate over keys, removing elements from the first non list found.
def lmpop(*keys, modifier: "LEFT", count: nil)
ensure_same_node(:lmpop, keys) do |node|
node.lmpop(*keys, modifier: modifier, count: count)
Expand Down
13 changes: 13 additions & 0 deletions test/lint/lists.rb
Expand Up @@ -203,6 +203,19 @@ def test_variadic_rpoplpush_expand
assert_equal 'c', redis.rpoplpush('{1}foo', '{1}bar')
end

def test_blmpop
target_version('7.0') do
assert_nil r.blmpop(1.0, '{1}foo')

r.lpush('{1}foo', %w[a b c d e f g])
assert_equal ['{1}foo', ['g']], r.blmpop(1.0, '{1}foo')
assert_equal ['{1}foo', ['f', 'e']], r.blmpop(1.0, '{1}foo', count: 2)

r.lpush('{1}foo2', %w[a b])
assert_equal ['{1}foo', ['a']], r.blmpop(1.0, '{1}foo', '{1}foo2', modifier: "RIGHT")
end
end

def test_lmpop
target_version('7.0') do
assert_nil r.lmpop('{1}foo')
Expand Down

0 comments on commit ff4399b

Please sign in to comment.