mirror of
https://github.com/simonw/datasette.git
synced 2026-07-08 16:44:34 +02:00
Remove the next_url extra - the key is always present
next_url became a default table JSON key alongside next, making the extra a no-op. Requesting ?_extra=next_url now returns the standard unknown-extra 400 error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
This commit is contained in:
parent
8b159144a5
commit
4874c29286
7 changed files with 23 additions and 43 deletions
|
|
@ -107,7 +107,6 @@ class TableContext(Context):
|
|||
human_description_en: str = from_extra()
|
||||
is_view: bool = from_extra()
|
||||
metadata: dict = from_extra()
|
||||
next_url: str = from_extra()
|
||||
primary_keys: list = from_extra()
|
||||
private: bool = from_extra()
|
||||
query: dict = from_extra()
|
||||
|
|
@ -124,6 +123,11 @@ class TableContext(Context):
|
|||
metadata={"help": "True if the data for this page was retrieved without errors"}
|
||||
)
|
||||
next: str = field(metadata={"help": "Pagination token for the next page, or None"})
|
||||
next_url: str = field(
|
||||
metadata={
|
||||
"help": "Full URL for the next page of results, or None if there are no more pages. See :ref:`json_api_pagination`."
|
||||
}
|
||||
)
|
||||
count_truncated: bool = field(
|
||||
metadata={
|
||||
"help": "True if ``count`` is a capped lower bound rather than an exact total, because Datasette stopped counting after its configured row-count limit."
|
||||
|
|
|
|||
|
|
@ -321,21 +321,6 @@ class HumanDescriptionEnExtra(Extra):
|
|||
return human_description_en
|
||||
|
||||
|
||||
class NextUrlExtra(Extra):
|
||||
description = "Full URL for the next page of results"
|
||||
example = ExtraExample(
|
||||
"/fixtures/facetable.json?_size=1&_extra=next_url",
|
||||
note=(
|
||||
"``null`` if there are no more pages of results. "
|
||||
"See :ref:`json_api_pagination`."
|
||||
),
|
||||
)
|
||||
scopes = {ExtraScope.TABLE}
|
||||
|
||||
async def resolve(self, context):
|
||||
return context.next_url
|
||||
|
||||
|
||||
class ColumnsExtra(Extra):
|
||||
description = "List of column names returned by this table, row or query."
|
||||
example = ExtraExample("/fixtures/facetable.json?_extra=columns")
|
||||
|
|
@ -1250,7 +1235,6 @@ TABLE_EXTRA_BUNDLES = {
|
|||
"count",
|
||||
"count_sql",
|
||||
"human_description_en",
|
||||
"next_url",
|
||||
"metadata",
|
||||
"query",
|
||||
"columns",
|
||||
|
|
@ -1286,7 +1270,6 @@ TABLE_EXTRA_CLASSES = [
|
|||
SuggestedFacetsExtra,
|
||||
FacetInstancesProvider,
|
||||
HumanDescriptionEnExtra,
|
||||
NextUrlExtra,
|
||||
ColumnsExtra,
|
||||
AllColumnsExtra,
|
||||
PrimaryKeysExtra,
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ These can be repeated or comma-separated:
|
|||
|
||||
::
|
||||
|
||||
?_extra=columns&_extra=count,next_url
|
||||
?_extra=columns&_extra=count,count_sql
|
||||
|
||||
Requesting an ``_extra`` name that does not exist returns a ``400`` error in the :ref:`standard error format <json_api_errors>`, for example ``{"ok": false, "error": "Unknown _extra: nope", ...}``.
|
||||
|
||||
|
|
@ -437,17 +437,6 @@ The available table extras are listed below.
|
|||
|
||||
"where state = \"CA\" sorted by pk"
|
||||
|
||||
``next_url``
|
||||
Full URL for the next page of results
|
||||
|
||||
``GET /fixtures/facetable.json?_size=1&_extra=next_url``
|
||||
|
||||
``null`` if there are no more pages of results. See :ref:`json_api_pagination`.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
"http://localhost/fixtures/facetable.json?_size=1&_extra=next_url&_next=1"
|
||||
|
||||
``columns``
|
||||
List of column names returned by this table, row or query.
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ Many of these keys are shared with the :ref:`JSON API <json_api>` for this page.
|
|||
Pagination token for the next page, or None
|
||||
|
||||
``next_url`` - ``str``
|
||||
Full URL for the next page of results
|
||||
Full URL for the next page of results, or None if there are no more pages. See :ref:`json_api_pagination`.
|
||||
|
||||
``ok`` - ``bool``
|
||||
True if the data for this page was retrieved without errors
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ def test_config_cache_size(app_client_larger_cache_size):
|
|||
def test_config_force_https_urls():
|
||||
with make_app_client(settings={"force_https_urls": True}) as client:
|
||||
response = client.get(
|
||||
"/fixtures/facetable.json?_size=3&_facet=state&_extra=next_url,suggested_facets"
|
||||
"/fixtures/facetable.json?_size=3&_facet=state&_extra=suggested_facets"
|
||||
)
|
||||
assert response.json["next_url"].startswith("https://")
|
||||
assert response.json["facet_results"]["results"]["state"]["results"][0][
|
||||
|
|
|
|||
|
|
@ -739,3 +739,11 @@ async def test_sql_interrupted_html_page_keeps_rich_error(ds_client):
|
|||
)
|
||||
assert response.status_code == 400
|
||||
assert "<textarea" in response.text
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_next_url_extra_no_longer_exists(ds_client):
|
||||
# next_url is always present in table JSON; the extra was removed
|
||||
response = await ds_client.get("/fixtures/facetable.json?_extra=next_url")
|
||||
data = assert_canonical_error(response, 400)
|
||||
assert data["errors"] == ["Unknown _extra: next_url"]
|
||||
|
|
|
|||
|
|
@ -323,10 +323,6 @@ async def test_paginate_tables_and_views(
|
|||
fetched = []
|
||||
count = 0
|
||||
while path:
|
||||
if "?" in path:
|
||||
path += "&_extra=next_url"
|
||||
else:
|
||||
path += "?_extra=next_url"
|
||||
response = await ds_client.get(path)
|
||||
assert response.status_code == 200
|
||||
count += 1
|
||||
|
|
@ -359,9 +355,7 @@ async def test_validate_page_size(ds_client, path, expected_error):
|
|||
@pytest.mark.asyncio
|
||||
async def test_page_size_zero(ds_client):
|
||||
"""For _size=0 we return the counts, empty rows and no continuation token"""
|
||||
response = await ds_client.get(
|
||||
"/fixtures/no_primary_key.json?_size=0&_extra=count,next_url"
|
||||
)
|
||||
response = await ds_client.get("/fixtures/no_primary_key.json?_size=0&_extra=count")
|
||||
assert response.status_code == 200
|
||||
assert [] == response.json()["rows"]
|
||||
assert 202 == response.json()["count"]
|
||||
|
|
@ -372,7 +366,7 @@ async def test_page_size_zero(ds_client):
|
|||
@pytest.mark.asyncio
|
||||
async def test_paginate_compound_keys(ds_client):
|
||||
fetched = []
|
||||
path = "/fixtures/compound_three_primary_keys.json?_shape=objects&_extra=next_url"
|
||||
path = "/fixtures/compound_three_primary_keys.json?_shape=objects"
|
||||
page = 0
|
||||
while path:
|
||||
page += 1
|
||||
|
|
@ -393,7 +387,9 @@ async def test_paginate_compound_keys(ds_client):
|
|||
@pytest.mark.asyncio
|
||||
async def test_paginate_compound_keys_with_extra_filters(ds_client):
|
||||
fetched = []
|
||||
path = "/fixtures/compound_three_primary_keys.json?content__contains=d&_shape=objects&_extra=next_url"
|
||||
path = (
|
||||
"/fixtures/compound_three_primary_keys.json?content__contains=d&_shape=objects"
|
||||
)
|
||||
page = 0
|
||||
while path:
|
||||
page += 1
|
||||
|
|
@ -446,7 +442,7 @@ async def test_paginate_compound_keys_with_extra_filters(ds_client):
|
|||
],
|
||||
)
|
||||
async def test_sortable(ds_client, query_string, sort_key, human_description_en):
|
||||
path = f"/fixtures/sortable.json?_shape=objects&_extra=human_description_en,next_url&{query_string}"
|
||||
path = f"/fixtures/sortable.json?_shape=objects&_extra=human_description_en&{query_string}"
|
||||
fetched = []
|
||||
page = 0
|
||||
while path:
|
||||
|
|
@ -850,7 +846,7 @@ def test_page_size_matching_max_returned_rows(
|
|||
app_client_returned_rows_matches_page_size,
|
||||
):
|
||||
fetched = []
|
||||
path = "/fixtures/no_primary_key.json?_extra=next_url"
|
||||
path = "/fixtures/no_primary_key.json"
|
||||
while path:
|
||||
response = app_client_returned_rows_matches_page_size.get(path)
|
||||
fetched.extend(response.json["rows"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue