diff --git a/datasette/views/table.py b/datasette/views/table.py index 190529f4..eb155407 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -1158,7 +1158,7 @@ def _escape_like(value): # Returns the exclusive upper bound for an indexed prefix search: -# "abc" -> "abd", so `pk >= "abc" and pk < "abd"` covers "abc%". +# For example, values beginning with "abc" fall below the next prefix boundary. # The LIKE clause is still applied separately for exact escaped-LIKE semantics. def _prefix_range_end(value): if not value: @@ -1221,6 +1221,9 @@ def _autocomplete_response_rows(rows, pks, label_column): return response_rows +AUTOCOMPLETE_TIME_LIMIT_MS = 500 + + class TableAutocompleteView(BaseView): name = "table-autocomplete" @@ -1289,7 +1292,9 @@ class TableAutocompleteView(BaseView): ) try: - results = await db.execute(sql, params, custom_time_limit=500) + results = await db.execute( + sql, params, custom_time_limit=AUTOCOMPLETE_TIME_LIMIT_MS + ) except QueryInterrupted: fallback_where = _autocomplete_prefix_like(pks[0]) prefix_end = _prefix_range_end(q) @@ -1312,7 +1317,11 @@ class TableAutocompleteView(BaseView): order_by=_autocomplete_pk_order_by(pks), ) try: - results = await db.execute(fallback_sql, params, custom_time_limit=500) + results = await db.execute( + fallback_sql, + params, + custom_time_limit=AUTOCOMPLETE_TIME_LIMIT_MS, + ) except QueryInterrupted: return Response.json({"rows": []}) diff --git a/docs/introspection.rst b/docs/introspection.rst index 7702a4b5..4834f441 100644 --- a/docs/introspection.rst +++ b/docs/introspection.rst @@ -201,6 +201,15 @@ Search example with ``?q=facet`` returns only items matching ``.*facet.*``: When multiple search terms are provided (e.g., ``?q=user+profile``), items must match the pattern ``.*user.*profile.*``. Results are ordered by relevance, then by item type and shortest display name. +.. _AutocompleteDebugView: + +/-/debug/autocomplete +--------------------- + +The debug tool at ``/-/debug/autocomplete`` can be used to try out the autocomplete component against a specific table. Pass ``?database=db&table=table`` to display an autocomplete field backed by that table's ``/-/autocomplete`` endpoint. + +Without those query string arguments, the page lists up to five tables with detected label columns, scanning at most 100 tables. + .. _JsonDataView_threads: /-/threads diff --git a/tests/test_autocomplete.py b/tests/test_autocomplete.py index d7d78848..abe19af2 100644 --- a/tests/test_autocomplete.py +++ b/tests/test_autocomplete.py @@ -1,6 +1,7 @@ import pytest from datasette.app import Datasette +import datasette.views.table as table_views @pytest.mark.asyncio @@ -190,7 +191,8 @@ async def test_autocomplete_primary_key_called_label(): @pytest.mark.asyncio -async def test_autocomplete_timeout_uses_prefix_fallback(): +async def test_autocomplete_timeout_uses_prefix_fallback(monkeypatch): + monkeypatch.setattr(table_views, "AUTOCOMPLETE_TIME_LIMIT_MS", 1) ds = Datasette( memory=True, config={ @@ -200,7 +202,6 @@ async def test_autocomplete_timeout_uses_prefix_fallback(): }, settings={ "num_sql_threads": 1, - "sql_time_limit_ms": 1, }, ) db = ds.add_memory_database("autocomplete_timeout")