/[gnue]/gnue-common/src/datasources/drivers/Base/RecordSet.py
ViewVC logotype

Diff of /gnue-common/src/datasources/drivers/Base/RecordSet.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by jcater, Wed Nov 19 02:07:07 2003 UTC revision 1.2 by jcater, Tue Nov 25 17:01:31 2003 UTC
# Line 0  Line 1 
1    #
2    # This file is part of GNU Enterprise.
3    #
4    # GNU Enterprise is free software; you can redistribute it
5    # and/or modify it under the terms of the GNU General Public
6    # License as published by the Free Software Foundation; either
7    # version 2, or (at your option) any later version.
8    #
9    # GNU Enterprise is distributed in the hope that it will be
10    # useful, but WITHOUT ANY WARRANTY; without even the implied
11    # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12    # PURPOSE. See the GNU General Public License for more details.
13    #
14    # You should have received a copy of the GNU General Public
15    # License along with program; see the file COPYING. If not,
16    # write to the Free Software Foundation, Inc., 59 Temple Place
17    # - Suite 330, Boston, MA 02111-1307, USA.
18    #
19    # Copyright 2000-2003 Free Software Foundation
20    #
21    # FILE:
22    # GConnection.py
23    #
24    # DESCRIPTION:
25    #
26    # NOTES:
27    #
28    
29    __all__ = ['RecordSet']
30    
31    from gnue.common.apps import GDebug
32    from gnue.common.datasources import GConditions, Exceptions
33    import string
34    
35    ###########################################################
36    #
37    #
38    #
39    ###########################################################
40    class RecordSet:
41    
42      def __init__(self, parent, initialData={}, dbIdentifier=None, defaultData={}):
43        self._detailObjects = []
44        self._dbIdentifier = dbIdentifier
45        self._deleteFlag = 0
46        self._updateFlag = 0
47        self._parent = parent
48        self._modifiedFlags = {}      # If field name is present as a key,
49                                      # then field has been modified
50    
51        self._cachedDetailResultSets = {}
52    
53        self._initialData = initialData
54    
55        if self._initialData and len(self._initialData):
56          self._insertFlag = 0
57          self._emptyFlag = 0
58          self._fields = {}
59          self._fields.update(initialData)
60        else:
61          self._insertFlag = 1
62          self._emptyFlag = 1
63          self._fields = {}
64          self._fields.update(defaultData)
65    
66      def __setitem__(self, attr, val):
67        self.setField(attr, val)
68    
69      def __getitem__(self, attr):
70        return self.getField(attr)
71    
72      # Returns 1=Record has uncommitted changes
73      def isPending(self):
74    
75        # The _insertFlag and _deleteFlag takes care of records that
76        # were inserted, but then deleted before a save (i.e., nothing to do)
77        if self._emptyFlag or self._insertFlag and self._deleteFlag:
78          return 0
79        else:
80          return self._insertFlag or self._deleteFlag or self._updateFlag
81    
82    
83      # Returns 1=Record is pending a deletion
84      def isDeleted(self):
85        if self._emptyFlag:
86          return 0
87        else:
88          return self._deleteFlag and not self._insertFlag
89    
90    
91      # Returns 1=Record is pending an update
92      def isModified(self):
93        if self._emptyFlag or self._insertFlag:
94          return 0
95        else:
96          return self._updateFlag
97    
98    
99      # Returns 1=Record is pending an insertion
100      def isInserted(self):
101        if self._emptyFlag:
102          return 0
103        else:
104          return self._insertFlag and not self._deleteFlag
105    
106    
107      # Returns 1=Record is empty (inserted, but no data set)
108      def isEmpty(self):
109        return self._emptyFlag
110    
111    
112      # Returns current value of "field"
113      def getField(self, field):
114        try:
115          return self._fields[field]
116        except KeyError:
117          try:
118    
119            # TODO: When we're confident that
120            # TODO: all field names are lowercase,
121            # TODO: then this can be removed.
122    
123            return self._fields[string.lower(field)]
124          except KeyError:
125            # If a field value has yet to be set
126            # (either from a query or via a setField),
127            # then _fields will not contain a key
128            # for the requested field even though
129            # the field name may still be valid.
130            return None
131    
132    
133      # Sets current value of "field"
134      # If trackMod is set to 0 then the modification flag isn't raised
135      def setField(self, field, value, trackMod = 1):
136        # If this field is bound to a datasource and the datasource is read only,
137        # generate an error.
138        if self._parent.isFieldBound(field) and self._parent.isReadOnly():
139          # Provide better feedback??
140          tmsg = _("Attempted to modify read only field '%s'") % field
141          raise Exceptions.ReadOnlyError, tmsg
142        else:
143          fn = string.lower(field)
144          self._fields[fn] = value
145          if trackMod == 1:
146            if self._parent.isFieldBound(field):
147              self._emptyFlag = 0
148              self._updateFlag = 1
149              self._modifiedFlags[fn] = 1
150    
151              try:
152                self._parent._dataObject._dataSource._onModification(self)
153              except AttributeError:
154                pass
155        return value
156    
157      # Batch mode of above setField method
158      # If trackMod is set to 0 then the modification flag isn't raised
159      def setFields(self, updateDict, trackMod = 1):
160        # If this field is bound to a datasource and the datasource is read only,
161        # generate an error.
162        for field in updateDict.keys():
163          self.setField(field, updateDict[field], trackMod)
164    
165    
166      # Returns 1=Field has been modified
167      def isFieldModified(self, fieldName):
168        if self._modifiedFlags.has_key (fieldName):
169          return 1
170        else:
171          #TODO: the string.lower() line should never be called but is left here
172          #TODO: until the code is clean
173          return self._modifiedFlags.has_key (string.lower(fieldName))
174    
175    
176      # Mark the current record as deleted
177      def delete(self):
178        if self._parent.isReadOnly():
179          # Provide better feedback??
180          tmsg = _("Attempted to delete from a read only datasource")
181          raise Exceptions.ReadOnlyError, tmsg
182        else:
183          self._deleteFlag = 1
184    
185    
186      # Posts changes to database
187      def post(self):
188        # Should a post() to a read only datasource cause a ReadOnlyError?
189        # It does no harm to attempt to post since nothing will be posted,
190        # But does this allow sloppy programming?
191    
192        GDebug.printMesg(5,'Preparing to post datasource %s' %  self._parent._dataObject.name)
193    
194        # Save the initial status so we know if any triggers changed us
195        status = (self._insertFlag, self._deleteFlag, self._updateFlag)
196    
197        # Call the hooks for commit-level hooks
198        if not self._emptyFlag and hasattr(self._parent._dataObject,'_dataSource'):
199    
200          if self._insertFlag and not self._deleteFlag:
201            self._parent._dataObject._dataSource._beforeCommitInsert(self)
202          elif self._deleteFlag and not self._insertFlag:
203            self._parent._dataObject._dataSource._beforeCommitDelete(self)
204          elif self._updateFlag:
205            self._parent._dataObject._dataSource._beforeCommitUpdate(self)
206    
207        #
208        # If the record status changed while we were doing the triggers,
209        # start from the beginning and run the triggers again.
210        #
211        if status != (self._insertFlag, self._deleteFlag, self._updateFlag):
212          self.post()
213          return
214    
215    
216        if self.isPending():
217          GDebug.printMesg(5,'Posting datasource %s' % self._parent._dataObject.name)
218    
219          if self.isPending():
220            self._postChanges()
221    
222    
223        # Post all detail records
224        for child in (self._cachedDetailResultSets.keys()):
225          c = self._cachedDetailResultSets[child]._dataObject
226          # Set the primary key for any new child records
227          fk = {}
228          for i in range(len(c._masterfields)):
229            fk[c._detailfields[i]] = self.getField(c._masterfields[i])
230    
231          self._cachedDetailResultSets[child].post(foreign_keys=fk)
232    
233    
234      # Sets the ResultSet associated with this master record
235      def addDetailResultSet(self, resultSet):
236        self._cachedDetailResultSets[resultSet._dataObject] = resultSet
237    
238    
239      ###
240      ### Methods below should be over-written by Vendor Specific functions
241      ###
242    
243      # Post any changes to database
244      def _postChanges(self):
245        return 1
246    

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26