diff --git a/lib/redis/commands/lists.rb b/lib/redis/commands/lists.rb index 4dbb9eac4..c6383e47d 100644 --- a/lib/redis/commands/lists.rb +++ b/lib/redis/commands/lists.rb @@ -183,6 +183,32 @@ 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. + # + # @example Popping a element + # redis.lmpop('list') + # #=> ['list', ['a']] + # @example With count option + # redis.lmpop('list', count: 2) + # #=> ['list', ['a', 'b']] + # + # @params key [String, Array] 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>] list of popped elements or nil + def lmpop(*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_command(args) + end + # Get an element from a list by its index. # # @param [String] key diff --git a/lib/redis/distributed.rb b/lib/redis/distributed.rb index 75d33cc80..e92d417fa 100644 --- a/lib/redis/distributed.rb +++ b/lib/redis/distributed.rb @@ -542,6 +542,13 @@ 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. + def lmpop(*keys, modifier: "LEFT", count: nil) + ensure_same_node(:lmpop, keys) do |node| + node.lmpop(*keys, modifier: modifier, count: count) + end + end + # Get the number of members in a set. def scard(key) node_for(key).scard(key) diff --git a/test/lint/lists.rb b/test/lint/lists.rb index 3d400ec60..fdb37bbe7 100644 --- a/test/lint/lists.rb +++ b/test/lint/lists.rb @@ -202,5 +202,18 @@ def test_variadic_rpoplpush_expand redis.rpush('{1}bar', %w[d e f]) assert_equal 'c', redis.rpoplpush('{1}foo', '{1}bar') end + + def test_lmpop + target_version('7.0') do + assert_nil r.lmpop('{1}foo') + + r.lpush('{1}foo', %w[a b c d e f g]) + assert_equal ['{1}foo', ['g']], r.lmpop('{1}foo') + assert_equal ['{1}foo', ['f', 'e']], r.lmpop('{1}foo', count: 2) + + r.lpush('{1}foo2', %w[a b]) + assert_equal ['{1}foo', ['a']], r.lmpop('{1}foo', '{1}foo2', modifier: "RIGHT") + end + end end end