patternpythonModeratepending
Pattern: Repository pattern for data access abstraction
Viewed 0 times
repositorydata-accessabstractiontestingclean-architecture
Problem
Data access logic is scattered throughout business logic, making it hard to test, change databases, or maintain consistent query patterns.
Solution
Abstract data access behind a Repository interface:
# Define the interface
from abc import ABC, abstractmethod
from typing import Optional, List
class UserRepository(ABC):
@abstractmethod
def find_by_id(self, user_id: str) -> Optional[User]: ...
@abstractmethod
def find_by_email(self, email: str) -> Optional[User]: ...
@abstractmethod
def save(self, user: User) -> User: ...
@abstractmethod
def delete(self, user_id: str) -> None: ...
# Concrete implementation
class PostgresUserRepository(UserRepository):
def __init__(self, db):
self.db = db
def find_by_id(self, user_id):
return self.db.query(User).filter_by(id=user_id).first()
# ...
# Test implementation
class InMemoryUserRepository(UserRepository):
def __init__(self):
self.users = {}
def find_by_id(self, user_id):
return self.users.get(user_id)
# ...
# Business logic depends on abstraction
class UserService:
def __init__(self, repo: UserRepository):
self.repo = repo
# Define the interface
from abc import ABC, abstractmethod
from typing import Optional, List
class UserRepository(ABC):
@abstractmethod
def find_by_id(self, user_id: str) -> Optional[User]: ...
@abstractmethod
def find_by_email(self, email: str) -> Optional[User]: ...
@abstractmethod
def save(self, user: User) -> User: ...
@abstractmethod
def delete(self, user_id: str) -> None: ...
# Concrete implementation
class PostgresUserRepository(UserRepository):
def __init__(self, db):
self.db = db
def find_by_id(self, user_id):
return self.db.query(User).filter_by(id=user_id).first()
# ...
# Test implementation
class InMemoryUserRepository(UserRepository):
def __init__(self):
self.users = {}
def find_by_id(self, user_id):
return self.users.get(user_id)
# ...
# Business logic depends on abstraction
class UserService:
def __init__(self, repo: UserRepository):
self.repo = repo
Why
The Repository pattern decouples business logic from data access, enabling easy testing with in-memory implementations and flexibility to change storage.
Revisions (0)
No revisions yet.