main logo
Subject: [dabo-dev] dabo Commit 1495
Author: Ed Leafe
Posted: 2005/10/31 18:52:25
 
View Entire Thread
New Search


dabo Commit
Revision 1495
Date: 2005-10-31 15:52:27 -0800 (Mon, 31 Oct 2005)
Author: ed

Changed:
U trunk/dabo/db/dCursorMixin.py

Log:
Added a new class named 'DataSet', which is a subclass of tuple. The purpose of this class is to allow SQL-like selections and joins to be made on data as it exists in Dabo, instead of strictly on the backend. For example, let's say you create two cursors, and then want to do a join on the data in them. In Fox it's no big deal, but you currently can't do that in Dabo without calling back to the database and re-fetching the data.

As of now there is a *very* rudimentary 'select()' method for this class. As time goes on, I'd like to flesh it out a bit more, and then eventually create a join() method to go along with it that would accept another DataSet object along with a bunch of conditions, and return the appropriate result set.


Diff:
Modified: trunk/dabo/db/dCursorMixin.py
===================================================================
--- trunk/dabo/db/dCursorMixin.py 2005-10-31 22:19:32 UTC (rev 1494)
+++ trunk/dabo/db/dCursorMixin.py 2005-10-31 23:52:27 UTC (rev 1495)
@@ -67,7 +67,7 @@
# it will be a separate object.
self.sqlManager = self
# Attribute that holds the data of the cursor
- self._records = ()
+ self._records = DataSet()
# Attribute that holds the current row number
self.__rownumber = -1

@@ -161,14 +161,13 @@
# Not all backends support 'fetchall' after executing a query
# that doesn't return records, such as an update.
try:
- self._records = self.fetchall()
+ self._records = DataSet(self.fetchall())
except:
pass

# Some backend programs do odd things to the description
# This allows each backend to handle these quirks individually.
self.BackendObject.massageDescription(self)
-
if self.RowCount > 0:
self.RowNumber = max(0, self.RowNumber)
maxrow = max(0, (self.RowCount-1) )
@@ -195,8 +194,7 @@
else:
dic[fldNames[i]] = row[i]
tmpRows.append(dic)
- self._records = tuple(tmpRows)
-
+ self._records = DataSet(tmpRows)
else:
# Make all string values into unicode
for row in self._records:
@@ -205,7 +203,6 @@
if isinstance(val, str):
# String; convert it to unicode
row[fld]= unicode(val, self.Encoding)
-
# There can be a problem with the MySQLdb adapter if
# the mx modules are installed on the machine, the adapter
# will use that type instead of the native datetime.
@@ -222,6 +219,8 @@
except ImportError:
# mx not installed; no problem
pass
+ # Convert to DataSet
+ self._records = DataSet(self._records)
return res


@@ -375,7 +374,7 @@
newRows = []
for elem in sortList:
newRows.append(elem[1])
- self._records = tuple(newRows)
+ self._records = DataSet(newRows)

# restore the RowNumber
if currRowKey:
@@ -664,6 +663,7 @@
filtRec[fld] = rec[fld]
retlist.append(filtRec)
ret = tuple(retlist)
+ ret = DataSet(ret)
return ret
except AttributeError:
return ()
@@ -851,7 +851,7 @@
# Copy the _blank dict to the _records, and adjust everything accordingly
tmprows = list(self._records)
tmprows.append(self._blank.copy())
- self._records = tuple(tmprows)
+ self._records = DataSet(tmprows)
# Adjust the RowCount and position
self.RowNumber = self.RowCount - 1
# Add the 'new record' flag to the last record (the one we just added)
@@ -942,7 +942,7 @@
"""
lRec = list(self._records)
del lRec[r]
- self._records = tuple(lRec)
+ self._records = DataSet(lRec)
self.RowNumber = min(self.RowNumber, self.RowCount-1)


@@ -1626,3 +1626,45 @@

UserSQL = property(_getUserSQL, _setUserSQL, None,
_("SQL statement to run. If set, the automatic SQL builder will not be used."))
+
+
+
+class DataSet(tuple):
+ """ This class assumes that its contents are not ordinary tuples, but
+ rather tuples consisting of dicts, where the dict keys are field names.
+ This is the data structure returned by the dCursorMixin class.
+ """
+ def select(self, flds=None, where=None, orderBy=None):
+ fldList = []
+ whereList = []
+ orderByList = []
+ if flds is None or flds == "*":
+ # All fields
+ flds = self[0].keys()
+ elif isinstance(flds, basestring):
+ # Convert to list
+ flds = [flds]
+ for fld in flds:
+ fldList.append("'%s' : rec['%s']" % (fld, fld))
+ fldsToReturn = ", ".join(fldList)
+ fldsToReturn = "{%s}" % fldsToReturn
+
+ # Where list elements. Each element should be in the form: <fld> <op> <val>
+ # TODO: add support for format: <fld>.func() <op> <val>
+ # or: func(<fld>) <op> <val>
+ if where is None:
+ whereClause = ""
+ else:
+ if isinstance(where, basestring):
+ where = [where]
+ for wh in where:
+ fld, op, val = wh.split(" ", 2)
+ whereList.append("rec['%s'] %s %s" % (fld, op, val))
+ whereClause = " and ".join(whereList)
+ if whereClause:
+ whereClause = " if %s" % whereClause
+
+ stmnt = "[%s for rec in self %s]" % (fldsToReturn, whereClause)
+ resultSet = eval(stmnt)
+ return resultSet
+
\ No newline at end of file





 
©2005 Ed Leafe
<-- Prior Message New Search Next Message -->