The Repository Pattern separates data-access operations from application logic behind a simple interface. It hides whether data comes from a REST API, cache, file, or database. section 4.3.3
A practical implementation develops in stages:
- Define a generic BaseRepository contract for creating, reading, updating, deleting, and listing entities. section 4.3.3
- Implement InMemoryAssetRepository with a typed list, enabling end-to-end testing without an external database. section 4.3.3
- Delegate AssetManager operations to the repository instead of embedding data-access details in application services. section 4.3.3
- Replace the in-memory implementation with SQLAlchemyAssetRepository when persistence through PostgreSQL is required. section 4.3.4
Listing 4.26 Code for BaseRepository, our generic data access layer
from abc import ABC, abstractmethod
from typing import List, TypeVar, Generic
T = TypeVar('T')
class BaseRepository(ABC, Generic[T]):
@abstractmethod
def create(self, entity: T) -> None:
pass
@abstractmethod
def read(self, entity_id: int) -> T:
pass
@abstractmethod
def update(self, entity: T) -> None:
pass
@abstractmethod
def delete(self, entity_id: int) -> None:
pass
@abstractmethod
def get_entities(self) -> List[T]:
pass
Use the generic abstract class as the repository contract that concrete data stores must implement. section 4.3.3
Swapping storage implementations
Application wiring can choose InMemoryAssetRepository for a lightweight run or SQLAlchemyAssetRepository with a database session for durable storage, while AssetManager remains unchanged. section 4.3.4








