From 9cb44be42f012a68c8c3904a37008200cc7bb1f4 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 3 Jun 2020 14:04:40 -0700 Subject: [PATCH] Docs and tests for "params", closes #797 --- docs/sql_queries.rst | 70 ++++++++++++++++++++++++++++++-------- tests/test_canned_write.py | 7 +++- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/docs/sql_queries.rst b/docs/sql_queries.rst index dc239a84..aa1edc98 100644 --- a/docs/sql_queries.rst +++ b/docs/sql_queries.rst @@ -121,32 +121,68 @@ Here's an example of a canned query with a named parameter: .. code-block:: 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; + from facetable + join facet_cities on facetable.city_id = facet_cities.id + where neighborhood like '%' || :text || '%' + order by neighborhood; -In the canned query JSON it looks like this: +In the canned query metadata (here :ref:`metadata_yaml` as ``metadata.yaml``) it looks like this: + +.. code-block:: yaml + + databases: + fixtures: + queries: + 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 + +Here's the equivalent using JSON (as ``metadata.json``): .. code-block:: json { "databases": { - "fixtures": { - "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;", - "title": "Search neighborhoods", - "description_html": "Demonstrating simple like search" - } - } - } + "fixtures": { + "queries": { + "neighborhood_search": { + "sql": "select neighborhood, facet_cities.name, state\nfrom facetable\n join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%'\norder by neighborhood", + "title": "Search neighborhoods" + } + } + } } } +Note that we are using SQLite string concatenation here - the ``||`` operator - to add wildcard ``%`` characters to the string provided by the user. + You can try this canned query out here: https://latest.datasette.io/fixtures/neighborhood_search?text=town -Note that we are using SQLite string concatenation here - the ``||`` operator - -to add wildcard ``%`` characters to the string provided by the user. +In this example the ``:text`` named parameter is automatically extracted from the query using a regular expression. + +You can alternatively provide an explicit list of named parameters using the ``"params"`` key, like this: + +.. code-block:: yaml + + databases: + fixtures: + queries: + neighborhood_search: + params: + - text + 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 .. _canned_queries_default_fragment: @@ -181,6 +217,8 @@ Writable canned queries Canned queries by default are read-only. You can use the ``"write": true`` key to indicate that a canned query can write to the database. +You may wish to use this feature in conjunction with :ref:`authentication`. + .. code-block:: json { @@ -226,7 +264,9 @@ For example: } } -You may wish to use this feature in conjunction with :ref:`authentication`. +You can use ``"params"`` to explicitly list the named parameters that should be displayed as form fields - otherwise they will be automatically detected. + +You can pre-populate form fields when the page first loads using a querystring, e.g. ``/mydatabase/add_name?name=Prepopulated``. The user will have to submit the form to execute the query. .. _pagination: diff --git a/tests/test_canned_write.py b/tests/test_canned_write.py index 52c8aec2..692d726e 100644 --- a/tests/test_canned_write.py +++ b/tests/test_canned_write.py @@ -27,7 +27,7 @@ def canned_write_client(): }, "update_name": { "sql": "update names set name = :name where rowid = :rowid", - "params": ["rowid", "name"], + "params": ["rowid", "name", "extra"], "write": True, }, } @@ -86,3 +86,8 @@ def test_insert_error(canned_write_client): assert [["ERROR", 3]] == canned_write_client.ds.unsign( response.cookies["ds_messages"], "messages" ) + + +def test_custom_params(canned_write_client): + response = canned_write_client.get("/data/update_name?extra=foo") + assert '' in response.text