From 2a4fba7aa4401b98ef0486977adce961117010e7 Mon Sep 17 00:00:00 2001 From: Mike Dirolf Date: Fri, 30 Jan 2009 12:22:13 -0500 Subject: [PATCH] eval() --- pymongo/database.py | 21 +++++++++++++++++++++ test/test_database.py | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/pymongo/database.py b/pymongo/database.py index b9b4d5d2f..4a54d317d 100644 --- a/pymongo/database.py +++ b/pymongo/database.py @@ -22,6 +22,7 @@ from dbref import DBRef from son_manipulator import ObjectIdInjector, ObjectIdShuffler from collection import Collection from errors import InvalidName, CollectionInvalid, OperationFailure +from code import Code # sort directions ASCENDING = 1 @@ -345,3 +346,23 @@ class Database(object): if not isinstance(dbref, DBRef): raise TypeError("cannot dereference a %s" % type(dbref)) return self[dbref.collection()].find_one(dbref.id()) + + def eval(self, code, *args): + """Evaluate a JavaScript expression on the Mongo server. + + Useful if you need to touch a lot of data lightly; in such a scenario + the network transfer of the data could be a bottleneck. The `code` + argument must be a JavaScript function. Additional positional + arguments will be passed to that function when it is run on the + server. + + Raises TypeError if `code` is not an instance of (str, unicode). Raises + OperationFailure if the eval fails. Returns the result of the + evaluation. + """ + if not isinstance(code, types.StringTypes): + raise TypeError("code must be an instance of (str, unicode)") + + command = SON([("$eval", Code(code)), ("args", args)]) + result = self._command(command) + return result.get("retval", None) diff --git a/test/test_database.py b/test/test_database.py index d0c5695ab..6cb909937 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -247,6 +247,26 @@ class TestDatabase(unittest.TestCase): key = db.test.save(obj) self.assertEqual(obj, db.dereference(DBRef("test", key))) + def test_eval(self): + db = self.connection.pymongo_test + db.test.remove({}) + + self.assertRaises(TypeError, db.eval, None) + self.assertRaises(TypeError, db.eval, 5) + self.assertRaises(TypeError, db.eval, []) + + self.assertEqual(3, db.eval("function (x) {return x;}", 3)) + self.assertEqual(3, db.eval(u"function (x) {return x;}", 3)) + + self.assertEqual(None, db.eval("function (x) {db.test.save({y:x});}", 5)) + self.assertEqual(db.test.find_one()["y"], 5) + + self.assertEqual(5, db.eval("function (x, y) {return x + y;}", 2, 3)) + self.assertEqual(5, db.eval("function () {return 5;}")) + self.assertEqual(5, db.eval("2 + 3;")) + + self.assertRaises(OperationFailure, db.eval, "5 ++ 5;") + # TODO some of these tests belong in the collection level testing. def test_save_find_one(self): db = Database(self.connection, "pymongo_test")