Skip to content

Added GET argument to SET command #1412

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 5 commits into from
Aug 8, 2021
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
32 changes: 29 additions & 3 deletions redis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,20 @@ 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.
Expand Down Expand Up @@ -671,7 +685,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,
Expand Down Expand Up @@ -1691,6 +1705,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)

Expand Down Expand Up @@ -1822,7 +1839,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``

Expand All @@ -1838,8 +1855,13 @@ 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]
options = {}
if ex is not None:
pieces.append('EX')
if isinstance(ex, datetime.timedelta):
Expand All @@ -1859,7 +1881,11 @@ def set(self, name, value,
if keepttl:
pieces.append('KEEPTTL')

return self.execute_command('SET', *pieces)
if get:
pieces.append('GET')
options["get"] = True

return self.execute_command('SET', *pieces, **options)

def __setitem__(self, name, value):
self.set(name, value)
Expand Down
8 changes: 8 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,14 @@ 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', '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'

def test_setex(self, r):
assert r.setex('a', 60, '1')
assert r['a'] == b'1'
Expand Down