Skip to content

Commit

Permalink
Querysets are now lest restrictive when querying duplicate fields (#332
Browse files Browse the repository at this point in the history
…, #333)
  • Loading branch information
rozza committed Jun 4, 2013
1 parent 985bfd2 commit ee72535
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 8 deletions.
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog

Changes in 0.8.2
================
- Querysets are now lest restrictive when querying duplicate fields (#332, #333)
- FileField now honouring db_alias (#341)
- Removed customised __set__ change tracking in ComplexBaseField (#344)
- Removed unused var in _get_changed_fields (#347)
Expand Down
5 changes: 3 additions & 2 deletions mongoengine/queryset/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def visit_query(self, query):
class DuplicateQueryConditionsError(InvalidQueryError):
pass


class SimplificationVisitor(QNodeVisitor):
"""Simplifies query trees by combinging unnecessary 'and' connection nodes
into a single Q-object.
Expand All @@ -39,6 +40,7 @@ def visit_combination(self, combination):
try:
return Q(**self._query_conjunction(queries))
except DuplicateQueryConditionsError:
# Cannot be simplified
pass
return combination

Expand Down Expand Up @@ -127,8 +129,7 @@ def __init__(self, operation, children):
# If the child is a combination of the same type, we can merge its
# children directly into this combinations children
if isinstance(node, QCombination) and node.operation == operation:
# self.children += node.children
self.children.append(node)
self.children += node.children
else:
self.children.append(node)

Expand Down
30 changes: 24 additions & 6 deletions tests/queryset/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ class TestDoc(Document):
x = IntField()
y = StringField()

# Check than an error is raised when conflicting queries are anded
query = (Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(query, {'$and': [ {'x': {'$lt': 7}}, {'x': {'$lt': 3}} ]})
self.assertEqual(query, {'$and': [{'x': {'$lt': 7}}, {'x': {'$lt': 3}}]})

query = (Q(y="a") & Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(query, {'$and': [{'y': "a"}, {'x': {'$lt': 7}}, {'x': {'$lt': 3}}]})

# Check normal cases work without an error
query = Q(x__lt=7) & Q(x__gt=3)
Expand Down Expand Up @@ -323,10 +325,26 @@ class User(Document):
pk = ObjectId()
User(email='[email protected]', pk=pk).save()

self.assertEqual(1, User.objects.filter(
Q(email='[email protected]') |
Q(name='John Doe')
).limit(2).filter(pk=pk).count())
self.assertEqual(1, User.objects.filter(Q(email='[email protected]') |
Q(name='John Doe')).limit(2).filter(pk=pk).count())

def test_chained_q_or_filtering(self):

class Post(EmbeddedDocument):
name = StringField(required=True)

class Item(Document):
postables = ListField(EmbeddedDocumentField(Post))

Item.drop_collection()

Item(postables=[Post(name="a"), Post(name="b")]).save()
Item(postables=[Post(name="a"), Post(name="c")]).save()
Item(postables=[Post(name="a"), Post(name="b"), Post(name="c")]).save()

self.assertEqual(Item.objects(Q(postables__name="a") & Q(postables__name="b")).count(), 2)
self.assertEqual(Item.objects.filter(postables__name="a").filter(postables__name="b").count(), 2)


if __name__ == '__main__':
unittest.main()

1 comment on commit ee72535

@wojcikstefan
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Please sign in to comment.