Implementation and tests for exec_js field substitution
This commit is contained in:
parent
200e9eca92
commit
d0e0b291df
@ -1,6 +1,7 @@
|
|||||||
from connection import _get_db
|
from connection import _get_db
|
||||||
|
|
||||||
import pymongo
|
import pymongo
|
||||||
|
import re
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
|
||||||
@ -593,6 +594,21 @@ class QuerySet(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def _sub_js_fields(self, code):
|
||||||
|
"""When fields are specified with [~fieldname] syntax, where
|
||||||
|
*fieldname* is the Python name of a field, *fieldname* will be
|
||||||
|
substituted for the MongoDB name of the field (specified using the
|
||||||
|
:attr:`name` keyword argument in a field's constructor).
|
||||||
|
"""
|
||||||
|
def field_sub(match):
|
||||||
|
# Extract just the field name, and look up the field objects
|
||||||
|
field_name = match.group(1).split('.')
|
||||||
|
fields = QuerySet._lookup_field(self._document, field_name)
|
||||||
|
# Substitute the correct name for the field into the javascript
|
||||||
|
return '["%s"]' % fields[-1].name
|
||||||
|
|
||||||
|
return re.sub('\[\s*~([A-z_][A-z_0-9.]+?)\s*\]', field_sub, code)
|
||||||
|
|
||||||
def exec_js(self, code, *fields, **options):
|
def exec_js(self, code, *fields, **options):
|
||||||
"""Execute a Javascript function on the server. A list of fields may be
|
"""Execute a Javascript function on the server. A list of fields may be
|
||||||
provided, which will be translated to their correct names and supplied
|
provided, which will be translated to their correct names and supplied
|
||||||
@ -608,6 +624,8 @@ class QuerySet(object):
|
|||||||
:param options: options that you want available to the function
|
:param options: options that you want available to the function
|
||||||
(accessed in Javascript through the ``options`` object)
|
(accessed in Javascript through the ``options`` object)
|
||||||
"""
|
"""
|
||||||
|
code = self._sub_js_fields(code)
|
||||||
|
|
||||||
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']
|
||||||
|
@ -387,6 +387,58 @@ class QuerySetTest(unittest.TestCase):
|
|||||||
|
|
||||||
BlogPost.drop_collection()
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
|
def test_exec_js_field_sub(self):
|
||||||
|
"""Ensure that field substitutions occur properly in exec_js functions.
|
||||||
|
"""
|
||||||
|
class Comment(EmbeddedDocument):
|
||||||
|
content = StringField(name='body')
|
||||||
|
|
||||||
|
class BlogPost(Document):
|
||||||
|
name = StringField(name='doc-name')
|
||||||
|
comments = ListField(EmbeddedDocumentField(Comment), name='cmnts')
|
||||||
|
|
||||||
|
BlogPost.drop_collection()
|
||||||
|
|
||||||
|
comments1 = [Comment(content='cool'), Comment(content='yay')]
|
||||||
|
post1 = BlogPost(name='post1', comments=comments1)
|
||||||
|
post1.save()
|
||||||
|
|
||||||
|
comments2 = [Comment(content='nice stuff')]
|
||||||
|
post2 = BlogPost(name='post2', comments=comments2)
|
||||||
|
post2.save()
|
||||||
|
|
||||||
|
code = """
|
||||||
|
function getComments() {
|
||||||
|
var comments = [];
|
||||||
|
db[collection].find(query).forEach(function(doc) {
|
||||||
|
var docComments = doc[~comments];
|
||||||
|
for (var i = 0; i < docComments.length; i++) {
|
||||||
|
comments.push({
|
||||||
|
'document': doc[~name],
|
||||||
|
'comment': doc[~comments][i][~comments.content]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
sub_code = BlogPost.objects._sub_js_fields(code)
|
||||||
|
code_chunks = ['doc["cmnts"];', 'doc["doc-name"],',
|
||||||
|
'doc["cmnts"][i]["body"]']
|
||||||
|
for chunk in code_chunks:
|
||||||
|
self.assertTrue(chunk in sub_code)
|
||||||
|
|
||||||
|
results = BlogPost.objects.exec_js(code)
|
||||||
|
expected_results = [
|
||||||
|
{u'comment': u'cool', u'document': u'post1'},
|
||||||
|
{u'comment': u'yay', u'document': u'post1'},
|
||||||
|
{u'comment': u'nice stuff', u'document': u'post2'},
|
||||||
|
]
|
||||||
|
self.assertEqual(results, expected_results)
|
||||||
|
|
||||||
|
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.
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user