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

Diff of /gnue-common/src/datasources/drivers/Base/ResultSet.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    # ResultSet.py
23    #
24    # DESCRIPTION:
25    #
26    # NOTES:
27    #
28    
29    __all__ = ['ResultSet']
30    
31    from gnue.common.apps import GDebug
32    from gnue.common.datasources import GConditions, Exceptions
33    import string
34    
35    from RecordSet import RecordSet
36    
37    ###########################################################
38    #
39    #
40    #
41    ###########################################################
42    class ResultSet:
43    
44      _recordSetClass = RecordSet
45    
46      def __init__(self, dataObject, cursor=None,defaultValues={},masterRecordSet=None):
47         self._dataObject = dataObject
48         self._cursor = cursor
49         self._cachedRecords = []
50         self._currentRecord = -1
51         self._masterRecordSet = masterRecordSet
52         self._readonly = 0
53         self._recordCount = 0
54         self._postingRecord = None
55    
56         self._defaultValues = {}
57         self._defaultValues.update(defaultValues)
58    
59         self.current = None
60    
61         if masterRecordSet:
62           masterRecordSet.addDetailResultSet(self)
63    
64      # Since we are overriding __len__
65      def __nonzero__(self):
66        return 1
67    
68      # Return the # of records
69      def __len__(self):
70        return self.getRecordCount()
71    
72      def __getitem__(self, index):
73        rs = self.getRecord(index)
74        if not rs:
75          raise IndexError
76        else:
77          return rs
78    
79    
80      # Returns whether this result set is read only or not
81      def isReadOnly(self):
82        return self._readonly
83    
84    
85      # Returns 1=At first record, 0=Not first record
86      def isFirstRecord(self):
87        return (self._currentRecord == 0)
88    
89    
90      # Returns 1=At last record, 0=Not last record
91      def isLastRecord(self):
92        if self._currentRecord < len(self._cachedRecords) - 1 or \
93           self._cacheNextRecord():
94          return 0
95        else:
96          return 1
97    
98    
99      # returns -1=No records in memory, #=Current record #
100      def getRecordNumber(self):
101        return self._currentRecord
102    
103    
104      # returns # of records currently loaded
105      def getCacheCount(self):
106        return len(self._cachedRecords)
107    
108      # returns # of records the
109      def getRecordCount(self):
110        return self._recordCount  > 0 and self._recordCount or self.getCacheCount()
111    
112      # Get a specific record (0=based)
113      def getRecord(self, record):
114        while (record + 1 > len(self._cachedRecords)) and self._cacheNextRecord():
115          pass
116    
117        if record + 1 > len(self._cachedRecords):
118          return None
119        else:
120          return self._cachedRecords[record]
121    
122    
123      # move to record #, returns 1=New record loaded, 0=invalid #
124      def setRecord(self, record):
125    
126        while (record > len(self._cachedRecords) -1) and self._cacheNextRecord():
127          pass
128    
129        if record >= len(self._cachedRecords):
130          return None
131        else:
132          self._currentRecord = record
133          self.current = self._cachedRecords[self._currentRecord]
134          self.notifyDetailObjects()
135          return self.current
136    
137      # returns 1=New record loaded, 0=No more records
138      def nextRecord(self):
139        if self._currentRecord + 1 == len(self._cachedRecords):
140          if not self._cacheNextRecord():
141            return None
142    
143        self._currentRecord += 1
144        self.current = self._cachedRecords[self._currentRecord]
145        self.notifyDetailObjects()
146        return self.current
147    
148    
149      # returns 1=New record loaded, 0=At first record
150      def prevRecord(self):
151        if self._currentRecord < 1:
152          return None
153        else:
154          self._currentRecord -= 1
155          self.current = self._cachedRecords[self._currentRecord]
156          self.notifyDetailObjects()
157          return self.current
158    
159    
160      # returns 1=at first record, 0=No records loaded
161      def firstRecord(self):
162        if self._currentRecord < 0:
163          if not self._cacheNextRecord():
164            return None
165    
166        self._currentRecord = 0
167        self.current = self._cachedRecords[0]
168        self.notifyDetailObjects()
169        return self.current
170    
171    
172    
173      # returns 1=at last record, 0=No records loaded
174      def lastRecord(self):
175        if self._currentRecord == -1:
176          return None
177        else:
178          while self._cacheNextRecord():
179            pass
180          self._currentRecord = len(self._cachedRecords) - 1
181          self.current = self._cachedRecords[self._currentRecord]
182          self.notifyDetailObjects()
183          return self.current
184    
185    
186    
187      # Insert a blank record after the current record
188      def insertRecord(self):
189        if self.isReadOnly():
190          # Provide better feedback??
191          tmsg =  _("Attempted to insert into a read only datasource")
192          raise Exceptions.ReadOnlyError, tmsg
193        else:
194          GDebug.printMesg(7,'Inserting a blank record')
195          self._currentRecord += 1
196          self._cachedRecords.insert(self._currentRecord, self._createEmptyRecord())
197          self._recordCount += 1
198          self.current = self._cachedRecords[self._currentRecord]
199    
200          # Set any dataobject-wide default values
201          for field in self._dataObject._defaultValues.keys():
202            self.current.setField(field, self._dataObject._defaultValues[field],0)
203    
204          # Set any resultset specific values
205          for field in self._defaultValues.keys():
206            self.current.setField(field, self._defaultValues[field],0)
207    
208          # Pull any primary keys from a master record set
209          if self._masterRecordSet != None and hasattr(self._dataObject, '_masterfields'):
210            i = 0
211            for field in self._dataObject._masterfields:
212              self.current.setField(self._dataObject._detailfields[i],self._masterRecordSet.getField(field),0)
213              i += 1
214    
215          self.notifyDetailObjects()
216          return self.current
217    
218    
219      # Returns 1=DataObject, or a detail resultset, has uncommitted changes
220      def isPending(self):
221        for rec in (self._cachedRecords):
222          if rec.isPending():
223            return 1
224          else:
225            for detail in rec._cachedDetailResultSets.values():
226              if detail.isPending():
227                return 1
228        return 0
229    
230    
231      # Returns 1=DataObject has uncommitted changes
232      def isRecordPending(self):
233        return self.current.isPending()
234    
235    
236      def getPostingRecordset(self):
237        global postingRecordset
238        return postingRecordset
239    
240      # Post changes to the database
241      def post(self, foreign_keys={}):
242        global postingRecordset
243        # post our changes
244        self._update_cursor = self._dataObject._dataConnection.cursor()
245    
246        recordPosition = 0
247        while recordPosition < len(self._cachedRecords):
248          self._postingRecord = self._cachedRecords[recordPosition]
249          postingRecordset = self._postingRecord
250          delete = self._postingRecord._emptyFlag or self._postingRecord._deleteFlag
251          if not delete:
252            # Flip the flag for 'default' values to true so that hidden
253            # default fields are included in insert statements
254            if self._postingRecord.isPending():
255              for field in self._dataObject._defaultValues.keys():
256                self._postingRecord._modifiedFlags[field] = 1
257    
258            for field in foreign_keys.keys():
259              self._postingRecord._fields[field] = foreign_keys[field]
260              # Some DBs will throw an exception if you update a Primary Key
261              # (even if you are updating to the same value)
262              if self._postingRecord._insertFlag:
263                self._postingRecord._modifiedFlags[field] = 1
264    
265            recordPosition += 1
266          else:
267            # Adjust the current record if a preceding record
268            # or the current record is deleted
269            if recordPosition <= self._currentRecord:
270              self._currentRecord -= 1
271            self._cachedRecords.pop(recordPosition)
272            self._recordCount -= 1
273    
274          self._postingRecord.post()
275    
276        # Move to record 0 if all preceding records were deleted
277        # (or set to -1 if all records were deleted)
278        if self._currentRecord < 0:
279          if len(self._cachedRecords):
280            self._currentRecord = 0
281          else:
282            self._currentRecord = -1
283    # TODO: I don't think we need this anymore
284    #    if self._currentRecord >= self._recordCount:
285    #      self._currentRecord = self._recordCount - 1
286    
287      def notifyDetailObjects(self):
288        GDebug.printMesg(5,'Master record changed; Notifying Detail Objects')
289        for detail in self._dataObject._detailObjects:
290          if detail[1]:
291            detail[1].masterResultSetChanged(self,
292                                             detail[0]._masterRecordChanged(self))
293    
294    
295      # Returns 1=Field is bound to a database field
296      def isFieldBound(self, fieldName):
297        if self._dataObject._fieldReferences.has_key(fieldName):
298          return 1
299        else:
300          #TODO: the string.lower() line should never be called but is left
301          #TODO: here untill the code is cleaned up
302          return self._dataObject._fieldReferences.has_key(string.lower(fieldName))
303    
304    
305      # Load cacheCount number of new records
306      def _cacheNextRecord(self):
307        rs = self._loadNextRecord()
308        if rs:
309          self._dataObject._dataSource._onRecordLoaded(self._cachedRecords[-1])
310        return rs
311    
312    
313    
314      ###
315      ### Methods below should be overridden by Vendor Specific functions
316      ### (_createEmptyRecord may not need to be overridden in all cases)
317      ###
318    
319      # Load cacheCount number of new records
320      def _loadNextRecord(self):
321        return 0
322    
323      # Create an empty recordset
324      def _createEmptyRecord(self):
325        return self._recordSetClass(self)
326    
327      # Iterator support (Python 2.2+)
328      def __iter__(self):
329        return _ResultSetIter(self)
330    
331    
332    
333    # A simple resultset iterator
334    # Lets you use ResultSets as:
335    #
336    #   for record in myResultSet:
337    #      blah
338    #
339    # NOTE: Python 2.2+  (but it won't get called in
340    #    Python 2.1 or below, so not a problem)
341    #
342    class _ResultSetIter:
343      def __init__(self, resultset):
344        self.resultset = resultset
345        self.used = 0
346        self.done = 0
347    
348      def __iter__(self):
349        return self
350    
351      def next(self):
352        if self.done:
353          raise StopIteration
354        if self.used:
355          rs = self.resultset.firstRecord()
356        else:
357          rs = self.resultset.nextRecord()
358    
359        if not rs:
360          raise StopIteration
361        else:
362          return rs
363    
364    
365    # TODO: wtf?
366    postingRecordset = None
367    

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