Added support for partial compound key matches.
[didex.git] / didex / values.py
... / ...
CommitLineData
1import threading
2from . import store, lib, index
3from .store import storedesc
4
5__all__ = ["simple", "multi", "compound"]
6
7class 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
25class base(storedesc):
26 def __init__(self, store, indextype, name, datatype):
27 self.store = store
28 self.indextype = indextype
29 self.name = name
30 self.typ = datatype
31 self.idx = None
32 self.lk = threading.Lock()
33
34 def index(self):
35 with self.lk:
36 if self.idx is None:
37 self.idx = self.indextype(self.store.db(), self.name, self.typ)
38 return self.idx
39
40 def get(self, **kwargs):
41 return cursor(self.index().get(**kwargs), self.store)
42
43class descbase(base):
44 def __init__(self, store, indextype, name, datatype, default):
45 super().__init__(store, indextype, name, datatype)
46 self.default = default
47 self.mattr = "__idx_%s_new" % name
48 self.iattr = "__idx_%s_cur" % name
49
50 def __get__(self, obj, cls):
51 if obj is None: return self
52 return getattr(obj, self.mattr, self.default)
53
54 def __set__(self, obj, val):
55 setattr(obj, self.mattr, val)
56
57 def __delete__(self, obj):
58 delattr(obj, self.mattr)
59
60class simple(descbase):
61 def __init__(self, store, indextype, name, datatype, default=None):
62 super().__init__(store, indextype, name, datatype, default)
63
64 def register(self, id, obj, tx):
65 val = self.__get__(obj, None)
66 self.index().put(val, id, tx=tx)
67 tx.postcommit(lambda: setattr(obj, self.iattr, val))
68
69 def unregister(self, id, obj, tx):
70 self.index().remove(getattr(obj, self.iattr), id, tx=tx)
71 tx.postcommit(lambda: delattr(obj, self.iattr))
72
73 def update(self, id, obj, tx):
74 val = self.__get__(obj, None)
75 ival = getattr(obj, self.iattr)
76 if val != ival:
77 idx = self.index()
78 idx.remove(ival, id, tx=tx)
79 idx.put(val, id, tx=tx)
80 tx.postcommit(lambda: setattr(obj, self.iattr, val))
81
82class multi(descbase):
83 def __init__(self, store, indextype, name, datatype):
84 super().__init__(store, indextype, name, datatype, ())
85
86 def register(self, id, obj, tx):
87 vals = frozenset(self.__get__(obj, None))
88 idx = self.index()
89 for val in vals:
90 idx.put(val, id, tx=tx)
91 tx.postcommit(lambda: setattr(obj, self.iattr, vals))
92
93 def unregister(self, id, obj, tx):
94 idx = self.index()
95 for val in getattr(obj, self.iattr):
96 idx.remove(val, id, tx=tx)
97 tx.postcommit(lambda: delattr(obj, self.iattr))
98
99 def update(self, id, obj, tx):
100 vals = frozenset(self.__get__(obj, None))
101 ivals = getattr(obj, self.iattr)
102 if vals != ivals:
103 idx = self.index()
104 for val in ivals - vals:
105 idx.remove(val, id, tx=tx)
106 for val in vals - ivals:
107 idx.put(val, id, tx=tx)
108 tx.postcommit(lambda: setattr(obj, self.iattr, vals))
109
110class compound(base):
111 def __init__(self, indextype, name, *parts):
112 super().__init__(parts[0].store, indextype, name, index.compound(*(part.typ for part in parts)))
113 self.parts = parts
114 self.iattr = "__idx_%s_cur" % name
115
116 def minim(self, *parts):
117 return self.typ.minim(*parts)
118 def maxim(self, *parts):
119 return self.typ.maxim(*parts)
120
121 def get(self, *, partial=None, **spec):
122 if partial is not None:
123 return super().get(ge=self.minim(*partial), le = self.maxim(*partial), **spec)
124 else:
125 return super().get(**spec)
126
127 def register(self, id, obj, tx):
128 val = tuple(part.__get__(obj, None) for part in self.parts)
129 self.index().put(val, id, tx=tx)
130 tx.postcommit(lambda: setattr(obj, self.iattr, val))
131
132 def unregister(self, id, obj, tx):
133 self.index().remove(getattr(obj, self.iattr), id, tx=tx)
134 tx.postcommit(lambda: delattr(obj, self.iattr))
135
136 def update(self, id, obj, tx):
137 val = tuple(part.__get__(obj, None) for part in self.parts)
138 ival = getattr(obj, self.iattr)
139 if val != ival:
140 idx = self.index()
141 idx.remove(ival, id, tx=tx)
142 idx.put(val, id, tx=tx)
143 tx.postcommit(lambda: setattr(obj, self.iattr, val))