# python imports from math import ceil # constants PAGINATOR_MAX_LIMIT = 1000 class PaginateCursor: def __init__(self, current_page_size: int, current_page: int, offset: int): self.current_page_size = current_page_size self.current_page = current_page self.offset = offset def __str__(self): return f"{self.current_page_size}:{self.current_page}:{self.offset}" @classmethod def from_string(self, value): """Return the cursor value from string format""" try: bits = value.split(":") if len(bits) != 3: raise ValueError("Cursor must be in the format 'value:offset:is_prev'") return self(int(bits[0]), int(bits[1]), int(bits[2])) except (TypeError, ValueError) as e: raise ValueError(f"Invalid cursor format: {e}") def paginate(base_queryset, queryset, cursor, on_result): # validating for cursor if cursor is None: cursor_object = PaginateCursor(PAGINATOR_MAX_LIMIT, 0, 0) else: cursor_object = PaginateCursor.from_string(cursor) # getting the issues count total_results = base_queryset.count() page_size = min(cursor_object.current_page_size, PAGINATOR_MAX_LIMIT) # getting the total pages available based on the page size total_pages = ceil(total_results / page_size) # Calculate the start and end index for the paginated data start_index = 0 if cursor_object.current_page > 0: start_index = cursor_object.current_page * page_size end_index = min(start_index + page_size, total_results) # Get the paginated data paginated_data = queryset[start_index:end_index] # Create the pagination info object prev_cursor = f"{page_size}:{cursor_object.current_page - 1}:0" cursor = f"{page_size}:{cursor_object.current_page}:0" next_cursor = None if end_index < total_results: next_cursor = f"{page_size}:{cursor_object.current_page + 1}:0" prev_page_results = False if cursor_object.current_page > 0: prev_page_results = True next_page_results = False if next_cursor: next_page_results = True if on_result: paginated_data = on_result(paginated_data) # returning the result paginated_data = { "prev_cursor": prev_cursor, "cursor": cursor, "next_cursor": next_cursor, "prev_page_results": prev_page_results, "next_page_results": next_page_results, "page_count": len(paginated_data), "total_results": total_results, "total_pages": total_pages, "results": paginated_data, } return paginated_data