def FROM(self, tr, *pattern, seed=Map()): # seed is immutable """Yields bindings that match PATTERN""" assert len(pattern) == len(self._items), "invalid item count" # TODO: validate that pattern does not have variables named # `alive?` or `changeid`. def bind(pattern, binding): for item in pattern: if isinstance(item, Variable): yield binding[item.name] else: yield item # The complexity really depends on the pattern. A pattern # only made of variables will scan the whole database. In # practice, the user will seldom do time traveling queries, so # it should rarely hit this code path. pattern = list(pattern) + [ nstore.var('alive?'), nstore.var('changeid') ] bindings = self._tuples.FROM(tr, *pattern, seed=seed) for binding in bindings: if not binding['alive?']: # The associated tuple is dead, so the bindings are # not valid in all cases. continue elif self.ask(self, *bind(pattern, binding)): # The bound pattern exist, so the bindings are valid binding = binding.delete('alive?') binding = binding.delete('changeid') yield binding else: continue
def change_message(self, tr, changeid, message): # Remove existing message if any bindings = self._changes.FROM(tr, changeid, 'message', nstore.var('message')) for binding in bindings: self._changes.delete(tr, changeid, 'message', binding['message']) # add message self._changes.add(tr, changeid, 'message', message)
def ask(self, tr, *items): assert len(items) == len(self._items), "Incorrect count of ITEMS" # Complexity is O(n), where n is the number of times the exact # same ITEMS was added and deleted. In pratice, n=0, n=1 or # n=2, and of course it always possible that it is more... bindings = self._tuples.FROM(tr, *items, nstore.var('alive?'), nstore.var('changeid')) found = False significance_max = fdb.tuple.Versionstamp(b'\x00' * 10) for binding in bindings: changeid = binding['changeid'] significance = self._changes.FROM(tr, changeid, 'significance', nstore.var('significance')) significance = next(significance) significance = significance['significance'] if (significance is not None) and (significance > significance_max): found = binding['alive?'] return found