Fixed cache bug.
[didex.git] / didex / values.py
1 import threading
2 from . import store, lib
3 from .store import storedesc
4
5 class cursor(lib.closable):
6     def __init__(self, bk, st):
7         self.bk = bk
8         self.st = st
9
10     def close(self):
11         self.bk.close()
12
13     def __iter__(self):
14         return self
15
16     def __next__(self):
17         k, id = next(self.bk)
18         return k, self.st.get(id)
19
20     def skip(self, n=1):
21         self.bk.skip(n)
22
23 class base(storedesc):
24     def __init__(self, store, indextype, name, datatype, default):
25         self.store = store
26         self.indextype = indextype
27         self.name = name
28         self.typ = datatype
29         self.default = default
30         self.idx = None
31         self.lk = threading.Lock()
32         self.mattr = "__idx_%s_new" % name
33         self.iattr = "__idx_%s_cur" % name
34
35     def index(self):
36         with self.lk:
37             if self.idx is None:
38                 self.idx = self.indextype(self.store.db(), self.name, self.typ)
39             return self.idx
40
41     def __get__(self, obj, cls):
42         if obj is None: return self
43         return getattr(obj, self.mattr, self.default)
44
45     def __set__(self, obj, val):
46         setattr(obj, self.mattr, val)
47
48     def __delete__(self, obj):
49         delattr(obj, self.mattr)
50
51     def get(self, **kwargs):
52         return cursor(self.index().get(**kwargs), self.store)
53
54 class simple(base):
55     def __init__(self, store, indextype, name, datatype, default=None):
56         super().__init__(store, indextype, name, datatype, default)
57
58     def register(self, id, obj, tx):
59         val = self.__get__(obj, None)
60         self.index().put(val, id, tx=tx)
61         tx.postcommit(lambda: setattr(obj, self.iattr, val))
62
63     def unregister(self, id, obj, tx):
64         self.index().remove(getattr(obj, self.iattr), id, tx=tx)
65         tx.postcommit(lambda: delattr(obj, self.iattr))
66
67     def update(self, id, obj, tx):
68         val = self.__get__(obj, None)
69         ival = getattr(obj, self.iattr)
70         if val != ival:
71             idx = self.index()
72             idx.remove(ival, id, tx=tx)
73             idx.put(val, id, tx=tx)
74             tx.postcommit(lambda: setattr(obj, self.iattr, val))
75
76 class multi(base):
77     def __init__(self, store, indextype, name, datatype):
78         super().__init__(store, indextype, name, datatype, ())
79
80     def register(self, id, obj, tx):
81         vals = frozenset(self.__get__(obj, None))
82         idx = self.index()
83         for val in vals:
84             idx.put(val, id, tx=tx)
85         tx.postcommit(lambda: setattr(obj, self.iattr, vals))
86
87     def unregister(self, id, obj, tx):
88         idx = self.index()
89         for val in getattr(obj, self.iattr):
90             idx.remove(val, id, tx=tx)
91         tx.postcommit(lambda: delattr(obj, self.iattr))
92
93     def update(self, id, obj, tx):
94         vals = frozenset(self.__get__(obj, None))
95         ivals = getattr(obj, self.iattr)
96         if vals != ivals:
97             idx = self.index()
98             for val in ivals - vals:
99                 idx.remove(val, id, tx=tx)
100             for val in vals - ivals:
101                 idx.put(val, id, tx=tx)
102             tx.postcommit(lambda: setattr(obj, self.iattr, vals))