-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmongo_store.py
71 lines (61 loc) · 2.32 KB
/
mongo_store.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""Just a converter from mongo collection to dictionary with _id as the key"""
import collections
import werkzeug.datastructures as datastruct
PRIMARY_KEY = '_id'
class MongoStore(collections.MutableMapping):
"""gets collection, creates dictionary, commit on changes"""
def __init__(self, mongo_collection, context):
"""
:param mongo_collection: collection to read/cache
:param context: context manager for collection operations
"""
self._collection = mongo_collection
self._context = context
self._store = {}
self.reload()
def reload(self):
"""read collection to dictionary"""
with self._context:
rows = tuple(self._collection.find({}))
self._store = {
row[PRIMARY_KEY]: datastruct.ImmutableDict(row) for row in rows
}
def __setitem__(self, key, value):
"""store key-value to collection (lazy if value isn't changed)"""
assert PRIMARY_KEY not in value or value[PRIMARY_KEY] == key
# copy before write
value = dict(value)
value[PRIMARY_KEY] = key
# do nothing on no changes
if key in self._store.keys() and value == self._store[key]:
return
with self._context:
self._collection.find_one_and_replace(
{PRIMARY_KEY: key},
value,
upsert=True
)
self._store[key] = datastruct.ImmutableDict(value)
def set_field(self, key, field, field_value):
"""Set single field in value dict, as value is immutable"""
if key not in self._store:
raise KeyError(key)
value = dict(self._store[key])
value[field] = field_value
self[key] = value
def __delitem__(self, key):
"""remove row from collection by key"""
if key not in self._store.keys():
raise KeyError(key)
with self._context:
self._collection.delete_one({PRIMARY_KEY: key})
del self._store[key]
def __getitem__(self, key):
"""read value by key from collection"""
return self._store[key]
def __len__(self):
"""getting row count of collection"""
return len(self._store)
def __iter__(self):
"""collection iterator"""
return self._store.__iter__()