Files
telegram-helper-bot/.cursor/rules/database-patterns.md
Andrey d2d7c83575 Обновлен Python до версии 3.11.9 и изменены зависимости в Dockerfile и pyproject.toml. Удалены устаревшие файлы RATE_LIMITING_SOLUTION.md и тесты для rate limiting.
Обновлены пути к библиотекам в Dockerfile для соответствия новой версии Python.
Исправлены все тесты, теперь все проходят
2026-01-25 16:07:27 +03:00

4.8 KiB
Raw Permalink Blame History

description, globs
description globs
Паттерны работы с базой данных, репозитории и модели
database/**/*.py
**/repositories/*.py

Паттерны работы с базой данных

Repository Pattern

Все операции с БД выполняются через репозитории. Каждый репозиторий:

  • Наследуется от DatabaseConnection из database/base.py
  • Работает с одной сущностью (User, Post, Blacklist, etc.)
  • Содержит методы для CRUD операций
  • Использует асинхронные методы _execute_query() и _execute_query_with_result()

Структура репозитория

from database.base import DatabaseConnection
from database.models import User

class UserRepository(DatabaseConnection):
    """Репозиторий для работы с пользователями."""
    
    async def create_tables(self):
        """Создание таблицы пользователей."""
        query = '''
            CREATE TABLE IF NOT EXISTS our_users (
                user_id INTEGER NOT NULL PRIMARY KEY,
                ...
            )
        '''
        await self._execute_query(query)
        self.logger.info("Таблица пользователей создана")
    
    async def add_user(self, user: User) -> None:
        """Добавление нового пользователя."""
        query = "INSERT OR IGNORE INTO our_users (...) VALUES (...)"
        params = (...)
        await self._execute_query(query, params)
        self.logger.info(f"Пользователь добавлен: {user.user_id}")
    
    async def get_user_by_id(self, user_id: int) -> Optional[User]:
        """Получение пользователя по ID."""
        query = "SELECT * FROM our_users WHERE user_id = ?"
        rows = await self._execute_query_with_result(query, (user_id,))
        # Преобразование row в модель User
        ...

Модели данных

  • Модели определены в database/models.py
  • Используются dataclasses или простые классы
  • Модели передаются между слоями (Repository → Service → Handler)

Работа с БД

AsyncBotDB

  • Основной интерфейс для работы с БД
  • Использует RepositoryFactory для доступа к репозиториям
  • Методы делегируют вызовы соответствующим репозиториям

DatabaseConnection

  • Базовый класс для всех репозиториев
  • Предоставляет методы:
    • _get_connection() - получение соединения
    • _execute_query() - выполнение запроса без результата
    • _execute_query_with_result() - выполнение запроса с результатом
  • Автоматически управляет соединениями (открытие/закрытие)
  • Настраивает PRAGMA для оптимизации SQLite

Важные правила

  1. Всегда используйте параметризованные запросы для защиты от SQL injection:

    # ✅ Правильно
    query = "SELECT * FROM users WHERE user_id = ?"
    await self._execute_query_with_result(query, (user_id,))
    
    # ❌ Неправильно
    query = f"SELECT * FROM users WHERE user_id = {user_id}"
    
  2. Логируйте важные операции:

    self.logger.info(f"Пользователь добавлен: {user_id}")
    self.logger.error(f"Ошибка при добавлении пользователя: {e}")
    
  3. Используйте транзакции для множественных операций (если нужно):

    async with await self._get_connection() as conn:
        await conn.execute(...)
        await conn.execute(...)
        await conn.commit()
    
  4. Обрабатывайте None при получении данных:

    rows = await self._execute_query_with_result(query, params)
    if not rows:
        return None
    row = rows[0]
    

RepositoryFactory

  • Создает и кэширует экземпляры репозиториев
  • Доступ через свойства: factory.users, factory.posts, etc.
  • Используется в AsyncBotDB для доступа к репозиториям

Миграции

  • SQL миграции в database/schema.sql
  • Python скрипты для миграций в scripts/
  • Всегда проверяйте существование таблиц перед созданием: CREATE TABLE IF NOT EXISTS