Author: luke
Date: 2007-02-21 14:26:44 -0700 (Wed, 21 Feb 2007)
New Revision: 2339
Added:
SQLObject/branches/sqlbuilder-views/sqlobject/tests/test_select_through.py
Modified:
SQLObject/branches/sqlbuilder-views/sqlobject/joins.py
SQLObject/branches/sqlbuilder-views/sqlobject/sresults.py
Log:
SelectResults.throughTo
Modified: SQLObject/branches/sqlbuilder-views/sqlobject/joins.py
===================================================================
--- SQLObject/branches/sqlbuilder-views/sqlobject/joins.py 2007-02-21 20:29:27 UTC (rev 2338)
+++ SQLObject/branches/sqlbuilder-views/sqlobject/joins.py 2007-02-21 21:26:44 UTC (rev 2339)
@@ -62,7 +62,7 @@
otherClass, self._setOtherClass)
self.joinColumn = joinColumn
self.joinMethodName = joinMethodName
- self.orderBy = orderBy
+ self._orderBy = orderBy
if not self.joinColumn:
# Here we set up the basic join, which is
# one-to-many, where the other class points to
@@ -70,6 +70,12 @@
self.joinColumn = styles.getStyle(
self.soClass).tableReference(self.soClass.sqlmeta.table)
+ def orderBy(self):
+ if self._orderBy is NoDefault:
+ self._orderBy = self.otherClass.sqlmeta.defaultOrder
+ return self._orderBy
+ orderBy = property(orderBy)
+
def _setOtherClass(self, cls):
self.otherClass = cls
@@ -77,8 +83,6 @@
return False
def _applyOrderBy(self, results, defaultSortClass):
- if self.orderBy is NoDefault:
- self.orderBy = defaultSortClass.sqlmeta.defaultOrder
if self.orderBy is not None:
results.sort(sorter(self.orderBy))
return results
@@ -159,8 +163,6 @@
else:
conn = None
results = self.otherClass.select(getattr(self.otherClass.q, self.soClass.sqlmeta.style.dbColumnToPythonAttr(self.joinColumn)) == inst.id, connection=conn)
- if self.orderBy is NoDefault:
- self.orderBy = self.otherClass.sqlmeta.defaultOrder
return results.orderBy(self.orderBy)
class SQLMultipleJoin(Join):
@@ -279,8 +281,6 @@
),
TableToId(self.soClass.sqlmeta.table, self.soClass.sqlmeta.idName, inst.id),
), clauseTables=(self.soClass.sqlmeta.table, self.otherClass.sqlmeta.table, self.intermediateTable))
- if self.orderBy is NoDefault:
- self.orderBy = self.otherClass.sqlmeta.defaultOrder
return results.orderBy(self.orderBy)
class SQLRelatedJoin(RelatedJoin):
Modified: SQLObject/branches/sqlbuilder-views/sqlobject/sresults.py
===================================================================
--- SQLObject/branches/sqlbuilder-views/sqlobject/sresults.py 2007-02-21 20:29:27 UTC (rev 2338)
+++ SQLObject/branches/sqlbuilder-views/sqlobject/sresults.py 2007-02-21 21:26:44 UTC (rev 2339)
@@ -1,6 +1,7 @@
import sqlbuilder
import dbconnection
import main
+import joins
StringType = type('')
@@ -281,4 +282,59 @@
% results)
return results[0]
+ def throughTo(self):
+ return _throughTo_getter(self)
+ throughTo = property(throughTo)
+
+ def _throughTo(self, attr):
+ ref = self.sourceClass.sqlmeta.columns.get(attr.endswith('ID') and attr or attr+'ID', None)
+ if ref and ref.foreignKey:
+ return self._throughToFK(ref)
+ else:
+ join = [x for x in self.sourceClass.sqlmeta.joins if x.joinMethodName==attr]
+ if join:
+ join = join[0]
+ if hasattr(join, 'otherColumn'):
+ return self._throughToRelatedJoin(join)
+ return self._throughToMultipleJoin(join)
+
+ raise AttributeError("throughTo argument (got %s) should be name of foreignKey or SQL*Join in %s" % (attr, self.sourceClass))
+
+ def _throughToFK(self, col):
+ otherClass = getattr(self.sourceClass, "_SO_class_"+col.foreignKey)
+ query = sqlbuilder.Alias(self.queryForSelect(), "%s_%s" % (self.sourceClass.__name__, col.name))
+ return otherClass.select(otherClass.q.id==getattr(query.q, getattr(self.sourceClass.q, col.name).fieldName),
+ distinct=True)
+
+ def _throughToMultipleJoin(self, join):
+ otherClass = join.otherClass
+ query = self.queryForSelect()
+ query = sqlbuilder.Alias(query, "%s_%s" % (self.sourceClass.__name__, join.joinMethodName))
+ joinColumn = getattr(otherClass.q, join.soClass.sqlmeta.style.dbColumnToPythonAttr(join.joinColumn))
+ return otherClass.select(joinColumn == getattr(query.q, self.sourceClass.q.id.fieldName),
+ distinct=True,
+ orderBy=join.orderBy)
+
+ def _throughToRelatedJoin(self, join):
+ otherClass = join.otherClass
+ intTable = sqlbuilder.Table(join.intermediateTable)
+ print join.joinColumn, join.otherColumn
+ query = self.queryForSelect().newItems([getattr(intTable, join.joinColumn)])
+ query = sqlbuilder.Alias(query, "%s_%s" % (self.sourceClass.__name__, join.joinMethodName))
+ print query
+ clause = sqlbuilder.AND(otherClass.q.id == getattr(intTable, join.otherColumn),
+ getattr(intTable, join.joinColumn) == getattr(query.q, join.joinColumn))
+ ret = otherClass.select(clause,
+ distinct=True,
+ orderBy=join.orderBy)
+ print ret
+ return ret
+
+
+class _throughTo_getter(object):
+ def __init__(self, inst):
+ self.sresult = inst
+ def __getattr__(self, attr):
+ return self.sresult._throughTo(attr)
+
__all__ = ['SelectResults']
Added: SQLObject/branches/sqlbuilder-views/sqlobject/tests/test_select_through.py
===================================================================
--- SQLObject/branches/sqlbuilder-views/sqlobject/tests/test_select_through.py (rev 0)
+++ SQLObject/branches/sqlbuilder-views/sqlobject/tests/test_select_through.py 2007-02-21 21:26:44 UTC (rev 2339)
@@ -0,0 +1,53 @@
+from sqlobject import *
+from sqlobject.sqlbuilder import *
+from sqlobject.tests.dbtest import *
+
+''' Going to test that complex sqlbuilder constructions are never
+ prematurely stringified. A straight-forward approach is to use
+ Bools, since postgresql wants special formatting in queries.
+ The test is whether a call to sqlrepr(x, 'postgres') includes
+ the appropriate bool formatting throughout.
+'''
+
+class SRThrough1(SQLObject):
+ three = ForeignKey('SRThrough3')
+ twos = SQLMultipleJoin('SRThrough2', joinColumn='oneID')
+
+class SRThrough2(SQLObject):
+ one = ForeignKey('SRThrough1')
+ threes = SQLRelatedJoin('SRThrough3', addRemoveName='Three')
+
+class SRThrough3(SQLObject):
+ name = StringCol()
+ ones = SQLMultipleJoin('SRThrough1', joinColumn='threeID')
+ twos = SQLRelatedJoin('SRThrough2')
+
+
+def setup_module(mod):
+ setupClass([mod.SRThrough3, mod.SRThrough1, mod.SRThrough2])
+ threes = inserts(mod.SRThrough3,
+ [('a',),('b',),('c',)],
+ 'name')
+ ones = inserts(mod.SRThrough1,
+ [(threes[0].id,),(threes[0].id,),(threes[2].id,)],
+ 'threeID')
+ twos = inserts(mod.SRThrough2,
+ [(ones[0].id,),(ones[1].id,),(ones[2].id,)],
+ 'oneID')
+ twos[0].addThree(threes[0])
+ twos[0].addThree(threes[1])
+ mod.threes = threes
+ mod.twos = twos
+ mod.ones = ones
+
+def testThroughFK():
+ assert list(threes[0].ones.throughTo.three) == [threes[0]]
+
+def testThroughMultipleJoin():
+ assert list(threes[0].ones.throughTo.twos) == [twos[0], twos[1]]
+
+def testThroughRelatedJoin():
+ print [list(x.threes) for x in threes[0].twos]
+ assert list(threes[0].twos.throughTo.threes) == [threes[0], threes[1]]
+
+
\ No newline at end of file
|