Coverage for ramose / paging.py: 100%

36 statements  

« 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 

4 

5from math import ceil 

6from typing import NamedTuple 

7from urllib.parse import urlencode 

8 

9_PAGINATION_KEYS = frozenset({"page", "page_size"}) 

10 

11 

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 

21 

22 

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) 

31 

32 

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) 

42 

43 

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)}"