# retoor <retoor@molodetz.nl>
from .core import db, get_table
from .relations import get_blocked_uids
PAGE_SIZE = 25
def paginate(
table,
*clauses,
before=None,
order=None,
cursor_field="created_at",
viewer_uid=None,
**filters,
):
order = order or ["-" + cursor_field]
clauses = list(clauses)
if table.has_column("deleted_at") and "deleted_at" not in filters:
clauses.append(table.table.columns.deleted_at.is_(None))
if viewer_uid and table.has_column("user_uid"):
blocked = get_blocked_uids(viewer_uid)
if blocked:
clauses.append(table.table.columns.user_uid.notin_(blocked))
if before:
clauses.append(table.table.columns[cursor_field] < before)
rows = list(table.find(*clauses, **filters, order_by=order, _limit=PAGE_SIZE + 1))
has_more = len(rows) > PAGE_SIZE
rows = rows[:PAGE_SIZE]
next_cursor = rows[-1][cursor_field] if has_more and rows else None
return rows, next_cursor
def interleave_by_author(rows, uid_key="user_uid"):
remaining = list(rows)
spread = []
last_owner = object()
while remaining:
pick = next(
(
index
for index, row in enumerate(remaining)
if row.get(uid_key) != last_owner
),
0,
)
row = remaining.pop(pick)
spread.append(row)
last_owner = row.get(uid_key)
return spread
def paginate_diverse(
table,
*clauses,
before=None,
order=None,
cursor_field="created_at",
uid_key="user_uid",
viewer_uid=None,
**filters,
):
rows, next_cursor = paginate(
table,
*clauses,
before=before,
order=order,
cursor_field=cursor_field,
viewer_uid=viewer_uid,
**filters,
)
return interleave_by_author(rows, uid_key=uid_key), next_cursor
def get_user_post_count(user_uid: str) -> int:
if "posts" not in db.tables:
return 0
return get_table("posts").count(user_uid=user_uid, deleted_at=None)
def build_pagination(page, total, per_page=25):
total_pages = max(1, __import__("math").ceil(total / per_page))
page = max(1, min(page, total_pages))
return {
"page": page,
"per_page": per_page,
"total": total,
"total_pages": total_pages,
"has_prev": page > 1,
"has_next": page < total_pages,
"prev_page": page - 1,
"next_page": page + 1,
}