Skip to content

Commit a21b54a

Browse files
author
Mike Dirolf
committed
Adding db.system_js - helper for dealing with server-side JS PYTHON-86.
Thanks Michael Schurter for idea and original implementation.
1 parent 49725ff commit a21b54a

File tree

2 files changed

+100
-11
lines changed

2 files changed

+100
-11
lines changed

pymongo/database.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def __init__(self, connection, name):
6767
self.__outgoing_manipulators = []
6868
self.__outgoing_copying_manipulators = []
6969
self.add_son_manipulator(ObjectIdInjector())
70+
self.__system_js = SystemJS(self)
7071

7172
def __check_name(self, name):
7273
for invalid_char in [" ", ".", "$", "/", "\\"]:
@@ -99,6 +100,16 @@ def method_overwritten(instance, method):
99100
if method_overwritten(manipulator, "transform_outgoing"):
100101
self.__outgoing_manipulators.insert(0, manipulator)
101102

103+
@property
104+
def system_js(self):
105+
"""A :class:`SystemJS` helper for this :class:`Database`.
106+
107+
See the documentation for :class:`SystemJS` for more details.
108+
109+
.. versionadded:: 1.4+
110+
"""
111+
return self.__system_js
112+
102113
@property
103114
def connection(self):
104115
"""The :class:`~pymongo.connection.Connection` instance for this
@@ -520,3 +531,51 @@ def __call__(self, *args, **kwargs):
520531
raise TypeError("'Database' object is not callable. If you meant to "
521532
"call the '%s' method on a 'Collection' object it is "
522533
"failing because no such method exists." % self.__name)
534+
535+
536+
class SystemJS(object):
537+
"""Helper class for dealing with stored JavaScript.
538+
"""
539+
540+
def __init__(self, database):
541+
"""Get a system js helper for the database `database`.
542+
543+
An instance of :class:`SystemJS` is automatically created for
544+
each :class:`Database` instance as :attr:`Database.system_js`,
545+
manual instantiation of this class should not be necessary.
546+
547+
:class:`SystemJS` instances allow for easy manipulation and
548+
access to `server-side JavaScript`_:
549+
550+
.. doctest::
551+
552+
>>> db.system_js.add1 = "function (x) { return x + 1; }"
553+
>>> db.system.js.find({"_id": "add1"}).count()
554+
1
555+
>>> db.system_js.add1(5)
556+
6.0
557+
>>> del db.system_js.add1
558+
>>> db.system.js.find({"_id": "add1"}).count()
559+
0
560+
561+
.. note:: Requires server version **>= 1.1.1**
562+
563+
.. versionadded:: 1.4+
564+
565+
.. _server-side JavaScript: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution#Server-sideCodeExecution-Storingfunctionsserverside
566+
"""
567+
# can't just assign it since we've overridden __setattr__
568+
object.__setattr__(self, "_database", database)
569+
570+
def __setattr__(self, name, code):
571+
self._database.system.js.save({"_id": name, "value": Code(code)},
572+
safe=True)
573+
574+
def __delattr__(self, name):
575+
self._database.system.js.remove({"_id": name}, safe=True)
576+
577+
def __getattr__(self, name):
578+
return lambda *args: self._database.eval("function() { return %s."
579+
"apply(this, "
580+
"arguments); }" % name,
581+
*args)

test/test_database.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,30 @@
1414

1515
"""Test the database module."""
1616

17-
import unittest
18-
import random
1917
import datetime
18+
import random
2019
import sys
2120
sys.path[0:0] = [""]
21+
import unittest
2222

23-
from pymongo.errors import InvalidName, InvalidOperation
24-
from pymongo.errors import CollectionInvalid, OperationFailure
25-
from pymongo.son import SON
26-
from pymongo.objectid import ObjectId
27-
from pymongo.database import Database
28-
from pymongo import ASCENDING, DESCENDING, OFF, SLOW_ONLY, ALL
29-
from pymongo.connection import Connection
23+
from pymongo import (ALL,
24+
ASCENDING,
25+
DESCENDING,
26+
OFF,
27+
SLOW_ONLY)
28+
from pymongo.code import Code
3029
from pymongo.collection import Collection
30+
from pymongo.connection import Connection
31+
from pymongo.database import Database
3132
from pymongo.dbref import DBRef
32-
from pymongo.code import Code
33+
from pymongo.errors import (CollectionInvalid,
34+
InvalidName,
35+
InvalidOperation,
36+
OperationFailure)
37+
from pymongo.objectid import ObjectId
38+
from pymongo.son import SON
3339
from pymongo.son_manipulator import AutoReference, NamespaceInjector
34-
from test_connection import get_connection
40+
from test.test_connection import get_connection
3541

3642

3743
class TestDatabase(unittest.TestCase):
@@ -458,5 +464,29 @@ def test_marc(self):
458464
self.assertEqual("buzz", db.users.find_one()["messages"][0]["title"])
459465
self.assertEqual("bar", db.users.find_one()["messages"][1]["title"])
460466

467+
def test_system_js(self):
468+
db = self.connection.pymongo_test
469+
db.system.js.remove()
470+
471+
self.assertEqual(0, db.system.js.count())
472+
db.system_js.add = "function(a, b) { return a + b; }"
473+
self.assertEqual(1, db.system.js.count())
474+
self.assertEqual(6, db.system_js.add(1, 5))
475+
476+
del db.system_js.add
477+
self.assertEqual(0, db.system.js.count())
478+
# TODO enable this after SERVER-602 is fixed
479+
# self.assertRaises(OperationFailure, db.system_js.add, 1, 5)
480+
481+
# TODO right now CodeWScope doesn't work w/ system js
482+
# db.system_js.scope = Code("return hello;", {"hello": 8})
483+
# self.assertEqual(8, db.system_js.scope())
484+
485+
self.assertRaises(OperationFailure, db.system_js.non_existant)
486+
487+
db.system_js.no_param = Code("return 5;")
488+
self.assertEqual(5, db.system_js.no_param())
489+
490+
461491
if __name__ == "__main__":
462492
unittest.main()

0 commit comments

Comments
 (0)