]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- get all comparison operators to document with sphinx - column based, relationship...
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 26 May 2011 17:30:26 +0000 (13:30 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 26 May 2011 17:30:26 +0000 (13:30 -0400)
Should fix misunderstandings like [ticket:2177]

doc/build/builder/builders.py
doc/build/core/expression_api.rst
doc/build/orm/internals.rst
doc/build/orm/mapper_config.rst
doc/build/orm/tutorial.rst
doc/build/static/docs.css
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/sql/expression.py

index c9656502497a2e683a3c65dff6e4b29fa72170bc..25e283e5d3d79d63ee5052daa0f37881307c2881 100644 (file)
@@ -158,7 +158,7 @@ class PopupLatexFormatter(LatexFormatter):
         LatexFormatter.format(self, self._filter_tokens(tokensource), outfile)
 
 def autodoc_skip_member(app, what, name, obj, skip, options):
-    if what == 'class' and skip and name == '__init__':
+    if what == 'class' and skip and name in ('__init__', '__eq__', '__ne__', '__lt__', '__le__') and obj.__doc__:
         return False
     else:
         return skip
index cfa22591dec792ff54900177cacc67a3187a36d4..b5e47b6ac2b3b973b5df58625855cec460c3ec43 100644 (file)
@@ -67,6 +67,10 @@ The expression package uses functions to construct SQL expressions.  The return
 
 .. autofunction:: null
 
+.. autofunction:: nullsfirst
+
+.. autofunction:: nullslast
+
 .. autofunction:: or_
 
 .. autofunction:: outparam
@@ -128,7 +132,6 @@ Classes
 
 .. autoclass:: _CompareMixin
   :members:
-  :undoc-members:
   :show-inheritance:
 
 .. autoclass:: ColumnOperators
index bb3e3ffb55f3e7f3d72530496b213bbeb3c97971..c23e5f2f732850a9c946bd2285a826094b6e0268 100644 (file)
@@ -19,10 +19,6 @@ Some key internal constructs are listed here.
     :members:
     :show-inheritance:
 
-.. autoclass:: sqlalchemy.orm.properties.DeferredColumnProperty
-    :members:
-    :show-inheritance:
-
 .. autoclass:: sqlalchemy.orm.state.InstanceState
     :members:
     :show-inheritance:
@@ -39,6 +35,7 @@ Some key internal constructs are listed here.
     :members:
     :show-inheritance:
 
+
 .. autoclass:: sqlalchemy.orm.descriptor_props.SynonymProperty
     :members:
     :show-inheritance:
index 96c641f905a3c098ca55fb5709937fc92325f92d..259a6ecbab900384956c78d9fe5b46306cf55792 100644 (file)
@@ -545,12 +545,8 @@ should be used in order to acquire the underlying mapped column.  This will
 return a column that is appropriately wrapped in any kind of subquery
 or aliasing that has been applied in the context of the generated SQL statement.
 
-.. autoclass:: sqlalchemy.orm.interfaces.PropComparator
-    :show-inheritance:
-
 .. autofunction:: comparable_property
 
-
 .. _mapper_composite:
 
 Composite Column Types
index f77225c4002efcf90c10008697b2fc718bae84d1..2a646d3e28e641a4440c5cd239537cb694bc17c2 100644 (file)
@@ -1061,6 +1061,8 @@ See :ref:`loading_toplevel` for information on
 :func:`~sqlalchemy.orm.subqueryload`. We'll also see another way to "eagerly"
 load in the next section.
 
+.. _ormtutorial_joins:
+
 Querying with Joins
 ====================
 
@@ -1107,6 +1109,11 @@ works better when one of the following forms are used::
     query.join(Address, User.addresses)              # same, with explicit target
     query.join('addresses')                          # same, using a string
 
+As you would expect, the same idea is used for "outer" joins, using the 
+:meth:`~.Query.outerjoin` function::
+
+    query.outerjoin(User.addresses)   # LEFT OUTER JOIN
+
 Note that when :meth:`~sqlalchemy.orm.query.Query.join` is called with an
 explicit target as well as an ON clause, we use a tuple as the argument. This
 is so that multiple joins can be chained together, as in::
@@ -1355,36 +1362,38 @@ usage of EXISTS automatically. Above, the statement can be expressed along the
 Common Relationship Operators
 -----------------------------
 
-Here's all the operators which build on relationships:
+Here's all the operators which build on relationships - each one
+is linked to its API documentation which includes full details on usage
+and behavior:
 
-* equals (used for many-to-one)::
+* :meth:`~.RelationshipProperty.Comparator.__eq__` (many-to-one "equals" comparison)::
 
     query.filter(Address.user == someuser)
 
-* not equals (used for many-to-one)::
+* :meth:`~.RelationshipProperty.Comparator.__ne__` (many-to-one "not equals" comparison)::
 
     query.filter(Address.user != someuser)
 
-* IS NULL (used for many-to-one)::
+* IS NULL (many-to-one comparison, also uses :meth:`~.RelationshipProperty.Comparator.__eq__`)::
 
     query.filter(Address.user == None)
 
-* contains (used for one-to-many and many-to-many collections)::
+* :meth:`~.RelationshipProperty.Comparator.contains` (used for one-to-many collections)::
 
     query.filter(User.addresses.contains(someaddress))
 
-* any (used for one-to-many and many-to-many collections)::
+* :meth:`~.RelationshipProperty.Comparator.any` (used for collections)::
 
     query.filter(User.addresses.any(Address.email_address == 'bar'))
 
     # also takes keyword arguments:
     query.filter(User.addresses.any(email_address='bar'))
 
-* has (used for many-to-one)::
+* :meth:`~.RelationshipProperty.Comparator.has` (used for scalar references)::
 
     query.filter(Address.user.has(name='ed'))
 
-* with_parent (used for any relationship)::
+* :meth:`.Query.with_parent` (used for any relationship)::
 
     session.query(Address).with_parent(someuser, 'addresses')
 
index 64659acf8105cc8a853e434e1f630791ea1c9d29..84a24771f4281312618ef4f8137d23c22b7e85d0 100644 (file)
@@ -247,6 +247,9 @@ div#dialect-documentation {
 
 /* SQL popup, code styles */
 
+.highlight {
+  background:none;
+}
 pre {
   background-color: #f0f0f0;  
   border: solid 1px #ccc;
index 7a87485566364f7c7d885d71b2cdc0f6e5f1b494..93200d371cce951fca7260d2791893e7fc3879c0 100644 (file)
@@ -185,7 +185,7 @@ class PropComparator(expression.ColumnOperators):
     User-defined subclasses of :class:`.PropComparator` may be created. The
     built-in Python comparison and math operator methods, such as
     ``__eq__()``, ``__lt__()``, ``__add__()``, can be overridden to provide
-    new operator behaivor. The custom :class:`.PropComparator` is passed to
+    new operator behavior. The custom :class:`.PropComparator` is passed to
     the mapper property via the ``comparator_factory`` argument. In each case,
     the appropriate subclass of :class:`.PropComparator` should be used::
 
index 53fb5d85deabfd3ec70212f8781e67c8810bba8f..b4ef7235cdf4ded1221e565ba9d2827b13f5217d 100644 (file)
@@ -177,6 +177,10 @@ class RelationshipProperty(StrategizedProperty):
     
     Public constructor is the :func:`.orm.relationship` function.
     
+    Of note here is the :class:`.RelationshipProperty.Comparator`
+    class, which implements comparison operations for scalar-
+    and collection-referencing mapped attributes.
+    
     """
 
     def __init__(self, argument,
@@ -278,7 +282,14 @@ class RelationshipProperty(StrategizedProperty):
             )
 
     class Comparator(PropComparator):
+        """Produce comparison operations for :func:`~.orm.relationship`-based
+         attributes."""
+
         def __init__(self, prop, mapper, of_type=None, adapter=None):
+            """Construction of :class:`.RelationshipProperty.Comparator`
+            is internal to the ORM's attribute mechanics.
+            
+            """
             self.prop = prop
             self.mapper = mapper
             self.adapter = adapter
@@ -314,12 +325,23 @@ class RelationshipProperty(StrategizedProperty):
             return op(self, *other, **kwargs)
 
         def of_type(self, cls):
+            """Produce a construct that represents a particular 'subtype' of
+            attribute for the parent class.
+            
+            Currently this is usable in conjunction with :meth:`.Query.join`
+            and :meth:`.Query.outerjoin`.
+            
+            """
             return RelationshipProperty.Comparator(
                                         self.property, 
                                         self.mapper, 
                                         cls, adapter=self.adapter)
 
         def in_(self, other):
+            """Produce an IN clause - this is not implemented 
+            for :func:`~.orm.relationship`-based attributes at this time.
+            
+            """
             raise NotImplementedError('in_() not yet supported for '
                     'relationships.  For a simple many-to-one, use '
                     'in_() against the set of foreign key values.')
@@ -327,6 +349,42 @@ class RelationshipProperty(StrategizedProperty):
         __hash__ = None
 
         def __eq__(self, other):
+            """Implement the ``==`` operator.
+
+            In a many-to-one context, such as::
+
+              MyClass.some_prop == <some object>
+
+            this will typically produce a
+            clause such as::
+  
+              mytable.related_id == <some id>
+  
+            Where ``<some id>`` is the primary key of the given 
+            object.
+  
+            The ``==`` operator provides partial functionality for non-
+            many-to-one comparisons:
+  
+            * Comparisons against collections are not supported.
+              Use :meth:`~.RelationshipProperty.Comparator.contains`.
+            * Compared to a scalar one-to-many, will produce a 
+              clause that compares the target columns in the parent to
+              the given target. 
+            * Compared to a scalar many-to-many, an alias
+              of the association table will be rendered as
+              well, forming a natural join that is part of the
+              main body of the query. This will not work for
+              queries that go beyond simple AND conjunctions of
+              comparisons, such as those which use OR. Use
+              explicit joins, outerjoins, or
+              :meth:`~.RelationshipProperty.Comparator.has` for
+              more comprehensive non-many-to-one scalar
+              membership tests.
+            * Comparisons against ``None`` given in a one-to-many
+              or many-to-many context produce a NOT EXISTS clause.
+
+            """
             if isinstance(other, (NoneType, expression._Null)):
                 if self.property.direction in [ONETOMANY, MANYTOMANY]:
                     return ~self._criterion_exists()
@@ -399,6 +457,45 @@ class RelationshipProperty(StrategizedProperty):
             return sql.exists([1], crit, from_obj=dest).correlate(source)
 
         def any(self, criterion=None, **kwargs):
+            """Produce an expression that tests a collection against
+            particular criterion, using EXISTS.
+            
+            An expression like::
+            
+                session.query(MyClass).filter(
+                    MyClass.somereference.any(SomeRelated.x==2)
+                )
+                
+                
+            Will produce a query like::
+            
+                SELECT * FROM my_table WHERE
+                EXISTS (SELECT 1 FROM related WHERE related.my_id=my_table.id 
+                AND related.x=2)
+                
+            Because :meth:`~.RelationshipProperty.Comparator.any` uses
+            a correlated subquery, its performance is not nearly as
+            good when compared against large target tables as that of
+            using a join.
+            
+            :meth:`~.RelationshipProperty.Comparator.any` is particularly
+            useful for testing for empty collections::
+            
+                session.query(MyClass).filter(
+                    ~MyClass.somereference.any()
+                )
+            
+            will produce::
+            
+                SELECT * FROM my_table WHERE
+                NOT EXISTS (SELECT 1 FROM related WHERE related.my_id=my_table.id)
+                
+            :meth:`~.RelationshipProperty.Comparator.any` is only
+            valid for collections, i.e. a :func:`.relationship`
+            that has ``uselist=True``.  For scalar references,
+            use :meth:`~.RelationshipProperty.Comparator.has`.
+            
+            """
             if not self.property.uselist:
                 raise sa_exc.InvalidRequestError(
                             "'any()' not implemented for scalar "
@@ -408,6 +505,33 @@ class RelationshipProperty(StrategizedProperty):
             return self._criterion_exists(criterion, **kwargs)
 
         def has(self, criterion=None, **kwargs):
+            """Produce an expression that tests a scalar reference against
+            particular criterion, using EXISTS.
+
+            An expression like::
+            
+                session.query(MyClass).filter(
+                    MyClass.somereference.has(SomeRelated.x==2)
+                )
+                
+                
+            Will produce a query like::
+            
+                SELECT * FROM my_table WHERE
+                EXISTS (SELECT 1 FROM related WHERE related.id==my_table.related_id
+                AND related.x=2)
+
+            Because :meth:`~.RelationshipProperty.Comparator.has` uses
+            a correlated subquery, its performance is not nearly as
+            good when compared against large target tables as that of
+            using a join.
+            
+            :meth:`~.RelationshipProperty.Comparator.has` is only
+            valid for scalar references, i.e. a :func:`.relationship`
+            that has ``uselist=False``.  For collection references,
+            use :meth:`~.RelationshipProperty.Comparator.any`.
+            
+            """
             if self.property.uselist:
                 raise sa_exc.InvalidRequestError(
                             "'has()' not implemented for collections.  "
@@ -415,6 +539,61 @@ class RelationshipProperty(StrategizedProperty):
             return self._criterion_exists(criterion, **kwargs)
 
         def contains(self, other, **kwargs):
+            """Return a simple expression that tests a collection for 
+            containment of a particular item.
+            
+            :meth:`~.RelationshipProperty.Comparator.contains` is
+            only valid for a collection, i.e. a
+            :func:`~.orm.relationship` that implements
+            one-to-many or many-to-many with ``uselist=True``.
+            
+            When used in a simple one-to-many context, an 
+            expression like::
+            
+                MyClass.contains(other)
+                
+            Produces a clause like::
+            
+                mytable.id == <some id>
+                
+            Where ``<some id>`` is the value of the foreign key
+            attribute on ``other`` which refers to the primary
+            key of its parent object. From this it follows that
+            :meth:`~.RelationshipProperty.Comparator.contains` is
+            very useful when used with simple one-to-many
+            operations.
+            
+            For many-to-many operations, the behavior of
+            :meth:`~.RelationshipProperty.Comparator.contains`
+            has more caveats. The association table will be
+            rendered in the statement, producing an "implicit"
+            join, that is, includes multiple tables in the FROM
+            clause which are equated in the WHERE clause::
+            
+                query(MyClass).filter(MyClass.contains(other))
+                
+            Produces a query like::
+            
+                SELECT * FROM my_table, my_association_table AS
+                my_association_table_1 WHERE
+                my_table.id = my_association_table_1.parent_id
+                AND my_association_table_1.child_id = <some id>
+                
+            Where ``<some id>`` would be the primary key of
+            ``other``. From the above, it is clear that
+            :meth:`~.RelationshipProperty.Comparator.contains`
+            will **not** work with many-to-many collections when
+            used in queries that move beyond simple AND
+            conjunctions, such as multiple
+            :meth:`~.RelationshipProperty.Comparator.contains`
+            expressions joined by OR. In such cases subqueries or
+            explicit "outer joins" will need to be used instead.
+            See :meth:`~.RelationshipProperty.Comparator.any` for
+            a less-performant alternative using EXISTS, or refer
+            to :meth:`.Query.outerjoin` as well as :ref:`ormtutorial_joins`
+            for more details on constructing outer joins.
+            
+            """
             if not self.property.uselist:
                 raise sa_exc.InvalidRequestError(
                             "'contains' not implemented for scalar "
@@ -461,6 +640,44 @@ class RelationshipProperty(StrategizedProperty):
             return ~self._criterion_exists(criterion)
 
         def __ne__(self, other):
+            """Implement the ``!=`` operator.
+
+            In a many-to-one context, such as::
+  
+              MyClass.some_prop != <some object>
+  
+            This will typically produce a clause such as::
+  
+              mytable.related_id != <some id>
+  
+            Where ``<some id>`` is the primary key of the
+            given object.
+  
+            The ``!=`` operator provides partial functionality for non-
+            many-to-one comparisons:
+  
+            * Comparisons against collections are not supported.
+              Use
+              :meth:`~.RelationshipProperty.Comparator.contains`
+              in conjunction with :func:`~.expression.not_`.
+            * Compared to a scalar one-to-many, will produce a 
+              clause that compares the target columns in the parent to
+              the given target. 
+            * Compared to a scalar many-to-many, an alias
+              of the association table will be rendered as
+              well, forming a natural join that is part of the
+              main body of the query. This will not work for
+              queries that go beyond simple AND conjunctions of
+              comparisons, such as those which use OR. Use
+              explicit joins, outerjoins, or
+              :meth:`~.RelationshipProperty.Comparator.has` in
+              conjunction with :func:`~.expression.not_` for
+              more comprehensive non-many-to-one scalar
+              membership tests.
+            * Comparisons against ``None`` given in a one-to-many
+              or many-to-many context produce an EXISTS clause.
+                
+            """
             if isinstance(other, (NoneType, expression._Null)):
                 if self.property.direction == MANYTOONE:
                     return sql.or_(*[x != None for x in
@@ -1253,7 +1470,6 @@ class RelationshipProperty(StrategizedProperty):
             target_adapter,
             )
 
-
 PropertyLoader = RelationProperty = RelationshipProperty
 log.class_logger(RelationshipProperty)
 
index 0f06e9ee76e01067c815140e3661f5c19b3c676e..eb40e9d40dafa047ef7ec2ac609b71b7a9f5685d 100644 (file)
@@ -57,7 +57,11 @@ def nullsfirst(column):
 
     e.g.::
 
-      order_by = [desc(table1.mycol).nullsfirst()]
+      someselect.order_by(desc(table1.mycol).nullsfirst())
+      
+    produces::
+    
+      ORDER BY mycol DESC NULLS FIRST
 
     """
     return _UnaryExpression(column, modifier=operators.nullsfirst_op)
@@ -67,7 +71,11 @@ def nullslast(column):
 
     e.g.::
 
-      order_by = [desc(table1.mycol).nullslast()]
+      someselect.order_by(desc(table1.mycol).nullslast())
+      
+    produces::
+    
+        ORDER BY mycol DESC NULLS LAST
 
     """
     return _UnaryExpression(column, modifier=operators.nullslast_op)
@@ -77,7 +85,11 @@ def desc(column):
 
     e.g.::
 
-      order_by = [desc(table1.mycol)]
+      someselect.order_by(desc(table1.mycol))
+      
+    produces::
+    
+        ORDER BY mycol DESC
 
     """
     return _UnaryExpression(column, modifier=operators.desc_op)
@@ -87,7 +99,11 @@ def asc(column):
 
     e.g.::
 
-      order_by = [asc(table1.mycol)]
+      someselect.order_by(asc(table1.mycol))
+      
+    produces::
+    
+      ORDER BY mycol ASC
 
     """
     return _UnaryExpression(column, modifier=operators.asc_op)
@@ -97,22 +113,21 @@ def outerjoin(left, right, onclause=None):
 
     The returned object is an instance of :class:`.Join`.
 
-    Similar functionality is also available via the :func:`outerjoin()`
-    method on any :class:`.FromClause`.
+    Similar functionality is also available via the 
+    :meth:`~.FromClause.outerjoin()` method on any 
+    :class:`.FromClause`.
 
-    left
-      The left side of the join.
+    :param left: The left side of the join.
 
-    right
-      The right side of the join.
+    :param right: The right side of the join.
 
-    onclause
-      Optional criterion for the ``ON`` clause, is derived from
-      foreign key relationships established between left and right
-      otherwise.
+    :param onclause:  Optional criterion for the ``ON`` clause, is 
+      derived from foreign key relationships established between 
+      left and right otherwise.
 
-    To chain joins together, use the :func:`join()` or :func:`outerjoin()`
-    methods on the resulting :class:`.Join` object.
+    To chain joins together, use the :meth:`.FromClause.join` or 
+    :meth:`.FromClause.outerjoin` methods on the resulting 
+    :class:`.Join` object.
 
     """
     return Join(left, right, onclause, isouter=True)
@@ -122,22 +137,22 @@ def join(left, right, onclause=None, isouter=False):
 
     The returned object is an instance of :class:`.Join`.
 
-    Similar functionality is also available via the :func:`join()` method
-    on any :class:`.FromClause`.
+    Similar functionality is also available via the 
+    :meth:`~.FromClause.join()` method on any 
+    :class:`.FromClause`.
 
-    left
-      The left side of the join.
+    :param left: The left side of the join.
 
-    right
-      The right side of the join.
+    :param right: The right side of the join.
 
-    onclause
-      Optional criterion for the ``ON`` clause, is derived from
-      foreign key relationships established between left and right
-      otherwise.
+    :param onclause:  Optional criterion for the ``ON`` clause, is 
+      derived from foreign key relationships established between 
+      left and right otherwise.
+
+    To chain joins together, use the :meth:`.FromClause.join` or 
+    :meth:`.FromClause.outerjoin` methods on the resulting 
+    :class:`.Join` object.
 
-    To chain joins together, use the :func:`join()` or :func:`outerjoin()`
-    methods on the resulting :class:`.Join` object.
 
     """
     return Join(left, right, onclause, isouter)
@@ -431,7 +446,17 @@ def not_(clause):
     return operators.inv(_literal_as_binds(clause))
 
 def distinct(expr):
-    """Return a ``DISTINCT`` clause."""
+    """Return a ``DISTINCT`` clause.
+    
+    e.g.::
+    
+        distinct(a)
+        
+    renders::
+    
+        DISTINCT a
+        
+    """
     expr = _literal_as_binds(expr)
     return _UnaryExpression(expr, operator=operators.distinct_op, type_=expr.type)
 
@@ -525,7 +550,17 @@ def extract(field, expr):
     return _Extract(field, expr)
 
 def collate(expression, collation):
-    """Return the clause ``expression COLLATE collation``."""
+    """Return the clause ``expression COLLATE collation``.
+    
+    e.g.::
+    
+        collate(mycolumn, 'utf8_bin')
+    
+    produces::
+    
+        mycolumn COLLATE utf8_bin
+
+    """
 
     expr = _literal_as_binds(expression)
     return _BinaryExpression(
@@ -1641,15 +1676,93 @@ class Operators(object):
     
     """
     def __and__(self, other):
+        """Implement the ``&`` operator.
+        
+        When used with SQL expressions, results in an
+        AND operation, equivalent to
+        :func:`~.expression.and_`, that is::
+        
+            a & b
+        
+        is equivalent to::
+        
+            from sqlalchemy import and_
+            and_(a, b)
+
+        Care should be taken when using ``&`` regarding
+        operator precedence; the ``&`` operator has the highest precedence.
+        The operands should be enclosed in parenthesis if they contain
+        further sub expressions::
+        
+            (a == 2) & (b == 4)
+
+        """
         return self.operate(operators.and_, other)
 
     def __or__(self, other):
+        """Implement the ``|`` operator.
+        
+        When used with SQL expressions, results in an
+        OR operation, equivalent to
+        :func:`~.expression.or_`, that is::
+        
+            a | b
+        
+        is equivalent to::
+        
+            from sqlalchemy import or_
+            or_(a, b)
+
+        Care should be taken when using ``|`` regarding
+        operator precedence; the ``|`` operator has the highest precedence.
+        The operands should be enclosed in parenthesis if they contain
+        further sub expressions::
+        
+            (a == 2) | (b == 4)
+
+        """
         return self.operate(operators.or_, other)
 
     def __invert__(self):
+        """Implement the ``~`` operator.
+        
+        When used with SQL expressions, results in a 
+        NOT operation, equivalent to 
+        :func:`~.expression.not_`, that is::
+        
+            ~a
+            
+        is equivalent to::
+        
+            from sqlalchemy import not_
+            not_(a)
+
+        """
         return self.operate(operators.inv)
 
     def op(self, opstring):
+        """produce a generic operator function.
+
+        e.g.::
+
+          somecolumn.op("*")(5)
+
+        produces::
+
+          somecolumn * 5
+
+        :param operator: a string which will be output as the infix operator
+          between this :class:`.ClauseElement` and the expression passed to the
+          generated function.
+
+        This function can also be used to make bitwise operators explicit. For
+        example::
+
+          somecolumn.op('&')(0xff)
+
+        is a bitwise AND of the value in somecolumn.
+
+        """
         def op(b):
             return self.operate(operators.op, opstring, b)
         return op
@@ -1713,115 +1826,278 @@ class ColumnOperators(Operators):
     so that the ``==`` operation above is replaced by a clause
     construct.
     
+    The docstrings here will describe column-oriented
+    behavior of each operator.  For ORM-based operators
+    on related objects and collections, see :class:`.RelationshipProperty.Comparator`.
+    
     """
 
     timetuple = None
     """Hack, allows datetime objects to be compared on the LHS."""
 
     def __lt__(self, other):
+        """Implement the ``<`` operator.
+        
+        In a column context, produces the clause ``a < b``.
+        
+        """
         return self.operate(operators.lt, other)
 
     def __le__(self, other):
+        """Implement the ``<=`` operator.
+        
+        In a column context, produces the clause ``a <= b``.
+        
+        """
         return self.operate(operators.le, other)
 
     __hash__ = Operators.__hash__
 
     def __eq__(self, other):
+        """Implement the ``==`` operator.
+        
+        In a column context, produces the clause ``a = b``.
+        If the target is ``None``, produces ``a IS NULL``.
+
+        """
         return self.operate(operators.eq, other)
 
     def __ne__(self, other):
+        """Implement the ``!=`` operator.
+
+        In a column context, produces the clause ``a != b``.
+        If the target is ``None``, produces ``a IS NOT NULL``.
+        
+        """
         return self.operate(operators.ne, other)
 
     def __gt__(self, other):
+        """Implement the ``>`` operator.
+        
+        In a column context, produces the clause ``a > b``.
+        
+        """
         return self.operate(operators.gt, other)
 
     def __ge__(self, other):
+        """Implement the ``>=`` operator.
+        
+        In a column context, produces the clause ``a >= b``.
+        
+        """
         return self.operate(operators.ge, other)
 
     def __neg__(self):
+        """Implement the ``-`` operator.
+        
+        In a column context, produces the clause ``-a``.
+        
+        """
         return self.operate(operators.neg)
 
     def concat(self, other):
+        """Implement the 'concat' operator.
+        
+        In a column context, produces the clause ``a || b``,
+        or uses the ``concat()`` operator on MySQL.
+        
+        """
         return self.operate(operators.concat_op, other)
 
     def like(self, other, escape=None):
+        """Implement the ``like`` operator.
+        
+        In a column context, produces the clause ``a LIKE other``.
+        
+        """
         return self.operate(operators.like_op, other, escape=escape)
 
     def ilike(self, other, escape=None):
+        """Implement the ``ilike`` operator.
+        
+        In a column context, produces the clause ``a ILIKE other``.
+        
+        """
         return self.operate(operators.ilike_op, other, escape=escape)
 
     def in_(self, other):
+        """Implement the ``in`` operator.
+        
+        In a column context, produces the clause ``a IN other``.
+        "other" may be a tuple/list of column expressions,
+        or a :func:`~.expression.select` construct.
+        
+        """
         return self.operate(operators.in_op, other)
 
     def startswith(self, other, **kwargs):
+        """Implement the ``startwith`` operator.
+
+        In a column context, produces the clause ``LIKE '<other>%'``
+        
+        """
         return self.operate(operators.startswith_op, other, **kwargs)
 
     def endswith(self, other, **kwargs):
+        """Implement the 'endswith' operator.
+        
+        In a column context, produces the clause ``LIKE '%<other>'``
+        
+        """
         return self.operate(operators.endswith_op, other, **kwargs)
 
     def contains(self, other, **kwargs):
+        """Implement the 'contains' operator.
+        
+        In a column context, produces the clause ``LIKE '%<other>%'``
+        
+        """
         return self.operate(operators.contains_op, other, **kwargs)
 
     def match(self, other, **kwargs):
+        """Implements the 'match' operator.
+        
+        In a column context, this produces a MATCH clause, i.e. 
+        ``MATCH '<other>'``.  The allowed contents of ``other`` 
+        are database backend specific.
+
+        """
         return self.operate(operators.match_op, other, **kwargs)
 
     def desc(self):
+        """Produce a :func:`~.expression.desc` clause against the
+        parent object."""
         return self.operate(operators.desc_op)
 
     def asc(self):
+        """Produce a :func:`~.expression.asc` clause against the
+        parent object."""
         return self.operate(operators.asc_op)
 
     def nullsfirst(self):
+        """Produce a :func:`~.expression.nullsfirst` clause against the
+        parent object."""
         return self.operate(operators.nullsfirst_op)
 
     def nullslast(self):
+        """Produce a :func:`~.expression.nullslast` clause against the
+        parent object."""
         return self.operate(operators.nullslast_op)
 
     def collate(self, collation):
+        """Produce a :func:`~.expression.collate` clause against
+        the parent object, given the collation string."""
         return self.operate(operators.collate, collation)
 
     def __radd__(self, other):
+        """Implement the ``+`` operator in reverse.
+
+        See :meth:`__add__`.
+        
+        """
         return self.reverse_operate(operators.add, other)
 
     def __rsub__(self, other):
+        """Implement the ``-`` operator in reverse.
+
+        See :meth:`__sub__`.
+        
+        """
         return self.reverse_operate(operators.sub, other)
 
     def __rmul__(self, other):
+        """Implement the ``*`` operator in reverse.
+
+        See :meth:`__mul__`.
+        
+        """
         return self.reverse_operate(operators.mul, other)
 
     def __rdiv__(self, other):
+        """Implement the ``/`` operator in reverse.
+
+        See :meth:`__div__`.
+        
+        """
         return self.reverse_operate(operators.div, other)
 
     def between(self, cleft, cright):
+        """Produce a :func:`~.expression.between` clause against
+        the parent object, given the lower and upper range."""
         return self.operate(operators.between_op, cleft, cright)
 
     def distinct(self):
+        """Produce a :func:`~.expression.distinct` clause against the parent object."""
         return self.operate(operators.distinct_op)
 
     def __add__(self, other):
+        """Implement the ``+`` operator.
+        
+        In a column context, produces the clause ``a + b``
+        if the parent object has non-string affinity.
+        If the parent object has a string affinity, 
+        produces the concatenation operator, ``a || b`` -
+        see :meth:`concat`.
+        
+        """
         return self.operate(operators.add, other)
 
     def __sub__(self, other):
+        """Implement the ``-`` operator.
+        
+        In a column context, produces the clause ``a - b``.
+        
+        """
         return self.operate(operators.sub, other)
 
     def __mul__(self, other):
+        """Implement the ``*`` operator.
+        
+        In a column context, produces the clause ``a * b``.
+        
+        """
         return self.operate(operators.mul, other)
 
     def __div__(self, other):
+        """Implement the ``/`` operator.
+        
+        In a column context, produces the clause ``a / b``.
+        
+        """
         return self.operate(operators.div, other)
 
     def __mod__(self, other):
+        """Implement the ``%`` operator.
+        
+        In a column context, produces the clause ``a % b``.
+        
+        """
         return self.operate(operators.mod, other)
 
     def __truediv__(self, other):
+        """Implement the ``//`` operator.
+        
+        In a column context, produces the clause ``a / b``.
+        
+        """
         return self.operate(operators.truediv, other)
 
     def __rtruediv__(self, other):
+        """Implement the ``//`` operator in reverse.
+        
+        See :meth:`__truediv__`.
+        
+        """
         return self.reverse_operate(operators.truediv, other)
 
 class _CompareMixin(ColumnOperators):
     """Defines comparison and math operations for :class:`.ClauseElement`
-    instances."""
+    instances.
+    
+    See :class:`.ColumnOperators` and :class:`.Operators` for descriptions 
+    of all operations.
+    
+    """
 
     def __compare(self, op, obj, negate=None, reverse=False,
                         **kwargs
@@ -1902,8 +2178,7 @@ class _CompareMixin(ColumnOperators):
         return o[0](self, op, other, reverse=True, *o[1:], **kwargs)
 
     def in_(self, other):
-        """Compare this element to the given element or collection using IN."""
-
+        """See :meth:`.ColumnOperators.in_`."""
         return self._in_impl(operators.in_op, operators.notin_op, other)
 
     def _in_impl(self, op, negate_op, seq_or_selectable):
@@ -1958,11 +2233,11 @@ class _CompareMixin(ColumnOperators):
                               negate=negate_op)
 
     def __neg__(self):
+        """See :meth:`.ColumnOperators.__neg__`."""
         return _UnaryExpression(self, operator=operators.neg)
 
     def startswith(self, other, escape=None):
-        """Produce the clause ``LIKE '<other>%'``"""
-
+        """See :meth:`.ColumnOperators.startswith`."""
         # use __radd__ to force string concat behavior
         return self.__compare(
             operators.like_op,
@@ -1972,8 +2247,7 @@ class _CompareMixin(ColumnOperators):
             escape=escape)
 
     def endswith(self, other, escape=None):
-        """Produce the clause ``LIKE '%<other>'``"""
-
+        """See :meth:`.ColumnOperators.endswith`."""
         return self.__compare(
             operators.like_op,
             literal_column("'%'", type_=sqltypes.String) + 
@@ -1981,8 +2255,7 @@ class _CompareMixin(ColumnOperators):
             escape=escape)
 
     def contains(self, other, escape=None):
-        """Produce the clause ``LIKE '%<other>%'``"""
-
+        """See :meth:`.ColumnOperators.contains`."""
         return self.__compare(
             operators.like_op,
             literal_column("'%'", type_=sqltypes.String) +
@@ -1991,11 +2264,7 @@ class _CompareMixin(ColumnOperators):
             escape=escape)
 
     def match(self, other):
-        """Produce a MATCH clause, i.e. ``MATCH '<other>'``
-
-        The allowed contents of ``other`` are database backend specific.
-
-        """
+        """See :meth:`.ColumnOperators.match`."""
         return self.__compare(operators.match_op,
                               self._check_literal(operators.match_op,
                               other))
@@ -2011,35 +2280,28 @@ class _CompareMixin(ColumnOperators):
         return _Label(name, self, self.type)
 
     def desc(self):
-        """Produce a DESC clause, i.e. ``<columnname> DESC``"""
-
+        """See :meth:`.ColumnOperators.desc`."""
         return desc(self)
 
     def asc(self):
-        """Produce a ASC clause, i.e. ``<columnname> ASC``"""
-
+        """See :meth:`.ColumnOperators.asc`."""
         return asc(self)
 
     def nullsfirst(self):
-        """Produce a NULLS FIRST clause, i.e. ``NULLS FIRST``"""
-
+        """See :meth:`.ColumnOperators.nullsfirst`."""
         return nullsfirst(self)
 
     def nullslast(self):
-        """Produce a NULLS LAST clause, i.e. ``NULLS LAST``"""
-
+        """See :meth:`.ColumnOperators.nullslast`."""
         return nullslast(self)
 
     def distinct(self):
-        """Produce a DISTINCT clause, i.e. ``DISTINCT <columnname>``"""
-
+        """See :meth:`.ColumnOperators.distinct`."""
         return _UnaryExpression(self, operator=operators.distinct_op,
                                 type_=self.type)
 
     def between(self, cleft, cright):
-        """Produce a BETWEEN clause, i.e. ``<column> BETWEEN <cleft> AND
-        <cright>``"""
-
+        """See :meth:`.ColumnOperators.between`."""
         return _BinaryExpression(
                 self,
                 ClauseList(
@@ -2050,33 +2312,13 @@ class _CompareMixin(ColumnOperators):
                 operators.between_op)
 
     def collate(self, collation):
-        """Produce a COLLATE clause, i.e. ``<column> COLLATE utf8_bin``"""
+        """See :meth:`.ColumnOperators.collate`."""
 
         return collate(self, collation)
 
     def op(self, operator):
-        """produce a generic operator function.
-
-        e.g.::
-
-          somecolumn.op("*")(5)
-
-        produces::
+        """See :meth:`.ColumnOperators.op`."""
 
-          somecolumn * 5
-
-        :param operator: a string which will be output as the infix operator
-          between this :class:`.ClauseElement` and the expression passed to the
-          generated function.
-
-        This function can also be used to make bitwise operators explicit. For
-        example::
-
-          somecolumn.op('&')(0xff)
-
-        is a bitwise AND of the value in somecolumn.
-
-        """
         return lambda other: self.__operate(operator, other)
 
     def _bind_param(self, operator, obj):