[CalendarServer-changes] [6886] CalendarServer/trunk/twext/enterprise/dal

source_changes at macosforge.org source_changes at macosforge.org
Fri Feb 4 17:14:12 PST 2011


Revision: 6886
          http://trac.macosforge.org/projects/calendarserver/changeset/6886
Author:   glyph at apple.com
Date:     2011-02-04 17:14:09 -0800 (Fri, 04 Feb 2011)
Log Message:
-----------
Expressions involving aggregates

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-05 00:36:03 UTC (rev 6885)
+++ CalendarServer/trunk/twext/enterprise/dal/syntax.py	2011-02-05 01:14:09 UTC (rev 6886)
@@ -82,12 +82,46 @@
 
 
 
-class FunctionInvocation(object):
+def comparison(comparator):
+    def __(self, other):
+        if other is None:
+            return NullComparison(self, comparator)
+        if isinstance(other, ColumnSyntax):
+            return ColumnComparison(self, comparator, other)
+        else:
+            return ConstantComparison(self, comparator, other)
+    return __
+
+
+
+class ExpressionSyntax(Syntax):
+    __eq__ = comparison('=')
+    __ne__ = comparison('!=')
+    __gt__ = comparison('>')
+    __ge__ = comparison('>=')
+    __lt__ = comparison('<')
+    __le__ = comparison('<=')
+    __add__ = comparison("+")
+    __sub__ = comparison("-")
+
+
+    def In(self, subselect):
+        # Can't be Select.__contains__ because __contains__ gets __nonzero__
+        # called on its result by the 'in' syntax.
+        return CompoundComparison(self, 'in', subselect)
+
+
+
+class FunctionInvocation(ExpressionSyntax):
     def __init__(self, name, arg):
         self.name = name
         self.arg = arg
 
 
+    def allColumns(self):
+        return self.arg.allColumns()
+
+
     def subSQL(self, placeholder, quote, allTables):
         result = SQLFragment(self.name)
         result.text += "("
@@ -217,35 +251,18 @@
 
 
 
-def comparison(comparator):
-    def __(self, other):
-        if other is None:
-            return NullComparison(self, comparator)
-        if isinstance(other, ColumnSyntax):
-            return ColumnComparison(self, comparator, other)
-        else:
-            return ConstantComparison(self, comparator, other)
-    return __
-
-
-
-class ColumnSyntax(Syntax):
+class ColumnSyntax(ExpressionSyntax):
     """
     Syntactic convenience for L{Column}.
     """
 
     modelType = Column
 
-    __eq__ = comparison('=')
-    __ne__ = comparison('!=')
-    __gt__ = comparison('>')
-    __ge__ = comparison('>=')
-    __lt__ = comparison('<')
-    __le__ = comparison('<=')
-    __add__ = comparison("+")
-    __sub__ = comparison("-")
 
+    def allColumns(self):
+        return [self]
 
+
     def subSQL(self, placeholder, quote, allTables):
         # XXX This, and 'model', could in principle conflict with column names.
         # Maybe do something about that.
@@ -258,13 +275,7 @@
         return SQLFragment(self.model.name)
 
 
-    def In(self, subselect):
-        # Can't be Select.__contains__ because __contains__ gets __nonzero__
-        # called on its result by the 'in' syntax.
-        return CompoundComparison(self, 'in', subselect)
 
-
-
 class Comparison(object):
 
     def __init__(self, a, op, b):
@@ -310,8 +321,13 @@
         return sqls
 
 
+
 class ConstantComparison(Comparison):
 
+    def allColumns(self):
+        return [self.a]
+
+
     def subSQL(self, placeholder, quote, allTables):
         sqls = SQLFragment()
         sqls.append(self.a.subSQL(placeholder, quote, allTables))
@@ -372,6 +388,18 @@
 
 
 
+def _columnsMatchTables(columns, tables):
+    for expression in columns:
+        for column in expression.allColumns():
+            for table in tables:
+                if column in table:
+                    break
+            else:
+                return False
+    return True
+
+
+
 class Select(_Statement):
     """
     'select' statement.
@@ -387,12 +415,9 @@
         if columns is None:
             columns = ALL_COLUMNS
         else:
-            for column in columns:
-                for table in From.tables():
-                    if column in table:
-                        break
-                else:
-                    raise TableMismatch()
+            if not _columnsMatchTables(columns, From.tables()):
+                raise TableMismatch()
+
             columns = _SomeColumns(columns)
         self.columns = columns
 

Modified: CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py
===================================================================
--- CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py	2011-02-05 00:36:03 UTC (rev 6885)
+++ CalendarServer/trunk/twext/enterprise/dal/test/test_sqlsyntax.py	2011-02-05 01:14:09 UTC (rev 6886)
@@ -274,7 +274,8 @@
 
     def test_max(self):
         """
-        Test for the 'Max' function.
+        L{Max}C{(column)} produces an object in the 'columns' clause that
+        renders the 'max' aggregate in SQL.
         """
         self.assertEquals(
             Select([Max(self.schema.BOZ.QUX)], From=self.schema.BOZ).toSQL(),
@@ -282,6 +283,16 @@
                 "select max(QUX) from BOZ"))
 
 
+    def test_aggregateComparison(self):
+        """
+        L{Max}C{(column) > constant} produces an object in the 'columns' clause
+        that renders a comparison to the 'max' aggregate in SQL.
+        """
+        self.assertEquals(Select([Max(self.schema.BOZ.QUX) + 12],
+                                From=self.schema.BOZ).toSQL(),
+                          SQLFragment("select max(QUX) + ? from BOZ", [12]))
+
+
     def test_len(self):
         """
         Test for the 'Len' function for determining character length of a
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110204/47e0e0fd/attachment-0001.html>


More information about the calendarserver-changes mailing list