Implement task API with input validation; implement error handling; refactoring

This commit is contained in:
Lexi / Zoe 2022-09-23 20:38:34 +02:00
parent 19d264a03b
commit 50aff05614
Signed by: binaryDiv
GPG key ID: F8D4956E224DA232
24 changed files with 612 additions and 131 deletions

View file

@ -0,0 +1,2 @@
from .base_repository import BaseRepository
from .task_repository import TaskRepository

View file

@ -0,0 +1,94 @@
__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()

View file

@ -0,0 +1,9 @@
from tofu_api.common.exceptions import AppException
class ObjectNotFoundException(AppException):
"""
Exception raised when a database object was not found, i.e. does not exist or is inaccessible for the user.
"""
status_code = 404
code = 'not_found'

View file

@ -0,0 +1,9 @@
from tofu_api.models import Task
from .base_repository import BaseRepository
class TaskRepository(BaseRepository[Task]):
"""
Repository for tasks.
"""
model_cls = Task