tofu-api/tofu_api/repositories/base_repository.py

95 lines
2.6 KiB
Python

__all__ = [
'BaseRepository',
'T_Model',
]
from abc import ABC, abstractmethod
from typing import Generic, Optional, Type, TypeVar
from sqlalchemy import select
from sqlalchemy.orm import Session
from tofu_api.models import BaseModel
from .exceptions import ObjectNotFoundException
T_Model = TypeVar('T_Model', bound=BaseModel)
class BaseRepository(Generic[T_Model], ABC):
"""
Base class for repositories.
"""
# Database session
session: Session
@property
@abstractmethod
def model_cls(self) -> Type[T_Model]:
"""
Set this to the model class.
"""
raise NotImplementedError
def __init__(self, *, session: Session):
self.session = session
@staticmethod
def _or_raise(resource: Optional[T_Model], exception_msg: Optional[str] = None) -> T_Model:
if resource is None:
raise ObjectNotFoundException(exception_msg)
return resource
def fetch_by_id(self, resource_id: int) -> T_Model:
"""
Fetches a resource by ID.
Raises an ObjectNotFoundException if no resource with the ID was found.
"""
resource = self.session.get(self.model_cls, resource_id)
return self._or_raise(resource, f'Resource with ID {resource_id} was not found.')
def fetch_all(self) -> list[T_Model]:
"""
Fetches all resources of the repository type.
"""
return self.session.scalars(
select(self.model_cls)
).all()
def commit_session(self) -> None:
"""
Commits the current database session.
"""
self.commit_session()
def rollback_session(self) -> None:
"""
Rolls back the current database session.
"""
self.rollback_session()
def save_resource(self, *resources: T_Model, commit: bool = True) -> None:
"""
Saves one or multiple resources to the database by adding them to the session and committing the session.
Set `commit` to False to skip committing (the session will still be flushed, though).
"""
for resource in resources:
self.session.add(resource)
self.session.flush()
if commit:
self.session.commit()
def delete_resource(self, *resources: T_Model, commit: bool = True) -> None:
"""
Deletes one or multiple resources from the database.
Set `commit` to False to skip committing (the session will still be flushed, though).
"""
for resource in resources:
self.session.delete(resource)
self.session.flush()
if commit:
self.session.commit()