Skip to content

Commit 93d4ed6

Browse files
committed
Add support for GET option to SET
I needed to implement this after switching to validating against a 6.2 Redis server, because the fuzzer in the hypothesis tests kept testing that feature by accident.
1 parent dabc409 commit 93d4ed6

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

fakeredis/_server.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,7 @@ def set_(self, key, value, *args):
14971497
xx = False
14981498
nx = False
14991499
keepttl = False
1500+
get = False
15001501
while i < len(args):
15011502
if casematch(args[i], b'nx'):
15021503
nx = True
@@ -1517,15 +1518,27 @@ def set_(self, key, value, *args):
15171518
elif casematch(args[i], b'keepttl'):
15181519
keepttl = True
15191520
i += 1
1521+
elif casematch(args[i], b'get'):
1522+
get = True
1523+
i += 1
15201524
else:
15211525
raise SimpleError(SYNTAX_ERROR_MSG)
15221526
if (xx and nx) or ((px is not None) + (ex is not None) + keepttl > 1):
15231527
raise SimpleError(SYNTAX_ERROR_MSG)
1528+
if nx and get:
1529+
# The command docs say this is allowed from Redis 7.0.
1530+
raise SimpleError(SYNTAX_ERROR_MSG)
1531+
1532+
old_value = None
1533+
if get:
1534+
if key.value is not None and type(key.value) is not bytes:
1535+
raise SimpleError(WRONGTYPE_MSG)
1536+
old_value = key.value
15241537

15251538
if nx and key:
1526-
return None
1539+
return old_value
15271540
if xx and not key:
1528-
return None
1541+
return old_value
15291542
if not keepttl:
15301543
key.value = value
15311544
else:
@@ -1534,7 +1547,7 @@ def set_(self, key, value, *args):
15341547
key.expireat = self._db.time + ex
15351548
if px is not None:
15361549
key.expireat = self._db.time + px / 1000.0
1537-
return OK
1550+
return OK if not get else old_value
15381551

15391552
@command((Key(), Int, bytes))
15401553
def setex(self, key, seconds, value):

test/test_fakeredis.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,38 @@ def test_set_xx(r):
821821
assert r.set('foo', 'bar', xx=True) is True
822822

823823

824+
@pytest.mark.min_server('6.2')
825+
def test_set_get(r):
826+
assert raw_command(r, 'set', 'foo', 'bar', 'GET') is None
827+
assert r.get('foo') == b'bar'
828+
assert raw_command(r, 'set', 'foo', 'baz', 'GET') == b'bar'
829+
assert r.get('foo') == b'baz'
830+
831+
832+
@pytest.mark.min_server('6.2')
833+
def test_set_get_xx(r):
834+
assert raw_command(r, 'set', 'foo', 'bar', 'XX', 'GET') is None
835+
assert r.get('foo') is None
836+
r.set('foo', 'bar')
837+
assert raw_command(r, 'set', 'foo', 'baz', 'XX', 'GET') == b'bar'
838+
assert r.get('foo') == b'baz'
839+
assert raw_command(r, 'set', 'foo', 'baz', 'GET') == b'baz'
840+
841+
842+
@pytest.mark.min_server('6.2')
843+
def test_set_get_nx(r):
844+
# Note: this will most likely fail on a 7.0 server, based on the docs for SET
845+
with pytest.raises(redis.ResponseError):
846+
raw_command(r, 'set', 'foo', 'bar', 'NX', 'GET')
847+
848+
849+
@pytest.mark.min_server('6.2')
850+
def set_get_wrongtype(r):
851+
r.lpush('foo', 'bar')
852+
with pytest.raises(redis.ResponseError):
853+
raw_command(r, 'set', 'foo', 'bar', 'GET')
854+
855+
824856
def test_del_operator(r):
825857
r['foo'] = 'bar'
826858
del r['foo']

test/test_hypothesis.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,10 @@ def commands(*args, **kwargs):
204204
| commands(st.just('mget'), st.lists(keys))
205205
| commands(st.sampled_from(['mset', 'msetnx']), st.lists(st.tuples(keys, values)))
206206
| commands(st.just('set'), keys, values,
207-
st.none() | st.just('nx'), st.none() | st.just('xx'))
207+
st.none() | st.just('nx'),
208+
st.none() | st.just('xx'),
209+
st.none() | st.just('keepttl'),
210+
st.none() | st.just('get'))
208211
| commands(st.just('setex'), keys, expires_seconds, values)
209212
| commands(st.just('psetex'), keys, expires_ms, values)
210213
| commands(st.just('setnx'), keys, values)

0 commit comments

Comments
 (0)