Proven
Data access logic scattered throughout the codebase creates maintenance challenges and tight coupling between domain models and database implementation. The Repository Pattern addresses:
The Repository Pattern encapsulates data access logic and provides a clean interface between domain models and database implementation, with automatic resource management and consistent transaction handling.
Core concept:
class BaseRepository:
"""Base repository with common CRUD operations"""
def __init__(self, session: AsyncSession):
self.session = session
async def create(self, **kwargs) -> Any:
# Use transaction context for automatic commit/rollback
async with self.session.begin():
instance = self.model(**kwargs)
self.session.add(instance)
# Automatic commit via context manager
return instance
async def get_by_id(self, id: str) -> Optional[Any]:
result = await self.session.execute(select(self.model).where(self.model.id == id))
return result.scalar_one_or_none()
class ProjectRepository(BaseRepository):
"""Domain-specific repository"""
model = ProjectDB
def __init__(self, session: AsyncSession):
super().__init__(session)
async def list_active_projects(self) -> List[Project]:
result = await self.session.execute(
select(ProjectDB).where(ProjectDB.is_archived == False)
)
db_projects = result.scalars().all()
return [db_project.to_domain() for db_project in db_projects]
from contextlib import asynccontextmanager
from services.database.session_factory import AsyncSessionFactory
async def service_example():
"""Example service using context manager for automatic resource management"""
async with AsyncSessionFactory.session_scope() as session:
repo = ProjectRepository(session)
return await repo.list_active_projects()
services/repositories/, services/database/repositories.pyConsolidated from:
pattern-catalog.md#1-repository-pattern - Implementation details and code examplesarchive/PATTERN-INDEX-legacy.md#repository-pattern - Status and location information