Establishes foundation for migrating baseball simulation from Discord bot to web application using service-oriented architecture pattern. Key components: - FastAPI application structure with dependency injection - Service layer foundation with base classes and container - Comprehensive directory documentation with README files - PostgreSQL containerization with Docker Compose - Testing structure for unit/integration/e2e tests - Migration planning documentation - Rotating log configuration per user requirements Architecture follows Model/Service/Controller pattern to improve testability, maintainability, and scalability over original monolithic Discord app. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
90 lines
2.5 KiB
Python
90 lines
2.5 KiB
Python
"""
|
|
Dependency injection container for services.
|
|
Manages service lifecycles and dependencies using FastAPI's dependency injection.
|
|
"""
|
|
|
|
import logging
|
|
from functools import lru_cache
|
|
from typing import Annotated
|
|
|
|
from fastapi import Depends
|
|
from sqlmodel import Session, SQLModel, create_engine
|
|
from sqlalchemy.pool import StaticPool
|
|
|
|
from app.config.constants import settings
|
|
|
|
|
|
logger = logging.getLogger(f'{__name__}.service_container')
|
|
|
|
|
|
# Database setup
|
|
engine = create_engine(
|
|
settings.DATABASE_URL,
|
|
echo=settings.DEBUG,
|
|
poolclass=StaticPool if "sqlite" in settings.DATABASE_URL else None,
|
|
connect_args={"check_same_thread": False} if "sqlite" in settings.DATABASE_URL else {}
|
|
)
|
|
|
|
|
|
def create_db_and_tables():
|
|
"""Create database tables."""
|
|
SQLModel.metadata.create_all(engine)
|
|
|
|
|
|
def get_session() -> Session:
|
|
"""
|
|
Dependency to get database session.
|
|
Each request gets its own session that's automatically closed.
|
|
"""
|
|
with Session(engine) as session:
|
|
try:
|
|
yield session
|
|
except Exception as e:
|
|
logger.error(f"Database session error: {str(e)}")
|
|
session.rollback()
|
|
raise
|
|
finally:
|
|
session.close()
|
|
|
|
|
|
# Type aliases for dependency injection
|
|
SessionDep = Annotated[Session, Depends(get_session)]
|
|
|
|
|
|
# Service dependencies - these will be implemented as services are created
|
|
def get_game_service(session: SessionDep):
|
|
"""Get GameService instance."""
|
|
from app.services.game_service import GameService
|
|
return GameService(session)
|
|
|
|
|
|
def get_user_service(session: SessionDep):
|
|
"""Get UserService instance."""
|
|
from app.services.user_service import UserService
|
|
return UserService(session)
|
|
|
|
|
|
def get_auth_service(session: SessionDep):
|
|
"""Get AuthService instance."""
|
|
from app.services.auth_service import AuthService
|
|
return AuthService(session)
|
|
|
|
|
|
def get_gameplay_service(session: SessionDep):
|
|
"""Get GameplayService instance."""
|
|
from app.services.gameplay_service import GameplayService
|
|
return GameplayService(session)
|
|
|
|
|
|
def get_ai_service(session: SessionDep):
|
|
"""Get AIService instance."""
|
|
from app.services.ai_service import AIService
|
|
return AIService(session)
|
|
|
|
|
|
# Type aliases for service dependencies
|
|
GameServiceDep = Annotated[object, Depends(get_game_service)]
|
|
UserServiceDep = Annotated[object, Depends(get_user_service)]
|
|
AuthServiceDep = Annotated[object, Depends(get_auth_service)]
|
|
GameplayServiceDep = Annotated[object, Depends(get_gameplay_service)]
|
|
AIServiceDep = Annotated[object, Depends(get_ai_service)] |