[CalendarServer-changes] [7040] CalendarServer/trunk/twext/enterprise/dal
source_changes at macosforge.org
source_changes at macosforge.org
Thu Feb 17 16:40:34 PST 2011
Revision: 7040
http://trac.macosforge.org/projects/calendarserver/changeset/7040
Author: glyph at apple.com
Date: 2011-02-17 16:40:17 -0800 (Thu, 17 Feb 2011)
Log Message:
-----------
Implementation of multi-table joins.
Modified Paths:
--------------
CalendarServer/trunk/twext/enterprise/dal/syntax.py
CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py
Modified: CalendarServer/trunk/twext/enterprise/dal/syntax.py
===================================================================
--- CalendarServer/trunk/twext/enterprise/dal/syntax.py 2011-02-17 22:46:22 UTC (rev 7039)
+++ CalendarServer/trunk/twext/enterprise/dal/syntax.py 2011-02-18 00:40:17 UTC (rev 7040)
@@ -249,7 +249,9 @@
modelType = Table
- def join(self, otherTableSyntax, on, type=''):
+ def join(self, otherTableSyntax, on=None, type=''):
+ if on is None:
+ type = 'cross'
return Join(self, type, otherTableSyntax, on)
@@ -291,33 +293,57 @@
class Join(object):
+ """
+ A DAL object representing an SQL 'join' statement.
- def __init__(self, firstTable, type, secondTableOrJoin, on):
- self.firstTable = firstTable
+ @ivar leftSide: a L{Join} or L{TableSyntax} representing the left side of
+ this join.
+
+ @ivar rightSide: a L{TableSyntax} representing the right side of this join.
+
+ @ivar type: the type of join this is. For example, for a left outer join,
+ this would be C{'left outer'}.
+ @type type: C{str}
+
+ @ivar on: the 'on' clause of this table.
+
+ @type on: L{ExpressionSyntax}
+ """
+
+ def __init__(self, leftSide, type, rightSide, on):
+ self.leftSide = leftSide
self.type = type
- self.secondTableOrJoin = secondTableOrJoin
+ self.rightSide = rightSide
self.on = on
def subSQL(self, placeholder, quote, allTables):
stmt = SQLFragment()
- stmt.append(self.firstTable.subSQL(placeholder, quote, allTables))
+ stmt.append(self.leftSide.subSQL(placeholder, quote, allTables))
stmt.text += ' '
if self.type:
stmt.text += self.type
stmt.text += ' '
stmt.text += 'join '
- stmt.append(self.secondTableOrJoin.subSQL(placeholder, quote, allTables))
- stmt.text += ' on '
- stmt.append(self.on.subSQL(placeholder, quote, allTables))
+ stmt.append(self.rightSide.subSQL(placeholder, quote, allTables))
+ if self.type != 'cross':
+ stmt.text += ' on '
+ stmt.append(self.on.subSQL(placeholder, quote, allTables))
return stmt
def tables(self):
- return self.firstTable.tables() + self.secondTableOrJoin.tables()
+ return self.leftSide.tables() + self.rightSide.tables()
+ def join(self, otherTable, on=None, type=None):
+ if on is None:
+ type = 'cross'
+ return Join(self, type, otherTable, on)
+
+
+
class ColumnSyntax(ExpressionSyntax):
"""
Syntactic convenience for L{Column}.
Modified: CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py
===================================================================
--- CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py 2011-02-17 22:46:22 UTC (rev 7039)
+++ CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py 2011-02-18 00:40:17 UTC (rev 7040)
@@ -186,6 +186,51 @@
)
+ def test_crossJoin(self):
+ """
+ A join with no clause specified will generate a cross join. (This is an
+ explicit synonym for an implicit join: i.e. 'select * from FOO, BAR'.)
+ """
+ self.assertEquals(
+ Select(From=self.schema.FOO.join(self.schema.BOZ)).toSQL(),
+ SQLFragment("select * from FOO cross join BOZ")
+ )
+
+
+ def test_joinJoin(self):
+ """
+ L{Join.join} will result in a multi-table join.
+ """
+ self.assertEquals(
+ Select([self.schema.FOO.BAR,
+ self.schema.BOZ.QUX],
+ From=self.schema.FOO
+ .join(self.schema.BOZ).join(self.schema.OTHER)).toSQL(),
+ SQLFragment(
+ "select FOO.BAR, QUX from FOO "
+ "cross join BOZ cross join OTHER")
+ )
+
+
+ def test_multiJoin(self):
+ """
+ L{Join.join} has the same signature as L{TableSyntax.join} and supports
+ the same 'on' and 'type' arguments.
+ """
+
+ self.assertEquals(
+ Select([self.schema.FOO.BAR],
+ From=self.schema.FOO.join(
+ self.schema.BOZ).join(
+ self.schema.OTHER,
+ self.schema.OTHER.BAR == self.schema.FOO.BAR,
+ 'left outer')).toSQL(),
+ SQLFragment(
+ "select FOO.BAR from FOO cross join BOZ left outer join OTHER "
+ "on OTHER.BAR = FOO.BAR")
+ )
+
+
def test_columnSelection(self):
"""
If a column is specified by the argument to L{Select}, those will be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110217/a26bd80e/attachment.html>
More information about the calendarserver-changes
mailing list