Skip to content
Merged
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
44 changes: 26 additions & 18 deletions mongodol/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from pymongo import MongoClient

from dol import KvReader, Collection as DolCollection, BaseValuesView, BaseItemsView
from dol import KvReader, Collection as DolCollection

from mongodol.constants import ID, PyMongoCollectionSpec, end_of_cursor, DFLT_TEST_DB
from mongodol.util import (
Expand All @@ -17,6 +17,12 @@
projection_union,
get_mongo_collection_pymongo_obj,
)
from mongodol.views import (
MongoItemsView,
MongoValuesView,
bulk_items,
bulk_values,
)


# TODO: mgc type annotation
Expand Down Expand Up @@ -123,7 +129,8 @@ class MongoCollectionReader(MongoCollectionCollection, KvReader):
>>> assert v != {'the': 'default'}

``s.keys()``, ``s.values()``, and ``s.items()`` are ``collections.abc.MappingViews`` instances
(specialized for mongo).
(specialized for mongo -- see :mod:`mongodol.views`: they fetch the whole collection in
a single query, and keep doing so, correctly, when the store is wrapped by ``dol``).

>>> assert type(s.keys()) == s.KeysView
>>> assert type(s.values()) == s.ValuesView
Expand Down Expand Up @@ -160,19 +167,10 @@ class MongoCollectionReader(MongoCollectionCollection, KvReader):

_projections_are_flattened = False

class ValuesView(BaseValuesView):
def __contains__(self, v):
return self._mapping.contains_value(v)

def __iter__(self):
return self._mapping.iter_values()

class ItemsView(BaseItemsView):
def __contains__(self, item):
return self._mapping.contains_item(item)

def __iter__(self):
return self._mapping.iter_items()
#: Views that resolve the bulk-read fast path through any ``dol`` wrapper chain,
#: rather than through blind attribute delegation. See :mod:`mongodol.views`.
ValuesView = MongoValuesView
ItemsView = MongoItemsView

def __init__(
self,
Expand Down Expand Up @@ -538,20 +536,30 @@ def __getitem__(self, k):


class MongoBaseStore(Store):
"""A ``Store`` that forwards the mongo bulk-read protocol through its transforms.

Historically this was the *only* way to get ``values()``/``items()`` to honour a
wrapper's transforms -- hence ``mongodol.trans.wrap_kvs``, which uses it as the
wrapper class. It is no longer needed for that: :mod:`mongodol.views` resolves the
bulk path through any wrapper chain, so plain ``dol.wrap_kvs`` now works too. It is
kept because it also forwards the write-side bulk methods (``append``/``extend``),
and because code may call ``iter_values()``/``contains_value()`` directly.
"""

def contains_value(self, v):
return self.store.contains_value(self._data_of_obj(v))

def iter_values(self):
return map(self._obj_of_data, self.store.iter_values())
return map(self._obj_of_data, bulk_values(self.store))

def contains_item(self, item):
k, v = item
return self.store.contains_item((self._id_of_key(k), self._data_of_obj(v)))

def iter_items(self):
yield from (
return (
(self._key_of_id(key), self._obj_of_data(doc))
for key, doc in self.store.iter_items()
for key, doc in bulk_items(self.store)
)

def append(self, v):
Expand Down
19 changes: 14 additions & 5 deletions mongodol/stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
MongoCollectionPersister,
)
from mongodol.trans import PostGet, ObjOfData, normalize_result
from mongodol.views import disable_bulk_read

single_value_fetch_with_unicity_validation = partial(
wrap_kvs, postget=PostGet.single_value_fetch_with_unicity_validation
Expand Down Expand Up @@ -66,8 +67,12 @@ class MongoCollectionFirstDocReader(MongoCollectionReader):
"""


# ``disable_bulk_read``: ``s[key]`` collects *all* docs matching the key into a list,
# whereas the inherited one-query bulk stream yields single docs -- so ``values()`` and
# ``items()`` must take the per-key path here to stay equal to ``s[key]``.
@disable_bulk_read
@wrap_kvs(
postget=partial(ObjOfData.all_docs_fetch, doc_collector=list)
postget=partial(PostGet.all_docs_fetch, doc_collector=list)
) # list is default but explicit here to show that other choices possible
class MongoCollectionMultipleDocsReader(MongoCollectionReader):
"""A mongo collection (kv-)reader where s[key] will return the list of all key-matching docs.
Expand Down Expand Up @@ -96,8 +101,10 @@ class MongoCollectionFirstDocPersister(MongoCollectionPersisterWithResultMapping
"""


# See the ``disable_bulk_read`` note on MongoCollectionMultipleDocsReader.
@disable_bulk_read
@wrap_kvs(
postget=partial(ObjOfData.all_docs_fetch, doc_collector=list)
postget=partial(PostGet.all_docs_fetch, doc_collector=list)
) # list is default but explicit here to show that other choices possible
class MongoCollectionMultipleDocsPersister(MongoCollectionPersisterWithResultMapping):
"""A mongo collection (kv-)reader where s[key] will return the list of all key-matching docs.
Expand All @@ -113,9 +120,11 @@ def __setitem__(self, k, v):
), (
f"v (value) must be mappings (often dictionaries) or a collection of mappings. Were:\n\tk={k}\n\tv={v}"
)
self._mgc.delete_many(self._merge_with_filt(k))
_v = v if isinstance(v, Collection) else [v]
return self._mgc.insert_many([self._build_doc(k, vi) for vi in _v])
self.mgc.delete_many(self._merge_with_filt(k))
# A Mapping is itself a Collection, so it must be tested for first, or a single
# doc would be "iterated" into its field names.
docs = [v] if isinstance(v, Mapping) else list(v)
return self.mgc.insert_many([self._build_doc(k, doc) for doc in docs])


class MongoStore(Store):
Expand Down
26 changes: 0 additions & 26 deletions mongodol/tests/not_working.py

This file was deleted.

Loading
Loading