Changeset 47
- Timestamp:
- 03/08/04 19:23:17 (5 years ago)
- Files:
-
- trunk/classes/dBizobj.py (modified) (19 diffs)
- trunk/classes/dCursorMixin.py (modified) (15 diffs)
- trunk/classes/dMemento.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/classes/dBizobj.py
r27 r47 2 2 import dConnection 3 3 import dCursorMixin 4 import types 5 4 6 5 7 ### TODO ### - Change to Gadfly … … 14 16 # is useful for parameterized queries 15 17 noDataOnLoad = 0 18 # Holds the params to be merged with the sql in the cursor 19 _params = () 16 20 # Reference to the cursor object 17 21 _cursor = None … … 20 24 # Base class to instantiate for the cursor object 21 25 ### TODO ### - change to Gadfly for default 22 cursorBaseClass = cursors.DictCursor 26 #cursorBaseClass = cursors.DictCursor 27 cursorBaseClass = cursors.Cursor 23 28 # Reference to the parent bizobj to this one. 24 29 _parent = None 25 30 # Collection of child bizobjs for this 26 _ children = []31 __children = [] 27 32 # Name of field that is the PK 28 33 keyField = "" … … 78 83 # Need to raise an exception here! 79 84 pass 85 86 # Need to set this so that different instances don't mix up the references 87 # contained in this list. 88 self.__children = [] 80 89 81 90 82 91 def getCursorClass(self, main, secondary): 83 class result(main, secondary): 92 class cursorMix(main, secondary): 93 superMixin = main 94 superCursor = secondary 84 95 def __init__(self, *args, **kwargs): 85 96 if hasattr(main, "__init__"): … … 88 99 if hasattr(secondary, "__init__"): 89 100 apply(secondary.__init__,(self,) + args, kwargs) 90 return result101 return cursorMix 91 102 92 103 … … 194 205 195 206 # Iterate through the child bizobjs, telling them to save themselves. 196 for child in self._ children:207 for child in self.__children: 197 208 if child.isChanged(): 198 209 # No need to start another transaction. And since this is a child bizobj, … … 240 251 if ret == k.FILE_OK: 241 252 # Tell each child to cancel themselves 242 for child in self._ children:253 for child in self.__children: 243 254 ret = child.cancel(allRows) 244 255 if not ret == k.FILE_OK: … … 260 271 self._errorMsg = "" 261 272 262 if not self.beforeDelete() or self.beforePointerMove():273 if not self.beforeDelete() or not self.beforePointerMove(): 263 274 return k.FILE_CANCEL 264 275 265 276 if self.deleteChildLogic == k.REFINTEG_RESTRICT: 266 277 # See if there are any child records 267 for child in self._ children:278 for child in self.__children: 268 279 if child.getRowCount() > 0: 269 280 self.addToErrorMsg("Deletion prohibited - there are related child records.") … … 271 282 272 283 ret = self._cursor.delete() 273 ### TODO - add this logic to the cursor's Delete 274 # * If adding a new record, just revert it. 275 # IF IsAdding(This.cAlias) 276 # lnRetVal = This.oBehavior.Cancel() 277 278 if ret == k.FILE_OK: 279 if self._cursor.rowcount == 0: 284 285 if ret == k.FILE_OK: 286 if self._cursor.getRowCount() == 0: 280 287 # Hook method for handling the deletion of the last record in the cursor. 281 288 self.onDeleteLastRecord() … … 283 290 # ensure that any changed data they may have is reverted. They are then requeried to 284 291 # populate them with data for the current record in this bizobj. 285 for child in self._ children:292 for child in self.__children: 286 293 if self.deleteChildLogic == k.REFINTEG_CASCADE: 287 294 child.deleteAll() … … 302 309 def deleteAll(self): 303 310 """ Iterate through all the rows in the bizobj's cursor, deleting each one-by-one""" 304 while self._cursor. rowcount> 0:311 while self._cursor.getRowCount() > 0: 305 312 self.first() 306 313 ret = self.delete() … … 328 335 if self.newChildOnNew: 329 336 # Add records to all children set to have records created on a new parent record. 330 for child in self._ children:337 for child in self.__children: 331 338 if child.newRecordOnNewParent: 332 339 child.new() … … 370 377 self.afterRequery(ret) 371 378 return ret 379 380 381 def setParams(self, params): 382 """ accepts a tuple that will be merged with the sql statement using the '%' 383 string format function. """ 384 # if params != types.TupleType: 385 # params = tuple(params) 386 self._params = params 372 387 373 388 … … 390 405 if not ret: 391 406 # see if any child bizobjs have changed 392 for child in self._ children:407 for child in self.__children: 393 408 ret = ret and child.isChanged() 394 409 … … 403 418 def onNew(self): 404 419 """ Populates the record with any default values """ 405 self._cursor.setDefault Vals(self.defaultValues())420 self._cursor.setDefaults(self.defaultValues) 406 421 407 422 # Call the custom hook method … … 417 432 """ During the creation of the form, child bizobjs are added by the parent. 418 433 This stores the child reference here, and sets the reference to the parent in the child. """ 419 if child not in self._ children:420 self._ children.append(child)434 if child not in self.__children: 435 self.__children.append(child) 421 436 child.setParent(self) 422 437 … … 430 445 """ Called to assure that all child bizobjs have had their data sets refreshed to 431 446 match the current status. """ 432 if len(self._ children) == 0:447 if len(self.__children) == 0: 433 448 return k.REQUERY_SUCCESS 434 449 if self.beforeChildRequery(): 435 450 ret = k.REQUERY_SUCCESS 436 for child in self._ children:451 for child in self.__children: 437 452 ret = child.requery() 438 453 if not ret == k.REQUERY_SUCCESS: … … 445 460 self.addToErrorMsg(self._cursor.getErrorMsg()) 446 461 447 self.after RequeryAllChildren()462 self.afterChildRequery(ret) 448 463 return ret 449 464 … … 478 493 use this method to create a tuple to be passed to the cursor, where 479 494 it will be used to modify the query using standard printf syntax. """ 480 return None495 return self._params 481 496 482 497 trunk/classes/dCursorMixin.py
r26 r47 15 15 # Holds the dict used for adding new blank records 16 16 _blank = {} 17 # Last executed sql statement 18 lastSQL = "" 19 # Last executed sql params 20 lastParams = None 17 21 18 22 … … 34 38 35 39 40 def execute(self, sql, params=None): 41 """ 42 The idea here is to let the super class do the actual work in retrieving the data. However, 43 many cursor classes can only return row information as a list, not as a dictionary. This 44 method will detect that, and convert the results to a dictionary. 45 """ 46 47 self.superCursor.execute(self, sql, params) 48 49 if self._rows: 50 if type(self._rows[0]) == types.TupleType: 51 # Need to convert each row to a Dict 52 tmpRows = [] 53 # First, get the description property and extract the field names from that 54 fldNames = [] 55 for fld in self.description: 56 fldNames.append(fld[0]) 57 fldcount = len(fldNames) 58 # Now go through each row, and convert it to a dictionary. We will then 59 # add that dictionary to the tmpRows list. When all is done, we will replace 60 # the _rows property with that list of dictionaries 61 for row in self._rows: 62 dic= {} 63 for i in range(0, fldcount-1): 64 dic[fldNames[i]] = row[i] 65 tmpRows.append(dic) 66 self._rows = tuple(tmpRows) 67 68 36 69 def requery(self, params=None): 37 if params is None: 38 sql = self.sql 39 else: 40 sql = self.sql % params 70 self.lastSQL = self.sql 71 self.lastParams = params 41 72 try: 42 self.execute(s ql)73 self.execute(self.sql, params) 43 74 except: 44 75 return k.REQUERY_ERROR … … 49 80 50 81 def setMemento(self): 51 self.addMemento(self.rownumber) 82 if self.rowcount > 0: 83 if (self.rownumber >= 0) and (self.rownumber < self.rowcount): 84 self.addMemento(self.rownumber) 52 85 53 86 … … 55 88 """ Returns the value of the requested field """ 56 89 ret = None 57 if self.rowcount == 0:90 if self.rowcount <= 0: 58 91 self.addToErrorMsg("No records in the data set") 59 92 else: … … 69 102 """ Sets the value of the specified field """ 70 103 ret = 0 71 if self.rowcount == 0:104 if self.rowcount <= 0: 72 105 self.addToErrorMsg("No records in the data set") 73 106 else: … … 79 112 self.addToErrorMsg("Field '" + fld + "' does not exist in the data set") 80 113 return ret 114 115 116 def getRowCount(self): 117 ret = -1 118 if hasattr(self, "rowcount"): 119 ret = self.rowcount 120 return ret 81 121 82 122 … … 130 170 ret = k.FILE_OK 131 171 if self.rowcount > 0: 132 if self.rownumber < (self.rowcount-1): 133 self.rownumber = self.rowcount-1 134 else: 135 ret = k.FILE_EOF 136 self.addToErrorMsg("Already at the end of the data set.") 172 self.rownumber = self.rowcount-1 137 173 else: 138 174 ret = k.FILE_NORECORDS … … 146 182 147 183 # Make sure that there is data to save 148 if self.rowcount == 0:184 if self.rowcount <= 0: 149 185 self.addToErrorMsg("No data to save") 150 186 return k.FILE_CANCEL … … 229 265 230 266 # Make sure that there is data to save 231 if not self.rowcount > 0:267 if not self.rowcount >= 0: 232 268 self.addToErrorMsg("No data to cancel") 233 269 return k.FILE_CANCEL … … 238 274 recs = (self._rows[self.rownumber],) 239 275 240 for i in range(self.rowcount , 0, -1):276 for i in range(self.rowcount-1, 0, -1): 241 277 rec = self._rows[i] 242 278 newrec = rec.has_key(k.CURSOR_NEWFLAG) … … 245 281 ret = self.delete(i) 246 282 else: 247 ret = cancelrow(i)283 ret = self.cancelRow(rec) 248 284 if ret != k.FILE_OK: 249 285 break 250 286 return ret 251 252 253 def delete(self, rownum): 254 ret = k.FILE_OK 287 288 289 def cancelRow(self, rec): 290 mem = rec[k.CURSOR_MEMENTO] 291 diff = mem.makeDiff(rec) 292 if diff: 293 for fld, val in diff.items(): 294 rec[fld] = val 295 return k.FILE_OK 296 297 298 def delete(self, rownum=None): 299 ret = k.FILE_OK 300 301 if rownum is None: 302 # assume that it is the current row that is to be deleted 303 rownum = self.rownumber 304 255 305 rec = self._rows[rownum] 256 306 newrec = rec.has_key(k.CURSOR_NEWFLAG) … … 266 316 res = self.execute(sql) 267 317 268 self.restoreProps(restoreRows=0) 269 if not res: 318 if res: 319 # First, delete the row from the held properties 320 tmprows = list(self.holdrows) 321 del tmprows[rownum] 322 self.holdrows = tuple(tmprows) 323 # Now restore the properties 324 self.restoreProps() 325 else: 270 326 # Nothing was deleted 271 327 ret = FILE_CANCEL 272 328 return ret 273 274 275 def cancelrow(self, rec):276 mem = rec[k.CURSOR_MEMENTO]277 329 278 330 … … 303 355 def setStructure(self): 304 356 import re 305 pat = re.compile(" \s*select\s*.*\s*from\s*.*\s*((?:where\s(.*))+)\s*", re.I | re.M)357 pat = re.compile("(\s*select\s*.*\s*from\s*.*\s*)((?:where\s(.*))+)\s*", re.I | re.M) 306 358 if pat.search(self.sql): 307 359 # There is a WHERE clause. Add the NODATA clause 308 tmpsql = pat.sub(" where 1=0 ", self.sql)360 tmpsql = pat.sub("\\1 where 1=0 ", self.sql) 309 361 else: 310 362 # no WHERE clause. See if it has GROUP BY or ORDER BY clauses 311 pat = re.compile(" \s*select\s*.*\s*from\s*.*\s*((?:group\s*by\s(.*))+)\s*", re.I | re.M)363 pat = re.compile("(\s*select\s*.*\s*from\s*.*\s*)((?:group\s*by\s(.*))+)\s*", re.I | re.M) 312 364 if pat.search(self.sql): 313 tmpsql = pat.sub(" where 1=0 ", self.sql)365 tmpsql = pat.sub("\\1 where 1=0 ", self.sql) 314 366 else: 315 pat = re.compile(" \s*select\s*.*\s*from\s*.*\s*((?:order\s*by\s(.*))+)\s*", re.I | re.M)367 pat = re.compile("(\s*select\s*.*\s*from\s*.*\s*)((?:order\s*by\s(.*))+)\s*", re.I | re.M) 316 368 if pat.search(self.sql): 317 tmpsql = pat.sub(" where 1=0 ", self.sql)369 tmpsql = pat.sub("\\1 where 1=0 ", self.sql) 318 370 else: 319 371 # Nothing. So just tack it on the end. 320 372 tmpsql = sql + " where 1=0 " 321 373 374 # We need to save and restore the cursor properties, since this query will wipe 'em out. 375 self.saveProps() 322 376 self.execute(tmpsql) 377 self.restoreProps() 378 323 379 dscrp = self.description 324 380 for fld in dscrp: … … 333 389 # Int 334 390 _blank[fld] = 0 335 391 392 393 def moveToPK(self, pk): 394 """ Find the record in the result set (if any) whose value in the keyField 395 field matches the passed value. If found, set the current position to that 396 record. If not found, set the position to the first record. """ 397 self.rownumber = 0 398 for i in range(0, len(self._rows)): 399 rec = self._rows[i] 400 if rec[self.keyField] == pk: 401 self.rownumber = i 402 break 403 336 404 337 405 def checkPK(self): … … 382 450 383 451 def saveProps(self, saverows=1): 384 self. tmprows = self._rows385 self. tmpcount = self.rowcount386 self. tmppos = self.rownumber387 self. tmpdesc = self.description388 389 390 def restoreProps(self, restore rows=1):391 if restore rows:392 self._rows = self. tmprows452 self.holdrows = self._rows 453 self.holdcount = self.rowcount 454 self.holdpos = self.rownumber 455 self.holddesc = self.description 456 457 458 def restoreProps(self, restoreRows=1): 459 if restoreRows: 460 self._rows = self.holdrows 393 461 self.rowcount = len(self._rows) 394 self.rownumber = min(self. tmppos, self.rowcount-1)395 self.description = self. tmpdesc462 self.rownumber = min(self.holdpos, self.rowcount-1) 463 self.description = self.holddesc 396 464 397 465 trunk/classes/dMemento.py
r25 r47 17 17 the passed dictionary of values is identical to the current snapshot.""" 18 18 return (self._snapshot != newvals) 19 19 20 20 def makeDiff(self, newvals, newrec):21 def makeDiff(self, newvals, isNewRecord=0): 21 22 """ The idea here is to create a dictionary containing just the values 22 23 that have changed in the newvals dict., as compared to the snapshot. … … 34 35 # OK, if this is a new record, include all the values. Otherwise, just 35 36 # include the changed ones. 36 if newrecor self._snapshot[kk] != vv:37 if isNewRecord or self._snapshot[kk] != vv: 37 38 ret[kk] = vv 38 39 return ret
