X-Git-Url: http://dolda2000.com/gitweb/?p=didex.git;a=blobdiff_plain;f=didex%2Fvalues.py;h=ddb8285206cbf26e65e5b636b09a0b39fad04342;hp=8479d4214086f63539315f05206d0ebd820d0400;hb=e38ebdef74ec4b11c9ab70677f1c8896ca8ab634;hpb=fed04312788aef5e52e5549fe5325988d2bb56eb diff --git a/didex/values.py b/didex/values.py index 8479d42..ddb8285 100644 --- a/didex/values.py +++ b/didex/values.py @@ -2,7 +2,7 @@ import threading from . import store, lib, index from .store import storedesc -__all__ = ["simple", "multi", "compound"] +__all__ = ["simple", "multi", "compound", "idlink"] class cursor(lib.closable): def __init__(self, bk, st): @@ -31,21 +31,41 @@ class base(storedesc): self.idx = None self.lk = threading.Lock() - def index(self): + def index(self, tx): with self.lk: if self.idx is None: - self.idx = self.indextype(self.store.db(), self.name, self.typ) + self.idx = self.indextype(self.store.db(), self.name, self.typ, tx=tx) return self.idx def get(self, **kwargs): - return cursor(self.index().get(**kwargs), self.store) + return cursor(self.index(None).get(**kwargs), self.store) + + def get1(self, *, check=False, default=KeyError, **kwargs): + with self.get(**kwargs) as cursor: + try: + k, v = next(cursor) + except StopIteration: + if default is not KeyError: + return default + raise KeyError("no matches in " + self.name, kwargs) + if check: + try: + next(cursor) + except StopIteration: + pass + else: + raise ValueError("unexpected multiple matchies in " + self.name, kwargs) + return v + + def list(self, **kwargs): + with self.get(**kwargs) as cursor: + return [v for k, v in cursor] class descbase(base): def __init__(self, store, indextype, name, datatype, default): super().__init__(store, indextype, name, datatype) self.default = default - self.mattr = "__idx_%s_new" % name - self.iattr = "__idx_%s_cur" % name + self.mattr = "__ival_%s" % name def __get__(self, obj, cls): if obj is None: return self @@ -63,21 +83,25 @@ class simple(descbase): def register(self, id, obj, tx): val = self.__get__(obj, None) - self.index().put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, val)) + self.index(tx).put(val, id, tx=tx) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) def unregister(self, id, obj, tx): - self.index().remove(getattr(obj, self.iattr), id, tx=tx) - tx.postcommit(lambda: delattr(obj, self.iattr)) + self.index(tx).remove(self.store.icache[obj, self], id, tx=tx) + tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) def update(self, id, obj, tx): val = self.__get__(obj, None) - ival = getattr(obj, self.iattr) + ival = self.store.icache[obj, self] if val != ival: - idx = self.index() + idx = self.index(tx) idx.remove(ival, id, tx=tx) idx.put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, val)) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) + + def loaded(self, id, obj, tx): + val = self.__get__(obj, None) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) class multi(descbase): def __init__(self, store, indextype, name, datatype): @@ -85,48 +109,84 @@ class multi(descbase): def register(self, id, obj, tx): vals = frozenset(self.__get__(obj, None)) - idx = self.index() + idx = self.index(tx) for val in vals: idx.put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, vals)) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), vals)) def unregister(self, id, obj, tx): - idx = self.index() - for val in getattr(obj, self.iattr): + idx = self.index(tx) + for val in self.store.icache[obj, self]: idx.remove(val, id, tx=tx) - tx.postcommit(lambda: delattr(obj, self.iattr)) + tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) def update(self, id, obj, tx): vals = frozenset(self.__get__(obj, None)) - ivals = getattr(obj, self.iattr) + ivals = self.store.icache[obj, self] if vals != ivals: - idx = self.index() + idx = self.index(tx) for val in ivals - vals: idx.remove(val, id, tx=tx) for val in vals - ivals: idx.put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, vals)) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) + + def loaded(self, id, obj, tx): + vals = frozenset(self.__get__(obj, None)) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) class compound(base): def __init__(self, indextype, name, *parts): super().__init__(parts[0].store, indextype, name, index.compound(*(part.typ for part in parts))) self.parts = parts - self.iattr = "__idx_%s_cur" % name + + def minim(self, *parts): + return self.typ.minim(*parts) + def maxim(self, *parts): + return self.typ.maxim(*parts) + + def get(self, *, partial=None, **spec): + if partial is not None: + return super().get(ge=self.minim(*partial), le = self.maxim(*partial), **spec) + else: + return super().get(**spec) def register(self, id, obj, tx): val = tuple(part.__get__(obj, None) for part in self.parts) - self.index().put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, val)) + self.index(tx).put(val, id, tx=tx) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) def unregister(self, id, obj, tx): - self.index().remove(getattr(obj, self.iattr), id, tx=tx) - tx.postcommit(lambda: delattr(obj, self.iattr)) + self.index(tx).remove(self.store.icache[obj, self], id, tx=tx) + tx.postcommit(lambda: self.store.icache.__delitem__((obj, self))) def update(self, id, obj, tx): val = tuple(part.__get__(obj, None) for part in self.parts) - ival = getattr(obj, self.iattr) + ival = self.store.icache[obj, self] if val != ival: - idx = self.index() + idx = self.index(tx) idx.remove(ival, id, tx=tx) idx.put(val, id, tx=tx) - tx.postcommit(lambda: setattr(obj, self.iattr, val)) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) + + def loaded(self, id, obj, tx): + val = tuple(part.__get__(obj, None) for part in self.parts) + tx.postcommit(lambda: self.store.icache.__setitem__((obj, self), val)) + +class idlink(object): + def __init__(self, name, atype): + self.atype = atype + self.battr = "__idlink_%s" % name + + def __get__(self, obj, cls): + if obj is None: return self + ret = self.atype.store.get(getattr(obj, self.battr)) + assert isinstance(ret, self.atype) + return ret + + def __set__(self, obj, val): + assert isinstance(val, self.atype) + setattr(obj, self.battr, val.id) + + def __delete__(self, obj): + delattr(obj, self.battr)