Commit | Line | Data |
---|---|---|
b080a59c | 1 | import threading |
bd14729f | 2 | from . import store, lib, index |
b080a59c FT |
3 | from .store import storedesc |
4 | ||
9ef33548 | 5 | __all__ = ["simple", "multi", "compound", "idlink"] |
cbf73d3a | 6 | |
b080a59c FT |
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): | |
bd14729f | 26 | def __init__(self, store, indextype, name, datatype): |
b080a59c FT |
27 | self.store = store |
28 | self.indextype = indextype | |
29 | self.name = name | |
30 | self.typ = datatype | |
b080a59c FT |
31 | self.idx = None |
32 | self.lk = threading.Lock() | |
b080a59c | 33 | |
73761d10 | 34 | def index(self, tx): |
b080a59c FT |
35 | with self.lk: |
36 | if self.idx is None: | |
73761d10 | 37 | self.idx = self.indextype(self.store.db(), self.name, self.typ, tx=tx) |
b080a59c FT |
38 | return self.idx |
39 | ||
bd14729f | 40 | def get(self, **kwargs): |
73761d10 | 41 | return cursor(self.index(None).get(**kwargs), self.store) |
bd14729f | 42 | |
874b91d5 FT |
43 | def get1(self, *, check=False, default=KeyError, **kwargs): |
44 | with self.get(**kwargs) as cursor: | |
45 | try: | |
46 | k, v = next(cursor) | |
47 | except StopIteration: | |
48 | if default is not KeyError: | |
49 | return default | |
50 | raise KeyError("no matches in " + self.name, kwargs) | |
51 | if check: | |
52 | try: | |
53 | next(cursor) | |
54 | except StopIteration: | |
55 | pass | |
56 | else: | |
57 | raise ValueError("unexpected multiple matchies in " + self.name, kwargs) | |
58 | return v | |
59 | ||
60 | def list(self, **kwargs): | |
61 | with self.get(**kwargs) as cursor: | |
62 | return [v for k, v in cursor] | |
63 | ||
bd14729f FT |
64 | class descbase(base): |
65 | def __init__(self, store, indextype, name, datatype, default): | |
66 | super().__init__(store, indextype, name, datatype) | |
67 | self.default = default | |
e38ebdef | 68 | self.mattr = "__ival_%s" % name |
bd14729f | 69 | |
b080a59c FT |
70 | def __get__(self, obj, cls): |
71 | if obj is None: return self | |
72 | return getattr(obj, self.mattr, self.default) | |
73 | ||
74 | def __set__(self, obj, val): | |
75 | setattr(obj, self.mattr, val) | |
76 | ||
77 | def __delete__(self, obj): | |
78 | delattr(obj, self.mattr) | |
79 | ||
bd14729f | 80 | class simple(descbase): |
b080a59c FT |
81 | def __init__(self, store, indextype, name, datatype, default=None): |
82 | super().__init__(store, indextype, name, datatype, default) | |
83 | ||
84 | def register(self, id, obj, tx): | |
85 | val = self.__get__(obj, None) | |
73761d10 | 86 | self.index(tx).put(val, id, tx=tx) |
e38ebdef | 87 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) |
b080a59c FT |
88 | |
89 | def unregister(self, id, obj, tx): | |
e38ebdef FT |
90 | self.index(tx).remove(self.store.icache[obj, self], id, tx=tx) |
91 | tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) | |
b080a59c FT |
92 | |
93 | def update(self, id, obj, tx): | |
94 | val = self.__get__(obj, None) | |
e38ebdef | 95 | ival = self.store.icache[obj, self] |
b080a59c | 96 | if val != ival: |
73761d10 | 97 | idx = self.index(tx) |
b080a59c FT |
98 | idx.remove(ival, id, tx=tx) |
99 | idx.put(val, id, tx=tx) | |
e38ebdef FT |
100 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) |
101 | ||
102 | def loaded(self, id, obj, tx): | |
103 | val = self.__get__(obj, None) | |
104 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) | |
b080a59c | 105 | |
bd14729f | 106 | class multi(descbase): |
b080a59c FT |
107 | def __init__(self, store, indextype, name, datatype): |
108 | super().__init__(store, indextype, name, datatype, ()) | |
109 | ||
110 | def register(self, id, obj, tx): | |
111 | vals = frozenset(self.__get__(obj, None)) | |
73761d10 | 112 | idx = self.index(tx) |
b080a59c FT |
113 | for val in vals: |
114 | idx.put(val, id, tx=tx) | |
e38ebdef | 115 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), vals)) |
b080a59c FT |
116 | |
117 | def unregister(self, id, obj, tx): | |
73761d10 | 118 | idx = self.index(tx) |
e38ebdef | 119 | for val in self.store.icache[obj, self]: |
b080a59c | 120 | idx.remove(val, id, tx=tx) |
e38ebdef | 121 | tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) |
b080a59c FT |
122 | |
123 | def update(self, id, obj, tx): | |
124 | vals = frozenset(self.__get__(obj, None)) | |
e38ebdef | 125 | ivals = self.store.icache[obj, self] |
b080a59c | 126 | if vals != ivals: |
73761d10 | 127 | idx = self.index(tx) |
b080a59c FT |
128 | for val in ivals - vals: |
129 | idx.remove(val, id, tx=tx) | |
130 | for val in vals - ivals: | |
131 | idx.put(val, id, tx=tx) | |
e38ebdef FT |
132 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) |
133 | ||
134 | def loaded(self, id, obj, tx): | |
135 | vals = frozenset(self.__get__(obj, None)) | |
cbcc163b | 136 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), vals)) |
bd14729f FT |
137 | |
138 | class compound(base): | |
139 | def __init__(self, indextype, name, *parts): | |
140 | super().__init__(parts[0].store, indextype, name, index.compound(*(part.typ for part in parts))) | |
141 | self.parts = parts | |
bd14729f | 142 | |
177fbee6 FT |
143 | def minim(self, *parts): |
144 | return self.typ.minim(*parts) | |
145 | def maxim(self, *parts): | |
146 | return self.typ.maxim(*parts) | |
147 | ||
148 | def get(self, *, partial=None, **spec): | |
149 | if partial is not None: | |
150 | return super().get(ge=self.minim(*partial), le = self.maxim(*partial), **spec) | |
151 | else: | |
152 | return super().get(**spec) | |
153 | ||
bd14729f FT |
154 | def register(self, id, obj, tx): |
155 | val = tuple(part.__get__(obj, None) for part in self.parts) | |
73761d10 | 156 | self.index(tx).put(val, id, tx=tx) |
e38ebdef | 157 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) |
bd14729f FT |
158 | |
159 | def unregister(self, id, obj, tx): | |
e38ebdef FT |
160 | self.index(tx).remove(self.store.icache[obj, self], id, tx=tx) |
161 | tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) | |
bd14729f FT |
162 | |
163 | def update(self, id, obj, tx): | |
164 | val = tuple(part.__get__(obj, None) for part in self.parts) | |
e38ebdef | 165 | ival = self.store.icache[obj, self] |
bd14729f | 166 | if val != ival: |
73761d10 | 167 | idx = self.index(tx) |
bd14729f FT |
168 | idx.remove(ival, id, tx=tx) |
169 | idx.put(val, id, tx=tx) | |
e38ebdef FT |
170 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) |
171 | ||
172 | def loaded(self, id, obj, tx): | |
173 | val = tuple(part.__get__(obj, None) for part in self.parts) | |
174 | tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) | |
9ef33548 FT |
175 | |
176 | class idlink(object): | |
177 | def __init__(self, name, atype): | |
178 | self.atype = atype | |
179 | self.battr = "__idlink_%s" % name | |
180 | ||
181 | def __get__(self, obj, cls): | |
182 | if obj is None: return self | |
183 | ret = self.atype.store.get(getattr(obj, self.battr)) | |
184 | assert isinstance(ret, self.atype) | |
185 | return ret | |
186 | ||
187 | def __set__(self, obj, val): | |
188 | assert isinstance(val, self.atype) | |
189 | setattr(obj, self.battr, val.id) | |
190 | ||
191 | def __delete__(self, obj): | |
192 | delattr(obj, self.battr) |