searchmode: raw table metadata property, closes #1389

pull/868/head^2
Simon Willison 2021-07-10 11:30:48 -07:00
rodzic c8feaf0b62
commit 83f6799a96
3 zmienionych plików z 66 dodań i 11 usunięć

Wyświetl plik

@ -495,7 +495,13 @@ class TableView(RowTableShared):
if pair[0].startswith("_search") and pair[0] != "_searchmode"
)
search = ""
search_mode_raw = special_args.get("_searchmode") == "raw"
search_mode_raw = table_metadata.get("searchmode") == "raw"
# Or set it from the querystring
qs_searchmode = special_args.get("_searchmode")
if qs_searchmode == "escaped":
search_mode_raw = False
if qs_searchmode == "raw":
search_mode_raw = True
if fts_table and search_args:
if "_search" in search_args:
# Simple ?_search=xxx

Wyświetl plik

@ -36,7 +36,11 @@ Advanced SQLite search queries
SQLite full-text search includes support for `a variety of advanced queries <https://www.sqlite.org/fts5.html#full_text_query_syntax>`__, including ``AND``, ``OR``, ``NOT`` and ``NEAR``.
By default Datasette disables these features to ensure they do not cause any confusion for users who are not aware of them. You can disable this escaping and use the advanced queries by adding ``?_searchmode=raw`` to the table page query string.
By default Datasette disables these features to ensure they do not cause errors or confusion for users who are not aware of them. You can disable this escaping and use the advanced queries by adding ``&_searchmode=raw`` to the table page query string.
If you want to enable these operators by default for a specific table, you can do so by adding ``"searchmode": "raw"`` to the metadata configuration for that table, see :ref:`full_text_search_table_or_view`.
If that option has been specified in the table metadata but you want to over-ride it and return to the default behavior you can append ``&_searchmode=escaped`` to the query string.
.. _full_text_search_table_or_view:
@ -53,19 +57,24 @@ https://latest.datasette.io/fixtures/searchable_view?_fts_table=searchable_fts&_
The ``fts_table`` metadata property can be used to specify an associated FTS table. If the primary key column in your table which was used to populate the FTS table is something other than ``rowid``, you can specify the column to use with the ``fts_pk`` property.
Here is an example which enables full-text search for a ``display_ads`` view which is defined against the ``ads`` table and hence needs to run FTS against the ``ads_fts`` table, using the ``id`` as the primary key::
The ``"searchmode": "raw"`` property can be used to default the table to accepting SQLite advanced search operators, as described in :ref:`full_text_search_advanced_queries`.
Here is an example which enables full-text search (with SQLite advanced search operators) for a ``display_ads`` view which is defined against the ``ads`` table and hence needs to run FTS against the ``ads_fts`` table, using the ``id`` as the primary key:
.. code-block:: json
{
"databases": {
"russian-ads": {
"tables": {
"display_ads": {
"fts_table": "ads_fts",
"fts_pk": "id"
"databases": {
"russian-ads": {
"tables": {
"display_ads": {
"fts_table": "ads_fts",
"fts_pk": "id",
"search_mode": "raw"
}
}
}
}
}
}
}
.. _full_text_search_custom_sql:

Wyświetl plik

@ -1078,6 +1078,46 @@ def test_searchable(app_client, path, expected_rows):
assert expected_rows == response.json["rows"]
_SEARCHMODE_RAW_RESULTS = [
[1, "barry cat", "terry dog", "panther"],
[2, "terry dog", "sara weasel", "puma"],
]
@pytest.mark.parametrize(
"table_metadata,querystring,expected_rows",
[
(
{},
"_search=te*+AND+do*",
[],
),
(
{"searchmode": "raw"},
"_search=te*+AND+do*",
_SEARCHMODE_RAW_RESULTS,
),
(
{},
"_search=te*+AND+do*&_searchmode=raw",
_SEARCHMODE_RAW_RESULTS,
),
# Can be over-ridden with _searchmode=escaped
(
{"searchmode": "raw"},
"_search=te*+AND+do*&_searchmode=escaped",
[],
),
],
)
def test_searchmode(table_metadata, querystring, expected_rows):
with make_app_client(
metadata={"databases": {"fixtures": {"tables": {"searchable": table_metadata}}}}
) as client:
response = client.get("/fixtures/searchable.json?" + querystring)
assert expected_rows == response.json["rows"]
@pytest.mark.parametrize(
"path,expected_rows",
[