From: richard Date: Fri, 19 Jul 2002 03:36:34 +0000 (+0000) Subject: Implemented the destroy() method needed by the session database (and possibly X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=4b49a95cf5001a573043ec7c463dea45274b62c2;p=roundup.git Implemented the destroy() method needed by the session database (and possibly others). At the same time, I removed the leading underscores from the hyperdb methods that Really Didn't Need Them. The journal also raises IndexError now for all situations where there is a request for the journal of a node that doesn't have one. It used to return [] in _some_ situations, but not all. This _may_ break code, but the tests pass... git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@903 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/roundup/backends/back_anydbm.py b/roundup/backends/back_anydbm.py index dbdd21b..933738d 100644 --- a/roundup/backends/back_anydbm.py +++ b/roundup/backends/back_anydbm.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.51 2002-07-18 23:07:08 richard Exp $ +#$Id: back_anydbm.py,v 1.52 2002-07-19 03:36:34 richard Exp $ ''' This module defines a backend that saves the hyperdatabase in a database chosen by anydbm. It is guaranteed to always be available in python @@ -63,6 +63,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): self.cache = {} # cache of nodes loaded or created self.dirtynodes = {} # keep track of the dirty nodes by class self.newnodes = {} # keep track of the new nodes by class + self.destroyednodes = {}# keep track of the destroyed nodes by class self.transactions = [] self.indexer = Indexer(self.dir) # ensure files are group readable and writable @@ -141,7 +142,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): ''' if __debug__: print >>hyperdb.DEBUG, 'getclassdb', (self, classname, mode) - return self._opendb('nodes.%s'%classname, mode) + return self.opendb('nodes.%s'%classname, mode) def determine_db_type(self, path): ''' determine which DB wrote the class file @@ -157,12 +158,12 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): db_type = 'dbm' return db_type - def _opendb(self, name, mode): + def opendb(self, name, mode): '''Low-level database opener that gets around anydbm/dbm eccentricities. ''' if __debug__: - print >>hyperdb.DEBUG, '_opendb', (self, name, mode) + print >>hyperdb.DEBUG, 'opendb', (self, name, mode) # figure the class db type path = os.path.join(os.getcwd(), self.dir, name) @@ -171,7 +172,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): # new database? let anydbm pick the best dbm if not db_type: if __debug__: - print >>hyperdb.DEBUG, "_opendb anydbm.open(%r, 'n')"%path + print >>hyperdb.DEBUG, "opendb anydbm.open(%r, 'n')"%path return anydbm.open(path, 'n') # open the database with the correct module @@ -182,11 +183,11 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): "Couldn't open database - the required module '%s'"\ " is not available"%db_type if __debug__: - print >>hyperdb.DEBUG, "_opendb %r.open(%r, %r)"%(db_type, path, + print >>hyperdb.DEBUG, "opendb %r.open(%r, %r)"%(db_type, path, mode) return dbm.open(path, mode) - def _lockdb(self, name): + def lockdb(self, name): ''' Lock a database file ''' path = os.path.join(os.getcwd(), self.dir, '%s.lock'%name) @@ -199,8 +200,8 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): ''' Generate a new id for the given class ''' # open the ids DB - create if if doesn't exist - lock = self._lockdb('_ids') - db = self._opendb('_ids', 'c') + lock = self.lockdb('_ids') + db = self.opendb('_ids', 'c') if db.has_key(classname): newid = db[classname] = str(int(db[classname]) + 1) else: @@ -239,7 +240,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): ''' if __debug__: print >>hyperdb.DEBUG, 'savenode', (self, classname, nodeid, node) - self.transactions.append((self._doSaveNode, (classname, nodeid, node))) + self.transactions.append((self.doSaveNode, (classname, nodeid, node))) def getnode(self, classname, nodeid, db=None, cache=1): ''' get a node from the database @@ -264,6 +265,11 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): if not db.has_key(nodeid): raise IndexError, "no such %s %s"%(classname, nodeid) + # check the uncommitted, destroyed nodes + if (self.destroyednodes.has_key(classname) and + self.destroyednodes[classname].has_key(nodeid)): + raise IndexError, "no such %s %s"%(classname, nodeid) + # decode res = marshal.loads(db[nodeid]) @@ -276,6 +282,32 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): return res + def destroynode(self, classname, nodeid): + '''Remove a node from the database. Called exclusively by the + destroy() method on Class. + ''' + if __debug__: + print >>hyperdb.DEBUG, 'destroynode', (self, classname, nodeid) + + # remove from cache and newnodes if it's there + if (self.cache.has_key(classname) and + self.cache[classname].has_key(nodeid)): + del self.cache[classname][nodeid] + if (self.newnodes.has_key(classname) and + self.newnodes[classname].has_key(nodeid)): + del self.newnodes[classname][nodeid] + + # see if there's any obvious commit actions that we should get rid of + for entry in self.transactions[:]: + if entry[1][:2] == (classname, nodeid): + self.transactions.remove(entry) + + # add to the destroyednodes map + self.destroyednodes.setdefault(classname, {})[nodeid] = 1 + + # add the destroy commit action + self.transactions.append((self.doDestroyNode, (classname, nodeid))) + def serialise(self, classname, node): '''Copy the node contents, converting non-marshallable data into marshallable data. @@ -357,8 +389,14 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): def countnodes(self, classname, db=None): if __debug__: print >>hyperdb.DEBUG, 'countnodes', (self, classname, db) - # include the new nodes not saved to the DB yet - count = len(self.newnodes.get(classname, {})) + + count = 0 + + # include the uncommitted nodes + if self.newnodes.has_key(classname): + count += len(self.newnodes[classname]) + if self.destroyednodes.has_key(classname): + count -= len(self.destroyednodes[classname]) # and count those in the DB if db is None: @@ -369,12 +407,23 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): def getnodeids(self, classname, db=None): if __debug__: print >>hyperdb.DEBUG, 'getnodeids', (self, classname, db) + + res = [] + # start off with the new nodes - res = self.newnodes.get(classname, {}).keys() + if self.newnodes.has_key(classname): + res += self.newnodes[classname].keys() if db is None: db = self.getclassdb(classname) res = res + db.keys() + + # remove the uncommitted, destroyed nodes + if self.destroyednodes.has_key(classname): + for nodeid in self.destroyednodes[classname].keys(): + if db.has_key(nodeid): + res.remove(nodeid) + return res @@ -396,33 +445,36 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): if __debug__: print >>hyperdb.DEBUG, 'addjournal', (self, classname, nodeid, action, params) - self.transactions.append((self._doSaveJournal, (classname, nodeid, + self.transactions.append((self.doSaveJournal, (classname, nodeid, action, params))) def getjournal(self, classname, nodeid): ''' get the journal for id + + Raise IndexError if the node doesn't exist (as per history()'s + API) ''' if __debug__: print >>hyperdb.DEBUG, 'getjournal', (self, classname, nodeid) # attempt to open the journal - in some rare cases, the journal may # not exist try: - db = self._opendb('journals.%s'%classname, 'r') + db = self.opendb('journals.%s'%classname, 'r') except anydbm.error, error: - if str(error) == "need 'c' or 'n' flag to open new db": return [] - elif error.args[0] != 2: raise - return [] + if str(error) == "need 'c' or 'n' flag to open new db": + raise IndexError, 'no such %s %s'%(classname, nodeid) + elif error.args[0] != 2: + raise + raise IndexError, 'no such %s %s'%(classname, nodeid) try: journal = marshal.loads(db[nodeid]) except KeyError: db.close() - raise KeyError, 'no such %s %s'%(classname, nodeid) + raise IndexError, 'no such %s %s'%(classname, nodeid) db.close() res = [] - for entry in journal: - (nodeid, date_stamp, user, action, params) = entry - date_obj = date.Date(date_stamp) - res.append((nodeid, date_obj, user, action, params)) + for nodeid, date_stamp, user, action, params in journal: + res.append((nodeid, date.Date(date_stamp), user, action, params)) return res def pack(self, pack_before): @@ -440,7 +492,7 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): db_name = 'journals.%s'%classname path = os.path.join(os.getcwd(), self.dir, classname) db_type = self.determine_db_type(path) - db = self._opendb(db_name, 'w') + db = self.opendb(db_name, 'w') for key in db.keys(): journal = marshal.loads(db[key]) @@ -503,19 +555,24 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): self.cache = {} self.dirtynodes = {} self.newnodes = {} + self.destroyednodes = {} self.transactions = [] - def _doSaveNode(self, classname, nodeid, node): + def getCachedClassDB(self, classname): + ''' get the class db, looking in our cache of databases for commit + ''' + # get the database handle + db_name = 'nodes.%s'%classname + if not self.databases.has_key(db_name): + self.databases[db_name] = self.getclassdb(classname, 'c') + return self.databases[db_name] + + def doSaveNode(self, classname, nodeid, node): if __debug__: - print >>hyperdb.DEBUG, '_doSaveNode', (self, classname, nodeid, + print >>hyperdb.DEBUG, 'doSaveNode', (self, classname, nodeid, node) - # get the database handle - db_name = 'nodes.%s'%classname - if self.databases.has_key(db_name): - db = self.databases[db_name] - else: - db = self.databases[db_name] = self.getclassdb(classname, 'c') + db = self.getCachedClassDB(classname) # now save the marshalled data db[nodeid] = marshal.dumps(self.serialise(classname, node)) @@ -523,7 +580,16 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): # return the classname, nodeid so we reindex this content return (classname, nodeid) - def _doSaveJournal(self, classname, nodeid, action, params): + def getCachedJournalDB(self, classname): + ''' get the journal db, looking in our cache of databases for commit + ''' + # get the database handle + db_name = 'journals.%s'%classname + if not self.databases.has_key(db_name): + self.databases[db_name] = self.opendb(db_name, 'c') + return self.databases[db_name] + + def doSaveJournal(self, classname, nodeid, action, params): # serialise first if action in ('set', 'create'): params = self.serialise(classname, params) @@ -533,14 +599,9 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): params) if __debug__: - print >>hyperdb.DEBUG, '_doSaveJournal', entry + print >>hyperdb.DEBUG, 'doSaveJournal', entry - # get the database handle - db_name = 'journals.%s'%classname - if self.databases.has_key(db_name): - db = self.databases[db_name] - else: - db = self.databases[db_name] = self._opendb(db_name, 'c') + db = self.getCachedJournalDB(classname) # now insert the journal entry if db.has_key(nodeid): @@ -553,6 +614,23 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): db[nodeid] = marshal.dumps(l) + def doDestroyNode(self, classname, nodeid): + if __debug__: + print >>hyperdb.DEBUG, 'doDestroyNode', (self, classname, nodeid) + + # delete from the class database + db = self.getCachedClassDB(classname) + if db.has_key(nodeid): + del db[nodeid] + + # delete from the database + db = self.getCachedJournalDB(classname) + if db.has_key(nodeid): + del db[nodeid] + + # return the classname, nodeid so we reindex this content + return (classname, nodeid) + def rollback(self): ''' Reverse all actions from the current transaction. ''' @@ -560,11 +638,12 @@ class Database(FileStorage, hyperdb.Database, roundupdb.Database): print >>hyperdb.DEBUG, 'rollback', (self, ) for method, args in self.transactions: # delete temporary files - if method == self._doStoreFile: - self._rollbackStoreFile(*args) + if method == self.doStoreFile: + self.rollbackStoreFile(*args) self.cache = {} self.dirtynodes = {} self.newnodes = {} + self.destroyednodes = {} self.transactions = [] _marker = [] @@ -1075,6 +1154,23 @@ class Class(hyperdb.Class): self.fireReactors('retire', nodeid, None) + def destroy(self, nodeid): + """Destroy a node. + + WARNING: this method should never be used except in extremely rare + situations where there could never be links to the node being + deleted + WARNING: use retire() instead + WARNING: the properties of this node will not be available ever again + WARNING: really, use retire() instead + + Well, I think that's enough warnings. This method exists mostly to + support the session storage of the cgi interface. + """ + if self.db.journaltag is None: + raise DatabaseError, 'Database open read-only' + self.db.destroynode(self.classname, nodeid) + def history(self, nodeid): """Retrieve the journal of edits on a particular node. @@ -1550,9 +1646,15 @@ class Class(hyperdb.Class): # find all the String properties that have indexme for prop, propclass in self.getprops().items(): if isinstance(propclass, String) and propclass.indexme: - # and index them under (classname, nodeid, property) - self.db.indexer.add_text((self.classname, nodeid, prop), - str(self.get(nodeid, prop))) + try: + value = str(self.get(nodeid, prop)) + except IndexError: + # node no longer exists - entry should be removed + self.db.indexer.purge_entry((self.classname, nodeid, prop)) + else: + # and index them under (classname, nodeid, property) + self.db.indexer.add_text((self.classname, nodeid, prop), + value) # # Detector interface @@ -1676,6 +1778,9 @@ class IssueClass(Class, roundupdb.IssueClass): # #$Log: not supported by cvs2svn $ +#Revision 1.51 2002/07/18 23:07:08 richard +#Unit tests and a few fixes. +# #Revision 1.50 2002/07/18 11:50:58 richard #added tests for number type too # diff --git a/roundup/backends/back_bsddb.py b/roundup/backends/back_bsddb.py index 530a691..6e14a6e 100644 --- a/roundup/backends/back_bsddb.py +++ b/roundup/backends/back_bsddb.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb.py,v 1.19 2002-07-14 02:05:53 richard Exp $ +#$Id: back_bsddb.py,v 1.20 2002-07-19 03:36:34 richard Exp $ ''' This module defines a backend that saves the hyperdatabase in BSDDB. ''' @@ -51,22 +51,22 @@ class Database(Database): else: return bsddb.btopen(path, 'n') - def _opendb(self, name, mode): + def opendb(self, name, mode): '''Low-level database opener that gets around anydbm/dbm eccentricities. ''' if __debug__: - print >>hyperdb.DEBUG, self, '_opendb', (self, name, mode) + print >>hyperdb.DEBUG, self, 'opendb', (self, name, mode) # determine which DB wrote the class file path = os.path.join(os.getcwd(), self.dir, name) if not os.path.exists(path): if __debug__: - print >>hyperdb.DEBUG, "_opendb bsddb.open(%r, 'n')"%path + print >>hyperdb.DEBUG, "opendb bsddb.open(%r, 'n')"%path return bsddb.btopen(path, 'n') # open the database with the correct module if __debug__: - print >>hyperdb.DEBUG, "_opendb bsddb.open(%r, %r)"%(path, mode) + print >>hyperdb.DEBUG, "opendb bsddb.open(%r, %r)"%(path, mode) return bsddb.btopen(path, mode) # @@ -82,9 +82,10 @@ class Database(Database): 'r') except bsddb.error, error: if error.args[0] != 2: raise - return [] - # mor handling of bad journals - if not db.has_key(nodeid): return [] + raise IndexError, 'no such %s %s'%(classname, nodeid) + # more handling of bad journals + if not db.has_key(nodeid): + raise IndexError, 'no such %s %s'%(classname, nodeid) journal = marshal.loads(db[nodeid]) res = [] for entry in journal: @@ -94,7 +95,19 @@ class Database(Database): db.close() return res - def _doSaveJournal(self, classname, nodeid, action, params): + def getCachedJournalDB(self, classname): + ''' get the journal db, looking in our cache of databases for commit + ''' + # get the database handle + db_name = 'journals.%s'%classname + if self.databases.has_key(db_name): + return self.databases[db_name] + else: + db = bsddb.btopen(os.path.join(self.dir, db_name), 'c') + self.databases[db_name] = db + return db + + def doSaveJournal(self, classname, nodeid, action, params): # serialise first if action in ('set', 'create'): params = self.serialise(classname, params) @@ -103,9 +116,9 @@ class Database(Database): params) if __debug__: - print >>hyperdb.DEBUG, '_doSaveJournal', entry + print >>hyperdb.DEBUG, 'doSaveJournal', entry - db = bsddb.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c') + db = self.getCachedJournalDB(classname) if db.has_key(nodeid): s = db[nodeid] @@ -115,10 +128,12 @@ class Database(Database): l = [entry] db[nodeid] = marshal.dumps(l) - db.close() # #$Log: not supported by cvs2svn $ +#Revision 1.19 2002/07/14 02:05:53 richard +#. all storage-specific code (ie. backend) is now implemented by the backends +# #Revision 1.18 2002/05/15 06:21:21 richard # . node caching now works, and gives a small boost in performance # diff --git a/roundup/backends/back_bsddb3.py b/roundup/backends/back_bsddb3.py index bce357a..cb1034d 100644 --- a/roundup/backends/back_bsddb3.py +++ b/roundup/backends/back_bsddb3.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb3.py,v 1.14 2002-07-14 02:05:54 richard Exp $ +#$Id: back_bsddb3.py,v 1.15 2002-07-19 03:36:34 richard Exp $ import bsddb3, os, marshal from roundup import hyperdb, date @@ -48,22 +48,22 @@ class Database(Database): else: return bsddb3.btopen(path, 'c') - def _opendb(self, name, mode): + def opendb(self, name, mode): '''Low-level database opener that gets around anydbm/dbm eccentricities. ''' if __debug__: - print >>hyperdb.DEBUG, self, '_opendb', (self, name, mode) + print >>hyperdb.DEBUG, self, 'opendb', (self, name, mode) # determine which DB wrote the class file path = os.path.join(os.getcwd(), self.dir, name) if not os.path.exists(path): if __debug__: - print >>hyperdb.DEBUG, "_opendb bsddb3.open(%r, 'c')"%path + print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, 'c')"%path return bsddb3.btopen(path, 'c') # open the database with the correct module if __debug__: - print >>hyperdb.DEBUG, "_opendb bsddb3.open(%r, %r)"%(path, mode) + print >>hyperdb.DEBUG, "opendb bsddb3.open(%r, %r)"%(path, mode) return bsddb3.btopen(path, mode) # @@ -77,10 +77,11 @@ class Database(Database): try: db = bsddb3.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'r') - except bsddb3.NoSuchFileError: - return [] - # mor handling of bad journals - if not db.has_key(nodeid): return [] + except bsddb3._db.DBNoSuchFileError: + raise IndexError, 'no such %s %s'%(classname, nodeid) + # more handling of bad journals + if not db.has_key(nodeid): + raise IndexError, 'no such %s %s'%(classname, nodeid) journal = marshal.loads(db[nodeid]) res = [] for entry in journal: @@ -90,7 +91,19 @@ class Database(Database): db.close() return res - def _doSaveJournal(self, classname, nodeid, action, params): + def getCachedJournalDB(self, classname): + ''' get the journal db, looking in our cache of databases for commit + ''' + # get the database handle + db_name = 'journals.%s'%classname + if self.databases.has_key(db_name): + return self.databases[db_name] + else: + db = bsddb3.btopen(os.path.join(self.dir, db_name), 'c') + self.databases[db_name] = db + return db + + def doSaveJournal(self, classname, nodeid, action, params): # serialise first if action in ('set', 'create'): params = self.serialise(classname, params) @@ -99,9 +112,9 @@ class Database(Database): params) if __debug__: - print >>hyperdb.DEBUG, '_doSaveJournal', entry + print >>hyperdb.DEBUG, 'doSaveJournal', entry - db = bsddb3.btopen(os.path.join(self.dir, 'journals.%s'%classname), 'c') + db = self.getCachedJournalDB(classname) if db.has_key(nodeid): s = db[nodeid] @@ -111,10 +124,12 @@ class Database(Database): l = [entry] db[nodeid] = marshal.dumps(l) - db.close() # #$Log: not supported by cvs2svn $ +#Revision 1.14 2002/07/14 02:05:54 richard +#. all storage-specific code (ie. backend) is now implemented by the backends +# #Revision 1.13 2002/07/08 06:41:03 richard #Was reopening the database with 'n'. # diff --git a/roundup/backends/blobfiles.py b/roundup/backends/blobfiles.py index e74f05c..e099a97 100644 --- a/roundup/backends/blobfiles.py +++ b/roundup/backends/blobfiles.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: blobfiles.py,v 1.7 2002-07-14 06:14:40 richard Exp $ +#$Id: blobfiles.py,v 1.8 2002-07-19 03:36:34 richard Exp $ ''' This module exports file storage for roundup backends. Files are stored into a directory hierarchy. @@ -81,7 +81,7 @@ class FileStorage: open(name + '.tmp', 'wb').write(content) # save off the commit action - self.transactions.append((self._doStoreFile, (classname, nodeid, + self.transactions.append((self.doStoreFile, (classname, nodeid, property))) def getfile(self, classname, nodeid, property): @@ -105,7 +105,7 @@ class FileStorage: files_dir = os.path.join(self.dir, 'files') return files_in_dir(files_dir) - def _doStoreFile(self, classname, nodeid, property, **databases): + def doStoreFile(self, classname, nodeid, property, **databases): '''Store the file as part of a transaction commit. ''' # determine the name of the file to write to @@ -117,7 +117,7 @@ class FileStorage: # return the classname, nodeid so we reindex this content return (classname, nodeid) - def _rollbackStoreFile(self, classname, nodeid, property, **databases): + def rollbackStoreFile(self, classname, nodeid, property, **databases): '''Remove the temp file as a part of a rollback ''' # determine the name of the file to delete @@ -126,6 +126,9 @@ class FileStorage: os.remove(name+".tmp") # $Log: not supported by cvs2svn $ +# Revision 1.7 2002/07/14 06:14:40 richard +# Some more TODOs +# # Revision 1.6 2002/07/09 03:02:52 richard # More indexer work: # - all String properties may now be indexed too. Currently there's a bit of diff --git a/roundup/indexer.py b/roundup/indexer.py index 35e5a29..74bfcaf 100644 --- a/roundup/indexer.py +++ b/roundup/indexer.py @@ -14,7 +14,7 @@ # that promote freedom, but obviously am giving up any rights # to compel such. # -#$Id: indexer.py,v 1.11 2002-07-18 11:17:30 gmcm Exp $ +#$Id: indexer.py,v 1.12 2002-07-19 03:36:33 richard Exp $ ''' This module provides an indexer class, RoundupIndexer, that stores text indices in a roundup instance. This class makes searching the content of @@ -312,6 +312,8 @@ class Indexer: def purge_entry(self, identifier): ''' Remove a file from file index and word index ''' + self.load_index() + if not self.files.has_key(identifier): return @@ -333,6 +335,11 @@ class Indexer: # #$Log: not supported by cvs2svn $ +#Revision 1.11 2002/07/18 11:17:30 gmcm +#Add Number and Boolean types to hyperdb. +#Add conversion cases to web, mail & admin interfaces. +#Add storage/serialization cases to back_anydbm & back_metakit. +# #Revision 1.10 2002/07/14 23:17:24 richard #oops # diff --git a/test/test_db.py b/test/test_db.py index fc97d18..47a1bba 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -15,7 +15,7 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: test_db.py,v 1.35 2002-07-18 23:07:08 richard Exp $ +# $Id: test_db.py,v 1.36 2002-07-19 03:36:34 richard Exp $ import unittest, os, shutil, time @@ -34,6 +34,8 @@ def setupSchema(db, create, module): issue = module.IssueClass(db, "issue", title=String(indexme="yes"), status=Link("status"), nosy=Multilink("user"), deadline=Date(), foo=Interval(), files=Multilink("file")) + session = module.Class(db, 'session', title=String()) + session.disableJournalling() db.post_init() if create: status.create(name="unread") @@ -190,6 +192,51 @@ class anydbmDBTestCase(MyTestCase): self.assertNotEqual(num_files, self.db.numfiles()) self.assertEqual(num_files2, self.db.numfiles()) + def testDestroyNoJournalling(self): + ' test destroy on a class with no journalling ' + self.innerTestDestroy(klass=self.db.session) + + def testDestroyJournalling(self): + ' test destroy on a class with journalling ' + self.innerTestDestroy(klass=self.db.issue) + + def innerTestDestroy(self, klass): + newid = klass.create(title='Mr Friendly') + n = len(klass.list()) + self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') + klass.destroy(newid) + self.assertRaises(IndexError, klass.get, newid, 'title') + self.assertNotEqual(len(klass.list()), n) + if klass.do_journal: + self.assertRaises(IndexError, klass.history, newid) + + # now with a commit + newid = klass.create(title='Mr Friendly') + n = len(klass.list()) + self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') + self.db.commit() + klass.destroy(newid) + self.assertRaises(IndexError, klass.get, newid, 'title') + self.db.commit() + self.assertRaises(IndexError, klass.get, newid, 'title') + self.assertNotEqual(len(klass.list()), n) + if klass.do_journal: + self.assertRaises(IndexError, klass.history, newid) + + # now with a rollback + newid = klass.create(title='Mr Friendly') + n = len(klass.list()) + self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') + self.db.commit() + klass.destroy(newid) + self.assertNotEqual(len(klass.list()), n) + self.assertRaises(IndexError, klass.get, newid, 'title') + self.db.rollback() + self.assertEqual(klass.get(newid, 'title'), 'Mr Friendly') + self.assertEqual(len(klass.list()), n) + if klass.do_journal: + self.assertNotEqual(klass.history(newid), []) + def testExceptions(self): # this tests the exceptions that should be raised ar = self.assertRaises @@ -559,6 +606,9 @@ def suite(): # # $Log: not supported by cvs2svn $ +# Revision 1.35 2002/07/18 23:07:08 richard +# Unit tests and a few fixes. +# # Revision 1.34 2002/07/18 11:52:00 richard # oops #