Fix sort_query handling of polymorphic inheritance
This commit is contained in:
@@ -4,6 +4,12 @@ Changelog
|
|||||||
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
Here you can see the full list of changes between each SQLAlchemy-Utils release.
|
||||||
|
|
||||||
|
|
||||||
|
0.26.8 (2014-07-30)
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Fixed order by column property handling in sort_query when using polymorphic inheritance
|
||||||
|
|
||||||
|
|
||||||
0.26.7 (2014-07-29)
|
0.26.7 (2014-07-29)
|
||||||
^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|||||||
@@ -46,12 +46,10 @@ class QuerySorter(object):
|
|||||||
property_ = properties[attr]
|
property_ = properties[attr]
|
||||||
if isinstance(property_, ColumnProperty):
|
if isinstance(property_, ColumnProperty):
|
||||||
if isinstance(property_.columns[0], Label):
|
if isinstance(property_.columns[0], Label):
|
||||||
expr = property_.columns[0].name
|
return getattr(entity, property_.key)
|
||||||
else:
|
else:
|
||||||
expr = get_expr_attr(entity, property_.key)
|
return get_expr_attr(entity, property_.key)
|
||||||
return expr
|
return
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
mapper = sa.inspect(entity)
|
mapper = sa.inspect(entity)
|
||||||
|
|
||||||
@@ -81,6 +79,7 @@ class QuerySorter(object):
|
|||||||
self.query = query
|
self.query = query
|
||||||
self.labels = query_labels(query)
|
self.labels = query_labels(query)
|
||||||
self.entities = query_entities(query)
|
self.entities = query_entities(query)
|
||||||
|
|
||||||
for sort in args:
|
for sort in args:
|
||||||
if not sort:
|
if not sort:
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -5,24 +5,31 @@ from sqlalchemy_utils.functions import QuerySorterException
|
|||||||
from tests import TestCase
|
from tests import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
def assert_contains(clause, query):
|
||||||
|
# Test that query executes
|
||||||
|
query.all()
|
||||||
|
assert clause in str(query)
|
||||||
|
|
||||||
|
|
||||||
class TestSortQuery(TestCase):
|
class TestSortQuery(TestCase):
|
||||||
|
|
||||||
def test_without_sort_param_returns_the_query_object_untouched(self):
|
def test_without_sort_param_returns_the_query_object_untouched(self):
|
||||||
query = self.session.query(self.Article)
|
query = self.session.query(self.Article)
|
||||||
sorted_query = sort_query(query, '')
|
query = sort_query(query, '')
|
||||||
assert query == sorted_query
|
assert query == query
|
||||||
|
|
||||||
def test_column_ascending(self):
|
def test_column_ascending(self):
|
||||||
query = sort_query(self.session.query(self.Article), 'name')
|
query = sort_query(self.session.query(self.Article), 'name')
|
||||||
assert 'ORDER BY article.name ASC' in str(query)
|
assert_contains('ORDER BY article.name ASC', query)
|
||||||
|
|
||||||
def test_column_descending(self):
|
def test_column_descending(self):
|
||||||
query = sort_query(self.session.query(self.Article), '-name')
|
query = sort_query(self.session.query(self.Article), '-name')
|
||||||
assert 'ORDER BY article.name DESC' in str(query)
|
assert_contains('ORDER BY article.name DESC', query)
|
||||||
|
|
||||||
def test_skips_unknown_columns(self):
|
def test_skips_unknown_columns(self):
|
||||||
query = self.session.query(self.Article)
|
query = self.session.query(self.Article)
|
||||||
sorted_query = sort_query(query, '-unknown')
|
query = sort_query(query, '-unknown')
|
||||||
assert query == sorted_query
|
assert query == query
|
||||||
|
|
||||||
def test_non_silent_mode(self):
|
def test_non_silent_mode(self):
|
||||||
query = self.session.query(self.Article)
|
query = self.session.query(self.Article)
|
||||||
@@ -35,21 +42,21 @@ class TestSortQuery(TestCase):
|
|||||||
.join(self.Article.category)
|
.join(self.Article.category)
|
||||||
)
|
)
|
||||||
query = sort_query(query, 'name', silent=False)
|
query = sort_query(query, 'name', silent=False)
|
||||||
assert 'ORDER BY article.name ASC' in str(query)
|
assert_contains('ORDER BY article.name ASC', query)
|
||||||
|
|
||||||
def test_calculated_value_ascending(self):
|
def test_calculated_value_ascending(self):
|
||||||
query = self.session.query(
|
query = self.session.query(
|
||||||
self.Category, sa.func.count(self.Article.id).label('articles')
|
self.Category, sa.func.count(self.Article.id).label('articles')
|
||||||
)
|
)
|
||||||
query = sort_query(query, 'articles')
|
query = sort_query(query, 'articles')
|
||||||
assert 'ORDER BY articles ASC' in str(query)
|
assert_contains('ORDER BY articles ASC', query)
|
||||||
|
|
||||||
def test_calculated_value_descending(self):
|
def test_calculated_value_descending(self):
|
||||||
query = self.session.query(
|
query = self.session.query(
|
||||||
self.Category, sa.func.count(self.Article.id).label('articles')
|
self.Category, sa.func.count(self.Article.id).label('articles')
|
||||||
)
|
)
|
||||||
query = sort_query(query, '-articles')
|
query = sort_query(query, '-articles')
|
||||||
assert 'ORDER BY articles DESC' in str(query)
|
assert_contains('ORDER BY articles DESC', query)
|
||||||
|
|
||||||
def test_subqueried_scalar(self):
|
def test_subqueried_scalar(self):
|
||||||
article_count = (
|
article_count = (
|
||||||
@@ -65,7 +72,7 @@ class TestSortQuery(TestCase):
|
|||||||
self.Category, article_count.label('articles')
|
self.Category, article_count.label('articles')
|
||||||
)
|
)
|
||||||
query = sort_query(query, '-articles')
|
query = sort_query(query, '-articles')
|
||||||
assert 'ORDER BY articles DESC' in str(query)
|
assert_contains('ORDER BY articles DESC', query)
|
||||||
|
|
||||||
def test_aliased_joined_entity(self):
|
def test_aliased_joined_entity(self):
|
||||||
alias = sa.orm.aliased(self.Category, name='categories')
|
alias = sa.orm.aliased(self.Category, name='categories')
|
||||||
@@ -75,17 +82,17 @@ class TestSortQuery(TestCase):
|
|||||||
alias, self.Article.category
|
alias, self.Article.category
|
||||||
)
|
)
|
||||||
query = sort_query(query, '-categories-name')
|
query = sort_query(query, '-categories-name')
|
||||||
assert 'ORDER BY categories.name DESC' in str(query)
|
assert_contains('ORDER BY categories.name DESC', query)
|
||||||
|
|
||||||
def test_joined_table_column(self):
|
def test_joined_table_column(self):
|
||||||
query = self.session.query(self.Article).join(self.Article.category)
|
query = self.session.query(self.Article).join(self.Article.category)
|
||||||
sorted_query = sort_query(query, 'category-name')
|
query = sort_query(query, 'category-name')
|
||||||
assert 'category.name ASC' in str(sorted_query)
|
assert_contains('category.name ASC', query)
|
||||||
|
|
||||||
def test_multiple_columns(self):
|
def test_multiple_columns(self):
|
||||||
query = self.session.query(self.Article)
|
query = self.session.query(self.Article)
|
||||||
sorted_query = sort_query(query, 'name', 'id')
|
query = sort_query(query, 'name', 'id')
|
||||||
assert 'article.name ASC, article.id ASC' in str(sorted_query)
|
assert_contains('article.name ASC, article.id ASC', query)
|
||||||
|
|
||||||
def test_column_property(self):
|
def test_column_property(self):
|
||||||
self.Category.article_count = sa.orm.column_property(
|
self.Category.article_count = sa.orm.column_property(
|
||||||
@@ -95,8 +102,8 @@ class TestSortQuery(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
sorted_query = sort_query(query, 'article_count')
|
query = sort_query(query, 'article_count')
|
||||||
assert 'article_count ASC' in str(sorted_query)
|
assert_contains('article_count ASC', query)
|
||||||
|
|
||||||
def test_column_property_descending(self):
|
def test_column_property_descending(self):
|
||||||
self.Category.article_count = sa.orm.column_property(
|
self.Category.article_count = sa.orm.column_property(
|
||||||
@@ -106,8 +113,8 @@ class TestSortQuery(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
sorted_query = sort_query(query, '-article_count')
|
query = sort_query(query, '-article_count')
|
||||||
assert 'article_count DESC' in str(sorted_query)
|
assert_contains('article_count DESC', query)
|
||||||
|
|
||||||
def test_relationship_property(self):
|
def test_relationship_property(self):
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
@@ -122,19 +129,20 @@ class TestSortQuery(TestCase):
|
|||||||
def test_synonym_property(self):
|
def test_synonym_property(self):
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
query = sort_query(query, 'name_synonym')
|
query = sort_query(query, 'name_synonym')
|
||||||
assert 'ORDER BY name DESC'
|
assert_contains('ORDER BY name DESC', query)
|
||||||
|
|
||||||
def test_hybrid_property(self):
|
def test_hybrid_property(self):
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
query = sort_query(query, 'articles_count')
|
query = sort_query(query, 'articles_count')
|
||||||
assert 'ORDER BY (SELECT count(article.id) AS count_1' in str(query)
|
assert_contains('ORDER BY (SELECT count(article.id) AS count_1', query)
|
||||||
|
|
||||||
def test_hybrid_property_descending(self):
|
def test_hybrid_property_descending(self):
|
||||||
query = self.session.query(self.Category)
|
query = self.session.query(self.Category)
|
||||||
query = sort_query(query, '-articles_count')
|
query = sort_query(query, '-articles_count')
|
||||||
assert (
|
assert_contains(
|
||||||
'ORDER BY (SELECT count(article.id) AS count_1'
|
'ORDER BY (SELECT count(article.id) AS count_1',
|
||||||
) in str(query)
|
query
|
||||||
|
)
|
||||||
assert ' DESC' in str(query)
|
assert ' DESC' in str(query)
|
||||||
|
|
||||||
def test_assigned_hybrid_property(self):
|
def test_assigned_hybrid_property(self):
|
||||||
@@ -146,16 +154,22 @@ class TestSortQuery(TestCase):
|
|||||||
)
|
)
|
||||||
query = self.session.query(self.Article)
|
query = self.session.query(self.Article)
|
||||||
query = sort_query(query, 'some_hybrid')
|
query = sort_query(query, 'some_hybrid')
|
||||||
assert 'ORDER BY article.name ASC' in str(query)
|
assert_contains('ORDER BY article.name ASC', query)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSortQueryRelationshipCounts(TestCase):
|
||||||
|
"""
|
||||||
|
Currently this doesn't work with SQLite
|
||||||
|
"""
|
||||||
|
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
|
||||||
|
|
||||||
def test_relation_hybrid_property(self):
|
def test_relation_hybrid_property(self):
|
||||||
query = (
|
query = (
|
||||||
self.session.query(self.Article)
|
self.session.query(self.Article)
|
||||||
.join(self.Article.category)
|
.join(self.Article.category)
|
||||||
.correlate(self.Article.__table__)
|
).group_by(self.Article.id)
|
||||||
)
|
|
||||||
query = sort_query(query, '-category-articles_count')
|
query = sort_query(query, '-category-articles_count')
|
||||||
assert 'ORDER BY (SELECT count(article.id) AS count_1' in str(query)
|
assert_contains('ORDER BY (SELECT count(article.id) AS count_1', query)
|
||||||
|
|
||||||
def test_aliased_hybrid_property(self):
|
def test_aliased_hybrid_property(self):
|
||||||
alias = sa.orm.aliased(
|
alias = sa.orm.aliased(
|
||||||
@@ -168,6 +182,54 @@ class TestSortQuery(TestCase):
|
|||||||
.options(
|
.options(
|
||||||
sa.orm.contains_eager(self.Article.category, alias=alias)
|
sa.orm.contains_eager(self.Article.category, alias=alias)
|
||||||
)
|
)
|
||||||
)
|
).group_by(alias.id, self.Article.id)
|
||||||
query = sort_query(query, '-categories-articles_count')
|
query = sort_query(query, '-categories-articles_count')
|
||||||
assert 'ORDER BY (SELECT count(article.id) AS count_1' in str(query)
|
assert_contains('ORDER BY (SELECT count(article.id) AS count_1', query)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSortQueryWithPolymorphicInheritance(TestCase):
|
||||||
|
"""
|
||||||
|
Currently this doesn't work with SQLite
|
||||||
|
"""
|
||||||
|
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
|
||||||
|
|
||||||
|
def create_models(self):
|
||||||
|
class TextItem(self.Base):
|
||||||
|
__tablename__ = 'text_item'
|
||||||
|
id = sa.Column(sa.Integer, primary_key=True)
|
||||||
|
|
||||||
|
type = sa.Column(sa.Unicode(255))
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'polymorphic_on': type,
|
||||||
|
'with_polymorphic': '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
class Article(TextItem):
|
||||||
|
__tablename__ = 'article'
|
||||||
|
id = sa.Column(
|
||||||
|
sa.Integer, sa.ForeignKey(TextItem.id), primary_key=True
|
||||||
|
)
|
||||||
|
__mapper_args__ = {
|
||||||
|
'polymorphic_identity': u'article'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.TextItem = TextItem
|
||||||
|
self.Article = Article
|
||||||
|
|
||||||
|
def test_column_property(self):
|
||||||
|
self.TextItem.item_count = sa.orm.column_property(
|
||||||
|
sa.select(
|
||||||
|
[
|
||||||
|
sa.func.count('1')
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.select_from(self.TextItem.__table__)
|
||||||
|
.label('item_count')
|
||||||
|
)
|
||||||
|
|
||||||
|
query = sort_query(
|
||||||
|
self.session.query(self.TextItem),
|
||||||
|
'item_count'
|
||||||
|
)
|
||||||
|
assert_contains('ORDER BY (SELECT count(:param_2) AS count_2', query)
|
||||||
|
|||||||
Reference in New Issue
Block a user