exec_js functions now acknowledge Q objects

This commit is contained in:
Harry Marr 2010-01-23 03:05:27 +00:00
parent 21b7d8f8ea
commit 470e08f616
5 changed files with 66 additions and 14 deletions

View File

@ -1,6 +1,6 @@
include README.rst
include LICENSE
recursive-include docs *
prune docs/_build/*
prune docs/_build
recursive-include tests *
recursive-exclude * *.pyc *.swp

View File

@ -142,8 +142,8 @@ A :class:`~mongoengine.queryset.Q` object represents part of a query, and
can be initialised using the same keyword-argument syntax you use to query
documents. To build a complex query, you may combine
:class:`~mongoengine.queryset.Q` objects using the ``&`` (and) and ``|`` (or)
operators. To use :class:`~mongoengine.queryset.Q` objects, pass them in
as positional arguments to :attr:`Document.objects` when you filter it by
operators. To use a :class:`~mongoengine.queryset.Q` object, pass it in as the
first positional argument to :attr:`Document.objects` when you filter it by
calling it with keyword arguments::
# Get published posts

View File

@ -111,7 +111,7 @@ class QuerySet(object):
self._collection_obj = collection
self._accessed_collection = False
self._query = {}
self._where_clauses = []
self._where_clause = None
# If inheritance is allowed, only return instances and instances of
# subclasses of the class being used
@ -165,16 +165,18 @@ class QuerySet(object):
return index_list
def __call__(self, *q_objs, **query):
def __call__(self, q_obj=None, **query):
"""Filter the selected documents by calling the
:class:`~mongoengine.queryset.QuerySet` with a query.
:param q_objs: :class:`~mongoengine.queryset.Q` objects to be used in
the query
:param q_obj: a :class:`~mongoengine.queryset.Q` object to be used in
the query; the :class:`~mongoengine.queryset.QuerySet` is filtered
multiple times with different :class:`~mongoengine.queryset.Q`
objects, only the last one will be used
:param query: Django-style query keyword arguments
"""
for q in q_objs:
self._where_clauses.append(q.as_js(self._document))
if q_obj:
self._where_clause = q_obj.as_js(self._document)
query = QuerySet._transform_query(_doc_cls=self._document, **query)
self._query.update(query)
return self
@ -209,11 +211,11 @@ class QuerySet(object):
@property
def _cursor(self):
if not self._cursor_obj:
if self._cursor_obj is None:
self._cursor_obj = self._collection.find(self._query)
# Apply where clauses to cursor
for js in self._where_clauses:
self._cursor_obj.where(js)
if self._where_clause:
self._cursor_obj.where(self._where_clause)
# apply default ordering
if self._document._meta['ordering']:
@ -516,11 +518,17 @@ class QuerySet(object):
fields = [QuerySet._translate_field_name(self._document, f)
for f in fields]
collection = self._document._meta['collection']
scope = {
'collection': collection,
'query': self._query,
'options': options or {},
}
query = self._query
if self._where_clause:
query['$where'] = self._where_clause
scope['query'] = query
code = pymongo.code.Code(code, scope=scope)
db = _get_db()

View File

@ -240,7 +240,7 @@ class DocumentTest(unittest.TestCase):
info = BlogPost.objects._collection.index_information()
# _id, types, '-date', 'tags', ('cat', 'date')
self.assertEqual(len(info), 5)
self.assertEqual(len(info), 5)
# Indexes are lazy so use list() to perform query
list(BlogPost.objects)

View File

@ -264,6 +264,50 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection()
def test_exec_js_query(self):
"""Ensure that queries are properly formed for use in exec_js.
"""
class BlogPost(Document):
hits = IntField()
published = BooleanField()
BlogPost.drop_collection()
post1 = BlogPost(hits=1, published=False)
post1.save()
post2 = BlogPost(hits=1, published=True)
post2.save()
post3 = BlogPost(hits=1, published=True)
post3.save()
js_func = """
function(hitsField) {
var count = 0;
db[collection].find(query).forEach(function(doc) {
count += doc[hitsField];
});
return count;
}
"""
# Ensure that normal queries work
c = BlogPost.objects(published=True).exec_js(js_func, 'hits')
self.assertEqual(c, 2)
c = BlogPost.objects(published=False).exec_js(js_func, 'hits')
self.assertEqual(c, 1)
# Ensure that Q object queries work
c = BlogPost.objects(Q(published=True)).exec_js(js_func, 'hits')
self.assertEqual(c, 2)
c = BlogPost.objects(Q(published=False)).exec_js(js_func, 'hits')
self.assertEqual(c, 1)
BlogPost.drop_collection()
def test_delete(self):
"""Ensure that documents are properly deleted from the database.
"""