mirror of
https://github.com/simonw/datasette.git
synced 2026-10-28 06:07:03 +01:00
Merge 3bc7e7517a into c435a80030
This commit is contained in:
commit
394e05ac50
2 changed files with 46 additions and 3 deletions
|
|
@ -2140,10 +2140,10 @@ async def table_view_data(
|
|||
count_sql = f"select count(*) {from_sql}"
|
||||
|
||||
# Handle pagination driven by ?_next=
|
||||
_next = _next or request.args.get("_next")
|
||||
_next = _next if _next is not None else request.args.get("_next")
|
||||
|
||||
offset = ""
|
||||
if _next:
|
||||
if _next is not None:
|
||||
sort_value = None
|
||||
if is_view:
|
||||
# _next is an offset
|
||||
|
|
@ -2397,7 +2397,7 @@ async def table_view_data(
|
|||
|
||||
data = {
|
||||
"ok": True,
|
||||
"next": next_value and str(next_value) or None,
|
||||
"next": None if next_value is None else str(next_value),
|
||||
"next_url": next_url,
|
||||
}
|
||||
data.update(
|
||||
|
|
|
|||
|
|
@ -366,6 +366,49 @@ async def test_page_size_zero(ds_client):
|
|||
assert None is response.json()["next_url"]
|
||||
|
||||
|
||||
def test_paginate_table_with_empty_string_primary_key():
|
||||
# path_from_row_pks() returns "" for a row whose only primary key
|
||||
# value is the empty string, and "" is a legitimate _next= cursor.
|
||||
# The "next" key and the _next= handling both used a truthiness
|
||||
# check, so the token was dropped and pagination never advanced.
|
||||
with make_app_client(
|
||||
memory=True,
|
||||
extra_databases={
|
||||
"empty_pk": (
|
||||
"CREATE TABLE t (id TEXT PRIMARY KEY);"
|
||||
"INSERT INTO t (id) VALUES ('a'), (''), ('c'), ('d'), ('e');"
|
||||
)
|
||||
},
|
||||
) as client:
|
||||
fetched = []
|
||||
path = "/empty_pk/t.json?_size=1"
|
||||
page = 0
|
||||
while path:
|
||||
page += 1
|
||||
response = client.get(path)
|
||||
assert response.status == 200
|
||||
data = response.json
|
||||
fetched.extend(row["id"] for row in data["rows"])
|
||||
if data["next_url"]:
|
||||
# next_url and next agree, per docs/json_api.rst
|
||||
assert (
|
||||
urllib.parse.urlencode({"_next": data["next"]}) in data["next_url"]
|
||||
)
|
||||
path = data["next_url"]
|
||||
if path:
|
||||
path = path.replace("http://localhost", "")
|
||||
assert page < 30, "Possible infinite loop detected"
|
||||
|
||||
# Every row exactly once
|
||||
assert 5 == len(fetched)
|
||||
assert ["", "a", "c", "d", "e"] == sorted(fetched)
|
||||
assert 5 == page
|
||||
# And the final page has both keys null, as documented
|
||||
last = client.get("/empty_pk/t.json?_size=100").json
|
||||
assert None is last["next"]
|
||||
assert None is last["next_url"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_paginate_compound_keys(ds_client):
|
||||
fetched = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue