diff --git a/datasette/app.py b/datasette/app.py index 53ac6329..63f99e5f 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -303,7 +303,15 @@ class TableView(BaseView): async def data(self, request, name, hash, table): table = urllib.parse.unquote_plus(table) pks = await self.pks_for_table(name, table) - use_rowid = not pks + is_view = bool(list(await self.execute(name, "SELECT count(*) from sqlite_master WHERE type = 'view' and name=:n", { + 'n': table, + }))[0][0]) + view_definition = None + if is_view: + view_definition = list(await self.execute(name, 'select sql from sqlite_master where name = :n and type="view"', { + 'n': table, + }))[0][0]; + use_rowid = not pks and not is_view if use_rowid: select = 'rowid, *' order_by = 'rowid' @@ -311,6 +319,9 @@ class TableView(BaseView): select = '*' order_by = ', '.join(pks) + if is_view: + order_by = '' + # Special args start with _ and do not contain a __ # That's so if there is a column that starts with _ # it can still be queried using ?_col__exact=blah @@ -354,7 +365,10 @@ class TableView(BaseView): if where_clauses: where_clause = 'where {} '.format(' and '.join(where_clauses)) - sql = 'select {} from "{}" {}order by {} limit {}'.format( + if order_by: + order_by = 'order by {} '.format(order_by) + + sql = 'select {} from "{}" {}{}limit {}'.format( select, table, where_clause, order_by, self.page_size + 1, ) @@ -375,6 +389,8 @@ class TableView(BaseView): return { 'database': name, 'table': table, + 'is_view': is_view, + 'view_definition': view_definition, 'rows': rows[:self.page_size], 'table_rows': table_rows, 'columns': columns, diff --git a/datasette/templates/database.html b/datasette/templates/database.html index 607d836e..11284340 100644 --- a/datasette/templates/database.html +++ b/datasette/templates/database.html @@ -20,7 +20,7 @@ {% for table in tables %}
-

{{ table.name }}

+

{{ table.name }}

{% for column in table.columns[:9] %}{{ column }}{% if not loop.last %}, {% endif %}{% endfor %}{% if table.columns|length > 9 %}...{% endif %}

{{ "{:,}".format(table.table_rows) }} row{% if table.table_rows == 1 %}{% else %}s{% endif %}

@@ -30,31 +30,9 @@

Views

{% endif %} - - - - {% for column in columns %}{% endfor %} - - - - {% for row in rows %} - - {% for td in row %} - - {% endfor %} - - {% endfor %} - -
{{ column }}
- {% if loop.index == 2 and row.type in ("table", "view") %} - {{ td }} - {% else %} - {{ td }} - {% endif %} -
{% endblock %} diff --git a/datasette/templates/table.html b/datasette/templates/table.html index 657e7fc6..39d19055 100644 --- a/datasette/templates/table.html +++ b/datasette/templates/table.html @@ -16,7 +16,7 @@ {% block content %}
home / {{ database }}
-

{{ table }}

+

{{ table }}{% if is_view %} (view){% endif %}

{% if table_rows != None %}

{{ "{:,}".format(table_rows) }} total row{% if table_rows == 1 %}{% else %}s{% endif %} in this table

@@ -24,6 +24,10 @@

This data as .json, .jsono

+{% if view_definition %} +
{{ view_definition }}
+{% endif %} + diff --git a/tests/test_app.py b/tests/test_app.py index 25acdfc7..637e6bed 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -91,6 +91,21 @@ def test_table_page(three_table_app_client): }] +def test_view(three_table_app_client): + _, response = three_table_app_client.get('/four_tables/simple_view') + assert response.status == 200 + _, response = three_table_app_client.get('/four_tables/simple_view.jsono') + assert response.status == 200 + data = response.json + assert data['rows'] == [{ + 'upper_content': 'HELLO', + 'content': 'hello', + }, { + 'upper_content': 'WORLD', + 'content': 'world', + }] + + FOUR_TABLES = ''' CREATE TABLE simple_primary_key ( pk varchar(30) primary key, @@ -115,4 +130,7 @@ CREATE TABLE "Table With Space In Name" ( INSERT INTO simple_primary_key VALUES (1, 'hello'); INSERT INTO simple_primary_key VALUES (2, 'world'); + +CREATE VIEW simple_view AS + SELECT content, upper(content) AS upper_content FROM simple_primary_key; '''