Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ nosetests.xml
# Coverage
cover

# OSF-specific
#######################
Site/Cache/*
Site/Uploads/*

# Readme build
README.html

dump.rdb
39 changes: 32 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ modular-odm
.. image:: https://badge.fury.io/py/modular-odm.png
:target: http://badge.fury.io/py/modular-odm

A database-agnostic Document-Object Mapper for Python.
A Document-Object Mapper with support for multiple NoSQL backends.


Install
Expand All @@ -16,8 +16,8 @@ Install
$ pip install modular-odm


Example Usage with MongoDB
==========================
Example Usage
=============

Defining Models
---------------
Expand Down Expand Up @@ -49,6 +49,8 @@ Defining Models
Setting the Storage Backend
---------------------------

For **MongoDB**:

.. code-block:: python

from pymongo import MongoClient
Expand All @@ -59,6 +61,21 @@ Setting the Storage Backend
User.set_storage(storage.MongoStorage(db, collection="user"))
Comment.set_storage(storage.MongoStorage(db, collection="comment"))


For **Redis**:

.. note::
To use modularodm with Redis, you must have `redis-py <https://github.com/andymccurdy/redis-py>`_ installed.

.. code-block:: python

from redis import Redis
from modularodm import storage

db = redis.Redis()
User.set_storage(storage.RedisStorage(db, collection="user"))
Comment.set_storage(storage.RedisStorage(db, collection="comment"))

Creating and Querying
---------------------

Expand Down Expand Up @@ -91,26 +108,34 @@ TODO
Development
===========

Tests require `nose <http://nose.readthedocs.org/en/latest/>`_, `invoke <http://docs.pyinvoke.org/en/latest/>`_, and MongoDB.
Tests require `nose <http://nose.readthedocs.org/en/latest/>`_, `invoke <http://docs.pyinvoke.org/en/latest/>`_, MongoDB, and redis.

Installing MongoDB
------------------
Installing Dependencies
-----------------------

If you are on MacOSX with `homebrew <http://brew.sh/>`_, run

.. code-block:: bash

$ brew update
$ brew install mongodb
$ brew install redis

Then install the Python development requirements with

.. code-block:: bash

$ pip install -r dev-requirements.txt

Running Tests
-------------

To start mongodb, run
You must have both a mongo and redis server running to execute the tests.

.. code-block:: bash

$ invoke mongo
$ invoke redis

Run all tests with

Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ tox
wheel
invoke
sphinx
redis
1 change: 1 addition & 0 deletions modularodm/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .mongostorage import MongoStorage
from .picklestorage import PickleStorage
from .ephemeralstorage import EphemeralStorage
from .redisstorage import RedisStorage
18 changes: 13 additions & 5 deletions modularodm/storage/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from functools import wraps
import itertools

from modularodm import exceptions
from ..translators import DefaultTranslator

class KeyExistsException(Exception): pass
Expand Down Expand Up @@ -192,12 +193,19 @@ def flush(self):
"""Flush the database."""
raise NotImplementedError

def find_one(self, query=None, **kwargs):
"""Find a single record that matches ``query``.
"""
raise NotImplementedError

def find(self, query=None, **kwargs):
"""Query the database and return a query set.
"""
raise NotImplementedError

def find_one(self, query=None, **kwargs):
results = list(self.find(query))
if len(results) == 1:
return results[0]
elif len(results) == 0:
raise exceptions.NoResultsFound()
else:
raise exceptions.MultipleResultsFound(
'Query for find_one must return exactly one result; '
'returned {0}'.format(len(results))
)
3 changes: 2 additions & 1 deletion modularodm/storage/mongostorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(self, schema, cursor):
super(MongoQuerySet, self).__init__(schema)
self.data = cursor

# TODO: make this the default implementations of BaseQuerySet?
def __getitem__(self, index, raw=False):
super(MongoQuerySet, self).__getitem__(index)
key = self.data[index][self.primary]
Expand Down Expand Up @@ -117,7 +118,7 @@ def _ensure_index(self, key):

def __init__(self, db, collection):
self.collection = collection
self.store = db[self.collection]
self.store = db[self.collection] # a mongo collection

def find(self, query=None, **kwargs):
mongo_query = self._translate_query(query)
Expand Down
8 changes: 4 additions & 4 deletions modularodm/storage/picklestorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def get(self, primary_name, key):
return copy.deepcopy(data)

def _remove_by_pk(self, key, flush=True):
"""Retrieve value from store.
"""Remove value from store.

:param key: Key

Expand Down Expand Up @@ -201,10 +201,10 @@ def _match(self, value, query):
else:
raise TypeError('Query must be a QueryGroup or Query object.')

def find(self, query=None, **kwargs):
def find(self, query=None, by_pk=False, **kwargs):
"""
Return generator over query results. Takes optional
by_pk keyword argument; if true, return keys rather than
by_pk keyword argument; if True, return keys rather than
values.

"""
Expand All @@ -214,7 +214,7 @@ def find(self, query=None, **kwargs):
else:
for key, value in self.store.items():
if self._match(value, query):
if kwargs.get('by_pk'):
if by_pk:
yield key
else:
yield value
Expand Down
Loading