diff options
-rw-r--r-- | lib/sqlalchemy/ansisql.py | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 4 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/interfaces.py | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/orm/properties.py | 4 | ||||
-rw-r--r-- | lib/sqlalchemy/sql.py | 40 | ||||
-rw-r--r-- | test/orm/eager_relations.py | 4 | ||||
-rw-r--r-- | test/sql/select.py | 8 |
7 files changed, 50 insertions, 22 deletions
diff --git a/lib/sqlalchemy/ansisql.py b/lib/sqlalchemy/ansisql.py index 13e2c985d..ce3830db8 100644 --- a/lib/sqlalchemy/ansisql.py +++ b/lib/sqlalchemy/ansisql.py @@ -60,6 +60,7 @@ OPERATORS = { operator.gt : '>', operator.ge : '>=', operator.eq : '=', + sql.ColumnOperators.distinct_op : 'DISTINCT', sql.ColumnOperators.concat_op : '||', sql.ColumnOperators.like_op : 'LIKE', sql.ColumnOperators.notlike_op : 'NOT LIKE', @@ -69,6 +70,9 @@ OPERATORS = { sql.ColumnOperators.in_op : 'IN', sql.ColumnOperators.notin_op : 'NOT IN', sql.ColumnOperators.comma_op : ', ', + sql.ColumnOperators.desc_op : 'DESC', + sql.ColumnOperators.asc_op : 'ASC', + sql.Operators.from_ : 'FROM', sql.Operators.as_ : 'AS', sql.Operators.exists : 'EXISTS', @@ -392,7 +396,7 @@ class ANSICompiler(engine.Compiled, sql.ClauseVisitor): if unary.operator: s = self.operator_string(unary.operator) + " " + s if unary.modifier: - s = s + " " + unary.modifier + s = s + " " + self.operator_string(unary.modifier) return s def visit_binary(self, binary, **kwargs): diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index acff87332..6218371e0 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -98,8 +98,8 @@ class InstrumentedAttribute(interfaces.PropComparator): def expression_element(self): return self.comparator.expression_element() - def operate(self, op, other, **kwargs): - return op(self.comparator, other, **kwargs) + def operate(self, op, *other, **kwargs): + return op(self.comparator, *other, **kwargs) def reverse_operate(self, op, other, **kwargs): return op(other, self.comparator, **kwargs) diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 775892da1..abaeff49c 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -369,12 +369,6 @@ class PropComparator(sql.ColumnOperators): def expression_element(self): return self.clause_element() - def desc(self): - return self.clause_element().desc() - - def asc(self): - return self.clause_element().desc() - def contains_op(a, b): return a.contains(b) contains_op = staticmethod(contains_op) diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 0a47c0256..670fcccc9 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -70,8 +70,8 @@ class ColumnProperty(StrategizedProperty): def clause_element(self): return self.prop.columns[0] - def operate(self, op, other): - return op(self.prop.columns[0], other) + def operate(self, op, *other): + return op(self.prop.columns[0], *other) def reverse_operate(self, op, other): col = self.prop.columns[0] diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 06802cf6f..bc255c5af 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -47,7 +47,7 @@ def desc(column): order_by = [desc(table1.mycol)] """ - return _UnaryExpression(column, modifier="DESC") + return _UnaryExpression(column, modifier=ColumnOperators.desc_op) def asc(column): """Return an ascending ``ORDER BY`` clause element. @@ -56,7 +56,7 @@ def asc(column): order_by = [asc(table1.mycol)] """ - return _UnaryExpression(column, modifier="ASC") + return _UnaryExpression(column, modifier=ColumnOperators.asc_op) def outerjoin(left, right, onclause=None, **kwargs): """Return an ``OUTER JOIN`` clause element. @@ -362,7 +362,7 @@ def not_(clause): def distinct(expr): """return a ``DISTINCT`` clause.""" - return _UnaryExpression(expr, operator="DISTINCT") + return _UnaryExpression(expr, operator=ColumnOperators.distinct_op) def between(ctest, cleft, cright): """Return a ``BETWEEN`` predicate clause. @@ -1196,7 +1196,7 @@ class Operators(object): def operate(self, op, *other, **kwargs): raise NotImplementedError() - def reverse_operate(self, op, *other, **kwargs): + def reverse_operate(self, op, other, **kwargs): raise NotImplementedError() class ColumnOperators(Operators): @@ -1230,6 +1230,10 @@ class ColumnOperators(Operators): raise NotImplementedError() notin_op = staticmethod(notin_op) + def distinct_op(a): + return a.distinct() + distinct_op = staticmethod(distinct_op) + def startswith_op(a, b): return a.startswith(b) startswith_op = staticmethod(startswith_op) @@ -1246,6 +1250,14 @@ class ColumnOperators(Operators): return a.concat(b) concat_op = staticmethod(concat_op) + def desc_op(a): + return a.desc() + desc_op = staticmethod(desc_op) + + def asc_op(a): + return a.asc() + asc_op = staticmethod(asc_op) + def __lt__(self, other): return self.operate(operator.lt, other) @@ -1278,7 +1290,13 @@ class ColumnOperators(Operators): def endswith(self, other): return self.operate(ColumnOperators.endswith_op, other) - + + def desc(self): + return self.operate(ColumnOperators.desc_op) + + def asc(self): + return self.operate(ColumnOperators.asc_op) + def __radd__(self, other): return self.reverse_operate(operator.add, other) @@ -1292,8 +1310,11 @@ class ColumnOperators(Operators): return self.reverse_operate(operator.div, other) def between(self, cleft, cright): - return self.operate(Operators.between_op, (cleft, cright)) + return self.operate(ColumnOperators.between_op, cleft, cright) + def distinct(self): + return self.operate(ColumnOperators.distinct_op) + def __add__(self, other): return self.operate(operator.add, other) @@ -1340,6 +1361,7 @@ PRECEDENCE = { operator.ge:5, operator.le:5, ColumnOperators.between_op:5, + ColumnOperators.distinct_op:5, operator.inv:4, operator.and_:3, operator.or_:2, @@ -1394,9 +1416,9 @@ class _CompareMixin(ColumnOperators): ColumnOperators.like_op : (__compare, ColumnOperators.notlike_op), } - def operate(self, op, other): + def operate(self, op, *other): o = _CompareMixin.operators[op] - return o[0](self, op, other, *o[1:]) + return o[0](self, op, other[0], *o[1:]) def reverse_operate(self, op, other): return self._bind_param(other).operate(op, self) @@ -1456,7 +1478,7 @@ class _CompareMixin(ColumnOperators): def distinct(self): """produce a DISTINCT clause, i.e. ``DISTINCT <columnname>``""" - return _UnaryExpression(self, operator="DISTINCT") + return _UnaryExpression(self, operator=ColumnOperators.distinct_op) def between(self, cleft, cright): """produce a BETWEEN clause, i.e. ``<column> BETWEEN <cleft> AND <cright>``""" diff --git a/test/orm/eager_relations.py b/test/orm/eager_relations.py index d94332c09..dffc5322c 100644 --- a/test/orm/eager_relations.py +++ b/test/orm/eager_relations.py @@ -299,7 +299,7 @@ class EagerTest(QueryTest): q = sess.query(User) if testbase.db.engine.name != 'mssql': - l = q.join('orders').order_by(desc(Order.user_id)).limit(2).offset(1) + l = q.join('orders').order_by(Order.user_id.desc()).limit(2).offset(1) assert [ User(id=9, orders=[Order(id=2), Order(id=4)], @@ -311,7 +311,7 @@ class EagerTest(QueryTest): ) ] == l.all() - l = q.join('addresses').order_by(desc(Address.email_address)).limit(1).offset(0) + l = q.join('addresses').order_by(Address.email_address.desc()).limit(1).offset(0) assert [ User(id=7, orders=[Order(id=1), Order(id=3), Order(id=5)], diff --git a/test/sql/select.py b/test/sql/select.py index 2e099b01a..0edaab071 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -314,6 +314,14 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") A self.runtest( select([table1.c.myid]).distinct(), "SELECT DISTINCT mytable.myid FROM mytable" ) + + self.runtest( + select([func.count(table1.c.myid.distinct())]), "SELECT count(DISTINCT mytable.myid) FROM mytable" + ) + + self.runtest( + select([func.count(distinct(table1.c.myid))]), "SELECT count(DISTINCT mytable.myid) FROM mytable" + ) def testoperators(self): |