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