Skip to content

Commit

Permalink
Adding db.system_js - helper for dealing with server-side JS PYTHON-86.
Browse files Browse the repository at this point in the history
Thanks Michael Schurter for idea and original implementation.
  • Loading branch information
Mike Dirolf committed Feb 4, 2010
1 parent 49725ff commit a21b54a
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 11 deletions.
59 changes: 59 additions & 0 deletions pymongo/database.py
Expand Up @@ -67,6 +67,7 @@ def __init__(self, connection, name):
self.__outgoing_manipulators = []
self.__outgoing_copying_manipulators = []
self.add_son_manipulator(ObjectIdInjector())
self.__system_js = SystemJS(self)

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

@property
def system_js(self):
"""A :class:`SystemJS` helper for this :class:`Database`.
See the documentation for :class:`SystemJS` for more details.
.. versionadded:: 1.4+
"""
return self.__system_js

@property
def connection(self):
"""The :class:`~pymongo.connection.Connection` instance for this
Expand Down Expand Up @@ -520,3 +531,51 @@ def __call__(self, *args, **kwargs):
raise TypeError("'Database' object is not callable. If you meant to "
"call the '%s' method on a 'Collection' object it is "
"failing because no such method exists." % self.__name)


class SystemJS(object):
"""Helper class for dealing with stored JavaScript.
"""

def __init__(self, database):
"""Get a system js helper for the database `database`.
An instance of :class:`SystemJS` is automatically created for
each :class:`Database` instance as :attr:`Database.system_js`,
manual instantiation of this class should not be necessary.
:class:`SystemJS` instances allow for easy manipulation and
access to `server-side JavaScript`_:
.. doctest::
>>> db.system_js.add1 = "function (x) { return x + 1; }"
>>> db.system.js.find({"_id": "add1"}).count()
1
>>> db.system_js.add1(5)
6.0
>>> del db.system_js.add1
>>> db.system.js.find({"_id": "add1"}).count()
0
.. note:: Requires server version **>= 1.1.1**
.. versionadded:: 1.4+
.. _server-side JavaScript: http://www.mongodb.org/display/DOCS/Server-side+Code+Execution#Server-sideCodeExecution-Storingfunctionsserverside
"""
# can't just assign it since we've overridden __setattr__
object.__setattr__(self, "_database", database)

def __setattr__(self, name, code):
self._database.system.js.save({"_id": name, "value": Code(code)},
safe=True)

def __delattr__(self, name):
self._database.system.js.remove({"_id": name}, safe=True)

def __getattr__(self, name):
return lambda *args: self._database.eval("function() { return %s."
"apply(this, "
"arguments); }" % name,
*args)
52 changes: 41 additions & 11 deletions test/test_database.py
Expand Up @@ -14,24 +14,30 @@

"""Test the database module."""

import unittest
import random
import datetime
import random
import sys
sys.path[0:0] = [""]
import unittest

from pymongo.errors import InvalidName, InvalidOperation
from pymongo.errors import CollectionInvalid, OperationFailure
from pymongo.son import SON
from pymongo.objectid import ObjectId
from pymongo.database import Database
from pymongo import ASCENDING, DESCENDING, OFF, SLOW_ONLY, ALL
from pymongo.connection import Connection
from pymongo import (ALL,
ASCENDING,
DESCENDING,
OFF,
SLOW_ONLY)
from pymongo.code import Code
from pymongo.collection import Collection
from pymongo.connection import Connection
from pymongo.database import Database
from pymongo.dbref import DBRef
from pymongo.code import Code
from pymongo.errors import (CollectionInvalid,
InvalidName,
InvalidOperation,
OperationFailure)
from pymongo.objectid import ObjectId
from pymongo.son import SON
from pymongo.son_manipulator import AutoReference, NamespaceInjector
from test_connection import get_connection
from test.test_connection import get_connection


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

def test_system_js(self):
db = self.connection.pymongo_test
db.system.js.remove()

self.assertEqual(0, db.system.js.count())
db.system_js.add = "function(a, b) { return a + b; }"
self.assertEqual(1, db.system.js.count())
self.assertEqual(6, db.system_js.add(1, 5))

del db.system_js.add
self.assertEqual(0, db.system.js.count())
# TODO enable this after SERVER-602 is fixed
# self.assertRaises(OperationFailure, db.system_js.add, 1, 5)

# TODO right now CodeWScope doesn't work w/ system js
# db.system_js.scope = Code("return hello;", {"hello": 8})
# self.assertEqual(8, db.system_js.scope())

self.assertRaises(OperationFailure, db.system_js.non_existant)

db.system_js.no_param = Code("return 5;")
self.assertEqual(5, db.system_js.no_param())


if __name__ == "__main__":
unittest.main()

0 comments on commit a21b54a

Please sign in to comment.