From: Mike Bayer Date: Thu, 26 May 2011 17:30:26 +0000 (-0400) Subject: - get all comparison operators to document with sphinx - column based, relationship... X-Git-Tag: rel_0_7_1~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba299476b827ada34d01360e3024f87dd56dc967;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - get all comparison operators to document with sphinx - column based, relationship based. Should fix misunderstandings like [ticket:2177] --- diff --git a/doc/build/builder/builders.py b/doc/build/builder/builders.py index c965650249..25e283e5d3 100644 --- a/doc/build/builder/builders.py +++ b/doc/build/builder/builders.py @@ -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 diff --git a/doc/build/core/expression_api.rst b/doc/build/core/expression_api.rst index cfa22591de..b5e47b6ac2 100644 --- a/doc/build/core/expression_api.rst +++ b/doc/build/core/expression_api.rst @@ -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 diff --git a/doc/build/orm/internals.rst b/doc/build/orm/internals.rst index bb3e3ffb55..c23e5f2f73 100644 --- a/doc/build/orm/internals.rst +++ b/doc/build/orm/internals.rst @@ -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: diff --git a/doc/build/orm/mapper_config.rst b/doc/build/orm/mapper_config.rst index 96c641f905..259a6ecbab 100644 --- a/doc/build/orm/mapper_config.rst +++ b/doc/build/orm/mapper_config.rst @@ -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 diff --git a/doc/build/orm/tutorial.rst b/doc/build/orm/tutorial.rst index f77225c400..2a646d3e28 100644 --- a/doc/build/orm/tutorial.rst +++ b/doc/build/orm/tutorial.rst @@ -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') diff --git a/doc/build/static/docs.css b/doc/build/static/docs.css index 64659acf81..84a24771f4 100644 --- a/doc/build/static/docs.css +++ b/doc/build/static/docs.css @@ -247,6 +247,9 @@ div#dialect-documentation { /* SQL popup, code styles */ +.highlight { + background:none; +} pre { background-color: #f0f0f0; border: solid 1px #ccc; diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 7a87485566..93200d371c 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -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:: diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 53fb5d85de..b4ef7235cd 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -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 == + + this will typically produce a + clause such as:: + + mytable.related_id == + + Where ```` 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 == + + Where ```` 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 = + + Where ```` 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 != + + This will typically produce a clause such as:: + + mytable.related_id != + + Where ```` 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) diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 0f06e9ee76..eb40e9d40d 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -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 '%'`` + + """ 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 '%'`` + + """ 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 '%%'`` + + """ 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 ''``. 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 '%'``""" - + """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 '%'``""" - + """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 '%%'``""" - + """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 ''`` - - 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. `` DESC``""" - + """See :meth:`.ColumnOperators.desc`.""" return desc(self) def asc(self): - """Produce a ASC clause, i.e. `` 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 ``""" - + """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. `` BETWEEN AND - ``""" - + """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. `` 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):