[CalendarServer-changes] [8656] CalendarServer/branches/users/glyph/table-alias

source_changes at macosforge.org source_changes at macosforge.org
Mon Feb 13 10:03:40 PST 2012


Revision: 8656
          http://trac.macosforge.org/projects/calendarserver/changeset/8656
Author:   glyph at apple.com
Date:     2012-02-13 10:03:40 -0800 (Mon, 13 Feb 2012)
Log Message:
-----------
Add some docstrings, and add just enough of an implementation for the first two tests to pass.

Modified Paths:
--------------
    CalendarServer/branches/users/glyph/table-alias/twext/enterprise/dal/syntax.py

Property Changed:
----------------
    CalendarServer/branches/users/glyph/table-alias/

Modified: CalendarServer/branches/users/glyph/table-alias/twext/enterprise/dal/syntax.py
===================================================================
--- CalendarServer/branches/users/glyph/table-alias/twext/enterprise/dal/syntax.py	2012-02-13 18:03:37 UTC (rev 8655)
+++ CalendarServer/branches/users/glyph/table-alias/twext/enterprise/dal/syntax.py	2012-02-13 18:03:40 UTC (rev 8656)
@@ -463,10 +463,13 @@
     modelType = Table
 
     def alias(self):
-        return self
+        return TableAlias(self.model)
 
 
     def join(self, otherTableSyntax, on=None, type=''):
+        """
+        Create a L{Join}, representing a join between two tables.
+        """
         if on is None:
             type = 'cross'
         return Join(self, type, otherTableSyntax, on)
@@ -474,7 +477,8 @@
 
     def subSQL(self, metadata, allTables):
         """
-        For use in a 'from' clause.
+        Generate the L{SQLFragment} for this table's identification; this is
+        for use in a 'from' clause.
         """
         # XXX maybe there should be a specific method which is only invoked
         # from the FROM clause, that only tables and joins would implement?
@@ -482,19 +486,39 @@
 
 
     def __getattr__(self, attr):
+        """
+        Attributes named after columns on a L{TableSyntax} are returned by
+        accessing their names as attributes.  For example, if there is a schema
+        syntax object created from SQL equivalent to 'create table foo (bar
+        integer, baz integer)', 'schemaSyntax.foo.bar' and
+        'schemaSyntax.foo.baz'
+        """
         return ColumnSyntax(self.model.columnNamed(attr))
 
 
     def __iter__(self):
+        """
+        Yield a L{ColumnSyntax} for each L{Column} in this L{TableSyntax}'s
+        model's table.
+        """
         for column in self.model.columns:
             yield ColumnSyntax(column)
 
 
     def tables(self):
+        """
+        Return a C{list} of tables involved in the query by this table.  (This
+        method is expected by anything that can act as the C{From} clause: see
+        L{Join.tables})
+        """
         return [self]
 
 
     def aliases(self):
+        """
+        @return: a list of 2-tuples of (alias (C{str}), column
+            (C{ColumnSyntax})), enumerating all of the Python aliases provided.
+        """
         result = {}
         for k, v in self.__dict__.items():
             if isinstance(v, ColumnSyntax):
@@ -509,6 +533,23 @@
 
 
 
+class TableAlias(TableSyntax):
+    """
+    An alias for a table, under a different name, for the purpose of doing a
+    self-join.
+    """
+
+    def subSQL(self, metadata, allTables):
+        result = super(TableAlias, self).subSQL(metadata, allTables)
+        result.append(SQLFragment(" alias1"))
+        return result
+
+
+    def __getattr__(self, attr):
+        return AliasedColumnSyntax(self.model.columnNamed(attr))
+
+
+
 class Join(object):
     """
     A DAL object representing an SQL 'join' statement.
@@ -550,6 +591,11 @@
 
 
     def tables(self):
+        """
+        Return a C{list} of tables which this L{Join} will involve in a query:
+        all those present on the left side, as well as all those present on the
+        right side.
+        """
         return self.leftSide.tables() + self.rightSide.tables()
 
 
@@ -574,11 +620,18 @@
 class ColumnSyntax(ExpressionSyntax):
     """
     Syntactic convenience for L{Column}.
+
+    @ivar _alwaysQualified: a boolean indicating whether to always qualify the
+        column name in generated SQL, regardless of whether the column name is
+        specific enough even when unqualified.
+    @type _alwaysQualified: C{bool}
     """
 
     modelType = Column
 
+    _alwaysQualified = False
 
+
     def allColumns(self):
         return [self]
 
@@ -590,19 +643,47 @@
         if metadata.dialect == ORACLE_DIALECT and name.lower() in _KEYWORDS:
             name = '"%s"' % (name,)
 
-        for tableSyntax in allTables:
-            if self.model.table is not tableSyntax.model:
-                if self.model.name in (c.name for c in
-                                               tableSyntax.model.columns):
-                    return SQLFragment((self.model.table.name + '.' + name))
-        return SQLFragment(name)
+        if self._alwaysQualified:
+            qualified = True
+        else:
+            qualified = False
+            for tableSyntax in allTables:
+                if self.model.table is not tableSyntax.model:
+                    if self.model.name in (c.name for c in
+                                           tableSyntax.model.columns):
+                        qualified = True
+                        break
+        if qualified:
+            return SQLFragment(self._qualify(name))
+        else:
+            return SQLFragment(name)
 
 
     def __hash__(self):
         return hash(self.model) + 10
 
 
+    def _qualify(self, name):
+        return self.model.table.name + '.' + name
 
+
+
+class AliasedColumnSyntax(ColumnSyntax):
+    """
+    An L{AliasedColumnSyntax} is like a L{ColumnSyntax}, but it generates SQL
+    for a column of a table under an alias, rather than directly.  i.e. this is
+    used for C{'something.col'} in C{'select something.col from tablename
+    something'} rather than the 'col' in C{'select col from tablename'}.
+
+    @see: L{TableSyntax.alias}
+    """
+    _alwaysQualified = True
+
+    def _qualify(self, name):
+        return 'alias1.' + name
+
+
+
 class Comparison(ExpressionSyntax):
 
     def __init__(self, a, op, b):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120213/91f74286/attachment.html>


More information about the calendarserver-changes mailing list