Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,4 @@ that much better:
* Terence Honles (https://github.com/terencehonles)
* Sean Bermejo (https://github.com/seanbermejo)
* Juan Gutierrez (https://github.com/juannyg)
* DSeaStar (https://github.com/DSeaStar)
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Changelog
Development
===========
- (Fill this out as you fix issues and develop your features).
- Fix inc/dec atomic updates rejecting deltas outside a field's min_value/max_value #2339
- Add a warning that ``mongoengine.org`` is no longer controlled by the MongoEngine
project and appears to be an expired domain takeover.
- Fix querying GenericReferenceField with __in operator #2886
Expand Down
5 changes: 4 additions & 1 deletion mongoengine/base/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,10 @@ def _to_mongo_safe_call(self, value, use_db_field=True, fields=None):

def prepare_query_value(self, op, value):
"""Prepare a value that is being used in a query for PyMongo."""
if op in UPDATE_OPERATORS:
# $inc/$dec apply a delta, not the stored value. Checking min_value
# / max_value against the delta rejects legitimate decrements on
# fields with min_value=0 (see #2339).
if op in UPDATE_OPERATORS and op not in ("inc", "dec"):
self.validate(value)
return value

Expand Down
26 changes: 26 additions & 0 deletions tests/queryset/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,32 @@ class BlogPost(Document):
update = transform.update(BlogPost, push_all__tags=["mongo", "db"])
assert update == {"$push": {"tags": {"$each": ["mongo", "db"]}}}

def test_transform_update_inc_dec_ignores_min_max(self):
"""inc/dec pass a delta; min_value/max_value apply to stored values (#2339)."""

class Account(Document):
amount = FloatField(min_value=0, required=True)
count = IntField(min_value=0, max_value=100)
money = DecimalField(min_value=0)

update = transform.update(Account, dec__amount=10)
assert update == {"$inc": {"amount": -10.0}}

update = transform.update(Account, inc__count=1)
assert update == {"$inc": {"count": 1}}

update = transform.update(Account, dec__count=5)
assert update == {"$inc": {"count": -5}}

update = transform.update(Account, dec__money=3)
assert update == {"$inc": {"money": -3.0}}

with pytest.raises(ValidationError):
transform.update(Account, set__amount=-1)

with pytest.raises(ValidationError):
transform.update(Account, set__count=101)

def test_transform_update_no_operator_default_to_set(self):
"""Ensure the differences in behvaior between 'push' and 'push_all'"""

Expand Down