From 7271b642dd92b8001a20f11938caf2d2cfe32f1f Mon Sep 17 00:00:00 2001 From: 2014BDuck <2014bduck@gmail.com> Date: Mon, 26 Oct 2020 16:34:33 +0800 Subject: [PATCH 1/5] 1411 Added GET argument to SET command --- redis/client.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/redis/client.py b/redis/client.py index 42d1bfaa53..6e80f8b820 100755 --- a/redis/client.py +++ b/redis/client.py @@ -1691,6 +1691,9 @@ def getset(self, name, value): """ Sets the value at key ``name`` to ``value`` and returns the old value at key ``name`` atomically. + + As per Redis 6.2, GETSET is considered deprecated. + Please use SET with GET parameter in new code. """ return self.execute_command('GETSET', name, value) @@ -1822,7 +1825,7 @@ def restore(self, name, ttl, value, replace=False): return self.execute_command('RESTORE', *params) def set(self, name, value, - ex=None, px=None, nx=False, xx=False, keepttl=False): + ex=None, px=None, nx=False, xx=False, keepttl=False, get=False): """ Set the value at key ``name`` to ``value`` @@ -1838,6 +1841,10 @@ def set(self, name, value, ``keepttl`` if True, retain the time to live associated with the key. (Available since Redis 6.0) + + ``get`` if True, set the value at key ``name`` to ``value`` and return + the old value stored at key, or None when key did not exist. + (Available since Redis 6.2) """ pieces = [name, value] if ex is not None: @@ -1859,6 +1866,9 @@ def set(self, name, value, if keepttl: pieces.append('KEEPTTL') + if get: + pieces.append('GET') + return self.execute_command('SET', *pieces) def __setitem__(self, name, value): From 638874cd08d194fe26fd061821eef0b5dd5e695d Mon Sep 17 00:00:00 2001 From: 2014BDuck <2014bduck@gmail.com> Date: Mon, 26 Oct 2020 16:56:25 +0800 Subject: [PATCH 2/5] 1411 Added test case for set get --- tests/test_commands.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/test_commands.py b/tests/test_commands.py index 211307859a..ea46280afe 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -912,6 +912,12 @@ def test_set_keepttl(self, r): assert r.get('a') == b'2' assert 0 < r.ttl('a') <= 10 + @skip_if_server_version_lt('6.2.0') + def test_set_get(self, r): + assert r.set('a', 'foo', get=True) is None + assert r.set('a', 'bar', get=True) == b'foo' + assert r.get('a') == b'bar' + def test_setex(self, r): assert r.setex('a', 60, '1') assert r['a'] == b'1' From 15c47805530cead1753bf94dc823f699a79f4375 Mon Sep 17 00:00:00 2001 From: 2014BDuck <2014bduck@gmail.com> Date: Wed, 28 Oct 2020 20:10:18 +0800 Subject: [PATCH 3/5] 1411 Passed options in set command execution. Added set response parse function --- redis/client.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/redis/client.py b/redis/client.py index 6e80f8b820..6f4877e361 100755 --- a/redis/client.py +++ b/redis/client.py @@ -544,6 +544,19 @@ def parse_module_result(response): return True +def parse_set_result(response, **options): + """ + Handle SET result since GET argument is available since Redis 6.2. + Parsing SET result into: + - BOOL + - String when GET argument is used + """ + if options.get('get'): + # Redis will return a getCommand result. + # See `setGenericCommand` in t_string.c + return response + return response and str_if_bytes(response) == 'OK' + class Redis: """ Implementation of the Redis protocol. @@ -671,7 +684,7 @@ class Redis: 'SENTINEL SENTINELS': parse_sentinel_slaves_and_sentinels, 'SENTINEL SET': bool_ok, 'SENTINEL SLAVES': parse_sentinel_slaves_and_sentinels, - 'SET': lambda r: r and str_if_bytes(r) == 'OK', + 'SET': parse_set_result, 'SLOWLOG GET': parse_slowlog_get, 'SLOWLOG LEN': int, 'SLOWLOG RESET': bool_ok, @@ -1847,6 +1860,7 @@ def set(self, name, value, (Available since Redis 6.2) """ pieces = [name, value] + options = {} if ex is not None: pieces.append('EX') if isinstance(ex, datetime.timedelta): @@ -1868,8 +1882,9 @@ def set(self, name, value, if get: pieces.append('GET') + options["get"] = True - return self.execute_command('SET', *pieces) + return self.execute_command('SET', *pieces, **options) def __setitem__(self, name, value): self.set(name, value) From 8ffe5737878765e2eb405aa4ca55054158e43945 Mon Sep 17 00:00:00 2001 From: 2014BDuck <2014bduck@gmail.com> Date: Wed, 28 Oct 2020 20:13:01 +0800 Subject: [PATCH 4/5] 1141 Added few test case to set command with get argument --- tests/test_commands.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index ea46280afe..c04ed2670e 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -914,7 +914,9 @@ def test_set_keepttl(self, r): @skip_if_server_version_lt('6.2.0') def test_set_get(self, r): - assert r.set('a', 'foo', get=True) is None + assert r.set('a', 'True', get=True) is None + assert r.set('a', 'True', get=True) == b'True' + assert r.set('a', 'foo') is True assert r.set('a', 'bar', get=True) == b'foo' assert r.get('a') == b'bar' From fbe7dd62751df4f496282231d6da8eb253e93b2e Mon Sep 17 00:00:00 2001 From: 2014BDuck <2014bduck@gmail.com> Date: Wed, 28 Oct 2020 21:01:20 +0800 Subject: [PATCH 5/5] Fixed flake8 --- redis/client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/redis/client.py b/redis/client.py index 6f4877e361..46a73590e3 100755 --- a/redis/client.py +++ b/redis/client.py @@ -557,6 +557,7 @@ def parse_set_result(response, **options): return response return response and str_if_bytes(response) == 'OK' + class Redis: """ Implementation of the Redis protocol.