dabo Commit Revision 2588 Date: 2006-12-30 14:53:24 -0800 (Sat, 30 Dec 2006) Author: Paul
Changed: U branches/paul_sandbox/dabo/biz/dBizobj.py U branches/paul_sandbox/dabo/db/dCursorMixin.py
Log: I've worked a bit on the new memento design while on vacation here in Miami Beach, and things seem to be coming together nicely. Of course, with all big changes I keep finding other places to clean up, and I can't remember everything but when/if this gets merged back into trunk I'll be more specific about the changes.
Diff: Modified: branches/paul_sandbox/dabo/biz/dBizobj.py =================================================================== --- branches/paul_sandbox/dabo/biz/dBizobj.py 2006-12-30 18:02:17 UTC (rev 2587) +++ branches/paul_sandbox/dabo/biz/dBizobj.py 2006-12-30 22:53:24 UTC (rev 2588) @@ -6,8 +6,8 @@ from dabo.dLocalize import _ import dabo.dException as dException from dabo.dObject import dObject +from dabo.lib.profilehooks import profile as profile - class dBizobj(dObject): """ The middle tier, where the business logic resides.""" # Class to instantiate for the cursor object @@ -253,48 +253,55 @@ def saveAll(self, startTransaction=False, topLevel=True): - """ Iterates through all the records of the bizobj, and calls save() - for any record that has pending changes. - """ - changedRows = self.getChangedRows() - cursor = self._CurrentCursor + """Saves all changes to the bizobj and children.""" useTransact = startTransaction or topLevel - if useTransact: - # Tell the cursor to begin a transaction, if needed. - cursor.beginTransaction() - try: - self.scanRows(self.save, changedRows, startTransaction=False, topLevel=False) - except dException.ConnectionLostException, e: - raise dException.ConnectionLostException, e - except dException.DBQueryException, e: - # Something failed; reset things. + old_currentCursorKey = self.__currentCursorKey + old_pk = getattr(self.Record, self.KeyField) + + for key, cursor in self.__cursors.iteritems(): if useTransact: - cursor.rollbackTransaction() - # Pass the exception to the UI - raise dException.DBQueryException, e - except dException.dException, e: + # Tell the cursor to begin a transaction, if needed. + cursor.beginTransaction() +# self.scanRows(self.save, changedRows, startTransaction=False, topLevel=False) + print "saveAll: key, cursor:", key, cursor + self._CurrentCursor = key + changed_keys = list(set(cursor._mementos.keys() + cursor._newRecords.keys())) + for pk in changed_keys: + print "changed_key:", pk + self._moveToPK(pk) + try: + self.save(startTransaction=False, topLevel=False) + except dException.ConnectionLostException, e: + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) + raise dException.ConnectionLostException, e + except dException.DBQueryException, e: + # Something failed; reset things. + if useTransact: + cursor.rollbackTransaction() + # Pass the exception to the UI + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) + raise dException.DBQueryException, e + except dException.dException, e: + if useTransact: + cursor.rollbackTransaction() + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) + raise + if useTransact: - cursor.rollbackTransaction() - raise dException.dException, e + cursor.commitTransaction() - if useTransact: - cursor.commitTransaction() + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) - def _saveRowIfChanged(self, startTransaction, topLevel): - """ Meant to be called as part of a scan loop. That means that we can - assume that the current record is the one we want to act on. Also, we - can pass False for the two parameters, since they will have already been - accounted for in the calling method. - """ - if self.isChanged(): - self.save(startTransaction, topLevel) + def save(self, startTransaction=False, topLevel=True): + """Save any changes that have been made in the current row. - - def save(self, startTransaction=False, topLevel=True): - """ Save any changes that have been made in the data set. If the - save is successful, the save() of all child bizobjs will be + If the save is successful, the saveAll() of all child bizobjs will be called as well. """ cursor = self._CurrentCursor @@ -356,7 +363,7 @@ if useTransact: cursor.rollbackTransaction() # Pass the exception to the UI - raise dException.dException, e + raise # Some backends (Firebird particularly) need to be told to write # their changes even if no explicit transaction was started. @@ -369,38 +376,31 @@ def cancelAll(self): - """ Iterates through all the records, canceling each in turn. """ - errMsg = self.beforeCancel() - if errMsg: - raise dException.dException, errMsg - for cursor in self.__cursors.values(): - cursor.cancel(allRows=True) - for child in self.__children: - child.cancelAll() - self.afterCancel() + """Cancel all changes made to the current dataset, including all children.""" + self.scanChangedRows(self.cancel, allCursors=True) def cancel(self): - """ Cancel any changes to the current record, reverting the fields - back to their original values. + """Cancel all changes to the current record and all children. + + Two hook methods will be called: beforeCancel() and afterCancel(). The + former, if it returns an error message, will raise an exception and not + continue cancelling the record. """ errMsg = self.beforeCancel() if errMsg: raise dException.dException, errMsg - # Tell the cursor to cancel any changes + # Tell the cursor and all children to cancel themselves: self._CurrentCursor.cancel() - # Tell each child to cancel themselves for child in self.__children: child.cancelAll() - #child.requery() -# self.setMemento() self.afterCancel() def delete(self, startTransaction=False): - """ Delete the current row of the data set.""" + """Delete the current row of the data set.""" cursor = self._CurrentCursor errMsg = self.beforeDelete() if not errMsg: @@ -557,6 +557,43 @@ self.RowNumber = row + def scanChangedRows(self, func, allCursors=False, *args, **kwargs): + """Move the record pointer to each changed row, and call func. + + If allCursors is True, all other cursors for different parent records will + be iterated as well. + + If you want to end the scan on the next iteration, set self.exitScan=True. + + Records are scanned in arbitrary order. Any exception raised by calling + func() will be passed up to the caller. + """ + self.exitScan = False + old_currentCursorKey = self.__currentCursorKey + old_pk = getattr(self.Record, self.KeyField) + + if allCursors: + cursors = self.__cursors + else: + cursors = [{None: self._CurrentCursor}] + + for key, cursor in cursors.iteritems(): + self._CurrentCursor = key + changed_keys = list(set(cursor._mementos.keys() + cursor._newRecords.keys())) + for pk in changed_keys: + self._moveToPK(pk) + try: + func(*args, **kwargs) + except: + # Reset things and bail: + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) + raise + + self._CurrentCursor = old_currentCursorKey + self._moveToPK(old_pk) + + def getFieldNames(self): """Returns a tuple of all the field names in the cursor.""" flds = self._CurrentCursor.getFields() @@ -845,6 +882,7 @@ return ret + At profile def isAnyChanged(self): """ Returns True if any record in the current record set has been changed .DO.T @@ -939,6 +977,13 @@ # Fill in the link to the parent record if self.Parent and self.FillLinkFromParent and self.LinkField: self.setParentFK() + + # Add the new record flag if there's a KeyField defined: + if self.KeyField: + rec = self._CurrentCursor._records[self.RowNumber] + print "dbizobj.new(): pk: ", rec[self.KeyField] + self._CurrentCursor._newRecords[rec[self.KeyField]] = None + # Call the custom hook method self.onNew()
Modified: branches/paul_sandbox/dabo/db/dCursorMixin.py =================================================================== --- branches/paul_sandbox/dabo/db/dCursorMixin.py 2006-12-30 18:02:17 UTC (rev 2587) +++ branches/paul_sandbox/dabo/db/dCursorMixin.py 2006-12-30 22:53:24 UTC (rev 2588) @@ -831,11 +831,8 @@ row = self.RowNumber rec = self._records[row] - mem = self._mementos[rec[self.KeyField]] + mem = self._mementos.get(rec[self.KeyField], {}) - print "mementos:", self._mementos - print "mem", mem - for k, v in mem.items(): ret[k] = (v, rec[k]) return ret @@ -972,7 +969,7 @@ # this object started the transaction. if useTransaction: self.rollbackTransaction() - raise dException.QueryException, e + raise if useTransaction: self.beginTransaction() @@ -1169,9 +1166,7 @@ def delete(self, delRowNum=None): - """ Delete the specified row. If no row specified, - delete the currently active row. - """ + """Delete the specified row, or the currently active row.""" if self.RowNumber < 0 or self.RowCount == 0: # No query has been run yet raise dException.NoRecordsException, _("No record to delete") @@ -1180,10 +1175,12 @@ delRowNum = self.RowNumber rec = self._records[delRowNum] - newrec = rec.has_key(kons.CURSOR_NEWFLAG) - if newrec: +# newrec = rec.has_key(kons.CURSOR_NEWFLAG) + if self._newRecords.has_key(rec[self.KeyField]): + print "delete(): new record" res = True else: + print "delete(): not new record", self._newRecords pkWhere = self.makePkWhere() # some backends(PostgreSQL) don't return information about number of deleted rows # try to fetch it before @@ -1925,9 +1922,10 @@ def _getIsAdding(self): """ Return True if the current record is a new record.""" - return self._records[self.RowNumber].has_key(kons.CURSOR_NEWFLAG) - +# return self._records[self.RowNumber].has_key(kons.CURSOR_NEWFLAG) + return self._newRecords.has_key(self._records[self.RowNumber][self.KeyField]) + def _getKeyField(self): try: return self._keyField
©2006 Paul McNett |
|