kopia lustrzana https://github.com/simonw/datasette
Support title/description for canned queries, closes #342
Demo here: https://latest.datasette.io/fixtures/neighborhood_searchpull/349/head
rodzic
58fec99ab0
commit
6e37f091ed
|
@ -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(
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -232,6 +232,7 @@ class TableView(RowTableShared):
|
|||
name,
|
||||
hash,
|
||||
canned_query["sql"],
|
||||
metadata=canned_query,
|
||||
editable=False,
|
||||
canned_query=table,
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue