diff --git a/CHANGES.rst b/CHANGES.rst index 2a23e48..d04060a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,12 @@ Changelog Here you can see the full list of changes between each SQLAlchemy-Utils release. +0.27.3 (2014-10-22) +^^^^^^^^^^^^^^^^^^^ + +- Added supported for various SQLAlchemy objects in make_order_by_deterministic (previosly this function threw exceptions for other than Column objects) + + 0.27.2 (2014-10-21) ^^^^^^^^^^^^^^^^^^^ diff --git a/sqlalchemy_utils/__init__.py b/sqlalchemy_utils/__init__.py index 3f523f4..57d841a 100644 --- a/sqlalchemy_utils/__init__.py +++ b/sqlalchemy_utils/__init__.py @@ -78,7 +78,7 @@ from .types import ( from .models import Timestamp -__version__ = '0.27.2' +__version__ = '0.27.3' __all__ = ( diff --git a/sqlalchemy_utils/functions/sort_query.py b/sqlalchemy_utils/functions/sort_query.py index 3ea12e4..15004f7 100644 --- a/sqlalchemy_utils/functions/sort_query.py +++ b/sqlalchemy_utils/functions/sort_query.py @@ -1,4 +1,3 @@ -import six import sqlalchemy as sa from sqlalchemy.sql.expression import desc, asc @@ -174,23 +173,18 @@ def make_order_by_deterministic(query): return query order_by = query._order_by[0] - if isinstance(order_by, sa.Column): - order_by_func = sa.asc - column = order_by - elif isinstance(order_by, sa.sql.expression.UnaryExpression): + if isinstance(order_by, sa.sql.expression.UnaryExpression): if order_by.modifier == sa.sql.operators.desc_op: order_by_func = sa.desc else: order_by_func = sa.asc column = order_by.get_children()[0] - elif isinstance(order_by, six.string_types): - raise TypeError( - 'Order by str is not supported. Use SA Column objects instead.' - ) else: - raise TypeError('Only simple columns in query order by are supported.') + column = order_by + order_by_func = sa.asc - if has_unique_index(column): + # Queries that are ordered by an already + if isinstance(column, sa.Column) and has_unique_index(column): return query base_table = get_tables(query._entities[0])[0] diff --git a/tests/functions/test_make_order_by_deterministic.py b/tests/functions/test_make_order_by_deterministic.py index 5aa6ba3..c40aff5 100644 --- a/tests/functions/test_make_order_by_deterministic.py +++ b/tests/functions/test_make_order_by_deterministic.py @@ -1,4 +1,3 @@ -from pytest import raises import sqlalchemy as sa from sqlalchemy_utils.functions.sort_query import make_order_by_deterministic @@ -18,12 +17,25 @@ class TestMakeOrderByDeterministic(TestCase): sa.func.lower(name) ) + + class Article(self.Base): + __tablename__ = 'article' + id = sa.Column(sa.Integer, primary_key=True) + author_id = sa.Column(sa.Integer, sa.ForeignKey('user.id')) + author = sa.orm.relationship(User) + + User.article_count = sa.orm.column_property( + sa.select([sa.func.count()], from_obj=Article) + .where(Article.author_id == User.id) + .label('article_count') + ) + self.User = User def test_column_property(self): query = self.session.query(self.User).order_by(self.User.email_lower) - with raises(TypeError): - make_order_by_deterministic(query) + query = make_order_by_deterministic(query) + assert_contains('lower("user".name), "user".id ASC', query) def test_unique_column(self): query = self.session.query(self.User).order_by(self.User.email) @@ -52,8 +64,20 @@ class TestMakeOrderByDeterministic(TestCase): def test_string_order_by(self): query = self.session.query(self.User).order_by('name') - with raises(TypeError): - query = make_order_by_deterministic(query) + query = make_order_by_deterministic(query) + assert_contains('ORDER BY name, "user".id ASC', query) + + def test_annotated_label(self): + query = self.session.query(self.User).order_by(self.User.article_count) + query = make_order_by_deterministic(query) + assert_contains('article_count, "user".id ASC', query) + + def test_annotated_label_with_descending_order(self): + query = self.session.query(self.User).order_by( + sa.desc(self.User.article_count) + ) + query = make_order_by_deterministic(query) + assert_contains('ORDER BY article_count DESC, "user".id DESC', query) def test_query_without_order_by(self): query = self.session.query(self.User)