Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-47581: Add generic paginated query support #330

Merged
merged 10 commits into from
Nov 20, 2024
Merged

DM-47581: Add generic paginated query support #330

merged 10 commits into from
Nov 20, 2024

Conversation

rra
Copy link
Member

@rra rra commented Nov 19, 2024

Lift the pagninated query support from Gafaelfawr into Safir and make it generic so that it can be reused in Wobbly.

Pagination support consists of a cursor class, which defines how results are ordered and paginated and how the cursor is serialized and deserialized, a paginated query runner that contains the logic for applying limits and keyset pagination, and a paginated result container that wraps a list of Pydantic models with metadata about the pagination. Also define a cursor type for the common case of results ordered by a datetime and then a unique key, in descending order, so that cursors for that case can be easily constructed.

Fix the documentation build with current Sphinx. Adding TypeVar variables to the exports for documentation purposes is apparently now pointless since the documentation string appears to be forced to be generic documentation about type variables, so stop trying to include them.

@rra rra requested a review from fajpunk November 19, 2024 19:38
@rra rra marked this pull request as draft November 19, 2024 19:43
@rra rra force-pushed the tickets/DM-47581 branch from 0bc09e5 to 62ff262 Compare November 19, 2024 20:29
@rra rra marked this pull request as ready for review November 19, 2024 20:30
@rra rra force-pushed the tickets/DM-47581 branch 3 times, most recently from ee5c331 to 703a279 Compare November 19, 2024 20:39
docs/user-guide/database/pagination.rst Show resolved Hide resolved
safir/tests/database_test.py Outdated Show resolved Hide resolved
safir/tests/database_test.py Show resolved Hide resolved
safir/tests/database_test.py Show resolved Hide resolved
safir/src/safir/database/_pagination.py Outdated Show resolved Hide resolved
safir/src/safir/database/_pagination.py Show resolved Hide resolved
docs/user-guide/database/pagination.rst Outdated Show resolved Hide resolved
docs/user-guide/database/pagination.rst Outdated Show resolved Hide resolved
docs/user-guide/database/pagination.rst Outdated Show resolved Hide resolved
docs/user-guide/database/pagination.rst Show resolved Hide resolved
@fajpunk
Copy link
Member

fajpunk commented Nov 20, 2024

This is very very nice!

rra and others added 7 commits November 20, 2024 09:14
Lift the pagninated query support from Gafaelfawr into Safir and
make it generic so that it can be reused in Wobbly.

Pagination support consists of a cursor class, which defines how
results are ordered and paginated and how the cursor is serialized
and deserialized, a paginated query runner that contains the logic
for applying limits and keyset pagination, and a paginated result
container that wraps a list of Pydantic models with metadata about
the pagination. Also define a cursor type for the common case of
results ordered by a `datetime` and then a unique key, in descending
order, so that cursors for that case can be easily constructed.

Fix the documentation build with current Sphinx. Adding `TypeVar`
variables to the exports for documentation purposes is apparently
now pointless since the documentation string appears to be forced
to be generic documentation about type variables, so stop trying to
include them.
A copy/paste error left the return type in the documentation set to a subclass instead of the parent class.

Co-authored-by: Dan Fuchs <330402+fajpunk@users.noreply.github.com>
`PaginatedList` can hold any time of cursor, not just a `DatetimeIdCursor`.

Co-authored-by: Dan Fuchs <330402+fajpunk@users.noreply.github.com>
Don't use the word limit, since that implies a SQL limit clause, which should not be applied outside of the pagination code.

Co-authored-by: Dan Fuchs <330402+fajpunk@users.noreply.github.com>
Be explicit that the paginated query should not include a `LIMIT` directive.

Co-authored-by: Dan Fuchs <330402+fajpunk@users.noreply.github.com>
Fix several minor documentation and comment issues caught during
code review.
Return a next cursor if a previous cursor was used, even if the
query had no limit. Properly construct previous cursors when
following previous cursors backwards in the data.

Randomize the test data and add more tests for the `Link` headers
that would catch both of those problems.
@rra rra force-pushed the tickets/DM-47581 branch from 6a97fba to c487e58 Compare November 20, 2024 21:33
rra added 3 commits November 20, 2024 13:57
Document that the `id_column` of a `DatetimeIdCursor` must be an
integer. Document in multiple places that forward cursors include
the entry they are based on but previous cursors do not and should
return data starting with the entry immediately previous. Document
that the query is run twice, once with restrictions and then again
with `COUNT` to get the total number of available entries, and
therefore the `COUNT` query needs to be fast (and thus based on
indices or short tables).
Add separate methods to return the first, next, and previous URLs
for a paginated list to make the HATEOS approach a bit easier, and
implement `link_header` in terms of those methods.
The `query_object` and `query_row` methods had duplicate code for
the unpaginated case. Refactor that into a helper method.
@rra rra merged commit ab9e5e6 into main Nov 20, 2024
6 checks passed
@rra rra deleted the tickets/DM-47581 branch November 20, 2024 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants