Files
sakhteman/core/service/mysql_orm.py
T

82 lines
2.7 KiB
Python
Raw Normal View History

2026-02-17 22:37:43 +03:30
"""
SQLAlchemy async setup برای MySQL (فقط خواندنی).
از asyncmy به عنوان async driver استفاده می‌کند.
"""
from contextlib import asynccontextmanager
from typing import Optional
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import declarative_base, sessionmaker
from core.utils.mysql import get_mysql_config
# Base class برای تمام مدل‌های ORM
Base = declarative_base()
_engine = None
_async_session_maker = None
def get_mysql_url(connection_name: str = None) -> str:
"""ساخت URL برای SQLAlchemy از تنظیمات MySQL"""
cfg = get_mysql_config(connection_name)
return f"mysql+asyncmy://{cfg['user']}:{cfg['password']}@{cfg['host']}:{cfg['port']}/{cfg['db']}?charset=utf8mb4"
def get_async_engine(connection_name: str = None):
"""برگرداندن async engine (در اولین فراخوانی ساخته می‌شود)"""
global _engine
if _engine is None:
url = get_mysql_url(connection_name)
_engine = create_async_engine(
url,
echo=False, # برای debug می‌تونی True کنی
pool_pre_ping=True, # چک کردن کانکشن قبل از استفاده
pool_size=5,
max_overflow=10,
)
return _engine
def get_async_session_maker(connection_name: str = None):
"""برگرداندن async sessionmaker"""
global _async_session_maker
if _async_session_maker is None:
engine = get_async_engine(connection_name)
_async_session_maker = sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
autocommit=False,
autoflush=False,
)
return _async_session_maker
@asynccontextmanager
async def get_mysql_session(connection_name: str = None):
"""
Context manager برای گرفتن async session (فقط خواندنی).
استفاده:
async with get_mysql_session() as session:
result = await session.execute(select(User).where(User.id == 1))
user = result.scalar_one_or_none()
"""
session_maker = get_async_session_maker(connection_name)
async with session_maker() as session:
# تنظیم session به حالت فقط-خواندنی
await session.execute("SET SESSION TRANSACTION READ ONLY")
try:
yield session
finally:
await session.rollback() # برای read-only همیشه rollback می‌کنیم
async def close_mysql_engine():
"""بستن engine (مثلاً در shutdown اپ)."""
global _engine, _async_session_maker
if _engine is not None:
await _engine.dispose()
_engine = None
_async_session_maker = None