index 55c5456c8511ee57dabb8d4764b4c434e11998c8..4ea2a2dcdccdc5ad160733de44e8b47b9289327b 100644 (file)
def db_nuke(config):
shutil.rmtree(config.DATABASE)
+class Binary:
+
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+
+ def visit(self, visitor):
+ self.x.visit(visitor)
+ self.y.visit(visitor)
+
+class Unary:
+
+ def __init__(self, x):
+ self.x = x
+
+ def generate(self, atom):
+ return atom(self)
+
+ def visit(self, visitor):
+ self.x.visit(visitor)
+
+class Equals(Unary):
+
+ def evaluate(self, v):
+ return self.x in v
+
+ def visit(self, visitor):
+ visitor(self)
+
+class Not(Unary):
+
+ def evaluate(self, v):
+ return not self.x.evaluate(v)
+
+ def generate(self, atom):
+ return "NOT(%s)" % self.x.generate(atom)
+
+class Or(Binary):
+
+ def evaluate(self, v):
+ return self.x.evaluate(v) or self.y.evaluate(v)
+
+ def generate(self, atom):
+ return "(%s)OR(%s)" % (
+ self.x.generate(atom),
+ self.y.generate(atom))
+
+class And(Binary):
+
+ def evaluate(self, v):
+ return self.x.evaluate(v) and self.y.evaluate(v)
+
+ def generate(self, atom):
+ return "(%s)AND(%s)" % (
+ self.x.generate(atom),
+ self.y.generate(atom))
+
+def compile_expression(opcodes):
+
+ stack = []
+ push, pop = stack.append, stack.pop
+ for opcode in opcodes:
+ if opcode == -2: push(Not(pop()))
+ elif opcode == -3: push(And(pop(), pop()))
+ elif opcode == -4: push(Or(pop(), pop()))
+ else: push(Equals(opcode))
+
+ return pop()
+
+class Expression:
+
+ def __init__(self, v):
+ try:
+ opcodes = [int(x) for x in v]
+ if min(opcodes) >= -1: raise ValueError()
+
+ compiled = compile_expression(opcodes)
+ self.evaluate = lambda x: compiled.evaluate([int(y) for y in x])
+ except:
+ self.evaluate = lambda x: bool(set(x) & set(v))
+
#
# Now the database
#
def getclasses(self):
"""Return a list of the names of all existing classes."""
- return sorted(self.classes)
+ l = self.classes.keys()
+ l.sort()
+ return l
def getclass(self, classname):
"""Get the Class object representing a particular class.
# whichdb() function to do this
if not db_type or hasattr(anydbm, 'whichdb'):
if __debug__:
- logging.getLogger('hyperdb').debug(
+ logging.getLogger('roundup.hyperdb').debug(
"opendb anydbm.open(%r, 'c')"%path)
return anydbm.open(path, 'c')
raise hyperdb.DatabaseError(_("Couldn't open database - the "
"required module '%s' is not available")%db_type)
if __debug__:
- logging.getLogger('hyperdb').debug(
+ logging.getLogger('roundup.hyperdb').debug(
"opendb %r.open(%r, %r)"%(db_type, path, mode))
return dbm.open(path, mode)
""" perform the saving of data specified by the set/addnode
"""
if __debug__:
- logging.getLogger('hyperdb').debug('save %s%s %r'%(classname, nodeid, node))
+ logging.getLogger('roundup.hyperdb').debug(
+ 'save %s%s %r'%(classname, nodeid, node))
self.transactions.append((self.doSaveNode, (classname, nodeid, node)))
def getnode(self, classname, nodeid, db=None, cache=1):
cache_dict = self.cache.setdefault(classname, {})
if nodeid in cache_dict:
if __debug__:
- logging.getLogger('hyperdb').debug('get %s%s cached'%(classname, nodeid))
+ logging.getLogger('roundup.hyperdb').debug(
+ 'get %s%s cached'%(classname, nodeid))
self.stats['cache_hits'] += 1
return cache_dict[nodeid]
if __debug__:
self.stats['cache_misses'] += 1
start_t = time.time()
- logging.getLogger('hyperdb').debug('get %s%s'%(classname, nodeid))
+ logging.getLogger('roundup.hyperdb').debug(
+ 'get %s%s'%(classname, nodeid))
# get from the database and save in the cache
if db is None:
"""Remove a node from the database. Called exclusively by the
destroy() method on Class.
"""
- logging.getLogger('hyperdb').info('destroy %s%s'%(classname, nodeid))
+ logging.getLogger('roundup.hyperdb').info(
+ 'destroy %s%s'%(classname, nodeid))
# remove from cache and newnodes if it's there
if (classname in self.cache and nodeid in self.cache[classname]):
the current user.
"""
if __debug__:
- logging.getLogger('hyperdb').debug('addjournal %s%s %s %r %s %r'%(classname,
+ logging.getLogger('roundup.hyperdb').debug(
+ 'addjournal %s%s %s %r %s %r'%(classname,
nodeid, action, params, creator, creation))
if creator is None:
creator = self.getuid()
def setjournal(self, classname, nodeid, journal):
"""Set the journal to the "journal" list."""
if __debug__:
- logging.getLogger('hyperdb').debug('setjournal %s%s %r'%(classname,
- nodeid, journal))
+ logging.getLogger('roundup.hyperdb').debug(
+ 'setjournal %s%s %r'%(classname, nodeid, journal))
self.transactions.append((self.doSetJournal, (classname, nodeid,
journal)))
packed += 1
db[key] = marshal.dumps(l)
- logging.getLogger('hyperdb').info('packed %d %s items'%(packed,
- classname))
+ logging.getLogger('roundup.hyperdb').info(
+ 'packed %d %s items'%(packed, classname))
if db_type == 'gdbm':
db.reorganize()
The only backend this seems to affect is postgres.
"""
- logging.getLogger('hyperdb').info('commit %s transactions'%(
+ logging.getLogger('roundup.hyperdb').info('commit %s transactions'%(
len(self.transactions)))
# keep a handle to all the database files opened
def rollback(self):
""" Reverse all actions from the current transaction.
"""
- logging.getLogger('hyperdb').info('rollback %s transactions'%(
+ logging.getLogger('roundup.hyperdb').info('rollback %s transactions'%(
len(self.transactions)))
for method, args in self.transactions:
if not v:
match = not nv
else:
- # othewise, make sure this node has each of the
+ # otherwise, make sure this node has each of the
# required values
- for want in v:
- if want in nv:
- match = 1
- break
+ expr = Expression(v)
+ if expr.evaluate(nv): match = 1
elif t == STRING:
if nv is None:
nv = ''
repr(action), repr(params)])
return r
- def import_journals(self, entries):
- """Import a class's journal.
-
- Uses setjournal() to set the journal for each item."""
- properties = self.getprops()
- d = {}
- for l in entries:
- nodeid, jdate, user, action, params = tuple(map(eval, l))
- r = d.setdefault(nodeid, [])
- if action == 'set':
- for propname, value in params.iteritems():
- prop = properties[propname]
- if value is None:
- pass
- elif isinstance(prop, hyperdb.Date):
- value = date.Date(value)
- elif isinstance(prop, hyperdb.Interval):
- value = date.Interval(value)
- elif isinstance(prop, hyperdb.Password):
- pwd = password.Password()
- pwd.unpack(value)
- value = pwd
- params[propname] = value
- r.append((nodeid, date.Date(jdate), user, action, params))
-
- for nodeid, l in d.iteritems():
- self.db.setjournal(self.classname, nodeid, l)
-
class FileClass(hyperdb.FileClass, Class):
"""This class defines a large chunk of data. To support this, it has a
mandatory String property "content" which is typically saved off