Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: vmalloc/mongomock
base: bdb0b151cb
...
head fork: vmalloc/mongomock
compare: a24219ac80
  • 4 commits
  • 2 files changed
  • 0 commit comments
  • 2 contributors
Commits on Aug 17, 2012
@ca77y ca77y Adds count, modifies remove and find
Adds count method to collection. Adds possibility to remove by id. Adds possibility to return in the result of find
only selected fields. Changes the names of parameters of find and remove to comply to PyMongo but keeps the old ones
for backward compatibility.
7475fbf
Commits on Aug 18, 2012
@ca77y ca77y merge c0c7fc9
@ca77y ca77y whitespace fixes aa51fdf
Commits on Aug 20, 2012
@vmalloc Merge pull request #6 from ca77y/master
Adds count, modifies remove and find
a24219a
Showing with 73 additions and 14 deletions.
  1. +46 −14 mongomock/__init__.py
  2. +27 −0 tests/test__mongomock.py
View
60 mongomock/__init__.py
@@ -1,4 +1,5 @@
import operator
+import warnings
import re
from sentinels import NOTHING
@@ -30,6 +31,11 @@ def _all_op(doc_val, search_val):
dv = _force_list(doc_val)
return all(x in dv for x in search_val)
+def _print_deprecation_warning(old_param_name, new_param_name):
+ warnings.warn("'%s' has been deprecated to be in line with pymongo implementation, "
+ "a new parameter '%s' should be used instead. the old parameter will be kept for backward "
+ "compatibility purposes." % old_param_name, new_param_name, DeprecationWarning)
+
OPERATOR_MAP = {'$ne': operator.ne,
'$gt': _not_nothing_and(operator.gt),
'$gte': _not_nothing_and(operator.ge),
@@ -161,13 +167,29 @@ def update(self, spec, document, upsert=False, manipulate=False,
first = False
if not multi:
return
-
+
if not found and upsert:
self.insert(document)
-
- def find(self, filter=None):
- dataset = (document.copy() for document in self._iter_documents(filter))
+
+ def find(self, spec=None, fields=None, filter=None):
+ if filter is not None:
+ _print_deprecation_warning('filter', 'spec')
+ if spec is None:
+ spec = filter
+ dataset = (self._copy_only_fields(document, fields) for document in self._iter_documents(spec))
return Cursor(dataset)
+ def _copy_only_fields(self, doc, fields):
+ """Copy only the specified fields."""
+ if fields is None:
+ return doc.copy()
+ doc_copy = {}
+ if not fields:
+ fields = ["_id"]
+ for key in fields:
+ if key in doc:
+ doc_copy[key] = doc[key]
+ return doc_copy
+
def _iter_documents(self, filter=None):
return (document for document in itervalues(self._documents) if self._filter_applies(filter, document))
def find_one(self, filter=None):
@@ -175,7 +197,7 @@ def find_one(self, filter=None):
return next(self.find(filter))
except StopIteration:
return None
-
+
def find_and_modify(self, query={}, update=None, upsert=False, **kwargs):
old = self.find_one(query)
if not old:
@@ -187,7 +209,7 @@ def find_and_modify(self, query={}, update=None, upsert=False, **kwargs):
if kwargs.get('new', False):
return self.find_one({'_id':old['_id']})
return old
-
+
def _filter_applies(self, search_filter, document):
"""Returns a boolean indicating whether @search_filter applies
to @document.
@@ -196,10 +218,10 @@ def _filter_applies(self, search_filter, document):
return True
elif isinstance(search_filter, ObjectId):
search_filter = {'_id': search_filter}
-
+
for key, search in iteritems(search_filter):
doc_val = resolve_key_value(key, document)
-
+
if isinstance(search, dict):
is_match = all(
operator_string in OPERATOR_MAP and OPERATOR_MAP[operator_string] ( doc_val, search_val )
@@ -211,28 +233,38 @@ def _filter_applies(self, search_filter, document):
OPERATOR_MAP[key] ( doc_val, search )
else:
is_match = doc_val == search
-
+
if not is_match:
return False
-
+
return True
def save(self, to_save, manipulate=True, safe=False, **kwargs):
if not isinstance(to_save, dict):
raise TypeError("cannot save object of type %s" % type(to_save))
-
+
if "_id" not in to_save:
return self.insert(to_save)
else:
self.update({"_id": to_save["_id"]}, to_save, True,
manipulate, safe, _check_keys=True, **kwargs)
return to_save.get("_id", None)
- def remove(self, search_filter=None):
- """Remove objects matching search_filter from the collection."""
- to_delete = list(self.find(filter=search_filter))
+ def remove(self, spec_or_id=None, search_filter=None):
+ """Remove objects matching spec_or_id from the collection."""
+ if search_filter is not None:
+ _print_deprecation_warning('search_filter', 'spec_or_id')
+ if spec_or_id is None:
+ spec_or_id = search_filter if search_filter else {}
+ if not isinstance(spec_or_id, dict):
+ spec_or_id = {'_id': spec_or_id}
+ to_delete = list(self.find(spec=spec_or_id))
for doc in to_delete:
doc_id = doc['_id']
del self._documents[doc_id]
+ def count(self):
+ return len(self._documents)
+
+
class Cursor(object):
def __init__(self, dataset):
super(Cursor, self).__init__()
View
27 tests/test__mongomock.py
@@ -102,6 +102,14 @@ def test__bulk_insert(self):
del obj['_id'] # random ids can't be compared
# make sure objects were not changed in-place
self.assertEquals(objects, original_objects)
+ def test__count(self):
+ actual = self.collection.count()
+ self.assertEqual(0, actual)
+ data = dict(a=1, b=2)
+ self.collection.insert(data)
+ actual = self.collection.count()
+ self.assertEqual(1, actual)
+
class DocumentTest(FakePymongoDatabaseTest):
def setUp(self):
super(DocumentTest, self).setUp()
@@ -261,6 +269,19 @@ def test__find_sets(self):
self._assert_find({'x':{'$all':[2,5]}}, 'x', (prime,))
self._assert_find({'x':{'$all':[7,8]}}, 'x', ())
+ def test__return_only_selected_fields(self):
+ rec = {'name':'Chucky', 'type':'doll', 'model':'v6'}
+ self.collection.insert(rec)
+ result = list(self.collection.find({'name':'Chucky'}, fields=['type']))
+ self.assertEqual('doll', result[0]['type'])
+
+ def test__default_fields_to_id_if_empty(self):
+ rec = {'name':'Chucky', 'type':'doll', 'model':'v6'}
+ rec_id = self.collection.insert(rec)
+ result = list(self.collection.find({'name':'Chucky'}, fields=[]))
+ self.assertEqual(1, len(result[0]))
+ self.assertEqual(rec_id, result[0]['_id'])
+
class RemoveTest(DocumentTest):
"""Test the remove method."""
def test__remove(self):
@@ -289,6 +310,12 @@ def test__remove(self):
self.collection.remove({'name': 'sam'})
docs = list(self.collection.find())
self.assertEqual(len(docs), 0)
+ def test__remove_by_id(self):
+ expected = self.collection.count()
+ bob = {'name': 'bob'}
+ bob_id = self.collection.insert(bob)
+ self.collection.remove(bob_id)
+ self.assertEqual(expected, self.collection.count())
class UpdateTest(DocumentTest):
def test__update(self):

No commit comments for this range

Something went wrong with that request. Please try again.