mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Fixed bug with keyset pagination over compound primary keys
Closes #190
This commit is contained in:
parent
89d9fbb91b
commit
31f63d1672
5 changed files with 88 additions and 10 deletions
|
|
@ -20,6 +20,7 @@ from .utils import (
|
|||
Filters,
|
||||
compound_pks_from_path,
|
||||
CustomJSONEncoder,
|
||||
compound_keys_after_sql,
|
||||
detect_fts_sql,
|
||||
escape_css_string,
|
||||
escape_sqlite_table_name,
|
||||
|
|
@ -592,15 +593,10 @@ class TableView(RowTableShared):
|
|||
else:
|
||||
pk_values = compound_pks_from_path(next)
|
||||
if len(pk_values) == len(pks):
|
||||
param_counter = len(params)
|
||||
for pk, value in zip(pks, pk_values):
|
||||
where_clauses.append(
|
||||
'"{}" > :p{}'.format(
|
||||
pk, param_counter,
|
||||
)
|
||||
)
|
||||
params['p{}'.format(param_counter)] = value
|
||||
param_counter += 1
|
||||
where_clauses.append(compound_keys_after_sql(pks))
|
||||
param_len = len(params)
|
||||
for i, pk_value in enumerate(pk_values):
|
||||
params['p{}'.format(param_len + i)] = pk_value
|
||||
|
||||
where_clause = ''
|
||||
if where_clauses:
|
||||
|
|
|
|||
|
|
@ -29,6 +29,34 @@ def path_from_row_pks(row, pks, use_rowid):
|
|||
return ','.join(bits)
|
||||
|
||||
|
||||
def compound_keys_after_sql(pks):
|
||||
# Implementation of keyset pagination
|
||||
# See https://github.com/simonw/datasette/issues/190
|
||||
# For pk1/pk2/pk3 returns:
|
||||
#
|
||||
# ([pk1] > :p0)
|
||||
# or
|
||||
# ([pk1] = :p0 and [pk2] > :p1)
|
||||
# or
|
||||
# ([pk1] = :p0 and [pk2] = :p1 and [pk3] > :p2)
|
||||
or_clauses = []
|
||||
pks_left = pks[:]
|
||||
while pks_left:
|
||||
and_clauses = []
|
||||
last = pks_left[-1]
|
||||
rest = pks_left[:-1]
|
||||
and_clauses = ['[{}] = :p{}'.format(
|
||||
pk, i
|
||||
) for i, pk in enumerate(rest)]
|
||||
and_clauses.append('[{}] > :p{}'.format(
|
||||
last, len(rest)
|
||||
))
|
||||
or_clauses.append('({})'.format(' and '.join(and_clauses)))
|
||||
pks_left.pop()
|
||||
or_clauses.reverse()
|
||||
return '\n or\n'.join(or_clauses)
|
||||
|
||||
|
||||
class CustomJSONEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, sqlite3.Row):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue