Skip to content

Commit 81ec264

Browse files
authored
Merge pull request #719 from kysre/598-add-support-for-hashmaps
Add support for hashmaps
2 parents 4c4af16 + d2ce2fa commit 81ec264

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed

changelog.d/598.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support HashMaps

django_redis/cache.py

+20
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,23 @@ def close(self, **kwargs):
184184
@omit_exception
185185
def touch(self, *args, **kwargs):
186186
return self.client.touch(*args, **kwargs)
187+
188+
@omit_exception
189+
def hset(self, *args, **kwargs):
190+
return self.client.hset(*args, **kwargs)
191+
192+
@omit_exception
193+
def hdel(self, *args, **kwargs):
194+
return self.client.hdel(*args, **kwargs)
195+
196+
@omit_exception
197+
def hlen(self, *args, **kwargs):
198+
return self.client.hlen(*args, **kwargs)
199+
200+
@omit_exception
201+
def hkeys(self, *args, **kwargs):
202+
return self.client.hkeys(*args, **kwargs)
203+
204+
@omit_exception
205+
def hexists(self, *args, **kwargs):
206+
return self.client.hexists(*args, **kwargs)

django_redis/client/default.py

+76
Original file line numberDiff line numberDiff line change
@@ -813,3 +813,79 @@ def touch(
813813
# Convert to milliseconds
814814
timeout = int(timeout * 1000)
815815
return bool(client.pexpire(key, timeout))
816+
817+
def hset(
818+
self,
819+
name: str,
820+
key: KeyT,
821+
value: EncodableT,
822+
version: Optional[int] = None,
823+
client: Optional[Redis] = None,
824+
) -> int:
825+
"""
826+
Set the value of hash name at key to value.
827+
Returns the number of fields added to the hash.
828+
"""
829+
if client is None:
830+
client = self.get_client(write=True)
831+
nkey = self.make_key(key, version=version)
832+
nvalue = self.encode(value)
833+
return int(client.hset(name, nkey, nvalue))
834+
835+
def hdel(
836+
self,
837+
name: str,
838+
key: KeyT,
839+
version: Optional[int] = None,
840+
client: Optional[Redis] = None,
841+
) -> int:
842+
"""
843+
Remove keys from hash name.
844+
Returns the number of fields deleted from the hash.
845+
"""
846+
if client is None:
847+
client = self.get_client(write=True)
848+
nkey = self.make_key(key, version=version)
849+
return int(client.hdel(name, nkey))
850+
851+
def hlen(
852+
self,
853+
name: str,
854+
client: Optional[Redis] = None,
855+
) -> int:
856+
"""
857+
Return the number of items in hash name.
858+
"""
859+
if client is None:
860+
client = self.get_client(write=False)
861+
return int(client.hlen(name))
862+
863+
def hkeys(
864+
self,
865+
name: str,
866+
client: Optional[Redis] = None,
867+
) -> List[Any]:
868+
"""
869+
Return a list of keys in hash name.
870+
"""
871+
if client is None:
872+
client = self.get_client(write=False)
873+
try:
874+
return [self.reverse_key(k.decode()) for k in client.hkeys(name)]
875+
except _main_exceptions as e:
876+
raise ConnectionInterrupted(connection=client) from e
877+
878+
def hexists(
879+
self,
880+
name: str,
881+
key: KeyT,
882+
version: Optional[int] = None,
883+
client: Optional[Redis] = None,
884+
) -> bool:
885+
"""
886+
Return True if key exists in hash name, else False.
887+
"""
888+
if client is None:
889+
client = self.get_client(write=False)
890+
nkey = self.make_key(key, version=version)
891+
return bool(client.hexists(name, nkey))

tests/test_backend.py

+48
Original file line numberDiff line numberDiff line change
@@ -797,3 +797,51 @@ def test_clear(self, cache: RedisCache):
797797
cache.clear()
798798
value_from_cache_after_clear = cache.get("foo")
799799
assert value_from_cache_after_clear is None
800+
801+
def test_hset(self, cache: RedisCache):
802+
if isinstance(cache.client, ShardClient):
803+
pytest.skip("ShardClient doesn't support get_client")
804+
cache.hset("foo_hash1", "foo1", "bar1")
805+
cache.hset("foo_hash1", "foo2", "bar2")
806+
assert cache.hlen("foo_hash1") == 2
807+
assert cache.hexists("foo_hash1", "foo1")
808+
assert cache.hexists("foo_hash1", "foo2")
809+
810+
def test_hdel(self, cache: RedisCache):
811+
if isinstance(cache.client, ShardClient):
812+
pytest.skip("ShardClient doesn't support get_client")
813+
cache.hset("foo_hash2", "foo1", "bar1")
814+
cache.hset("foo_hash2", "foo2", "bar2")
815+
assert cache.hlen("foo_hash2") == 2
816+
deleted_count = cache.hdel("foo_hash2", "foo1")
817+
assert deleted_count == 1
818+
assert cache.hlen("foo_hash2") == 1
819+
assert not cache.hexists("foo_hash2", "foo1")
820+
assert cache.hexists("foo_hash2", "foo2")
821+
822+
def test_hlen(self, cache: RedisCache):
823+
if isinstance(cache.client, ShardClient):
824+
pytest.skip("ShardClient doesn't support get_client")
825+
assert cache.hlen("foo_hash3") == 0
826+
cache.hset("foo_hash3", "foo1", "bar1")
827+
assert cache.hlen("foo_hash3") == 1
828+
cache.hset("foo_hash3", "foo2", "bar2")
829+
assert cache.hlen("foo_hash3") == 2
830+
831+
def test_hkeys(self, cache: RedisCache):
832+
if isinstance(cache.client, ShardClient):
833+
pytest.skip("ShardClient doesn't support get_client")
834+
cache.hset("foo_hash4", "foo1", "bar1")
835+
cache.hset("foo_hash4", "foo2", "bar2")
836+
cache.hset("foo_hash4", "foo3", "bar3")
837+
keys = cache.hkeys("foo_hash4")
838+
assert len(keys) == 3
839+
for i in range(len(keys)):
840+
assert keys[i] == f"foo{i + 1}"
841+
842+
def test_hexists(self, cache: RedisCache):
843+
if isinstance(cache.client, ShardClient):
844+
pytest.skip("ShardClient doesn't support get_client")
845+
cache.hset("foo_hash5", "foo1", "bar1")
846+
assert cache.hexists("foo_hash5", "foo1")
847+
assert not cache.hexists("foo_hash5", "foo")

0 commit comments

Comments
 (0)