Skip to content

Commit

Permalink
Add LMPOP (#311)
Browse files Browse the repository at this point in the history
Currently failing due to needing redis-rb v5 (see also #281 and #293)
  • Loading branch information
Palladinium authored Nov 27, 2024
1 parent 69484fe commit 7a2677f
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ gem 'overcommit', '0.62.0'
# Pin tool versions (which are executed by Overcommit) for CI builds
gem 'rubocop', '1.44.1'

gem 'base64', '~> 0.2.0'
gem 'simplecov', '~> 0.22.0'
gem 'simplecov-lcov', '~> 0.8.0'
26 changes: 26 additions & 0 deletions lib/mock_redis/list_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,32 @@ def llen(key)
with_list_at(key, &:length)
end

def lmpop(*keys, **options)
keys.each do |key|
assert_listy(key)
end

modifier = options.is_a?(Hash) && options[:modifier]&.to_s&.downcase || 'left'
count = (options.is_a?(Hash) && options[:count]) || 1

unless %w[left right].include?(modifier)
raise Redis::CommandError, 'ERR syntax error'
end

keys.each do |key|
record_count = llen(key)
next if record_count.zero?

values = [count, record_count].min.times.map do
modifier == 'left' ? with_list_at(key, &:shift) : with_list_at(key, &:pop)
end

return [key, values]
end

nil
end

def lmove(source, destination, wherefrom, whereto)
assert_listy(source)
assert_listy(destination)
Expand Down
75 changes: 75 additions & 0 deletions spec/commands/lmpop_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
require 'spec_helper'

RSpec.describe '#lmpop(*keys)', redis: 7.0 do
before do
@list1 = 'mock-redis-test:lmpop-list'
@list2 = 'mock-redis-test:lmpop-list2'

@redises.lpush(@list1, 'c')
@redises.lpush(@list1, 'b')
@redises.lpush(@list1, 'a')

@redises.lpush(@list2, 'z')
@redises.lpush(@list2, 'y')
@redises.lpush(@list2, 'x')
end

it 'returns and removes the first element of the first non-empty list' do
expect(@redises.lmpop('empty', @list1, @list2)).to eq([@list1, ['a']])

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[b c])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'returns and removes the first element of the first non-empty list when modifier is LEFT' do
expect(@redises.lmpop('empty', @list1, @list2, modifier: 'LEFT')).to eq([@list1, ['a']])

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[b c])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'returns and removes the last element of the first non-empty list when modifier is RIGHT' do
expect(@redises.lmpop('empty', @list1, @list2, modifier: 'RIGHT')).to eq([@list1, ['c']])

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[a b])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'returns and removes multiple elements from the front when count is given' do
expect(@redises.lmpop('empty', @list1, @list2, count: 2)).to eq([@list1, %w[a b]])

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[c])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'returns and removes multiple elements from the back when count given and modifier is RIGHT' do
expect(@redises.lmpop('empty', @list1, @list2, count: 2, modifier: 'RIGHT')).to(
eq([@list1, %w[c b]])
)

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[a])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'returns falsed if all lists are empty' do
expect(@redises.lmpop('empty')).to be_nil

expect(@redises.lrange(@list1, 0, -1)).to eq(%w[a b c])
expect(@redises.lrange(@list2, 0, -1)).to eq(%w[x y z])
end

it 'removes empty lists' do
(@redises.llen(@list1) + @redises.llen(@list2)).times { @redises.lmpop(@list1, @list2) }
expect(@redises.get(@list1)).to be_nil
end

it 'raises an error for non-list source value' do
@redises.set(@list1, 'string value')

expect do
@redises.lmpop(@list1, @list2)
end.to raise_error(Redis::CommandError)
end

it_should_behave_like 'a list-only command'
end

0 comments on commit 7a2677f

Please sign in to comment.