mirror of
https://github.com/simonw/datasette.git
synced 2026-07-09 09:04:42 +02:00
Include next_url in default table JSON keys
Table JSON responses previously only included the next pagination token by default - the ready-to-follow next_url required ?_extra=next_url. Both keys are now always present (null on the final page), which the pagination documentation already claimed. The next_url extra remains valid for backwards compatibility. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
This commit is contained in:
parent
e0ba8b3c6a
commit
0bf3a54716
5 changed files with 33 additions and 2 deletions
|
|
@ -2318,6 +2318,7 @@ async def table_view_data(
|
|||
data = {
|
||||
"ok": True,
|
||||
"next": next_value and str(next_value) or None,
|
||||
"next_url": next_url,
|
||||
}
|
||||
data.update(
|
||||
await resolve_table_extras(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ The ``"rows"`` key is a list of objects, each one representing a row.
|
|||
|
||||
The ``"truncated"`` key lets you know if the query was truncated. This can happen if a SQL query returns more than 1,000 results (or the :ref:`setting_max_returned_rows` setting).
|
||||
|
||||
For table pages, an additional key ``"next"`` may be present. This indicates that the next page in the pagination set can be retrieved using ``?_next=VALUE``.
|
||||
For table pages, two additional keys are present: ``"next"``, an opaque token that can be used to retrieve the next page using ``?_next=TOKEN``, and ``"next_url"``, the full URL of that next page. Both are ``null`` on the final page. See :ref:`json_api_pagination`.
|
||||
|
||||
.. _json_api_errors:
|
||||
|
||||
|
|
@ -128,6 +128,7 @@ options:
|
|||
{
|
||||
"ok": true,
|
||||
"next": null,
|
||||
"next_url": null,
|
||||
"rows": [
|
||||
[3, "Detroit"],
|
||||
[2, "Los Angeles"],
|
||||
|
|
|
|||
|
|
@ -647,6 +647,7 @@ dispatched to `QueryView` (views/table.py:1703-1712).
|
|||
|---|---|
|
||||
| `ok` | `true` when data was retrieved without error |
|
||||
| `next` | pagination token string, or `null` on the last page |
|
||||
| `next_url` | absolute URL of the next page, or `null` on the last page |
|
||||
| `rows` | list of row objects `{column: value}` (default `_shape=objects`) |
|
||||
| `truncated` | always present; `false` for table pages |
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,14 @@ number.
|
|||
|
||||
---
|
||||
|
||||
## 3. Pagination: three mechanisms, two contracts (P2)
|
||||
## 3. Pagination: three mechanisms, two contracts (P2) — partially implemented
|
||||
|
||||
> **Status:** `next_url` now accompanies `next` in the default table JSON
|
||||
> keys (previously it required `?_extra=next_url`), so every response with
|
||||
> a `next` token also carries the ready-to-follow URL. Pagination tokens
|
||||
> are deliberately left undocumented as to their internal structure. The
|
||||
> `_size`/`page_size` naming and `has_more`/`total` differences remain
|
||||
> open.
|
||||
|
||||
| Endpoint | Mechanism | Token | Extras |
|
||||
|---|---|---|---|
|
||||
|
|
|
|||
|
|
@ -1491,6 +1491,7 @@ async def test_col_nocol_errors(ds_client, path, expected_error):
|
|||
{
|
||||
"ok": True,
|
||||
"next": None,
|
||||
"next_url": None,
|
||||
"columns": ["id", "content", "content2"],
|
||||
"rows": [{"id": "1", "content": "hey", "content2": "world"}],
|
||||
"truncated": False,
|
||||
|
|
@ -1501,6 +1502,7 @@ async def test_col_nocol_errors(ds_client, path, expected_error):
|
|||
{
|
||||
"ok": True,
|
||||
"next": None,
|
||||
"next_url": None,
|
||||
"rows": [{"id": "1", "content": "hey", "content2": "world"}],
|
||||
"truncated": False,
|
||||
"count": 1,
|
||||
|
|
@ -1627,3 +1629,22 @@ async def test_count_truncated_included_with_count_extra(tmp_path_factory):
|
|||
assert response.json()["count_truncated"] is True
|
||||
finally:
|
||||
ds.close()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_next_url_included_by_default(ds_client):
|
||||
response = await ds_client.get("/fixtures/compound_three_primary_keys.json")
|
||||
data = response.json()
|
||||
assert data["next"] is not None
|
||||
assert data["next_url"].endswith(
|
||||
"/fixtures/compound_three_primary_keys.json?_next="
|
||||
+ urllib.parse.quote(data["next"], safe="")
|
||||
)
|
||||
# Follow to the last page - next and next_url are both null there
|
||||
while data["next"]:
|
||||
response = await ds_client.get(
|
||||
"/fixtures/compound_three_primary_keys.json?_next=" + data["next"]
|
||||
)
|
||||
data = response.json()
|
||||
assert data["next"] is None
|
||||
assert data["next_url"] is None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue