Обновлены пути к библиотекам в Dockerfile для соответствия новой версии Python. Исправлены все тесты, теперь все проходят
4.8 KiB
4.8 KiB
description, globs
| description | globs | ||
|---|---|---|---|
| Паттерны работы с базой данных, репозитории и модели |
|
Паттерны работы с базой данных
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
Важные правила
-
Всегда используйте параметризованные запросы для защиты от 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}" -
Логируйте важные операции:
self.logger.info(f"Пользователь добавлен: {user_id}") self.logger.error(f"Ошибка при добавлении пользователя: {e}") -
Используйте транзакции для множественных операций (если нужно):
async with await self._get_connection() as conn: await conn.execute(...) await conn.execute(...) await conn.commit() -
Обрабатывайте 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