Coverage for ramose / paging.py: 100%
36 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-15 15:58 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-15 15:58 +0000
1# SPDX-FileCopyrightText: 2026 Arcangelo Massari <arcangelo.massari@unibo.it>
2#
3# SPDX-License-Identifier: ISC
5from math import ceil
6from typing import NamedTuple
7from urllib.parse import urlencode
9_PAGINATION_KEYS = frozenset({"page", "page_size"})
12class PaginationInfo(NamedTuple):
13 page: int
14 page_size: int
15 total_items: int
16 self_url: str
17 next_url: str
18 prev_url: str
19 first_url: str
20 last_url: str
23def build_pagination_info(base_path, query_params, page, page_size, total_items) -> PaginationInfo:
24 total_pages = ceil(total_items / page_size) if page_size > 0 else 0
25 self_url = _page_url(base_path, query_params, page, page_size, total_items)
26 next_url = _page_url(base_path, query_params, page + 1, page_size, total_items) if page < total_pages else ""
27 prev_url = _page_url(base_path, query_params, page - 1, page_size, total_items) if page > 1 else ""
28 first_url = _page_url(base_path, query_params, 1, page_size, total_items)
29 last_url = _page_url(base_path, query_params, max(total_pages, 1), page_size, total_items)
30 return PaginationInfo(page, page_size, total_items, self_url, next_url, prev_url, first_url, last_url)
33def build_link_header(pagination_info: PaginationInfo) -> str:
34 links = []
35 if pagination_info.next_url:
36 links.append(f'<{pagination_info.next_url}>; rel="next"')
37 if pagination_info.prev_url:
38 links.append(f'<{pagination_info.prev_url}>; rel="prev"')
39 links.append(f'<{pagination_info.first_url}>; rel="first"')
40 links.append(f'<{pagination_info.last_url}>; rel="last"')
41 return ", ".join(links)
44def _page_url(base_path, query_params, page, page_size, total_items):
45 params = {k: v for k, v in query_params.items() if k not in _PAGINATION_KEYS}
46 params["page"] = [str(page)]
47 params["page_size"] = [str(page_size)]
48 params["total_items"] = [str(total_items)]
49 return f"{base_path}?{urlencode(params, doseq=True)}"