Skip to content

LPOS: add new command #1354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docker/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
FROM redis:6.0.5-buster
FROM redis:6.0.6-buster
36 changes: 36 additions & 0 deletions redis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,42 @@ def rpushx(self, name, value):
"Push ``value`` onto the tail of the list ``name`` if ``name`` exists"
return self.execute_command('RPUSHX', name, value)

def lpos(self, name, value, rank=None, count=None, maxlen=None):
"""
Get position of ``value`` within the list ``name``

If specified, ``rank`` indicates the "rank" of the first element to
return in case there are multiple copies of ``value`` in the list.
By default, LPOS returns the position of the first occurrence of
``value`` in the list. When ``rank`` 2, LPOS returns the position of
the second ``value`` in the list. If ``rank`` is negative, LPOS
searches the list in reverse. For example, -1 would return the
position of the last occurrence of ``value`` and -2 would return the
position of the next to last occurrence of ``value``.

If specified, ``count`` indicates that LPOS should return a list of
up to ``count`` positions. A ``count`` of 2 would return a list of
up to 2 positions. A ``count`` of 0 returns a list of all positions
matching ``value``. When ``count`` is specified and but ``value``
does not exist in the list, an empty list is returned.

If specified, ``maxlen`` indicates the maximum number of list
elements to scan. A ``maxlen`` of 1000 will only return the
position(s) of items within the first 1000 entries in the list.
A ``maxlen`` of 0 (the default) will scan the entire list.
"""
pieces = [name, value]
if rank is not None:
pieces.extend(['RANK', rank])

if count is not None:
pieces.extend(['COUNT', count])

if maxlen is not None:
pieces.extend(['MAXLEN', maxlen])

return self.execute_command('LPOS', *pieces)

def sort(self, name, start=None, num=None, by=None, get=None,
desc=False, alpha=False, store=None, groups=False):
"""
Expand Down
32 changes: 32 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,38 @@ def test_rpush(self, r):
assert r.rpush('a', '3', '4') == 4
assert r.lrange('a', 0, -1) == [b'1', b'2', b'3', b'4']

@skip_if_server_version_lt('6.0.6')
def test_lpos(self, r):
assert r.rpush('a', 'a', 'b', 'c', '1', '2', '3', 'c', 'c') == 8
assert r.lpos('a', 'a') == 0
assert r.lpos('a', 'c') == 2

assert r.lpos('a', 'c', rank=1) == 2
assert r.lpos('a', 'c', rank=2) == 6
assert r.lpos('a', 'c', rank=4) is None
assert r.lpos('a', 'c', rank=-1) == 7
assert r.lpos('a', 'c', rank=-2) == 6

assert r.lpos('a', 'c', count=0) == [2, 6, 7]
assert r.lpos('a', 'c', count=1) == [2]
assert r.lpos('a', 'c', count=2) == [2, 6]
assert r.lpos('a', 'c', count=100) == [2, 6, 7]

assert r.lpos('a', 'c', count=0, rank=2) == [6, 7]
assert r.lpos('a', 'c', count=2, rank=-1) == [7, 6]

assert r.lpos('axxx', 'c', count=0, rank=2) == []
assert r.lpos('axxx', 'c') is None

assert r.lpos('a', 'x', count=2) == []
assert r.lpos('a', 'x') is None

assert r.lpos('a', 'a', count=0, maxlen=1) == [0]
assert r.lpos('a', 'c', count=0, maxlen=1) == []
assert r.lpos('a', 'c', count=0, maxlen=3) == [2]
assert r.lpos('a', 'c', count=0, maxlen=3, rank=-1) == [7, 6]
assert r.lpos('a', 'c', count=0, maxlen=7, rank=2) == [6]

def test_rpushx(self, r):
assert r.rpushx('a', 'b') == 0
assert r.lrange('a', 0, -1) == []
Expand Down