Skip to content

Commit

Permalink
Issue #598 extend support for the hashmap functions
Browse files Browse the repository at this point in the history
  • Loading branch information
rootart committed Jun 23, 2024
1 parent e11150a commit 0dadbb0
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 20 deletions.
1 change: 1 addition & 0 deletions changelog.d/731.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support for the hashmaps functions hsetnx, hget, hgetall, hmget hincrby
20 changes: 20 additions & 0 deletions django_redis/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,22 @@ def sunionstore(self, *args, **kwargs):
def hset(self, *args, **kwargs):
return self.client.hset(*args, **kwargs)

@omit_exception
def hsetnx(self, *args, **kwargs):
return self.client.hsetnx(*args, **kwargs)

@omit_exception
def hget(self, *args, **kwargs):
return self.client.hget(*args, **kwargs)

@omit_exception
def hgetall(self, *args, **kwargs):
return self.client.hgetall(*args, **kwargs)

@omit_exception
def hmget(self, *args, **kwargs):
return self.client.hmget(*args, **kwargs)

@omit_exception
def hdel(self, *args, **kwargs):
return self.client.hdel(*args, **kwargs)
Expand All @@ -272,3 +288,7 @@ def hkeys(self, *args, **kwargs):
@omit_exception
def hexists(self, *args, **kwargs):
return self.client.hexists(*args, **kwargs)

@omit_exception
def hincrby(self, *args, **kwargs):
return self.client.hincrby(*args, **kwargs)
109 changes: 99 additions & 10 deletions django_redis/client/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ def _incr(
# if cached value or total value is greater than 64 bit signed
# integer.
# elif int is encoded. so redis sees the data as string.
# In this situations redis will throw ResponseError
# In these situations redis will throw ResponseError

# try to keep TTL of key
timeout = self.ttl(key, version=version, client=client)
Expand Down Expand Up @@ -1103,7 +1103,7 @@ def touch(

def hset(
self,
name: str,
name: KeyT,
key: KeyT,
value: EncodableT,
version: Optional[int] = None,
Expand All @@ -1115,13 +1115,76 @@ def hset(
"""
if client is None:
client = self.get_client(write=True)
key_name = self.make_key(name, version=version)
nkey = self.make_key(key, version=version)
nvalue = self.encode(value)
return int(client.hset(name, nkey, nvalue))
return int(client.hset(key_name, nkey, nvalue))

def hsetnx(
self,
name: KeyT,
key: KeyT,
value: EncodableT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
client = self.get_client(write=True)
nkey = self.make_key(key, version=version)
key_name = self.make_key(name, version=version)
nvalue = self.encode(value)
return int(client.hsetnx(key_name, nkey, nvalue))

def hget(
self,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> Any:
"""
Return the value of hash name at key.
"""
if client is None:
client = self.get_client(write=False)
name = self.make_key(name, version=version)
nkey = self.make_key(key, version=version)
value = client.hget(name, nkey)
if value is None:
return None
return self.decode(value)

def hgetall(
self,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> Dict[str, Any]:

if client is None:
client = self.get_client(write=False)
name = self.make_key(name, version=version)
data = client.hgetall(name)
return {self.reverse_key(k.decode()): self.decode(v) for k, v in data.items()}

def hmget(
self,
name: KeyT,
*keys: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> List[Any]:
if client is None:
client = self.get_client(write=False)
name = self.make_key(name, version=version)
nkeys = [self.make_key(k, version=version) for k in keys]
return [
self.decode(v) if v is not None else None for v in client.hmget(name, nkeys)

Check warning on line 1182 in django_redis/client/default.py

View check run for this annotation

Codecov / codecov/patch

django_redis/client/default.py#L1182

Added line #L1182 was not covered by tests
]

def hdel(
self,
name: str,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
Expand All @@ -1132,39 +1195,44 @@ def hdel(
"""
if client is None:
client = self.get_client(write=True)
name = self.make_key(name, version=version)
nkey = self.make_key(key, version=version)
return int(client.hdel(name, nkey))

def hlen(
self,
name: str,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
"""
Return the number of items in hash name.
"""
if client is None:
client = self.get_client(write=False)
return int(client.hlen(name))
key_name = self.make_key(name, version=version)
return int(client.hlen(key_name))

def hkeys(
self,
name: str,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> List[Any]:
"""
Return a list of keys in hash name.
"""
key_name = self.make_key(name, version=version)
if client is None:
client = self.get_client(write=False)
try:
return [self.reverse_key(k.decode()) for k in client.hkeys(name)]
return [self.reverse_key(k.decode()) for k in client.hkeys(key_name)]
except _main_exceptions as e:
raise ConnectionInterrupted(connection=client) from e

def hexists(
self,
name: str,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
Expand All @@ -1174,5 +1242,26 @@ def hexists(
"""
if client is None:
client = self.get_client(write=False)
key_name = self.make_key(name, version=version)
nkey = self.make_key(key, version=version)
return bool(client.hexists(name, nkey))
return bool(client.hexists(key_name, nkey))

def hincrby(
self,
name: KeyT,
key: KeyT,
increment: int = 1,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
client = self.get_client(write=True)
key_name = self.make_key(name, version=version)
nkey = self.make_key(key, version=version)
try:
value = client.hincrby(key_name, nkey, increment)
except ResponseError as exc:
value = self.hget(key_name, nkey)
msg = f"Value: {value} is not an integer or out of range."
raise ValueError(msg) from exc
return int(value)
122 changes: 122 additions & 0 deletions django_redis/client/sharded.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,125 @@ def smismember(
key = self.make_key(key, version=version)
client = self.get_server(key)
return super().smismember(key, *members, version=version, client=client)

def hset(
self,
name: KeyT,
key: KeyT,
value: Any,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hset(key_name, key, value, version=version, client=client)

def hsetnx(
self,
name: KeyT,
key: KeyT,
value: Any,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hsetnx(key_name, key, value, version=version, client=client)

def hlen(
self,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hlen(key_name, version=version, client=client)

def hget(
self,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> Any:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hget(key_name, key, version=version, client=client)

def hexists(
self,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> bool:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hexists(key_name, key, version=version, client=client)

def hkeys(
self,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> List[Any]:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hkeys(key_name, client=client)

def hgetall(
self,
name: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> Any:
if client is None:
key_name = self.make_key(name, version=version)
client = self.get_server(key_name)
return super().hgetall(key_name, version=version, client=client)

def hincrby(
self,
name: KeyT,
key: KeyT,
increment: int = 1,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
name = self.make_key(name, version=version)
client = self.get_server(name)
return super().hincrby(
name, key, increment=increment, version=version, client=client
)

def hmget(
self,
name: KeyT,
*keys: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> List[Any]:
if client is None:
name = self.make_key(name, version=version)
client = self.get_server(name)
return super().hmget(name, *keys, version=version, client=client)

def hdel(
self,
name: KeyT,
key: KeyT,
version: Optional[int] = None,
client: Optional[Redis] = None,
) -> int:
if client is None:
name = self.make_key(name, version=version)
client = self.get_server(name)
return super().hdel(name, key, version=version, client=client)
Loading

0 comments on commit 0dadbb0

Please sign in to comment.