commit-gnue
[Top][All Lists]
Advanced

[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:





reply via email to

[Prev in Thread] Current Thread [Next in Thread]