[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnue] r7475 - trunk/gnue-common/src/datasources/drivers/Base
From: |
reinhard |
Subject: |
[gnue] r7475 - trunk/gnue-common/src/datasources/drivers/Base |
Date: |
Sat, 23 Apr 2005 08:57:14 -0500 (CDT) |
Author: reinhard
Date: 2005-04-23 08:57:13 -0500 (Sat, 23 Apr 2005)
New Revision: 7475
Modified:
trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py
Log:
Some cleanup and docstrings.
Modified: trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py 2005-04-23
13:05:56 UTC (rev 7474)
+++ trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py 2005-04-23
13:57:13 UTC (rev 7475)
@@ -21,7 +21,9 @@
#
# $Id$
-import string
+"""
+RecordSet class used by all database driver plugins.
+"""
from gnue.common.apps import errors
from gnue.common.datasources import Exceptions
@@ -32,7 +34,32 @@
# =============================================================================
class RecordSet:
+ """
+ Representation of a database record.
+ A RecordSet instance encapsulates a database record. Field values can be read
+ and written, and the RecordSet keeps track of which fields have been changed.
+ When the L{post} method is called, the RecordSet uses the assigned
+ L{Connection} object to store the changes in the backend. After L{post} has
+ been called, L{requery} should be called subsequently to make sure that the
+ RecordSet can requery all its field values from the database in case a server
+ side trigger has changed any of the fields. The L{post} and L{requery}
+ methods are separated so a caller can call the Connection's commit method in
+ between.
+
+ If the RecordSet is the detail in a master/detail relationship, it is aware
+ of its master record and makes sure that its foreign key fields are set to
+ the values from the master's primary key fields before inserting a new record
+ into the database backend, even if the master's primary key fields have
+ changed since the RecordSet instance was created (for example, because the
+ master record's primary key was set in an OnInsert database trigger).
+
+ If the RecordSet is the master in a master/detail relationship, it is aware
+ of all its details. It will notify all its detail L{DataSource} objects
+ whenever it has become the current record, and it posts/requeries all detail
+ L{ResultSet} objects after posting/requerying its own data.
+ """
+
# ---------------------------------------------------------------------------
# Constructor
# ---------------------------------------------------------------------------
@@ -113,7 +140,7 @@
self.__modifiedFlags = {}
# The detail ResultSets where this record is the master
- self._cachedDetailResultSets = {}
+ self.__cachedDetailResultSets = {}
# All field names that are used to link detail records (i.e. all fieldnames
# that appear as masterfield in any of my detail result sets)
@@ -126,9 +153,7 @@
# Existing record:
# Set the current state of all fields as given in the parameter
- for (field, value) in initialData.items ():
- self.__fields [field] = value
-
+ self.__fields = self.__initialData.copy ()
if self.__dataSource is not None:
self.__dataSource._onRecordLoaded (self)
@@ -143,7 +168,19 @@
for field in self.__boundFields:
self.__fields [field] = None
- # 3. Get default values from driver (e.g. initialize primary keys)
+ # 3. Get default values from driver - here the appserver dbdriver
+ # requests a new gnue_id and runs OnInit on server side.
+ # Note that the fields returned from initialize (i.e. the gnue_id) are
+ # considered dirty, this is necessary so the appserver dbdriver
+ # includes them in the store call when executing the insert.
+ # TODO: Consider this cleaner solution: Connection.initialize takes a
+ # second parameter with a field list, does the necessary requery itself,
+ # and returns all fields with their new values. All those fields are
+ # considered non-dirty and then, simply all primarykeyFields could be set
+ # as dirty for new records. If the Base Connection._initialize returns a
+ # dictionary with None for every field given, the call to
+ # Connection.initialize fully replaces steps 2., 3., and 4. except for
+ # the case that self.__connection is None.
if self.__connection:
defaults = self.__connection.initialize (self.__tablename)
for (fieldname, value) in defaults.items ():
@@ -152,8 +189,8 @@
# 4. Query current data from the backend, if the primary key was
# initialized above. This is used for appserver to retrieve the
# result of OnInit.
- # TODO: Meanwhile I think it would be better to put this into appserver's
- # Connection.initialize (and pass boundFields to that method).
+ # Note that the fields we get from this requery are *not* considered
+ # dirty.
if self.__primarykeyFields:
primarykeyIsComplete = True
for fieldname in self.__primarykeyFields:
@@ -162,7 +199,7 @@
break
if primarykeyIsComplete:
self.__initialData = self.__fields.copy ()
- self.requery ()
+ self.__do_requery ()
# 5. Get default values from DataSource. This has to be done after the
# requery, as these changes remain local until the first post.
@@ -336,7 +373,7 @@
def __hasPendingChildren (self):
- for child in self._cachedDetailResultSets.values ():
+ for child in self.__cachedDetailResultSets.values ():
if child.isPending ():
return True
return False
@@ -414,14 +451,14 @@
if self.__status == 'deleted':
self.__dataSource._beforeCommitDelete (self)
- # Check for empty primary key and set with the sequence value if so
- if self.__status in ['empty', 'inserted']:
- if len (self.__primarykeyFields) == 1 and \
- self.getField (self.__primarykeyFields [0]) is None and \
- self.__primarykeySeq is not None and \
- hasattr (self.__connection, 'getsequence'):
- pk = self.__connection.getsequence (self.__primarykeySeq)
- self.setField (self.__primarykeyFields [0], pk)
+ # Check for empty primary key and set with the sequence value if so
+ if self.__status in ['empty', 'inserted']:
+ if len (self.__primarykeyFields) == 1 and \
+ self.getField (self.__primarykeyFields [0]) is None and \
+ self.__primarykeySeq is not None and \
+ hasattr (self.__connection, 'getsequence'):
+ pk = self.__connection.getsequence (self.__primarykeySeq)
+ self.setField (self.__primarykeyFields [0], pk)
# If we have a connection (i.e. we aren't static or unbound), do the post
if self.__connection is not None:
@@ -455,7 +492,7 @@
self.__initialData = self.__fields.copy ()
# Post all detail records
- for child in (self._cachedDetailResultSets.values ()):
+ for child in (self.__cachedDetailResultSets.values ()):
child.post ()
@@ -477,7 +514,7 @@
self.__do_requery (self.__boundFields)
# Now, requery detail resultsets
- for (dataSource, resultSet) in self._cachedDetailResultSets.items ():
+ for (dataSource, resultSet) in self.__cachedDetailResultSets.items ():
dataSource._requeryResultSet (self, resultSet)
@@ -519,8 +556,8 @@
"""
# If we already have it in our cache, return it
- if self._cachedDetailResultSets.has_key (dataSource):
- resultset = self._cachedDetailResultSets [dataSource]
+ if self.__cachedDetailResultSets.has_key (dataSource):
+ resultset = self.__cachedDetailResultSets [dataSource]
if resultset.isPending () or int (gConfig ('CacheDetailRecords')):
dataSource._activateResultSet (resultset)
return resultset
@@ -533,7 +570,7 @@
resultset = dataSource.createResultSet (masterRecord = self)
# Remember it
- self._cachedDetailResultSets [dataSource] = resultset
+ self.__cachedDetailResultSets [dataSource] = resultset
# Remember the fields that serve as primary key for this master/detail link
for fieldname in fieldnames:
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gnue] r7475 - trunk/gnue-common/src/datasources/drivers/Base,
reinhard <=