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 README.rst
include LICENSE include LICENSE
recursive-include docs * recursive-include docs *
prune docs/_build/* prune docs/_build
recursive-include tests * recursive-include tests *
recursive-exclude * *.pyc *.swp 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 can be initialised using the same keyword-argument syntax you use to query
documents. To build a complex query, you may combine documents. To build a complex query, you may combine
:class:`~mongoengine.queryset.Q` objects using the ``&`` (and) and ``|`` (or) :class:`~mongoengine.queryset.Q` objects using the ``&`` (and) and ``|`` (or)
operators. To use :class:`~mongoengine.queryset.Q` objects, pass them in operators. To use a :class:`~mongoengine.queryset.Q` object, pass it in as the
as positional arguments to :attr:`Document.objects` when you filter it by first positional argument to :attr:`Document.objects` when you filter it by
calling it with keyword arguments:: calling it with keyword arguments::
# Get published posts # Get published posts

View File

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

View File

@ -240,7 +240,7 @@ class DocumentTest(unittest.TestCase):
info = BlogPost.objects._collection.index_information() info = BlogPost.objects._collection.index_information()
# _id, types, '-date', 'tags', ('cat', 'date') # _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 # Indexes are lazy so use list() to perform query
list(BlogPost.objects) list(BlogPost.objects)

View File

@ -264,6 +264,50 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection() 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): def test_delete(self):
"""Ensure that documents are properly deleted from the database. """Ensure that documents are properly deleted from the database.
""" """