Skip to content

Commit 4a6b1a2

Browse files
committed
Handle incr operation with $inc
1 parent ac41e29 commit 4a6b1a2

File tree

1 file changed

+24
-5
lines changed

1 file changed

+24
-5
lines changed

django_mongodb_backend/cache.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
from django.core.cache.backends.db import Options
66
from django.db import connections, router
77
from django.utils.functional import cached_property
8-
from pymongo import IndexModel
9-
from pymongo.errors import DuplicateKeyError
8+
from pymongo import IndexModel, ReturnDocument
9+
from pymongo.errors import DuplicateKeyError, OperationFailure
1010

1111

1212
class MongoSerializer:
1313
def __init__(self, protocol=None):
1414
self.protocol = pickle.HIGHEST_PROTOCOL if protocol is None else protocol
1515

1616
def dumps(self, obj):
17-
# Integers do not need serialization.
18-
if isinstance(obj, int):
17+
# Only skip pickling for integers, a int subclasses as bool should be
18+
# pickled.
19+
if type(obj) is int: # noqa: E721
1920
return obj
2021
return pickle.dumps(obj, self.protocol)
2122

@@ -83,7 +84,7 @@ def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
8384
num = self.collection_for_write.count_documents({}, hint="_id_")
8485
if num >= self._max_entries:
8586
self._cull(num)
86-
return self.collection_for_write.update_one(
87+
self.collection_for_write.update_one(
8788
{"key": key},
8889
{
8990
"$set": {
@@ -158,6 +159,24 @@ def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
158159
)
159160
return res.matched_count > 0
160161

162+
def incr(self, key, delta=1, version=None):
163+
serialized_key = self.make_and_validate_key(key, version=version)
164+
165+
try:
166+
updated = self.collection_for_write.find_one_and_update(
167+
{"key": serialized_key, **self._filter_expired(expired=False)},
168+
{
169+
"$inc": {"value": delta},
170+
},
171+
return_document=ReturnDocument.AFTER,
172+
)
173+
except OperationFailure as ex:
174+
raise TypeError("Cannot apply incr to a value of non-numeric type") from ex
175+
# Not exists
176+
if updated is None:
177+
raise ValueError(f"Key '{key}' not found.") from None
178+
return updated["value"]
179+
161180
def _get_expiration_time(self, timeout=None):
162181
if timeout is None:
163182
return None

0 commit comments

Comments
 (0)