Skip to content

Commit e54337e

Browse files
committed
Use UNION ALL for improved performance, refactor previous and forward queries in separate methods
1 parent ad7b006 commit e54337e

File tree

1 file changed

+47
-43
lines changed

1 file changed

+47
-43
lines changed

sqlalchemy_bind_manager/_repository/base_repository.py

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -197,63 +197,67 @@ def _cursor_paginated_query(
197197
asc(self._model_pk())
198198
)
199199

200-
# TODO: Use window functions
201-
if not is_before_cursor:
202-
previous_query = stmt.where(
203-
getattr(self._model, cursor_reference.column) <= cursor_reference.value
204-
)
205-
previous_query = (
206-
self._filter_order_by(
207-
previous_query, [(cursor_reference.column, SortDirection.DESC)]
208-
)
209-
.limit(1)
210-
.subquery("previous") # type: ignore
200+
previous_query = self._cursor_pagination_previous_item_query(
201+
stmt, cursor_reference, is_before_cursor
202+
).subquery("previous")
203+
204+
page_query = self._cursor_pagination_slice_query(
205+
stmt, cursor_reference, forward_limit, is_before_cursor
206+
).subquery("slice")
207+
208+
query = select(
209+
aliased(
210+
self._model,
211+
select(previous_query)
212+
.union_all(select(page_query))
213+
.order_by(cursor_reference.column)
214+
.subquery("cursor_pagination"), # type: ignore
211215
)
216+
)
217+
return query
212218

219+
def _cursor_pagination_slice_query(
220+
self,
221+
stmt: Select,
222+
cursor_reference: CursorReference,
223+
forward_limit: int,
224+
is_before_cursor: bool,
225+
):
226+
if not is_before_cursor:
213227
page_query = stmt.where(
214228
getattr(self._model, cursor_reference.column) > cursor_reference.value
215229
)
216-
page_query = (
217-
self._filter_order_by(
218-
page_query, [(cursor_reference.column, SortDirection.ASC)]
219-
)
220-
.limit(forward_limit)
221-
.subquery("page") # type: ignore
230+
page_query = self._filter_order_by(
231+
page_query, [(cursor_reference.column, SortDirection.ASC)]
222232
)
223233
else:
224-
previous_query = stmt.where(
225-
getattr(self._model, cursor_reference.column) >= cursor_reference.value
226-
)
227-
previous_query = (
228-
self._filter_order_by(
229-
previous_query, [(cursor_reference.column, SortDirection.ASC)]
230-
)
231-
.limit(1)
232-
.subquery("previous") # type: ignore
233-
)
234-
235234
page_query = stmt.where(
236235
getattr(self._model, cursor_reference.column) < cursor_reference.value
237236
)
238-
page_query = (
239-
self._filter_order_by(
240-
page_query, [(cursor_reference.column, SortDirection.DESC)]
241-
)
242-
.limit(forward_limit)
243-
.subquery("page") # type: ignore
237+
page_query = self._filter_order_by(
238+
page_query, [(cursor_reference.column, SortDirection.DESC)]
244239
)
240+
return page_query.limit(forward_limit)
245241

246-
query = select(
247-
aliased(
248-
self._model,
249-
select(previous_query)
250-
.union(select(page_query))
251-
.order_by(cursor_reference.column)
252-
.subquery(), # type: ignore
242+
def _cursor_pagination_previous_item_query(
243+
self, stmt: Select, cursor_reference: CursorReference, is_before_cursor: bool
244+
) -> Select:
245+
if not is_before_cursor:
246+
previous_query = stmt.where(
247+
getattr(self._model, cursor_reference.column) <= cursor_reference.value
248+
)
249+
previous_query = self._filter_order_by(
250+
previous_query, [(cursor_reference.column, SortDirection.DESC)]
251+
)
252+
else:
253+
previous_query = stmt.where(
254+
getattr(self._model, cursor_reference.column) >= cursor_reference.value
255+
)
256+
previous_query = self._filter_order_by(
257+
previous_query, [(cursor_reference.column, SortDirection.ASC)]
253258
)
254-
)
255259

256-
return query
260+
return previous_query.limit(1)
257261

258262
def _sanitised_query_limit(self, limit):
259263
return max(min(limit, self._max_query_limit), 0)

0 commit comments

Comments
 (0)