Skip to content

Commit

Permalink
Merge pull request #34 from ajite/feat-nested-sort
Browse files Browse the repository at this point in the history
feat: sorting works with nested attributes
  • Loading branch information
mrevutskyi authored Jun 30, 2022
2 parents d964ae8 + 4db7deb commit 9ce1636
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Upcoming version:
- Fix for an incorrect error message
- Returns 500 instead 400 response code in case of serialization errors in POST requests

Version 2.3.0
------------
- Allow sorting of nested fields

Version 2.2.9
-------------
Expand Down
2 changes: 1 addition & 1 deletion flask_restless/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""
#: The current version of this extension.
__version__ = '2.2.9'
__version__ = '2.3.0'


# The following names are available as part of the public API for Flask-Restless-NG.
Expand Down
21 changes: 10 additions & 11 deletions flask_restless/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,17 +416,16 @@ def get_field(obj, name):
if sort:
for (symbol, field_name) in sort:
direction_name = 'asc' if symbol == '+' else 'desc'
if '.' in field_name:
field_name, field_name_in_relation = field_name.split('.')
relation_model = aliased(get_related_model(model, field_name))
field = get_field(relation_model, field_name_in_relation)
direction = getattr(field, direction_name)
query = query.join(relation_model)
query = query.order_by(direction())
else:
field = get_field(model, field_name)
direction = getattr(field, direction_name)
query = query.order_by(direction())
related_model = model
while '.' in field_name:
field_name, _, field_name_in_relation = field_name.partition('.')
related_model = aliased(get_related_model(related_model, field_name))
field_name = field_name_in_relation
query = query.join(related_model)

field = get_field(related_model, field_name)
direction = getattr(field, direction_name)
query = query.order_by(direction())
else:
pks = primary_key_names(model)
pk_order = (getattr(model, field).asc() for field in pks)
Expand Down
65 changes: 65 additions & 0 deletions tests/test_jsonapi/test_sorting.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ..conftest import BaseTestClass
from .models import Article
from .models import Base
from .models import Comment
from .models import Person


Expand All @@ -22,6 +23,7 @@ def setup(self):
manager = APIManager(self.app, session=self.session)
manager.create_api(Article)
manager.create_api(Person)
manager.create_api(Comment)
Base.metadata.create_all(bind=self.engine)
yield
Base.metadata.drop_all(bind=self.engine)
Expand Down Expand Up @@ -165,3 +167,66 @@ def test_bad_request_on_incorrect_sorting_field(self):
def test_bad_request_on_incorrect_sorting_relationship_field(self):
query_string = {'sort': 'articles.unknown'}
self.fetch_and_validate('/api/person', query_string=query_string, expected_response_code=400, error_msg='No such field unknown')

def test_sort_nested_relationship_attributes(self):
"""Tests that the client can sort by nested relationship attributes.
For more information, see the `Sorting`_ section of the JSON API
specification.
.. _Sorting: https://jsonapi.org/format/#fetching-sorting
"""
self.session.add_all([
Person(pk=1, age=20),
Person(pk=2, age=10),
Person(pk=3, age=30),
Article(id=1, author_id=1),
Article(id=2, author_id=2),
Article(id=3, author_id=3),
Comment(id=1, author_id=1, article_id=1),
Comment(id=2, author_id=1, article_id=2),
Comment(id=3, author_id=1, article_id=3),
Comment(id=4, author_id=2, article_id=1),
Comment(id=5, author_id=2, article_id=2),
Comment(id=6, author_id=3, article_id=1)
])
self.session.commit()
query_string = {'sort': 'article.author.age'}
document = self.fetch_and_validate('/api/comment', query_string=query_string)
comments = document['data']
assert ['2', '5', '1', '4', '6', '3'] == [comment['id'] for comment in comments]

def test_sort_multiple_nested_relationship_attributes(self):
"""Tests that the client can sort by multiple nested relationship
attributes.
For more information, see the `Sorting`_ section of the JSON API
specification.
.. _Sorting: https://jsonapi.org/format/#fetching-sorting
"""
self.session.bulk_save_objects([
Person(pk=1, age=2, name=u'b'),
Person(pk=2, age=1, name=u'd'),
Person(pk=3, age=1, name=u'a'),
Article(id=1, author_id=1),
Article(id=2, author_id=2),
Article(id=3, author_id=3),
Comment(id=1, author_id=1, article_id=1),
Comment(id=2, author_id=1, article_id=2),
Comment(id=3, author_id=1, article_id=3),
Comment(id=4, author_id=2, article_id=1),
Comment(id=5, author_id=2, article_id=2),
Comment(id=6, author_id=3, article_id=1)
])
self.session.commit()
query_string = {'sort': 'article.author.age,article.author.name'}
document = self.fetch_and_validate('/api/comment', query_string=query_string)
comments = document['data']
assert ['3', '2', '5', '1', '4', '6'] == [comment['id'] for comment in comments]

def test_bad_request_on_incorrect_sorting_nested_relationship_field(self):
query_string = {'sort': 'article.author.unknown'}
self.fetch_and_validate('/api/comment', query_string=query_string, expected_response_code=400, error_msg='No such field unknown')

0 comments on commit 9ce1636

Please sign in to comment.