commit-gnue
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

r6489 - in trunk: gnue-appserver/src gnue-common/src/datasources/drivers


From: johannes
Subject: r6489 - in trunk: gnue-appserver/src gnue-common/src/datasources/drivers/Base gnue-common/src/datasources/drivers/appserver/appserver
Date: Wed, 13 Oct 2004 01:38:10 -0500 (CDT)

Author: johannes
Date: 2004-10-13 01:38:06 -0500 (Wed, 13 Oct 2004)
New Revision: 6489

Modified:
   trunk/gnue-appserver/src/data.py
   trunk/gnue-appserver/src/geasInstance.py
   trunk/gnue-appserver/src/geasSession.py
   trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py
   trunk/gnue-common/src/datasources/drivers/appserver/appserver/RecordSet.py
Log:
Made OnInit-triggers functional


Modified: trunk/gnue-appserver/src/data.py
===================================================================
--- trunk/gnue-appserver/src/data.py    2004-10-13 01:05:16 UTC (rev 6488)
+++ trunk/gnue-appserver/src/data.py    2004-10-13 06:38:06 UTC (rev 6489)
@@ -27,8 +27,17 @@
 import whrandom
 import copy
 
+from gnue.common.apps import errors
 from gnue.common.datasources import GDataSource, GConditions, GConnections
 
+class StateChangeError (errors.SystemError):
+  def __init__ (self, table, row):
+    msg = u_("Changing state from 'commitable' to 'initialized' not allowed "
+             "in table '%(table)s' row %(row)s") \
+          % {'table': table, 'row': row}
+    errors.SystemError.__init__ (self, msg)
+
+
 # =============================================================================
 # Cache class
 # =============================================================================
@@ -53,8 +62,9 @@
   # ---------------------------------------------------------------------------
 
   def __init__ (self):
-    self.__old = {}                     # Original data
-    self.__new = {}                     # Changed (dirty) data
+    self.__old   = {}                     # Original data
+    self.__new   = {}                     # Changed (dirty) data
+    self.__state = {}                     # State of the data
 
   # ---------------------------------------------------------------------------
   # Store data in the cache
@@ -89,6 +99,15 @@
 
     fields [field] = value
 
+    # Update state information of the row
+    if self.rowState (table, row) is None:
+      self.__setState (table, row, 'initializing')
+
+    if dirty and self.rowState (table, row) == 'initialized':
+      self.__setState (table, row, 'commitable')
+
+
+
   # ---------------------------------------------------------------------------
   # Return whether a certain value is stored in the clean/dirty cache
   # ---------------------------------------------------------------------------
@@ -223,9 +242,68 @@
     Forget all data in the cache, original values as well as dirty values.
     """
 
-    self.__old = {}
-    self.__new = {}
+    self.__old   = {}
+    self.__new   = {}
+    self.__state = {}
 
+
+  # ---------------------------------------------------------------------------
+  # Update the state information of a given row
+  # ---------------------------------------------------------------------------
+
+  def initialized (self, table, row):
+    """
+    This function sets a row of a table to 'initialized'. This means the next
+    write () to this table makes this row 'commitable'
+    """
+
+    checktype (table, UnicodeType)
+    checktype (row, UnicodeType)
+
+    cState = self.rowState (table, row)
+    if cState is not None and cState == 'commitable':
+      raise StateChangeError, (table, row)
+
+    self.__setState (table, row, 'initialized')
+
+
+  # ---------------------------------------------------------------------------
+  # Create state information for a given table/row
+  # ---------------------------------------------------------------------------
+
+  def __setState (self, table, row, state):
+    """
+    """
+
+    checktype (table, UnicodeType)
+    checktype (row, UnicodeType)
+
+    if not self.__state.has_key (table):
+      self.__state [table] = {}
+
+    rows = self.__state [table]
+    rows [row] = state
+
+
+  # ---------------------------------------------------------------------------
+  # Return the current state of a row 
+  # ---------------------------------------------------------------------------
+
+  def rowState (self, table, row):
+    """
+    This function returns the current state of a row
+    """
+
+    checktype (table, UnicodeType)
+    checktype (row, UnicodeType)
+
+    if self.__state.has_key (table) and self.__state [table].has_key (row):
+      return self.__state [table] [row]
+
+    else:
+      return None
+
+
 # =============================================================================
 # Helper methods
 # =============================================================================
@@ -303,8 +381,17 @@
 
   datasource = _createDatasource (connections, database, content, order)
 
-  return datasource.createResultSet (conditions)
+  if isinstance (conditions, ListType):
+    cTree = GConditions.buildTreeFromList (conditions)
 
+  elif isinstance (conditions, DictType):
+    cTree = GConditions.buildTreeFromDict (conditions)
+
+  else:
+    cTree = conditions
+
+  return datasource.createResultSet (cTree)
+
 # -----------------------------------------------------------------------------
 # Create a result set containing only one row, identified by the gnue_id
 # -----------------------------------------------------------------------------
@@ -482,17 +569,17 @@
       if not self.__cache.has (table, row, field):
         uncachedFields.append(field)
 
-    if uncachedFields == []:
+    if uncachedFields == [] or self.__cache.status (table, row) == 'inserted':
       # already cached, no need to load from database
       r = record (self.__cache, self.__connections, self.__database, table, 
row)
     else:
       # not yet cached, need to load from database
       resultSet = _find (self.__connections, self.__database, table, row,
-                         fields)
+                         uncachedFields)
       if resultSet.current is None:
         return None
       r = record (self.__cache, self.__connections, self.__database, table, 
row)
-      r._fill (None, fields, resultSet.current)
+      r._fill (None, uncachedFields, resultSet.current)
     return r
 
   # ---------------------------------------------------------------------------
@@ -509,16 +596,17 @@
 
     # first perform all inserts
     for (table, row) in self.__inserted:
-      fields = tables [table] [row]
-      resultSet = _createEmptyResultSet (self.__connections,
-                                         self.__database,
-                                         table, fields.keys ())
-      resultSet.insertRecord ()
+      if self.__cache.rowState (table, row) == 'commitable':
+        fields = tables [table] [row]
+        resultSet = _createEmptyResultSet (self.__connections,
+                                           self.__database,
+                                           table, fields.keys ())
+        resultSet.insertRecord ()
 
-      for (field, value) in fields.items ():
-         resultSet.current.setField (field, value)
+        for (field, value) in fields.items ():
+           resultSet.current.setField (field, value)
 
-      resultSet.post ()
+        resultSet.post ()
 
     self.__inserted         = []
     self.__confirmedInserts = []
@@ -751,11 +839,11 @@
 
   def __init__ (self, cache, connections, database, table, row):
 
-    self.__cache = cache
+    self.__cache       = cache
     self.__connections = connections
-    self.__database = database
-    self.__table = table
-    self.__row = row
+    self.__database    = database
+    self.__table       = table
+    self.__row         = row
 
   # ---------------------------------------------------------------------------
   # Cache a single value for this record
@@ -824,6 +912,24 @@
 
     self.__cache.write (self.__table, self.__row, field, value, 1)
 
+
+  # ---------------------------------------------------------------------------
+  # Set this record to initialized state
+  # ---------------------------------------------------------------------------
+
+  def initialized (self):
+    """
+    This function marks this record as 'initialized' so following changes will
+    make it commitable.
+    """
+
+    self.__cache.initialized (self.__table, self.__row)
+
+  def status (self):
+    return self.__cache.status (self.__table, self.__row)
+
+
+
 # =============================================================================
 # Self test code
 # =============================================================================
@@ -874,6 +980,7 @@
 
   print 'connection.insertRecord ...',
   r = c.insertRecord (u'address_person')
+  r.initialized ()
   print 'Ok'
 
   print 'record.getField ...',

Modified: trunk/gnue-appserver/src/geasInstance.py
===================================================================
--- trunk/gnue-appserver/src/geasInstance.py    2004-10-13 01:05:16 UTC (rev 
6488)
+++ trunk/gnue-appserver/src/geasInstance.py    2004-10-13 06:38:06 UTC (rev 
6489)
@@ -383,7 +383,15 @@
   # Update instance-stamps (creation- or modification-date/user )
   # ---------------------------------------------------------------------------
 
-  def updateStamp (self, creation = False):
+  def updateStamp (self):
+    if self.__record.status () == 'inserted':
+      creation = True
+    elif self.__record.status () == 'changed':
+      creation = False
+
+    else:
+      return
+
     (datefield, userfield) = [('gnue_modifydate', 'gnue_modifyuser'),
                               ('gnue_createdate', 'gnue_createuser')][creation]
     if self.has_key (datefield):
@@ -391,4 +399,3 @@
 
     if self.has_key (userfield) and self.__session.user is not None:
       self.__putValue (userfield, self.__session.user, False)
-

Modified: trunk/gnue-appserver/src/geasSession.py
===================================================================
--- trunk/gnue-appserver/src/geasSession.py     2004-10-13 01:05:16 UTC (rev 
6488)
+++ trunk/gnue-appserver/src/geasSession.py     2004-10-13 06:38:06 UTC (rev 
6489)
@@ -412,6 +412,8 @@
     instance = geasInstance.geasInstance (self, self.__connection, record,
                                           classdef)
 
+    instance.updateStamp ()
+
     onInits = {}
     for proc in classdef.procedures.values ():
       if proc.gnue_name.upper () == 'ONINIT':
@@ -424,6 +426,9 @@
     for proc in onInits.values ():
       instance.call (proc, None)
 
+    # all modifications are 'serious' from now on 
+    record.initialized ()
+
     return instance
 
   # ---------------------------------------------------------------------------
@@ -468,14 +473,14 @@
         if object_id:
           instance = self.__findInstance (classdef, object_id, [])
           new_object_id = object_id
-          created = False
         else:
           instance = self.__newInstance (classdef)
           new_object_id = instance.get ([u'gnue_id']) [0]
-          created = True
 
         instance.put (propertylist, data [i])
-        instance.updateStamp (created)
+        if object_id:
+          # TODO: this update of mod-stamps could be moved into data.py ?!
+          instance.updateStamp ()
 
         i += 1
         result.append (new_object_id)

Modified: trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py 2004-10-13 
01:05:16 UTC (rev 6488)
+++ trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py 2004-10-13 
06:38:06 UTC (rev 6489)
@@ -1,6 +1,9 @@
+# GNU Enterprise Common - Database Drivers - Base Record Set
 #
-# This file is part of GNU Enterprise.
+# Copyright 2001-2004 Free Software Foundation
 #
+# This file is part of GNU Enterprise
+#
 # GNU Enterprise is free software; you can redistribute it
 # and/or modify it under the terms of the GNU General Public
 # License as published by the Free Software Foundation; either
@@ -16,37 +19,32 @@
 # write to the Free Software Foundation, Inc., 59 Temple Place
 # - Suite 330, Boston, MA 02111-1307, USA.
 #
-# Copyright 2000-2004 Free Software Foundation
-#
-# FILE:
-# GConnection.py
-#
-# DESCRIPTION:
-#
-# NOTES:
-#
-# $Id :$
+# $Id$
 
 __all__ = ['RecordSet']
 
-from gnue.common.apps import GDebug
+from gnue.common.apps import errors
 from gnue.common.datasources import GConditions, Exceptions
 import string
 
-###########################################################
-#
-#
-#
-###########################################################
+# =============================================================================
+# This class implements the basic record set
+# =============================================================================
+
 class RecordSet:
 
-  def __init__(self, parent, initialData={}, dbIdentifier=None, 
defaultData={}):
+  # --------------------------------------------------------------------------
+  # Constructor
+  # --------------------------------------------------------------------------
+
+  def __init__ (self, parent, initialData = {}, dbIdentifier = None,
+                defaultData = {}):
     self._detailObjects = []
-    self._dbIdentifier = dbIdentifier
-    self._deleteFlag = False
-    self._updateFlag = False
-    self._parent = parent
-    self._fieldOrder = {}
+    self._dbIdentifier  = dbIdentifier
+    self._deleteFlag    = False
+    self._updateFlag    = False
+    self._parent        = parent
+    self._fieldOrder    = {}
     self._modifiedFlags = {}      # If field name is present as a key,
                                   # then field has been modified
 
@@ -54,40 +52,40 @@
 
     self._initialData = initialData
 
-    if self._initialData and len(self._initialData):
+    if self._initialData and len (self._initialData):
       self._insertFlag = False
-      self._emptyFlag = False
-      self._fields = {}
-      self._fields.update(initialData)
+      self._emptyFlag  = False
+      self._fields     = {}
+      self._fields.update (initialData)
     else:
       self._insertFlag = True
-      self._emptyFlag = True
-      self._fields = {}
-      self._fields.update(defaultData)
+      self._emptyFlag  = True
+      self._fields     = {}
+      self._fields.update (defaultData)
 
     gDebug (3, "Initial Data: %s" % self._fields)
 
+
   # ===========================================================================
   # Dictionary emulation
   # ===========================================================================
   def __setitem__(self, attr, val):
-    gDebug (4, "setField from __setitem__: %s (%s)" % (attr, val))
-    self.setField(attr, val)
+    self.setField (attr, val)
 
-  def __getitem__(self, attr):
-    return self.getField(attr)
+  def __getitem__ (self, attr):
+    return self.getField (attr)
   
-  def keys(self):
-    return self._fields.keys()
+  def keys (self):
+    return self._fields.keys ()
   
-  def values(self):
-    return self._fields.values()
+  def values (self):
+    return self._fields.values ()
 
-  def items(self):
-    return self._fields.items()
+  def items (self):
+    return self._fields.items ()
     
   # Returns 1=Record has uncommitted changes
-  def isPending(self):
+  def isPending (self):
 
     # The _insertFlag and _deleteFlag takes care of records that
     # were inserted, but then deleted before a save (i.e., nothing to do)
@@ -230,12 +228,13 @@
 
 
   # Posts changes to database
-  def post(self, recordNumber=None):
+  def post (self, recordNumber = None):
     # Should a post() to a read only datasource cause a ReadOnlyError?
     # It does no harm to attempt to post since nothing will be posted,
     # But does this allow sloppy programming?
 
-    GDebug.printMesg(5,'Preparing to post datasource %s' %  
self._parent._dataObject.name)
+    gDebug (5, 'Preparing to post datasource %s' \
+               % self._parent._dataObject.name)
 
     # Save the initial status so we know if any triggers changed us
     status = (self._insertFlag, self._deleteFlag, self._updateFlag)
@@ -260,7 +259,7 @@
 
 
     if self.isPending():
-      GDebug.printMesg(5,'Posting datasource %s' % 
self._parent._dataObject.name)
+      gDebug (5, 'Posting datasource %s' % self._parent._dataObject.name)
 
       if self.isPending():
         self._postChanges(recordNumber)
@@ -301,20 +300,23 @@
     if self._deleteFlag:
       self._postDelete ()
 
-    elif self._insertFlag:
-      self._postInsert (self._fields)
-
-    elif self._updateFlag:
+    elif self._insertFlag or self._updateFlag:
       modifiedFields = {}
-      for field in (self._modifiedFlags.keys ()):
+      for field in self._modifiedFlags.keys ():
         modifiedFields [field] = self._fields [field]
-      self._postUpdate (modifiedFields)
+
+      if self._insertFlag:
+        self._postInsert (modifiedFields)
+      else:
+        self._postUpdate (modifiedFields)
+
       self._modifiedFlags = {}
 
     self._deleteFlag = False
     self._insertFlag = False
     self._updateFlag = False
 
+
   def _postDelete (self):
     """
     Post a deletion to the backend. Descendants should override this function


Property changes on: trunk/gnue-common/src/datasources/drivers/Base/RecordSet.py
___________________________________________________________________
Name: svn:keywords
   - +Id
   + Id

Modified: 
trunk/gnue-common/src/datasources/drivers/appserver/appserver/RecordSet.py
===================================================================
--- trunk/gnue-common/src/datasources/drivers/appserver/appserver/RecordSet.py  
2004-10-13 01:05:16 UTC (rev 6488)
+++ trunk/gnue-common/src/datasources/drivers/appserver/appserver/RecordSet.py  
2004-10-13 06:38:06 UTC (rev 6489)
@@ -33,6 +33,7 @@
   """
   Handles a record (i.e. an instance) in the GNUe-AppServer backend.
   """
+
   # ---------------------------------------------------------------------------
   # Initialization
   # ---------------------------------------------------------------------------
@@ -41,15 +42,22 @@
 
     Base.RecordSet.__init__ (self, parent, initialData = initialData)
 
-    self.__sm = sm
+    self.__sm         = sm
     self.__session_id = session_id
-    self.__classname = classname
+    self.__classname  = classname
 
+    if not self._fields.has_key ('gnue_id'):
+      self.__initRecord ()
+
+
   # ---------------------------------------------------------------------------
   # Delete
   # ---------------------------------------------------------------------------
 
   def _postDelete (self):
+    """
+    This function deletes the current record.
+    """
 
     self.__sm.delete (self.__session_id,
                       self.__classname,
@@ -60,48 +68,45 @@
   # ---------------------------------------------------------------------------
 
   def _postInsert (self, fields):
+    """
+    This function updates the current record with the given fields.
 
-    self._fields ['gnue_id'] = self.__sm.store (self.__session_id,
-                                                self.__classname,
-                                                [None],
-                                                fields.keys (),
-                                                [fields.values ()]) [0]
-    self._updateRecord ()
+    @param fields: dictionary with the new fields and their values
+    """
 
+    self.__updateRecord (fields)
 
+
   # ---------------------------------------------------------------------------
   # Update
   # ---------------------------------------------------------------------------
 
   def _postUpdate (self, fields):
+    """
+    This function updates the current reocrd with the given fields.
 
-    self.__sm.store (self.__session_id,
-                     self.__classname,
-                     [self._fields ['gnue_id']],
-                     fields.keys (),
-                     [fields.values ()])
-    self._updateRecord ()
+    @param fields: dictionary with the new fields and their values
+    """
 
-  # ---------------------------------------------------------------------------
-  # Update all fields of a record after update/inserts
-  # ---------------------------------------------------------------------------
+    self.__updateRecord (fields)
 
-  def _updateRecord (self):
-    propertylist = self._fields.keys ()
-    res = self.__sm.load (self.__session_id, self.__classname,
-                          [self._fields ['gnue_id']], propertylist)
 
-    for ix in range (0, len (propertylist)):
-      self._fields [propertylist [ix]] = res [0][ix]
-
-
   # ---------------------------------------------------------------------------
   # Call a server-side function
   # ---------------------------------------------------------------------------
 
   def callFunc (self, methodname, parameters):
+    """
+    This function calls a procedure of the current record (object). All pending
+    changes of the record will be posted first.
 
-    if self.isEmpty ():
+    @param methodname: name of the procedure to be called
+    @param parameters: dictionary with parameters for the procedure
+
+    @return: return value of the procedure
+    """
+
+    if self._fields.get ('gnue_id') is None:
       raise errors.ApplicationError, u_("Function call for empty record")
 
     # Before calling the function, post all pending changes to the server
@@ -112,3 +117,64 @@
                            [self._fields ['gnue_id']],
                            methodname,
                            parameters) [0]
+
+
+  # ---------------------------------------------------------------------------
+  # Initialize a record 
+  # ---------------------------------------------------------------------------
+
+  def __initRecord (self):
+    """
+    This function creates a new instance of a record and loads all fields from
+    the backend. The store () creates a new gnue_id, calls all OnInit-triggers
+    of the class and loads all fields afterwards, where the state of the record
+    is still 'clean'.
+    """
+
+    self._fields ['gnue_id'] = self.__sm.store (self.__session_id,
+                                                self.__classname,
+                                                [None], [], [[]]) [0]
+    for field in self._parent._dataObject._fieldReferences.keys ():
+      self._fields [field] = None
+
+    self.__updateFields ()
+
+
+  # ---------------------------------------------------------------------------
+  # Update a record with the given fields
+  # ---------------------------------------------------------------------------
+
+  def __updateRecord (self, fields):
+    """
+    This function updates the record with the given fields dictionary where the
+    keys are the field names and the values are the field values. After calling
+    the store () function all fields will be reloaded so implicit changes will
+    be reflected in the _fields-dictionary.
+
+    @param fields: dictionary with fields (name = key, data = value)
+    """
+
+    self.__sm.store (self.__session_id,
+                     self.__classname,
+                     [self._fields ['gnue_id']],
+                     fields.keys (),
+                     [fields.values ()])
+    self.__updateFields ()
+
+
+  # ---------------------------------------------------------------------------
+  # Update all fields of a record after update/inserts
+  # ---------------------------------------------------------------------------
+
+  def __updateFields (self):
+    """
+    This function loads all fields from the backend and updates the record's
+    _field dictionary with the new values.
+    """
+
+    propertylist = self._fields.keys ()
+    res = self.__sm.load (self.__session_id, self.__classname,
+                          [self._fields ['gnue_id']], propertylist)
+
+    for ix in range (0, len (propertylist)):
+      self._fields [propertylist [ix]] = res [0][ix]





reply via email to

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