Skip to content

Commit

Permalink
Implement zpopmin/zpopmax
Browse files Browse the repository at this point in the history
  • Loading branch information
cunla committed Oct 17, 2022
1 parent 50bba22 commit 3af548d
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 5 deletions.
4 changes: 2 additions & 2 deletions REDIS_COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ list of [unimplemented commands](#unimplemented-commands).
* zincrby
* zinterstore
* zlexcount
* zpopmax
* zpopmin
* zrange
* zrangebylex
* zrangebyscore
Expand Down Expand Up @@ -322,8 +324,6 @@ All of the redis commands are implemented in fakeredis with these exceptions:
* zintercard
* zmpop
* zmscore
* zpopmax
* zpopmin
* zrandmember
* zrangestore
* zunion
Expand Down
12 changes: 12 additions & 0 deletions fakeredis/_basefakesocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,15 @@ def _expireat(self, key, timestamp, *args):
return 0
key.expireat = timestamp
return 1

def _zpop(self, key, count, reverse):
zset = key.value
members = list(zset)
if reverse:
members.reverse()
members = members[:count]
res = [(bytes(member), self._encodefloat(zset.get(member), True)) for member in members]
res = list(itertools.chain.from_iterable(res))
for item in members:
zset.discard(item)
return res
11 changes: 10 additions & 1 deletion fakeredis/_fakesocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,16 @@ def pfmerge(self, dest, *sources):
return OK

# Sorted set commands
# TODO: [b]zpopmin/zpopmax,

@command((Key(ZSet),), (Int,))
def zpopmin(self, key, count=1):
return self._zpop(key, count, False)

@command((Key(ZSet),), (Int,))
def zpopmax(self, key, count=1):
return self._zpop(key, count, True)

# TODO: bzpopmin/bzpopmax,

@staticmethod
def _limit_items(items, offset, count):
Expand Down
4 changes: 2 additions & 2 deletions fakeredis/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,8 @@ def __eq__(self, other):
def valid_response_type(value, nested=False):
if isinstance(value, NoResponse) and not nested:
return True
if value is not None and not isinstance(value, (bytes, SimpleString, SimpleError,
int, list)):
if (value is not None
and not isinstance(value, (bytes, SimpleString, SimpleError, int, list))):
return False
if isinstance(value, list):
if any(not valid_response_type(item, True) for item in value):
Expand Down
37 changes: 37 additions & 0 deletions test/test_sorted_set_cmds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import redis.client
from packaging.version import Version

import testtools

REDIS_VERSION = Version(redis.__version__)


def test_zpopmin(r):
testtools.zadd(r, 'foo', {'one': 1})
testtools.zadd(r, 'foo', {'two': 2})
testtools.zadd(r, 'foo', {'three': 3})
assert r.zpopmin('foo', count=2) == [(b'one', 1.0), (b'two', 2.0)]
assert r.zpopmin('foo', count=2) == [(b'three', 3.0)]


def test_zpopmin_too_many(r):
testtools.zadd(r, 'foo', {'one': 1})
testtools.zadd(r, 'foo', {'two': 2})
testtools.zadd(r, 'foo', {'three': 3})
assert r.zpopmin('foo', count=5) == [(b'one', 1.0), (b'two', 2.0), (b'three', 3.0)]


def test_zpopmax(r):
testtools.zadd(r, 'foo', {'one': 1})
testtools.zadd(r, 'foo', {'two': 2})
testtools.zadd(r, 'foo', {'three': 3})
assert r.zpopmax('foo', count=2) == [(b'three', 3.0), (b'two', 2.0)]
assert r.zpopmax('foo', count=2) == [(b'one', 1.0)]


def test_zpopmax_too_many(r):
testtools.zadd(r, 'foo', {'one': 1})
testtools.zadd(r, 'foo', {'two': 2})
testtools.zadd(r, 'foo', {'three': 3})
assert r.zpopmax('foo', count=5) == [(b'three', 3.0), (b'two', 2.0), (b'one', 1.0), ]

0 comments on commit 3af548d

Please sign in to comment.