[Top][All Lists]
[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]
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- r6489 - in trunk: gnue-appserver/src gnue-common/src/datasources/drivers/Base gnue-common/src/datasources/drivers/appserver/appserver,
johannes <=