From a77ad503edb6b511a1cc042607cc318185ea2782 Mon Sep 17 00:00:00 2001 From: netocp Date: Mon, 7 Oct 2019 21:34:50 -0400 Subject: add type filter to scan function Fixed #1220 --- CHANGES | 1 + redis/client.py | 25 ++++++++++++++++++++----- tests/test_commands.py | 8 ++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 074fac6..c200eea 100644 --- a/CHANGES +++ b/CHANGES @@ -19,6 +19,7 @@ specified in the SSL cert. By default 'ssl_check_hostname' is False for backwards compatibility. #1196 * Slightly optimized command packing. Thanks @Deneby67. #1255 + * Added support for the TYPE argument to SCAN. Thanks @netocp. #1220 * 3.3.11 * Further fix for the SSLError -> TimeoutError mapping to work on obscure releases of Python 2.7. diff --git a/redis/client.py b/redis/client.py index fba80c9..9d38c50 100755 --- a/redis/client.py +++ b/redis/client.py @@ -2058,34 +2058,49 @@ class Redis(object): return self.execute_command('SORT', *pieces, **options) # SCAN COMMANDS - def scan(self, cursor=0, match=None, count=None): + def scan(self, cursor=0, match=None, count=None, _type=None): """ Incrementally return lists of key names. Also return a cursor indicating the scan position. ``match`` allows for filtering the keys by pattern - ``count`` allows for hint the minimum number of returns + ``count`` provides a hint to Redis about the number of keys to + return per batch. + + ``_type`` filters the returned values by a particular Redis type. + Stock Redis instances allow for the following types: + HASH, LIST, SET, STREAM, STRING, ZSET + Additionally, Redis modules can expose other types as well. """ pieces = [cursor] if match is not None: pieces.extend([b'MATCH', match]) if count is not None: pieces.extend([b'COUNT', count]) + if _type is not None: + pieces.extend([b'TYPE', _type]) return self.execute_command('SCAN', *pieces) - def scan_iter(self, match=None, count=None): + def scan_iter(self, match=None, count=None, _type=None): """ Make an iterator using the SCAN command so that the client doesn't need to remember the cursor position. ``match`` allows for filtering the keys by pattern - ``count`` allows for hint the minimum number of returns + ``count`` provides a hint to Redis about the number of keys to + return per batch. + + ``_type`` filters the returned values by a particular Redis type. + Stock Redis instances allow for the following types: + HASH, LIST, SET, STREAM, STRING, ZSET + Additionally, Redis modules can expose other types as well. """ cursor = '0' while cursor != 0: - cursor, data = self.scan(cursor=cursor, match=match, count=count) + cursor, data = self.scan(cursor=cursor, match=match, + count=count, _type=_type) for item in data: yield item diff --git a/tests/test_commands.py b/tests/test_commands.py index 00752fa..b2bd2da 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1065,6 +1065,14 @@ class TestRedisCommands(object): _, keys = r.scan(match='a') assert set(keys) == {b'a'} + @skip_if_server_version_lt('5.9.101') + def test_scan_type(self, r): + r.sadd('a-set', 1) + r.hset('a-hash', 'foo', 2) + r.lpush('a-list', 'aux', 3) + _, keys = r.scan(match='a*', _type='SET') + assert set(keys) == {b'a-set'} + @skip_if_server_version_lt('2.8.0') def test_scan_iter(self, r): r.set('a', 1) -- cgit v1.2.1