Skip to content

Commit

Permalink
Merge pull request #12 from vvmruder/implement_sorting_fix_paging
Browse files Browse the repository at this point in the history
fix paging bug, add sorting via url params
  • Loading branch information
vvmruder authored Mar 6, 2018
2 parents 396a945 + 322a3fb commit bdcd83f
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
Pyramid REST Changelog
======================

## 3.1.0-rc4

* fix paging which was called in wrong order for LIMIT and OFFSET
* implement sorting of one column via URL params _order_by_ and _direction_

## 3.1.0-rc3

* fix filtering for non ascii charsets when LIKE is used
Expand Down
13 changes: 13 additions & 0 deletions pyramid_georest/lib/description.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,16 @@ def as_dict(self):
'column_count': self.column_count,
'columns': self.column_descriptions
}

def is_valid_column(self, column_name):
"""
Args:
column_name (unicode): The column name which should be validated.
Returns:
bool: Whether the column name was valid for this model or not.
"""
if self.column_descriptions.get(column_name):
return True
else:
return False
56 changes: 48 additions & 8 deletions pyramid_georest/lib/rest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
from pyramid_georest.lib.renderer import RenderProxy, AdapterProxy
from pyramid_georest.lib.database import Connection
from pyramid_georest.routes import create_api_routing, check_route_prefix
from sqlalchemy import or_, and_
from sqlalchemy import cast
from sqlalchemy import String
from sqlalchemy import or_, and_, cast, String, desc, asc
from sqlalchemy.sql.expression import text
from sqlalchemy.orm import Session
from sqlalchemy.orm.exc import MultipleResultsFound
Expand All @@ -38,6 +36,9 @@

log = logging.getLogger('pyramid_georest')

DIRECTION_ASC = ['ASC', 'asc', 'ascending']
DIRECTION_DESC = ['DESC', 'desc', 'descending']


class Clause(object):

Expand Down Expand Up @@ -586,7 +587,8 @@ def geometry_treatment_(self, key, value):
else:
return value

def read(self, session, request, rest_filter=None, offset=None, limit=None):
def read(self, session, request, rest_filter=None, offset=None, limit=None, order_by=None,
direction=None):
"""
The method which is used by the api to read a bunch of records from the database.
Expand All @@ -600,17 +602,27 @@ def read(self, session, request, rest_filter=None, offset=None, limit=None):
present too.
limit (int or None): The limit which is used for paging reason. It is only applied of offest is
present too.
order_by (unicode or None): The column name which the sort is assigned to. It is only used if
direction is present too.
direction (unicode or None): The direction which is used for sorting. It is only used if order_by
is present too.
Returns:
list of sqlalchemy.ext.declarative.DeclarativeMeta: A list of database records found for the
request.
"""
query = session.query(self.orm_model)
if rest_filter is not None:
query = rest_filter.filter(query)
if isinstance(order_by, unicode) and isinstance(direction, unicode):
column = self.model_description.column_classes.get(order_by)
if direction in DIRECTION_ASC:
query = query.order_by(asc(column))
elif direction in DIRECTION_DESC:
query = query.order_by(desc(column))
if isinstance(offset, int) and isinstance(limit, int):
query = query.offset(offset)
query = query.limit(limit)
if rest_filter is not None:
query = rest_filter.filter(query)
results = query.all()
return results

Expand Down Expand Up @@ -926,6 +938,8 @@ def read(self, request):
rest_filter = Filter(service.model_description, **request.json_body.get('filter'))
offset = request.params.get('offset')
limit = request.params.get('limit')
order_by = request.params.get('order_by')
direction = request.params.get('direction')
if offset and limit:
try:
offset = int(offset)
Expand All @@ -941,9 +955,35 @@ def read(self, request):
log.error(e)
log.error(hint_txt)
raise HTTPBadRequest(hint_txt)
results = service.read(session, request, rest_filter, offset=offset, limit=limit)
else:
results = service.read(session, request, rest_filter)
offset = None
limit = None

if order_by and direction:
if not isinstance(order_by, unicode):
hint_txt = 'Value for order_by has to be string.'
log.error(hint_txt)
raise HTTPBadRequest(hint_txt)
if not isinstance(direction, unicode):
hint_txt = 'Value for direction has to be string.'
log.error(hint_txt)
raise HTTPBadRequest(hint_txt)
if direction not in DIRECTION_ASC + DIRECTION_DESC:
raise HTTPBadRequest(
'The parameter direction has to be one of the values: {0}'.format(
DIRECTION_ASC + DIRECTION_DESC
)
)
if not service.model_description.is_valid_column(order_by):
raise HTTPBadRequest('The parameter order_by has to be one of the models columns. The passed '
'column name was {}'.format(order_by)
)
else:
order_by = None
direction = None

results = service.read(session, request, rest_filter, offset=offset, limit=limit,
order_by=order_by, direction=direction)
return service.renderer_proxy.render(request, results, service.model_description)

def count(self, request):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

setup(
name='pyramid_georest',
version='3.1.0-rc3',
version='3.1.0-rc4',
description='pyramid_georest, extension for pyramid web frame work to provide rest interface for '
'sql-alchemy mappers',
long_description=README + '\n\n' + CHANGES,
Expand Down

0 comments on commit bdcd83f

Please sign in to comment.