Repository navigation
fix: reject out-of-range limit and offset; previous past the end goes to the last records - #10
Conversation
… to the last page limit and offset went into the SQL unchecked, so a negative or oversized value made Postgres fail and the client got a 500 with its error. Bound them on the Query parameters (limit 1 to 2^63-1, offset 0 to 2^63-1), so those get a 422 naming the parameter and no SQL runs. Past the end of the results, previous pointed at another empty page. Point it at the last page. Same fixes as CLEANDB-api#25 and #27.
matthewberry
left a comment
There was a problem hiding this comment.
Looks good. Reproduced: full suite 32 passed, and against main's app/, 6 of the 9 new tests in tests/test_pagination_bounds.py fail.
Nit on wording: "previous past the end goes to the last page" is really "the last limit records". With 25 records and pages of 10, previous goes to offset=15, not the page boundary at 20. Every row is still reachable, so only the PR text needs changing, unless lining up with page boundaries matters.
Couldn't reproduce, and it predates this PR: the data query has no ORDER BY, so limit/offset pages aren't guaranteed to be consistent between requests. With a 35k-row table it's unlikely to show up.
|
Agreed on the wording. Fixed in 894a3c2: the code comment, the test name ( On |
Ports moleculemaker/CLEANDB-api#25 (bounds) and the "previous past the end" part of moleculemaker/CLEANDB-api#27 to
/api/v1/data.Problem
limitandoffsetreach the SQL unchecked. From production:A negative
offsetfails the same way, and Postgres rejects values above the bigint maximum (2^63 - 1) with "bigint out of range" (seen on CLEANDB-api's Postgres 16; not re-checked here).limit=0returned no rows.previouspast the end points at another empty page. From production, with 35,753 records:Fix
limitis now 1 to2^63 - 1andoffset0 to2^63 - 1, asQuery(ge=…, le=…)bounds, so out-of-range values get a 422 naming the parameter and no SQL runs.previoususesmax(0, min(offset - limit, total - limit)), so past the end it goes to the lastlimitrecords (oroffset=0when there are fewer thanlimitresults). That isn't necessarily a page boundary: with 25 records and pages of 10 it'soffset=15, not 20. Every record is still reachable. Within the results the link is unchanged.The part of CLEANDB-api#27 about filters being dropped from links doesn't apply: oed-api's model field names match its query parameter names.
Tests
New
tests/test_pagination_bounds.py, modeled on CLEANDB-api's:limitof -1, 0 or2^63, andoffsetof -5 or2^63, each get a 422 whose only error is on that parameter, with no query sent to the database.limit=1,offset=0andoffset=2^63 - 1are accepted and reach the SQL unchanged.offset=100getspreviousatoffset=15and nonext.The six rejection and
previouscases fail onmain. Full suite: 32 passed (23 before, against a throwaway Postgres for the app's startup connection, as in #8).Not changed here
Requests above the page size are still capped at 5,000 for both formats, as #8 left them. A follow-up PR, stacked on this one, changes that to match CLEANDB-api#20.