-
-
Notifications
You must be signed in to change notification settings - Fork 685
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
Refactor out the keyset pagination code #2019
Comments
The inputs and outputs for this are pretty complex. Inputs:
Outputs:
|
I should turn I should also create something that bundles together |
Crucial utility function: datasette/datasette/utils/__init__.py Lines 137 to 160 in 0b4a286
|
Found more logic relating to this: datasette/datasette/views/table.py Lines 684 to 732 in 0b4a286
|
Relevant issue: Explains this comment: datasette/datasette/views/table.py Line 697 in 0b4a286
|
Maybe the correct level of abstraction here is that pagination is something that happens to a SQL query that is defined as SQL and params, without an order by or limit. That's then wrapped in a sub-select and those things are added to it, plus the necessary Need to check that the query plan for pagination of a subquery isn't slower than the plan for pagination as it works today. |
For the SQL underlying this page (the second page in that compound primary key paginated sequence): https://latest.datasette.io/fixtures/compound_three_primary_keys?_next=a%2Cd%2Cv The explain for that query rewritten as this: explain
select
*
from
(
select
pk1,
pk2,
pk3,
content
from
compound_three_primary_keys
)
where
(
(pk1 > :p0)
or (
pk1 = :p0
and pk2 > :p1
)
or (
pk1 = :p0
and pk2 = :p1
and pk3 > :p2
)
)
order by
pk1,
pk2,
pk3
limit
101 Both explains have 31 steps and look pretty much identical. |
A more complex example: https://latest.datasette.io/fixtures/sortable?_next=0~2E2650566289400591%2Ca%2Cu&_sort=sortable_with_nulls_2 SQL: select pk1, pk2, content, sortable, sortable_with_nulls, sortable_with_nulls_2, text from sortable where (sortable_with_nulls_2 > :p2 or (sortable_with_nulls_2 = :p2 and ((pk1 > :p0)
or
(pk1 = :p0 and pk2 > :p1)))) order by sortable_with_nulls_2, pk1, pk2 limit 101 Rewritten with a subselect: select * from (
select pk1, pk2, content, sortable, sortable_with_nulls, sortable_with_nulls_2, text from sortable
)
where (sortable_with_nulls_2 > :p2 or (sortable_with_nulls_2 = :p2 and ((pk1 > :p0)
or
(pk1 = :p0 and pk2 > :p1)))) order by sortable_with_nulls_2, pk1, pk2 limit 101 |
Even more complicated: https://latest.datasette.io/fixtures/sortable?sortable_with_nulls__notnull=1&_next=0~2E692704598586882%2Ce%2Cr&_sort=sortable_with_nulls_2 The rewritten SQL for that is: select * from (select pk1, pk2, content, sortable, sortable_with_nulls, sortable_with_nulls_2, text from sortable where "sortable_with_nulls" is not null)
where (sortable_with_nulls_2 > :p2 or (sortable_with_nulls_2 = :p2 and ((pk1 > :p0)
or
(pk1 = :p0 and pk2 > :p1)))) order by sortable_with_nulls_2, pk1, pk2 limit 101 And it still has the same number of explain steps as the current SQL witohut the subselect. |
So I think I can write an abstraction that applies keyset pagination to ANY arbitrary SQL query provided it is given the query, the existing params (so it can pick names for the new params that won't overlap with them), the desired sort order, any existing Those tie breakers will be either the primary key(s) or What about the case of SQL views, where offset/limit should be used instead? I'm inclined to have that as a separate pagination abstraction entirely, with the calling code deciding which pagination helper to use based on if keyset pagination makes sense or not. Might be easier to design a class structure for this starting with Might put these in |
Doing this as a class makes sense to me. There are a few steps:
|
I'm going to build completely separate tests for this in |
select
pk1,
pk2,
content,
sortable,
sortable_with_nulls,
sortable_with_nulls_2,
text
from
sortable
where
(
sortable_with_nulls is null
and (
(pk1 > :p0)
or (
pk1 = :p0
and pk2 > :p1
)
)
)
order by
sortable_with_nulls desc,
pk1,
pk2
limit
101 Generated by this page: https://latest.datasette.io/fixtures/sortable?_next=%24null%2Ch%2Cr&_sort_desc=sortable_with_nulls The |
Rather than duplicate this rather awful hack: datasette/datasette/views/table.py Lines 694 to 714 in 0b4a286
I'm tempted to say that the code that calls the new pagination helper needs to ensure that the |
While working on:
I noticed that some of the most complex code in the existing table view is the code that implements keyset pagination:
datasette/datasette/views/table.py
Lines 417 to 493 in 0b4a286
Extracting that into a utility function would simplify that code a lot.
The text was updated successfully, but these errors were encountered: