2 from . import store, lib, index
3 from .store import storedesc
5 __all__ = ["simple", "multi", "compound"]
7 class cursor(lib.closable):
8 def __init__(self, bk, st):
20 return k, self.st.get(id)
25 class base(storedesc):
26 def __init__(self, store, indextype, name, datatype):
28 self.indextype = indextype
32 self.lk = threading.Lock()
37 self.idx = self.indextype(self.store.db(), self.name, self.typ)
40 def get(self, **kwargs):
41 return cursor(self.index().get(**kwargs), self.store)
43 def get1(self, *, check=False, default=KeyError, **kwargs):
44 with self.get(**kwargs) as cursor:
48 if default is not KeyError:
50 raise KeyError("no matches in " + self.name, kwargs)
57 raise ValueError("unexpected multiple matchies in " + self.name, kwargs)
60 def list(self, **kwargs):
61 with self.get(**kwargs) as cursor:
62 return [v for k, v in cursor]
65 def __init__(self, store, indextype, name, datatype, default):
66 super().__init__(store, indextype, name, datatype)
67 self.default = default
68 self.mattr = "__idx_%s_new" % name
69 self.iattr = "__idx_%s_cur" % name
71 def __get__(self, obj, cls):
72 if obj is None: return self
73 return getattr(obj, self.mattr, self.default)
75 def __set__(self, obj, val):
76 setattr(obj, self.mattr, val)
78 def __delete__(self, obj):
79 delattr(obj, self.mattr)
81 class simple(descbase):
82 def __init__(self, store, indextype, name, datatype, default=None):
83 super().__init__(store, indextype, name, datatype, default)
85 def register(self, id, obj, tx):
86 val = self.__get__(obj, None)
87 self.index().put(val, id, tx=tx)
88 tx.postcommit(lambda: setattr(obj, self.iattr, val))
90 def unregister(self, id, obj, tx):
91 self.index().remove(getattr(obj, self.iattr), id, tx=tx)
92 tx.postcommit(lambda: delattr(obj, self.iattr))
94 def update(self, id, obj, tx):
95 val = self.__get__(obj, None)
96 ival = getattr(obj, self.iattr)
99 idx.remove(ival, id, tx=tx)
100 idx.put(val, id, tx=tx)
101 tx.postcommit(lambda: setattr(obj, self.iattr, val))
103 class multi(descbase):
104 def __init__(self, store, indextype, name, datatype):
105 super().__init__(store, indextype, name, datatype, ())
107 def register(self, id, obj, tx):
108 vals = frozenset(self.__get__(obj, None))
111 idx.put(val, id, tx=tx)
112 tx.postcommit(lambda: setattr(obj, self.iattr, vals))
114 def unregister(self, id, obj, tx):
116 for val in getattr(obj, self.iattr):
117 idx.remove(val, id, tx=tx)
118 tx.postcommit(lambda: delattr(obj, self.iattr))
120 def update(self, id, obj, tx):
121 vals = frozenset(self.__get__(obj, None))
122 ivals = getattr(obj, self.iattr)
125 for val in ivals - vals:
126 idx.remove(val, id, tx=tx)
127 for val in vals - ivals:
128 idx.put(val, id, tx=tx)
129 tx.postcommit(lambda: setattr(obj, self.iattr, vals))
131 class compound(base):
132 def __init__(self, indextype, name, *parts):
133 super().__init__(parts[0].store, indextype, name, index.compound(*(part.typ for part in parts)))
135 self.iattr = "__idx_%s_cur" % name
137 def minim(self, *parts):
138 return self.typ.minim(*parts)
139 def maxim(self, *parts):
140 return self.typ.maxim(*parts)
142 def get(self, *, partial=None, **spec):
143 if partial is not None:
144 return super().get(ge=self.minim(*partial), le = self.maxim(*partial), **spec)
146 return super().get(**spec)
148 def register(self, id, obj, tx):
149 val = tuple(part.__get__(obj, None) for part in self.parts)
150 self.index().put(val, id, tx=tx)
151 tx.postcommit(lambda: setattr(obj, self.iattr, val))
153 def unregister(self, id, obj, tx):
154 self.index().remove(getattr(obj, self.iattr), id, tx=tx)
155 tx.postcommit(lambda: delattr(obj, self.iattr))
157 def update(self, id, obj, tx):
158 val = tuple(part.__get__(obj, None) for part in self.parts)
159 ival = getattr(obj, self.iattr)
162 idx.remove(ival, id, tx=tx)
163 idx.put(val, id, tx=tx)
164 tx.postcommit(lambda: setattr(obj, self.iattr, val))