mirror of
https://github.com/simonw/datasette.git
synced 2026-07-10 01:24:45 +02:00
Remove has_more from query list JSON - next: null signals the end
next: null (with next_url: null) is the single end-of-results signal across the API, keeping default response keys to a minimum. The StoredQueryPage.has_more attribute on the documented Python API is unchanged. Also fixes a bug this uncovered: the query list JSON next_url pointed at the HTML page (it was built from the query list path, dropping the .json extension) and was a relative path where the table view next_url is absolute. It is now built from the request path and absolute, so it preserves the requested format and can be followed directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
This commit is contained in:
parent
5c418efd7f
commit
e892c686c2
5 changed files with 36 additions and 8 deletions
|
|
@ -83,7 +83,6 @@ def stored_query_page_to_dict(page: StoredQueryPage) -> dict[str, Any]:
|
|||
return {
|
||||
"queries": [stored_query_to_dict(query) for query in page.queries],
|
||||
"next": page.next,
|
||||
"has_more": page.has_more,
|
||||
"limit": page.limit,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,9 +120,9 @@ class QueryListView(BaseView):
|
|||
if key != "_next"
|
||||
]
|
||||
pairs.append(("_next", page.next))
|
||||
next_url = "{}?{}".format(
|
||||
query_list_path,
|
||||
urlencode(pairs),
|
||||
next_url = self.ds.absolute_url(
|
||||
request,
|
||||
"{}?{}".format(request.path, urlencode(pairs)),
|
||||
)
|
||||
|
||||
current_filters = {
|
||||
|
|
@ -208,7 +208,6 @@ class QueryListView(BaseView):
|
|||
"queries": page.queries,
|
||||
"next": page.next,
|
||||
"next_url": next_url,
|
||||
"has_more": page.has_more,
|
||||
"limit": page.limit,
|
||||
"show_private_note": any(query.is_private for query in page.queries),
|
||||
"show_trusted_note": any(query.is_trusted for query in page.queries),
|
||||
|
|
|
|||
|
|
@ -1038,7 +1038,7 @@ databases (`database`/`database_color` are null, `show_database` true).
|
|||
400 `"is_write must be 0 or 1"`), `source`, `owner_id`.
|
||||
- **Response** — 200:
|
||||
`{"ok": true, "database", "database_color", "queries": [...], "next",
|
||||
"next_url", "has_more", "limit", "show_private_note",
|
||||
"next_url", "limit", "show_private_note",
|
||||
"show_trusted_note", "query_list_path", "show_database",
|
||||
"facets": [{title, items: [{label, count, href, active}]}],
|
||||
"filters": {q, is_write, is_private, source, owner_id}}`.
|
||||
|
|
|
|||
|
|
@ -209,7 +209,13 @@ number.
|
|||
> values (previously silently clamped), and the `/-/allowed` and
|
||||
> `/-/rules` debug endpoints renamed `page`/`page_size` to
|
||||
> `_page`/`_size` with the same validation (400 instead of silent
|
||||
> capping at 200). The `has_more`/`total` differences remain open.
|
||||
> capping at 200). `has_more` has been **removed** from the query-list
|
||||
> JSON — `next: null` is the single end-of-results signal everywhere,
|
||||
> keeping default response keys minimal (`total` remains a debug-endpoint
|
||||
> nicety). Fixing this also uncovered and fixed a bug where the query
|
||||
> list's JSON `next_url` pointed at the HTML page (it dropped the `.json`
|
||||
> extension) and was relative where the table `next_url` is absolute.
|
||||
> §3 is now fully resolved.
|
||||
|
||||
| Endpoint | Mechanism | Token | Extras |
|
||||
|---|---|---|---|
|
||||
|
|
|
|||
|
|
@ -879,7 +879,7 @@ async def test_query_list_html_defaults_to_twenty_and_shows_pagination():
|
|||
assert response.text.count('aria-label="Query pagination"') == 1
|
||||
assert "Demo query 20" in response.text
|
||||
assert "Demo query 21" not in response.text
|
||||
assert 'href="/data/-/queries?_next=' in response.text
|
||||
assert 'href="http://localhost/data/-/queries?_next=' in response.text
|
||||
assert len(json_response.json()["queries"]) == 25
|
||||
|
||||
|
||||
|
|
@ -3827,3 +3827,27 @@ async def test_stored_query_json_uses_parameters_not_params():
|
|||
query = [q for q in listing["queries"] if q["name"] == "with_params"][0]
|
||||
assert query["parameters"] == ["name", "age"]
|
||||
assert "params" not in query
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_query_list_json_signals_pagination_via_next_only():
|
||||
ds = Datasette(memory=True)
|
||||
ds.add_memory_database("query_list_next_only", name="data")
|
||||
await ds.invoke_startup()
|
||||
for i in range(3):
|
||||
await ds.add_query(
|
||||
"data",
|
||||
name="q{}".format(i),
|
||||
sql="select {}".format(i),
|
||||
)
|
||||
first = (await ds.client.get("/data/-/queries.json?_size=2")).json()
|
||||
assert "has_more" not in first
|
||||
assert first["next"] is not None
|
||||
assert first["next_url"] is not None
|
||||
# The internal test client cannot follow absolute URLs
|
||||
next_path = first["next_url"].replace("http://localhost", "")
|
||||
assert next_path.startswith("/data/-/queries.json?")
|
||||
last = (await ds.client.get(next_path)).json()
|
||||
assert "has_more" not in last
|
||||
assert last["next"] is None
|
||||
assert last["next_url"] is None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue