Support title/description for canned queries, closes #342

Demo here: https://latest.datasette.io/fixtures/neighborhood_search
pull/349/head
Simon Willison 2018-07-15 19:33:30 -07:00
rodzic 58fec99ab0
commit 6e37f091ed
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 17E2DEA2588B7F52
9 zmienionych plików z 62 dodań i 17 usunięć

Wyświetl plik

@ -174,6 +174,14 @@ class Datasette:
]
return self._app_css_hash
def get_canned_queries(self, database_name):
names = self.metadata.get("databases", {}).get(database_name, {}).get(
"queries", {}
).keys()
return [
self.get_canned_query(database_name, name) for name in names
]
def get_canned_query(self, database_name, query_name):
query = self.metadata.get("databases", {}).get(database_name, {}).get(
"queries", {}
@ -181,7 +189,10 @@ class Datasette:
query_name
)
if query:
return {"name": query_name, "sql": query}
if not isinstance(query, dict):
query = {"sql": query}
query["name"] = query_name
return query
async def get_table_definition(self, database_name, table, type_="table"):
table_definition_rows = list(

Wyświetl plik

@ -51,7 +51,7 @@
<h2>Queries</h2>
<ul>
{% for query in queries %}
<li><a href="/{{ database }}-{{ database_hash }}/{{ query.name|urlencode }}" title="{{ query.sql }}">{{ query.name }}</a></li>
<li><a href="/{{ database }}-{{ database_hash }}/{{ query.name|urlencode }}" title="{{ query.description or query.sql }}">{{ query.title or query.name }}</a></li>
{% endfor %}
</ul>
{% endif %}

Wyświetl plik

@ -21,7 +21,9 @@
{% block content %}
<div class="hd"><a href="/">home</a> / <a href="/{{ database }}-{{ database_hash }}">{{ database }}</a></div>
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_hash[:6] }}">{{ database }}</h1>
<h1 style="padding-left: 10px; border-left: 10px solid #{{ database_hash[:6] }}">{{ metadata.title or database }}</h1>
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
<form class="sql" action="/{{ database }}-{{ database_hash }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="get">
<h3>Custom SQL query{% if rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(rows|length) }} row{% if rows|length == 1 %}{% else %}s{% endif %}{% endif %}</h3>

Wyświetl plik

@ -433,7 +433,7 @@ class BaseView(RenderMixin):
async def custom_sql(
self, request, name, hash, sql, editable=True, canned_query=None,
_size=None
metadata=None, _size=None
):
params = request.raw_args
if "sql" in params:
@ -483,6 +483,7 @@ class BaseView(RenderMixin):
"named_parameter_values": named_parameter_values,
"editable": editable,
"canned_query": canned_query,
"metadata": metadata,
"config": self.ds.config,
}, templates

Wyświetl plik

@ -27,10 +27,7 @@ class DatabaseView(BaseView):
"tables": tables,
"hidden_count": len([t for t in tables if t["hidden"]]),
"views": info["views"],
"queries": [
{"name": query_name, "sql": query_sql}
for query_name, query_sql in (metadata.get("queries") or {}).items()
],
"queries": self.ds.get_canned_queries(name),
}, {
"database_hash": hash,
"show_hidden": request.args.get("_show_hidden"),

Wyświetl plik

@ -232,6 +232,7 @@ class TableView(RowTableShared):
name,
hash,
canned_query["sql"],
metadata=canned_query,
editable=False,
canned_query=table,
)

Wyświetl plik

@ -73,7 +73,9 @@ queries inside your ``metadata.json`` file. Here's an example::
"databases": {
"sf-trees": {
"queries": {
"just_species": "select qSpecies from Street_Tree_List"
"just_species": {
"sql": select qSpecies from Street_Tree_List"
}
}
}
}
@ -92,6 +94,11 @@ For the above example, that URL would be::
/sf-trees/just_species
You can optionally include ``"title"`` and ``"description"`` keys to show a
title and description on the canned query page. As with regular table metadata
you can alternatively specify ``"description_html"`` to have your description
rendered as HTML (rather than having HTML special characters escaped).
Canned queries support named parameters, so if you include those in the SQL you
will then be able to enter them using the form fields on the canned query page
or by adding them to the URL. This means canned queries can be used to create
@ -111,7 +118,11 @@ In the canned query JSON it looks like this::
"databases": {
"fixtures": {
"queries": {
"neighborhood_search": "select neighborhood, facet_cities.name, state\nfrom facetable join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%' order by neighborhood;"
"neighborhood_search": {
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%' order by neighborhood;",
"title": "Search neighborhoods",
"description_html": "<b>Demonstrating</b> simple like search"
}
}
}
}

Wyświetl plik

@ -161,13 +161,18 @@ METADATA = {
},
'queries': {
'pragma_cache_size': 'PRAGMA cache_size;',
'neighborhood_search': '''
select neighborhood, facet_cities.name, state
from facetable
join facet_cities on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood;
'''
'neighborhood_search': {
'sql': '''
select neighborhood, facet_cities.name, state
from facetable
join facet_cities
on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood;
''',
'title': 'Search neighborhoods',
'description_html': '<b>Demonstrating</b> simple like search',
},
}
},
}

Wyświetl plik

@ -754,3 +754,20 @@ def test_404_trailing_slash_redirect(app_client, path, expected_redirect):
response = app_client.get(path, allow_redirects=False)
assert 302 == response.status
assert expected_redirect == response.headers["Location"]
def test_canned_query_with_custom_metadata(app_client):
response = app_client.get("/fixtures/neighborhood_search?text=town")
assert response.status == 200
soup = Soup(response.body, "html.parser")
assert "Search neighborhoods" == soup.find("h1").text
assert (
"""
<div class="metadata-description">
<b>
Demonstrating
</b>
simple like search
</div>""".strip()
== soup.find("div", {"class": "metadata-description"}).prettify().strip()
)