kopia lustrzana https://github.com/simonw/datasette
New hide_sql canned query option, refs #1422
rodzic
b7037f5ece
commit
66e143c76e
|
@ -33,7 +33,9 @@
|
|||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||
|
||||
<form class="sql" action="{{ urls.database(database) }}{% if canned_query %}/{{ canned_query }}{% endif %}" method="{% if canned_write %}post{% else %}get{% endif %}">
|
||||
<h3>Custom SQL query{% if display_rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(display_rows|length) }} row{% if display_rows|length == 1 %}{% else %}s{% endif %}{% endif %}{% if not query_error %} <span class="show-hide-sql">{% if hide_sql %}(<a href="{{ path_with_removed_args(request, {'_hide_sql': '1'}) }}">show</a>){% else %}(<a href="{{ path_with_added_args(request, {'_hide_sql': '1'}) }}">hide</a>){% endif %}</span>{% endif %}</h3>
|
||||
<h3>Custom SQL query{% if display_rows %} returning {% if truncated %}more than {% endif %}{{ "{:,}".format(display_rows|length) }} row{% if display_rows|length == 1 %}{% else %}s{% endif %}{% endif %}{% if not query_error %}
|
||||
<span class="show-hide-sql">(<a href="{{ show_hide_link }}">{{ show_hide_text }}</a>)</span>
|
||||
{% endif %}</h3>
|
||||
{% if error %}
|
||||
<p class="message-error">{{ error }}</p>
|
||||
{% endif %}
|
||||
|
@ -44,8 +46,11 @@
|
|||
<pre id="sql-query">{% if query %}{{ query.sql }}{% endif %}</pre>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if not canned_query %}<input type="hidden" name="sql" value="{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}">{% endif %}
|
||||
<input type="hidden" name="_hide_sql" value="1">
|
||||
{% if not canned_query %}
|
||||
<input type="hidden" name="sql"
|
||||
value="{% if query and query.sql %}{{ query.sql }}{% else %}select * from {{ tables[0].name|escape_sqlite }}{% endif %}"
|
||||
>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if named_parameter_values %}
|
||||
<h3>Query parameters</h3>
|
||||
|
@ -54,9 +59,10 @@
|
|||
{% endfor %}
|
||||
{% endif %}
|
||||
<p>
|
||||
<button id="sql-format" type="button" hidden>Format SQL</button>
|
||||
{% if not hide_sql %}<button id="sql-format" type="button" hidden>Format SQL</button>{% endif %}
|
||||
{% if canned_write %}<input type="hidden" name="csrftoken" value="{{ csrftoken() }}">{% endif %}
|
||||
<input type="submit" value="Run SQL">
|
||||
{{ show_hide_hidden }}
|
||||
{% if canned_query and edit_sql_url %}<a href="{{ edit_sql_url }}" class="canned-query-edit-sql">Edit SQL</a>{% endif %}
|
||||
</p>
|
||||
</form>
|
||||
|
|
|
@ -5,6 +5,8 @@ import json
|
|||
from markupsafe import Markup, escape
|
||||
from urllib.parse import parse_qsl, urlencode
|
||||
|
||||
import markupsafe
|
||||
|
||||
from datasette.utils import (
|
||||
await_me_maybe,
|
||||
check_visibility,
|
||||
|
@ -415,6 +417,29 @@ class QueryView(DataView):
|
|||
}
|
||||
)
|
||||
)
|
||||
|
||||
show_hide_hidden = ""
|
||||
if metadata.get("hide_sql"):
|
||||
if bool(params.get("_show_sql")):
|
||||
show_hide_link = path_with_removed_args(request, {"_show_sql"})
|
||||
show_hide_text = "hide"
|
||||
show_hide_hidden = (
|
||||
'<input type="hidden" name="_show_sql" value="1">'
|
||||
)
|
||||
else:
|
||||
show_hide_link = path_with_added_args(request, {"_show_sql": 1})
|
||||
show_hide_text = "show"
|
||||
else:
|
||||
if bool(params.get("_hide_sql")):
|
||||
show_hide_link = path_with_removed_args(request, {"_hide_sql"})
|
||||
show_hide_text = "show"
|
||||
show_hide_hidden = (
|
||||
'<input type="hidden" name="_hide_sql" value="1">'
|
||||
)
|
||||
else:
|
||||
show_hide_link = path_with_added_args(request, {"_hide_sql": 1})
|
||||
show_hide_text = "hide"
|
||||
hide_sql = show_hide_text == "show"
|
||||
return {
|
||||
"display_rows": display_rows,
|
||||
"custom_sql": True,
|
||||
|
@ -425,9 +450,10 @@ class QueryView(DataView):
|
|||
"metadata": metadata,
|
||||
"config": self.ds.config_dict(),
|
||||
"request": request,
|
||||
"path_with_added_args": path_with_added_args,
|
||||
"path_with_removed_args": path_with_removed_args,
|
||||
"hide_sql": "_hide_sql" in params,
|
||||
"show_hide_link": show_hide_link,
|
||||
"show_hide_text": show_hide_text,
|
||||
"show_hide_hidden": markupsafe.Markup(show_hide_hidden),
|
||||
"hide_sql": hide_sql,
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -674,7 +674,7 @@ The main focus of this release is a major upgrade to the :ref:`plugin_register_o
|
|||
* Visually distinguish float and integer columns - useful for figuring out why order-by-column might be returning unexpected results. (:issue:`729`)
|
||||
* The :ref:`internals_request`, which is passed to several plugin hooks, is now documented. (:issue:`706`)
|
||||
* New ``metadata.json`` option for setting a custom default page size for specific tables and views, see :ref:`metadata_page_size`. (:issue:`751`)
|
||||
* Canned queries can now be configured with a default URL fragment hash, useful when working with plugins such as `datasette-vega <https://github.com/simonw/datasette-vega>`__, see :ref:`canned_queries_default_fragment`. (:issue:`706`)
|
||||
* Canned queries can now be configured with a default URL fragment hash, useful when working with plugins such as `datasette-vega <https://github.com/simonw/datasette-vega>`__, see :ref:`canned_queries_options`. (:issue:`706`)
|
||||
* Fixed a bug in ``datasette publish`` when running on operating systems where the ``/tmp`` directory lives in a different volume, using a backport of the Python 3.8 ``shutil.copytree()`` function. (:issue:`744`)
|
||||
* Every plugin hook is now covered by the unit tests, and a new unit test checks that each plugin hook has at least one corresponding test. (:issue:`771`, :issue:`773`)
|
||||
|
||||
|
|
|
@ -187,14 +187,28 @@ You can alternatively provide an explicit list of named parameters using the ``"
|
|||
order by neighborhood
|
||||
title: Search neighborhoods
|
||||
|
||||
.. _canned_queries_default_fragment:
|
||||
.. _canned_queries_options:
|
||||
|
||||
Setting a default fragment
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Additional canned query options
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Additional options can be specified for canned queries in the YAML or JSON configuration.
|
||||
|
||||
hide_sql
|
||||
++++++++
|
||||
|
||||
Canned queries default to displaying their SQL query at the top of the page. If the query is extremely long you may want to hide it by default, with a "show" link that can be used to make it visible.
|
||||
|
||||
Add the ``"hide_sql": true`` option to hide the SQL query by default.
|
||||
|
||||
fragment
|
||||
++++++++
|
||||
|
||||
Some plugins, such as `datasette-vega <https://github.com/simonw/datasette-vega>`__, can be configured by including additional data in the fragment hash of the URL - the bit that comes after a ``#`` symbol.
|
||||
|
||||
You can set a default fragment hash that will be included in the link to the canned query from the database index page using the ``"fragment"`` key:
|
||||
You can set a default fragment hash that will be included in the link to the canned query from the database index page using the ``"fragment"`` key.
|
||||
|
||||
This example demonstrates both ``fragment`` and ``hide_sql``:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
|
@ -204,7 +218,8 @@ You can set a default fragment hash that will be included in the link to the can
|
|||
"queries": {
|
||||
"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;",
|
||||
"fragment": "fragment-goes-here"
|
||||
"fragment": "fragment-goes-here",
|
||||
"hide_sql": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,6 +360,7 @@ METADATA = {
|
|||
"title": "Search neighborhoods",
|
||||
"description_html": "<b>Demonstrating</b> simple like search",
|
||||
"fragment": "fragment-goes-here",
|
||||
"hide_sql": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1241,7 +1241,7 @@ def test_show_hide_sql_query(app_client):
|
|||
def test_canned_query_with_hide_has_no_hidden_sql(app_client):
|
||||
# For a canned query the show/hide should NOT have a hidden SQL field
|
||||
# https://github.com/simonw/datasette/issues/1411
|
||||
response = app_client.get("/fixtures/neighborhood_search?_hide_sql=1")
|
||||
response = app_client.get("/fixtures/pragma_cache_size?_hide_sql=1")
|
||||
soup = Soup(response.body, "html.parser")
|
||||
hiddens = soup.find("form").select("input[type=hidden]")
|
||||
assert [
|
||||
|
@ -1249,6 +1249,55 @@ def test_canned_query_with_hide_has_no_hidden_sql(app_client):
|
|||
] == [(hidden["name"], hidden["value"]) for hidden in hiddens]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"hide_sql,querystring,expected_hidden,expected_show_hide_link,expected_show_hide_text",
|
||||
(
|
||||
(False, "", None, "/_memory/one?_hide_sql=1", "hide"),
|
||||
(False, "?_hide_sql=1", "_hide_sql", "/_memory/one", "show"),
|
||||
(True, "", None, "/_memory/one?_show_sql=1", "show"),
|
||||
(True, "?_show_sql=1", "_show_sql", "/_memory/one", "hide"),
|
||||
),
|
||||
)
|
||||
def test_canned_query_show_hide_metadata_option(
|
||||
hide_sql,
|
||||
querystring,
|
||||
expected_hidden,
|
||||
expected_show_hide_link,
|
||||
expected_show_hide_text,
|
||||
):
|
||||
with make_app_client(
|
||||
metadata={
|
||||
"databases": {
|
||||
"_memory": {
|
||||
"queries": {
|
||||
"one": {
|
||||
"sql": "select 1 + 1",
|
||||
"hide_sql": hide_sql,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
memory=True,
|
||||
) as client:
|
||||
expected_show_hide_fragment = '(<a href="{}">{}</a>)'.format(
|
||||
expected_show_hide_link, expected_show_hide_text
|
||||
)
|
||||
response = client.get("/_memory/one" + querystring)
|
||||
html = response.text
|
||||
show_hide_fragment = html.split('<span class="show-hide-sql">')[1].split(
|
||||
"</span>"
|
||||
)[0]
|
||||
assert show_hide_fragment == expected_show_hide_fragment
|
||||
if expected_hidden:
|
||||
assert (
|
||||
'<input type="hidden" name="{}" value="1">'.format(expected_hidden)
|
||||
in html
|
||||
)
|
||||
else:
|
||||
assert '<input type="hidden" ' not in html
|
||||
|
||||
|
||||
def test_extra_where_clauses(app_client):
|
||||
response = app_client.get(
|
||||
"/fixtures/facetable?_where=neighborhood='Dogpatch'&_where=city_id=1"
|
||||
|
|
Ładowanie…
Reference in New Issue