X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=roundup%2Fhyperdb.py;h=9aa575ac63813004cce38c19c62f53cf26501a31;hb=93d14d9ee2e0dbdb5c8971ace98c923bb5f155e7;hp=c221d0adf3346e722f1bcc01af63f971551fa56c;hpb=6f262b4e3642167927681d9b8f49e7c803b273ae;p=roundup.git diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py index c221d0a..9aa575a 100644 --- a/roundup/hyperdb.py +++ b/roundup/hyperdb.py @@ -15,18 +15,19 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: hyperdb.py,v 1.48 2002-01-14 06:32:34 richard Exp $ +# $Id: hyperdb.py,v 1.58 2002-02-27 03:23:16 richard Exp $ __doc__ = """ Hyperdatabase implementation, especially field types. """ # standard python modules -import cPickle, re, string, weakref +import re, string, weakref, os # roundup modules import date, password +DEBUG = os.environ.get('HYPERDBDEBUG', '') # # Types @@ -54,17 +55,24 @@ class Interval: class Link: """An object designating a Link property that links to a node in a specified class.""" - def __init__(self, classname): + def __init__(self, classname, do_journal='no'): self.classname = classname + self.do_journal = do_journal == 'yes' def __repr__(self): return '<%s to "%s">'%(self.__class__, self.classname) class Multilink: """An object designating a Multilink property that links to nodes in a specified class. + + "classname" indicates the class to link to + + "do_journal" indicates whether the linked-to nodes should have + 'link' and 'unlink' events placed in their journal """ - def __init__(self, classname): + def __init__(self, classname, do_journal='no'): self.classname = classname + self.do_journal = do_journal == 'yes' def __repr__(self): return '<%s to "%s">'%(self.__class__, self.classname) @@ -204,6 +212,11 @@ transaction. ''' raise NotImplementedError + def pack(self, pack_before): + ''' pack the database + ''' + raise NotImplementedError + def commit(self): ''' Commit the current transactions. @@ -309,8 +322,9 @@ class Class: propvalues[key] = value # register the link with the newly linked node - self.db.addjournal(link_class, value, 'link', - (self.classname, newid, key)) + if self.properties[key].do_journal: + self.db.addjournal(link_class, value, 'link', + (self.classname, newid, key)) elif isinstance(prop, Multilink): if type(value) != type([]): @@ -336,8 +350,9 @@ class Class: if not self.db.hasnode(link_class, id): raise IndexError, '%s has no node %s'%(link_class, id) # register the link with the newly linked node - self.db.addjournal(link_class, id, 'link', - (self.classname, newid, key)) + if self.properties[key].do_journal: + self.db.addjournal(link_class, id, 'link', + (self.classname, newid, key)) elif isinstance(prop, String): if type(value) != type(''): @@ -348,11 +363,11 @@ class Class: raise TypeError, 'new property "%s" not a Password'%key elif isinstance(prop, Date): - if not isinstance(value, date.Date): + if value is not None and not isinstance(value, date.Date): raise TypeError, 'new property "%s" not a Date'%key elif isinstance(prop, Interval): - if not isinstance(value, date.Interval): + if value is not None and not isinstance(value, date.Interval): raise TypeError, 'new property "%s" not an Interval'%key # make sure there's data where there needs to be @@ -370,9 +385,11 @@ class Class: # convert all data to strings for key, prop in self.properties.items(): if isinstance(prop, Date): - propvalues[key] = propvalues[key].get_tuple() + if propvalues[key] is not None: + propvalues[key] = propvalues[key].get_tuple() elif isinstance(prop, Interval): - propvalues[key] = propvalues[key].get_tuple() + if propvalues[key] is not None: + propvalues[key] = propvalues[key].get_tuple() elif isinstance(prop, Password): propvalues[key] = str(propvalues[key]) @@ -414,8 +431,12 @@ class Class: # possibly convert the marshalled data to instances if isinstance(prop, Date): + if d[propname] is None: + return None return date.Date(d[propname]) elif isinstance(prop, Interval): + if d[propname] is None: + return None return date.Interval(d[propname]) elif isinstance(prop, Password): p = password.Password() @@ -484,6 +505,13 @@ class Class: # the writeable properties. prop = self.properties[key] + # if the value's the same as the existing value, no sense in + # doing anything + if node.has_key(key) and value == node[key]: + del propvalues[key] + continue + + # do stuff based on the prop type if isinstance(prop, Link): link_class = self.properties[key].classname # if it isn't a number, it's a key @@ -499,15 +527,16 @@ class Class: if not self.db.hasnode(link_class, value): raise IndexError, '%s has no node %s'%(link_class, value) - # register the unlink with the old linked node - if node[key] is not None: - self.db.addjournal(link_class, node[key], 'unlink', - (self.classname, nodeid, key)) + if self.properties[key].do_journal: + # register the unlink with the old linked node + if node[key] is not None: + self.db.addjournal(link_class, node[key], 'unlink', + (self.classname, nodeid, key)) - # register the link with the newly linked node - if value is not None: - self.db.addjournal(link_class, value, 'link', - (self.classname, nodeid, key)) + # register the link with the newly linked node + if value is not None: + self.db.addjournal(link_class, value, 'link', + (self.classname, nodeid, key)) elif isinstance(prop, Multilink): if type(value) != type([]): @@ -537,19 +566,22 @@ class Class: if id in value: continue # register the unlink with the old linked node - self.db.addjournal(link_class, id, 'unlink', - (self.classname, nodeid, key)) + if self.properties[key].do_journal: + self.db.addjournal(link_class, id, 'unlink', + (self.classname, nodeid, key)) l.remove(id) # handle additions for id in value: if not self.db.hasnode(link_class, id): - raise IndexError, '%s has no node %s'%(link_class, id) + raise IndexError, '%s has no node %s'%( + link_class, id) if id in l: continue # register the link with the newly linked node - self.db.addjournal(link_class, id, 'link', - (self.classname, nodeid, key)) + if self.properties[key].do_journal: + self.db.addjournal(link_class, id, 'link', + (self.classname, nodeid, key)) l.append(id) elif isinstance(prop, String): @@ -561,18 +593,23 @@ class Class: raise TypeError, 'new property "%s" not a Password'% key propvalues[key] = value = str(value) - elif isinstance(prop, Date): + elif value is not None and isinstance(prop, Date): if not isinstance(value, date.Date): raise TypeError, 'new property "%s" not a Date'% key propvalues[key] = value = value.get_tuple() - elif isinstance(prop, Interval): + elif value is not None and isinstance(prop, Interval): if not isinstance(value, date.Interval): raise TypeError, 'new property "%s" not an Interval'% key propvalues[key] = value = value.get_tuple() node[key] = value + # nothing to do? + if not propvalues: + return + + # do the set, and journal it self.db.setnode(self.classname, nodeid, node) self.db.addjournal(self.classname, nodeid, 'set', propvalues) @@ -608,6 +645,10 @@ class Class: return self.db.getjournal(self.classname, nodeid) # Locating nodes: + def hasnode(self, nodeid): + '''Determine if the given nodeid actually exists + ''' + return self.db.hasnode(self.classname, nodeid) def setkey(self, propname): """Select a String property of this class to be the key property. @@ -821,7 +862,7 @@ class Class: else: continue break - elif t == 2 and not v.search(node[k]): + elif t == 2 and (node[k] is None or not v.search(node[k])): # RE search break elif t == 6 and node[k] != v: @@ -1033,14 +1074,57 @@ class Node: return self.cl.retire(self.nodeid) -def Choice(name, *options): - cl = Class(db, name, name=hyperdb.String(), order=hyperdb.String()) +def Choice(name, db, *options): + '''Quick helper to create a simple class with choices + ''' + cl = Class(db, name, name=String(), order=String()) for i in range(len(options)): - cl.create(name=option[i], order=i) + cl.create(name=options[i], order=i) return hyperdb.Link(name) # # $Log: not supported by cvs2svn $ +# Revision 1.57 2002/02/20 05:23:24 richard +# Didn't accomodate new values for new properties +# +# Revision 1.56 2002/02/20 05:05:28 richard +# . Added simple editing for classes that don't define a templated interface. +# - access using the admin "class list" interface +# - limited to admin-only +# - requires the csv module from object-craft (url given if it's missing) +# +# Revision 1.55 2002/02/15 07:27:12 richard +# Oops, precedences around the way w0rng. +# +# Revision 1.54 2002/02/15 07:08:44 richard +# . Alternate email addresses are now available for users. See the MIGRATION +# file for info on how to activate the feature. +# +# Revision 1.53 2002/01/22 07:21:13 richard +# . fixed back_bsddb so it passed the journal tests +# +# ... it didn't seem happy using the back_anydbm _open method, which is odd. +# Yet another occurrance of whichdb not being able to recognise older bsddb +# databases. Yadda yadda. Made the HYPERDBDEBUG stuff more sane in the +# process. +# +# Revision 1.52 2002/01/21 16:33:19 rochecompaan +# You can now use the roundup-admin tool to pack the database +# +# Revision 1.51 2002/01/21 03:01:29 richard +# brief docco on the do_journal argument +# +# Revision 1.50 2002/01/19 13:16:04 rochecompaan +# Journal entries for link and multilink properties can now be switched on +# or off. +# +# Revision 1.49 2002/01/16 07:02:57 richard +# . lots of date/interval related changes: +# - more relaxed date format for input +# +# Revision 1.48 2002/01/14 06:32:34 richard +# . #502951 ] adding new properties to old database +# # Revision 1.47 2002/01/14 02:20:15 richard # . changed all config accesses so they access either the instance or the # config attriubute on the db. This means that all config is obtained from