Skip to content

Commit

Permalink
Support for variadic commands introduced in 2.4.
Browse files Browse the repository at this point in the history
A variable number of values can now be passed to the following
commands: SADD, HDEL, SREM, ZREM, ZADD, L/RPUSH to bring support
in line with Redis 2.4.

A caveat - for ZADD the original implementation of txRedis broke
from convention of 'ZADD key score value' to have the method accept
'zadd(key, value, score)' (for whatever reason). This mode is still
supported for backwards compatibility but if a sequence of arguments
are passed, we now support a more Redis-like convention of
'zadd(key, score1, value1, score2, value2)'.
  • Loading branch information
Reza Lotun committed Sep 21, 2011
1 parent 4d89fb2 commit f4602a2
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 21 deletions.
112 changes: 91 additions & 21 deletions txredis/protocol.py
Expand Up @@ -720,12 +720,34 @@ def push(self, key, value, tail=False, no_create=False):
else:
return self.lpush(key, value)

def lpush(self, key, value):
self._send('LPUSH', key, value)
def lpush(self, key, *values, **kwargs):
"""
Add string to head of list.
@param key : List key
@param values : Sequence of values to push
@param value : For backwards compatibility, a single value.
"""
if not kwargs:
self._send('LPUSH', key, *values)
elif 'value' in kwargs:
self._send('LPUSH', key, kwargs['value'])
else:
raise InvalidCommand('Need arguments for LPUSH')
return self.getResponse()

def rpush(self, key, value):
self._send('RPUSH', key, value)
def rpush(self, key, *values, **kwargs):
"""
Add string to end of list.
@param key : List key
@param values : Sequence of values to push
@param value : For backwards compatibility, a single value.
"""
if not kwargs:
self._send('RPUSH', key, *values)
elif 'value' in kwargs:
self._send('RPUSH', key, kwargs['value'])
else:
raise InvalidCommand('Need arguments for RPUSH')
return self.getResponse()

def lpushx(self, key, value):
Expand Down Expand Up @@ -1014,18 +1036,34 @@ def _list_to_set(self, res):
return set(res)
return res

def sadd(self, key, value):
def sadd(self, key, *values, **kwargs):
"""
Add a member to a set
"""
self._send('SADD', key, value)
@param key : SET key to add values to.
@param values : sequence of values to add to set
@param value : For backwards compatibility, add one value.
"""
if not kwargs:
self._send('SADD', key, *values)
elif 'value' in kwargs:
self._send('SADD', key, kwargs['value'])
else:
raise InvalidCommand('Need arguments for SADD')
return self.getResponse()

def srem(self, key, value):
def srem(self, key, *values, **kwargs):
"""
Remove a member from a set
"""
self._send('SREM', key, value)
@param key : Set key
@param values : Sequence of values to remove
@param value : For backwards compatibility, single value to remove.
"""
if not kwargs:
self._send('SREM', key, *values)
elif 'value' in kwargs:
self._send('SREM', key, kwargs['value'])
else:
raise InvalidCommand('Need arguments for SREM')
return self.getResponse()

def spop(self, key):
Expand Down Expand Up @@ -1373,11 +1411,19 @@ def hexists(self, key, field):
self._send('HEXISTS', key, field)
return self.getResponse()

def hdel(self, key, field):
def hdel(self, key, *fields, **kwargs):
"""
Removes field from the hash stored at key.
"""
self._send('HDEL', key, field)
@param key : Hash key
@param fields : Sequence of fields to remvoe
@param field : For backwards compatibility. Single field to remove.
"""
if not kwargs:
self._send('HDEL', key, *fields)
elif 'field' in kwargs:
self._send('HDEL', key, field)
else:
raise InvalidCommand('Need arguments for HDEL')
return self.getResponse()
hdelete = hdel # backwards compat for older txredis

Expand Down Expand Up @@ -1428,18 +1474,42 @@ def publish(self, channel, message):
# ZREMRANGEBYRANK
# ZREMRANGEBYSCORE
# ZUNIONSTORE / ZINTERSTORE
def zadd(self, key, member, score):
"""
Add a member to a sorted set, or update its score if it already exists
"""
self._send('ZADD', key, score, member)
def zadd(self, key, *item_tuples, **kwargs):
"""
Add members to a sorted set, or update its score if it already exists
@param key : Sorted set key
@param item_tuples : Sequence of score, value pairs.
e.g. zadd(key, score1, value1, score2, value2)
@param member : For backwards compatibility, member name.
@param score : For backwards compatibility, score.
NOTE: if there are only two arguments, the order is interpreted as (value, score)
for backwards compatibility reasons.
"""
if not kwargs and len(item_tuples) == 2 and isinstance(item_tuples[0], basestring):
self._send('ZADD', key, item_tuples[1], item_tuples[0])
elif not kwargs:
self._send('ZADD', key, *item_tuples)
elif 'member' in kwargs and 'score' in kwargs:
score, member = item_tuples
self._send('ZADD', key, kwargs['score'], kwargs['member'])
else:
raise InvalidCommand('Need arguments for ZADD')
return self.getResponse()

def zrem(self, key, member):
def zrem(self, key, *members, **kwargs):
"""
Remove a member from a sorted set
Remove members from a sorted set
@param key : Sorted set key
@param members : Sequeunce of members to remove
@param member : For backwards compatibility - if specified remove one member.
"""
self._send('ZREM', key, member)
if not kwargs:
self._send('ZREM', key, *members)
elif 'member' in kwargs:
self._send('ZREM', key, kwargs['member'])
else:
raise InvalidCommand('Need arguments for ZREM')
return self.getResponse()

def zremrangebyrank(self, key, start, end):
Expand Down
98 changes: 98 additions & 0 deletions txredis/test/test_redis.py
Expand Up @@ -715,6 +715,23 @@ def test_push(self):
ex = 0
t(a, ex)

@defer.inlineCallbacks
def test_push_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('l')
yield r.lpush('l', 'a', 'b', 'c', 'd')
a = yield r.llen('l')
ex = 4
t(a, ex)

yield r.rpush('l', 't', 'u', 'v', 'w')
a = yield r.llen('l')
ex = 8
t(a, ex)


@defer.inlineCallbacks
def test_llen(self):
r = self.redis
Expand Down Expand Up @@ -978,6 +995,18 @@ def test_sadd(self):
ex = 1
t(a, ex)

@defer.inlineCallbacks
def test_sadd_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('s')
a = yield r.sadd('s', 'a', 'b', 'c', 'd')
ex = 4
a = yield r.scard('s')
ex = 4
t(a, ex)

@defer.inlineCallbacks
def test_sdiff(self):
r = self.redis
Expand Down Expand Up @@ -1046,6 +1075,22 @@ def test_srem(self):
ex = 0
t(a, ex)

@defer.inlineCallbacks
def test_srem_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('s')
a = yield r.sadd('s', 'a', 'b', 'c', 'd')
ex = 4
t(a, ex)
a = yield r.srem('s', 'a', 'b')
ex = 2
t(a, ex)
a = yield r.scard('s')
ex = 2
t(a, ex)

@defer.inlineCallbacks
def test_spop(self):
r = self.redis
Expand Down Expand Up @@ -1378,6 +1423,21 @@ def test_basic(self):
ex = 2
t(a, ex)

@defer.inlineCallbacks
def test_hdel_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('d')
yield r.hset('d', 'a', 'vala')
yield r.hmset('d', {'a' : 'vala', 'b' : 'valb', 'c' : 'valc'})
a = yield r.hdel('d', 'a', 'b', 'c')
ex = 3
t(a, ex)
a = yield r.hgetall('d')
ex = {}
t(a, ex)

@defer.inlineCallbacks
def test_hincr(self):
r = self.redis
Expand Down Expand Up @@ -1610,6 +1670,44 @@ def test_zremrange(self):
ex = 3
t(a, ex)

@defer.inlineCallbacks
def test_add_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('z')
yield r.zadd('z', 'a', 1.0)
a = yield r.zcard('z')
ex = 1
t(a, ex)

# NB. note how for multiple argument it's score then val
yield r.zadd('z', 2.0, 'b', 3.0, 'c')
a = yield r.zcard('z')
ex = 3

@defer.inlineCallbacks
def test_zrem_variable(self):
r = self.redis
t = self.assertEqual

yield r.delete('z')
yield r.zadd('z', 'a', 1.0)
a = yield r.zcard('z')
ex = 1
t(a, ex)

# NB. note how for multiple argument it's score then val
yield r.zadd('z', 2.0, 'b', 3.0, 'c')
a = yield r.zcard('z')
ex = 3
t(a, ex)

yield r.zrem('z', 'a', 'b', 'c')
a = yield r.zcard('z')
ex = 0
t(a, ex)

@defer.inlineCallbacks
def test_zrangebyscore(self):
r = self.redis
Expand Down

0 comments on commit f4602a2

Please sign in to comment.