Repository: Krukov/cashews (language: python)

Issue:
fix: client side cahe always thinks that `None` value is already in cache
Here is the wrong part in the code:

```python
class BcastClientSide(Redis):


    async def set(self, key: str, value, *args, **kwargs):
        if await self._local_cache.get(key) == value:
            # If value in current client_cache - skip resetting
            return 0
        # the rest of the code...
```

When a function returns `None`, the result will not be saved in the cache because the code think that the result is already saved.

Solution:

```python
        if await self._local_cache.get(key, default=_empty) == value:
            # If value in current client_cache - skip resetting
            return 0
```


Discussion / hints:
Thanks ! Nice catch

Fix patch:
diff --git a/cashews/backends/client_side.py b/cashews/backends/client_side.py
index be428ad..4352f4a 100644
--- a/cashews/backends/client_side.py
+++ b/cashews/backends/client_side.py
@@ -138,7 +138,7 @@ async def get(self, key: str, default=None):
         return default
 
     async def set(self, key: str, value, *args, **kwargs):
-        if await self._local_cache.get(key) == value:
+        if await self._local_cache.get(key, default=_empty) == value:
             # If value in current client_cache - skip resetting
             return 0
         await self._local_cache.set(key, value, *args, **kwargs)  # not async by the way


Test patch:
diff --git a/tests/test_client_side_cache.py b/tests/test_client_side_cache.py
index 43eb749..7187aac 100644
--- a/tests/test_client_side_cache.py
+++ b/tests/test_client_side_cache.py
@@ -36,6 +36,22 @@ async def test_set_get_bcast(create_cache):
     assert await caches.get("key") is None
 
 
+async def test_set_none_bcast(create_cache):
+    cachef_local = Memory()
+    cachef = await create_cache(cachef_local)
+    caches_local = Memory()
+    caches = await create_cache(caches_local)
+
+    await cachef.set("key", None, expire=0.1)
+    await asyncio.sleep(0.01)  # skip init signal about invalidation
+    assert await cachef_local.exists("key")
+    assert await cachef.exists("key")
+
+    assert await caches.get("key") is None
+    assert await caches.exists("key")
+    assert await caches_local.exists("key")
+
+
 async def test_del_bcast(create_cache):
     cachef_local = Memory()
     cachef = await create_cache(cachef_local)