From c632fb8037e88e2b8fd8bfe8547d4bffb2e9ba97 Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Thu, 4 Sep 2025 20:53:44 +0400 Subject: [PATCH] refactor: repository delete mixin --- repositories/board.py | 14 ++------------ repositories/deal.py | 13 ++----------- repositories/mixins.py | 25 +++++++++++++++++++++++++ repositories/project.py | 14 ++------------ repositories/status.py | 13 ++----------- 5 files changed, 33 insertions(+), 46 deletions(-) create mode 100644 repositories/mixins.py diff --git a/repositories/board.py b/repositories/board.py index 38afb74..0715b77 100644 --- a/repositories/board.py +++ b/repositories/board.py @@ -1,4 +1,3 @@ -from datetime import datetime, timezone from typing import Optional from sqlalchemy import select @@ -6,10 +5,11 @@ from sqlalchemy.orm import selectinload from models import Board from repositories.base import BaseRepository +from repositories.mixins import RepDeleteMixin from schemas.board import UpdateBoardSchema, CreateBoardSchema -class BoardRepository(BaseRepository): +class BoardRepository(BaseRepository, RepDeleteMixin[Board]): async def get_all(self, project_id: int) -> list[Board]: stmt = ( select(Board) @@ -43,13 +43,3 @@ class BoardRepository(BaseRepository): await self.session.commit() await self.session.refresh(board) return board - - async def delete(self, board: Board, is_soft: bool): - if not is_soft: - await self.session.delete(board) - await self.session.commit() - return - - board.is_deleted = True - self.session.add(board) - await self.session.commit() diff --git a/repositories/deal.py b/repositories/deal.py index 88412c8..0fb8e8f 100644 --- a/repositories/deal.py +++ b/repositories/deal.py @@ -5,12 +5,13 @@ from sqlalchemy.orm import joinedload from models import Deal, CardStatusHistory, Board from repositories.base import BaseRepository +from repositories.mixins import RepDeleteMixin from schemas.base import SortDir from schemas.deal import UpdateDealSchema, CreateDealSchema from utils.sorting import apply_sorting -class DealRepository(BaseRepository): +class DealRepository(BaseRepository, RepDeleteMixin[Deal]): async def get_all( self, page: Optional[int], @@ -87,13 +88,3 @@ class DealRepository(BaseRepository): await self.session.commit() await self.session.refresh(deal) return deal - - async def delete(self, deal: Deal, is_soft: bool): - if not is_soft: - await self.session.delete(deal) - await self.session.commit() - return - - deal.is_deleted = True - self.session.add(deal) - await self.session.commit() diff --git a/repositories/mixins.py b/repositories/mixins.py new file mode 100644 index 0000000..9c2f7b7 --- /dev/null +++ b/repositories/mixins.py @@ -0,0 +1,25 @@ +from typing import Generic, TypeVar + +from sqlalchemy.ext.asyncio import AsyncSession + +EntityType = TypeVar("EntityType") + + +class RepBaseMixin(Generic[EntityType]): + session: AsyncSession + + +class RepDeleteMixin(RepBaseMixin[EntityType]): + async def delete(self, obj: EntityType, is_soft: bool) -> None: + if not is_soft: + await self.session.delete(obj) + await self.session.commit() + return + + if not hasattr(obj, "is_deleted"): + raise AttributeError( + f"{obj.__class__.__name__} does not support soft delete (missing `is_deleted` field)" + ) + obj.is_deleted = True + self.session.add(obj) + await self.session.commit() diff --git a/repositories/project.py b/repositories/project.py index 7cac5dd..4b29214 100644 --- a/repositories/project.py +++ b/repositories/project.py @@ -1,4 +1,3 @@ -from datetime import datetime, timezone from typing import Optional from sqlalchemy import select @@ -6,10 +5,11 @@ from sqlalchemy.orm import selectinload from models.project import Project from repositories.base import BaseRepository +from repositories.mixins import RepDeleteMixin from schemas.project import CreateProjectSchema, UpdateProjectSchema -class ProjectRepository(BaseRepository): +class ProjectRepository(BaseRepository, RepDeleteMixin[Project]): async def get_all(self) -> list[Project]: stmt = select(Project).where(Project.is_deleted.is_(False)).order_by(Project.id) result = await self.session.execute(stmt) @@ -38,13 +38,3 @@ class ProjectRepository(BaseRepository): await self.session.commit() await self.session.refresh(project) return project - - async def delete(self, project: Project, is_soft: bool): - if not is_soft: - await self.session.delete(project) - await self.session.commit() - return - - project.is_deleted = True - self.session.add(project) - await self.session.commit() diff --git a/repositories/status.py b/repositories/status.py index 9b02533..713d3ed 100644 --- a/repositories/status.py +++ b/repositories/status.py @@ -4,10 +4,11 @@ from sqlalchemy import select, func from models import Status, Deal from repositories.base import BaseRepository +from repositories.mixins import RepDeleteMixin from schemas.status import UpdateStatusSchema, CreateStatusSchema -class StatusRepository(BaseRepository): +class StatusRepository(BaseRepository, RepDeleteMixin[Status]): async def get_all(self, board_id: int) -> list[Status]: stmt = ( select(Status) @@ -44,13 +45,3 @@ class StatusRepository(BaseRepository): await self.session.commit() await self.session.refresh(status) return status - - async def delete(self, status: Status, is_soft: bool): - if not is_soft: - await self.session.delete(status) - await self.session.commit() - return - - status.is_deleted = True - self.session.add(status) - await self.session.commit()