From 9f2ec39fbc5481b0fa6585ccdd159ba9fd989bcc Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sun, 8 Apr 2018 18:01:23 -0700 Subject: [PATCH] Current sort order now reflected in human filter description Plus renamed human_description to human_description_en Refs #189 --- datasette/app.py | 15 ++++++++++++--- datasette/templates/table.html | 6 +++--- datasette/utils.py | 2 +- tests/test_api.py | 30 +++++++++++++++++++++++++----- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/datasette/app.py b/datasette/app.py index 72ff5264..67ee207f 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -773,8 +773,17 @@ class TableView(RowTableShared): # Almost certainly hit the timeout pass - # human_filter_description combines filters AND search, if provided - human_description = filters.human_description(extra=search_description) + # human_description_en combines filters AND search, if provided + human_description_en = filters.human_description_en(extra=search_description) + + if sort or sort_desc: + sorted_by = 'sorted by {}{}'.format( + (sort or sort_desc), + ' descending' if sort_desc else '', + ) + human_description_en = ' '.join([ + b for b in [human_description_en, sorted_by] if b + ]) async def extra_template(): display_columns, display_rows = await self.display_columns_and_rows( @@ -786,7 +795,6 @@ class TableView(RowTableShared): self.ds.update_with_inherited_metadata(metadata) return { 'database_hash': hash, - 'human_filter_description': human_description, 'supports_search': bool(fts_table), 'search': search or '', 'use_rowid': use_rowid, @@ -808,6 +816,7 @@ class TableView(RowTableShared): 'is_view': is_view, 'view_definition': view_definition, 'table_definition': table_definition, + 'human_description_en': human_description_en, 'rows': rows[:self.page_size], 'truncated': truncated, 'table_rows': table_rows, diff --git a/datasette/templates/table.html b/datasette/templates/table.html index 546e852f..91cf70f0 100644 --- a/datasette/templates/table.html +++ b/datasette/templates/table.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block title %}{{ database }}: {{ table }}: {% if filtered_table_rows or filtered_table_rows == 0 %}{{ "{:,}".format(filtered_table_rows) }} row{% if filtered_table_rows == 1 %}{% else %}s{% endif %}{% endif %} - {% if human_filter_description %}where {{ human_filter_description }}{% endif %}{% endblock %} + {% if human_description_en %}where {{ human_description_en }}{% endif %}{% endblock %} {% block extra_head %} {{ super() }} @@ -23,9 +23,9 @@ {% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %} -{% if filtered_table_rows or human_filter_description %} +{% if filtered_table_rows or human_description_en %}

{% if filtered_table_rows or filtered_table_rows == 0 %}{{ "{:,}".format(filtered_table_rows) }} row{% if filtered_table_rows == 1 %}{% else %}s{% endif %}{% endif %} - {% if human_filter_description %}where {{ human_filter_description }}{% endif %} + {% if human_description_en %}where {{ human_description_en }}{% endif %}

{% endif %} diff --git a/datasette/utils.py b/datasette/utils.py index b7798bf4..4a2e0ed5 100644 --- a/datasette/utils.py +++ b/datasette/utils.py @@ -460,7 +460,7 @@ class Filters: for filter in self._filters: yield filter.key, filter.display, filter.no_argument - def human_description(self, extra=None): + def human_description_en(self, extra=None): bits = [] if extra: bits.append(extra) diff --git a/tests/test_api.py b/tests/test_api.py index acdd5e71..98894c33 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -356,18 +356,19 @@ def test_paginate_compound_keys_with_extra_filters(app_client): assert expected == [f['content'] for f in fetched] -@pytest.mark.parametrize('query_string,sort_key', [ - ('_sort=sortable', lambda row: row['sortable']), - ('_sort_desc=sortable', lambda row: -row['sortable']), +@pytest.mark.parametrize('query_string,sort_key,human_description_en', [ + ('_sort=sortable', lambda row: row['sortable'], 'sorted by sortable'), + ('_sort_desc=sortable', lambda row: -row['sortable'], 'sorted by sortable descending'), ]) -def test_sortable(app_client, query_string, sort_key): - path = '/test_tables/sortable.jsono?{}'.format(query_string) +def test_sortable(app_client, query_string, sort_key, human_description_en): + path = '/test_tables/sortable.json?_shape=objects&{}'.format(query_string) fetched = [] page = 0 while path: page += 1 assert page < 100 response = app_client.get(path, gather_request=False) + assert human_description_en == response.json['human_description_en'] fetched.extend(response.json['rows']) path = response.json['next_url'] assert 5 == page @@ -380,6 +381,25 @@ def test_sortable(app_client, query_string, sort_key): ] +def test_sortable_and_filtered(app_client): + path = ( + '/test_tables/sortable.json' + '?content__contains=d&_sort_desc=sortable&_shape=objects' + ) + response = app_client.get(path, gather_request=False) + fetched = response.json['rows'] + expected = [ + row for row in generate_sortable_rows(201) + if 'd' in row['content'] + ] + expected.sort(key=lambda row: -row['sortable']) + assert [ + r['content'] for r in expected + ] == [ + r['content'] for r in fetched + ] + + @pytest.mark.parametrize('path,expected_rows', [ ('/test_tables/simple_primary_key.json?content=hello', [ ['1', 'hello'],