Skip to content

Commit

Permalink
Clients can disable default sorting by using sort=0 query parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
mrevutskyi committed Nov 11, 2022
1 parent 7ea7a92 commit b4588c0
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog
Changes in Flask-Restless-NG
============================

Version 2.4.0 (11/11/2022):
-------------
- Clients can disable default sorting by using `sort=0` query parameter

Version 2.3.1:
-------------
- Fix for an incorrect error message
Expand Down
4 changes: 4 additions & 0 deletions docs/fetching.rst
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ Clients can sort according to the sorting protocol described in the `Sorting
specification. Sorting by a nullable attribute will cause resources with null
attributes to appear first.

If ``sort`` parameter is not specified, data is sorted using the primary key

Clients can disable default sorting by using ``sort=0``


.. _pagination:

Expand Down
4 changes: 2 additions & 2 deletions flask_restless/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright 2011 Lincoln de Sousa <lincoln@comum.org>.
# Copyright 2012, 2013, 2014, 2015, 2016 Jeffrey Finkelstein
# <jeffrey.finkelstein@gmail.com> and contributors.
# Copyright 2020, 2021 Maksym Revutskyi <maksym.revutskyi@gmail.com> and contributors.
# Copyright 2020, 2021, 2022 Maksym Revutskyi <maksym.revutskyi@gmail.com> and contributors.
#
# This file is part of Flask-Restless-NG.
#
Expand All @@ -13,7 +13,7 @@
"""
#: The current version of this extension.
__version__ = '2.3.1'
__version__ = '2.4.0'


# The following names are available as part of the public API for Flask-Restless-NG.
Expand Down
2 changes: 1 addition & 1 deletion flask_restless/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def get_field(obj, name):
field = get_field(related_model, field_name)
direction = getattr(field, direction_name)
query = query.order_by(direction())
else:
elif sort is not None:
pks = primary_key_names(model)
pk_order = (getattr(model, field).asc() for field in pks)
query = query.order_by(*pk_order)
Expand Down
8 changes: 6 additions & 2 deletions flask_restless/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,12 @@ def collection_parameters():
# Determine sorting options.
sort = request.args.get(SORT_PARAM)
if sort:
sort = [('-', value[1:]) if value.startswith('-') else ('+', value)
for value in sort.split(',')]
if sort == '0':
# '0' disables default sorting
sort = None
else:
sort = [('-', value[1:]) if value.startswith('-') else ('+', value)
for value in sort.split(',')]
else:
sort = []
except (TypeError, KeyError, ValueError) as e:
Expand Down
10 changes: 10 additions & 0 deletions tests/test_jsonapi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,13 @@ class UnicodePK(Base):
"""Model with a primary key that has Unicode type. """
__tablename__ = 'unicode_pk'
name = Column(Unicode, primary_key=True)


class Unsorted(Base):
"""Model that should not have a primary_key to dest disabled sorting.
SQLAlchemy does not actually let us define a model without a primary key,
so the table has to be created without the PK manually before create_all()
"""
__tablename__ = 'unsorted'
id = Column(Integer, primary_key=True)
23 changes: 23 additions & 0 deletions tests/test_jsonapi/test_fetching_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .models import Comment
from .models import Parent
from .models import Person
from .models import Unsorted
from .models import Various


Expand All @@ -36,8 +37,17 @@ def setup(self):
manager.create_api(Parent, page_size=0)
manager.create_api(Child)
manager.create_api(Various)
manager.create_api(Unsorted)
self.manager = manager

with self.engine.connect() as connection:
connection.execute("""
create table unsorted
(
id int not null
);
""")

Base.metadata.create_all(bind=self.engine)
yield
Base.metadata.drop_all(bind=self.engine)
Expand Down Expand Up @@ -433,6 +443,19 @@ def test_sorting_null_field(self):
assert ['3', '2'] == person_ids[-2:]
assert {'1', '4'} == set(person_ids[:2])

def test_disabling_sorting(self):
"""Tests that sorting by a nullable field causes resources with a null attribute value to appear first."""
self.session.add(Unsorted(id=2))
self.session.add(Unsorted(id=1))
self.session.add(Unsorted(id=4))
self.session.add(Unsorted(id=3))
self.session.commit()
document = self.fetch_and_validate('/api/unsorted', query_string={'sort': '0'})
ids = [item['id'] for item in document['data']]
assert ids == ['2', '1', '4', '3']
assert 'sort=0' in document['links']['first']
assert 'sort=0' in document['links']['last']

def test_alternative_collection_name(self):
"""Tests for fetching a single resource with an alternate collection name."""
self.session.add(Person(pk=1))
Expand Down

0 comments on commit b4588c0

Please sign in to comment.