Files
AnonBot/services/business/pagination_service.py

186 lines
7.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Сервис для работы с пагинацией
"""
from typing import Any, List, Optional, Tuple
from aiogram.types import InlineKeyboardMarkup
from config.constants import DEFAULT_PAGE_SIZE, MIN_PAGE_NUMBER
from services.infrastructure.logger import get_logger
logger = get_logger(__name__)
class PaginationService:
"""Сервис для работы с пагинацией"""
def __init__(self):
pass
async def calculate_pagination_from_db(
self,
total_count: int,
page: int,
per_page: int = DEFAULT_PAGE_SIZE
) -> Tuple[int, int, int, int]:
"""
Расчет пагинации на основе общего количества записей в БД
Args:
total_count: Общее количество записей в БД
page: Номер страницы (начиная с 0)
per_page: Количество элементов на странице
Returns:
Кортеж (общееоличество, текущая_страница, общееоличество_страниц, offset)
"""
try:
total_pages = (total_count + per_page - 1) // per_page # Округление вверх
# Проверяем корректность номера страницы
if page < MIN_PAGE_NUMBER:
page = MIN_PAGE_NUMBER
elif page >= total_pages and total_pages > 0:
page = total_pages - 1
# Вычисляем offset для БД
offset = page * per_page
return total_count, page, total_pages, offset
except Exception as e:
logger.error(f"Ошибка при расчете пагинации из БД: {e}")
return MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER
def calculate_pagination(
self,
items: List[Any],
page: int,
per_page: int = DEFAULT_PAGE_SIZE
) -> Tuple[List[Any], int, int, int]:
"""
Расчет пагинации для списка элементов
Args:
items: Список элементов
page: Номер страницы (начиная с 0)
per_page: Количество элементов на странице
Returns:
Кортеж (элементы_страницы, общееоличество, текущая_страница, общееоличество_страниц)
"""
try:
total_items = len(items)
total_pages = (total_items + per_page - 1) // per_page # Округление вверх
# Проверяем корректность номера страницы
if page < MIN_PAGE_NUMBER:
page = MIN_PAGE_NUMBER
elif page >= total_pages and total_pages > 0:
page = total_pages - 1
# Вычисляем диапазон элементов для текущей страницы
start_idx = page * per_page
end_idx = min(start_idx + per_page, total_items)
page_items = items[start_idx:end_idx]
return page_items, total_items, page, total_pages
except Exception as e:
logger.error(f"Ошибка при расчете пагинации: {e}")
return [], MIN_PAGE_NUMBER, MIN_PAGE_NUMBER, MIN_PAGE_NUMBER
def format_pagination_info(
self,
current_page: int,
total_pages: int,
start_idx: int,
end_idx: int,
total_items: int
) -> str:
"""
Форматирование информации о пагинации
Args:
current_page: Текущая страница
total_pages: Общее количество страниц
start_idx: Начальный индекс
end_idx: Конечный индекс
total_items: Общее количество элементов
Returns:
Отформатированная строка с информацией о пагинации
"""
try:
info = f"📊 Показано {start_idx + 1}-{end_idx} из {total_items}\n"
info += f"📄 Страница {current_page + 1} из {total_pages}\n\n"
return info
except Exception as e:
logger.error(f"Ошибка при форматировании информации о пагинации: {e}")
return ""
def get_pagination_buttons(
self,
current_page: int,
total_pages: int,
callback_prefix: str,
additional_buttons: Optional[List[Tuple[str, str]]] = None
) -> List[Tuple[str, str]]:
"""
Получение кнопок пагинации
Args:
current_page: Текущая страница
total_pages: Общее количество страниц
callback_prefix: Префикс для callback_data
additional_buttons: Дополнительные кнопки
Returns:
Список кортежей (текст_кнопки, callback_data)
"""
try:
buttons = []
# Кнопка "Предыдущая"
if current_page > MIN_PAGE_NUMBER:
buttons.append(("⬅️", f"{callback_prefix}_page_{current_page - 1}"))
# Кнопка "Следующая"
if current_page < total_pages - 1:
buttons.append(("➡️", f"{callback_prefix}_page_{current_page + 1}"))
# Дополнительные кнопки
if additional_buttons:
buttons.extend(additional_buttons)
return buttons
except Exception as e:
logger.error(f"Ошибка при создании кнопок пагинации: {e}")
return []
def validate_page_number(self, page: int, total_pages: int) -> int:
"""
Валидация номера страницы
Args:
page: Номер страницы
total_pages: Общее количество страниц
Returns:
Валидный номер страницы
"""
try:
if page < 0:
return 0
elif page >= total_pages and total_pages > 0:
return total_pages - 1
else:
return page
except Exception as e:
logger.error(f"Ошибка при валидации номера страницы: {e}")
return MIN_PAGE_NUMBER