feat: MTG database integration with Redis caching

- Added MTG card ORM models (mtg_cards, mtg_sets tables)
- Created card_database service with search, get_by_name, get_by_set
- Added Redis client with caching layer (3600s TTL default)
- Created card router with caching on all endpoints:
  - Search cards (5min cache)
  - Get card by name (10min cache)
  - Get cards by set (15min cache)
  - Get card types/rarities (30min cache)
  - Get sets (1hr cache)
  - Get statistics (1hr cache)
- Updated settings.py:
  - Added JWT_SECRET_KEY field
  - Added DB_CONFIG and REDIS_CONFIG dictionaries
- Updated security.py to use JWT_SECRET_KEY with fallback
- Updated auth.py to use timezone-aware datetimes
- Updated refresh_mtg.py to use settings instead of os.environ
- Updated mtg_monitor.py to use settings for connections
- Added services package with __init__.py

All 20 tests passing.
This commit is contained in:
2026-07-18 18:41:05 +00:00
parent 167a352d44
commit 915242b330
20 changed files with 1804 additions and 287 deletions
+32 -2
View File
@@ -2,6 +2,7 @@
Database engine and session management.
Provides async SQLAlchemy engine and session factory for dependency injection.
Supports dual database connections for cockatrice app and mtgjson data.
"""
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import DeclarativeBase
@@ -9,6 +10,7 @@ from app.core.settings import get_settings
settings = get_settings()
# Primary database engine (cockatrice app)
engine = create_async_engine(
settings.DATABASE_URL,
echo=settings.DEBUG,
@@ -23,17 +25,32 @@ async_session = async_sessionmaker(
expire_on_commit=False,
)
# Secondary database engine (mtgjson data)
mtg_engine = create_async_engine(
settings.MTG_DATABASE_URL,
echo=settings.DEBUG,
pool_pre_ping=True,
pool_size=10,
max_overflow=5,
)
mtg_async_session = async_sessionmaker(
mtg_engine,
class_=AsyncSession,
expire_on_commit=False,
)
class Base(DeclarativeBase):
"""Base class for all ORM models."""
pass
__all__ = ["Base", "get_db", "async_session", "engine"]
__all__ = ["Base", "get_db", "async_session", "engine", "mtg_get_db", "mtg_async_session", "mtg_engine"]
async def get_db() -> AsyncSession:
"""FastAPI dependency that provides a database session."""
"""FastAPI dependency that provides a database session for the cockatrice app."""
async with async_session() as session:
try:
yield session
@@ -43,3 +60,16 @@ async def get_db() -> AsyncSession:
raise
finally:
await session.close()
async def mtg_get_db() -> AsyncSession:
"""FastAPI dependency that provides a database session for mtgjson data."""
async with mtg_async_session() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()