refactor: repository delete mixin

This commit is contained in:
2025-09-04 20:53:44 +04:00
parent fbab70d6c1
commit c632fb8037
5 changed files with 33 additions and 46 deletions

View File

@ -1,4 +1,3 @@
from datetime import datetime, timezone
from typing import Optional from typing import Optional
from sqlalchemy import select from sqlalchemy import select
@ -6,10 +5,11 @@ from sqlalchemy.orm import selectinload
from models import Board from models import Board
from repositories.base import BaseRepository from repositories.base import BaseRepository
from repositories.mixins import RepDeleteMixin
from schemas.board import UpdateBoardSchema, CreateBoardSchema from schemas.board import UpdateBoardSchema, CreateBoardSchema
class BoardRepository(BaseRepository): class BoardRepository(BaseRepository, RepDeleteMixin[Board]):
async def get_all(self, project_id: int) -> list[Board]: async def get_all(self, project_id: int) -> list[Board]:
stmt = ( stmt = (
select(Board) select(Board)
@ -43,13 +43,3 @@ class BoardRepository(BaseRepository):
await self.session.commit() await self.session.commit()
await self.session.refresh(board) await self.session.refresh(board)
return 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()

View File

@ -5,12 +5,13 @@ from sqlalchemy.orm import joinedload
from models import Deal, CardStatusHistory, Board from models import Deal, CardStatusHistory, Board
from repositories.base import BaseRepository from repositories.base import BaseRepository
from repositories.mixins import RepDeleteMixin
from schemas.base import SortDir from schemas.base import SortDir
from schemas.deal import UpdateDealSchema, CreateDealSchema from schemas.deal import UpdateDealSchema, CreateDealSchema
from utils.sorting import apply_sorting from utils.sorting import apply_sorting
class DealRepository(BaseRepository): class DealRepository(BaseRepository, RepDeleteMixin[Deal]):
async def get_all( async def get_all(
self, self,
page: Optional[int], page: Optional[int],
@ -87,13 +88,3 @@ class DealRepository(BaseRepository):
await self.session.commit() await self.session.commit()
await self.session.refresh(deal) await self.session.refresh(deal)
return 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()

25
repositories/mixins.py Normal file
View File

@ -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()

View File

@ -1,4 +1,3 @@
from datetime import datetime, timezone
from typing import Optional from typing import Optional
from sqlalchemy import select from sqlalchemy import select
@ -6,10 +5,11 @@ from sqlalchemy.orm import selectinload
from models.project import Project from models.project import Project
from repositories.base import BaseRepository from repositories.base import BaseRepository
from repositories.mixins import RepDeleteMixin
from schemas.project import CreateProjectSchema, UpdateProjectSchema from schemas.project import CreateProjectSchema, UpdateProjectSchema
class ProjectRepository(BaseRepository): class ProjectRepository(BaseRepository, RepDeleteMixin[Project]):
async def get_all(self) -> list[Project]: async def get_all(self) -> list[Project]:
stmt = select(Project).where(Project.is_deleted.is_(False)).order_by(Project.id) stmt = select(Project).where(Project.is_deleted.is_(False)).order_by(Project.id)
result = await self.session.execute(stmt) result = await self.session.execute(stmt)
@ -38,13 +38,3 @@ class ProjectRepository(BaseRepository):
await self.session.commit() await self.session.commit()
await self.session.refresh(project) await self.session.refresh(project)
return 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()

View File

@ -4,10 +4,11 @@ from sqlalchemy import select, func
from models import Status, Deal from models import Status, Deal
from repositories.base import BaseRepository from repositories.base import BaseRepository
from repositories.mixins import RepDeleteMixin
from schemas.status import UpdateStatusSchema, CreateStatusSchema from schemas.status import UpdateStatusSchema, CreateStatusSchema
class StatusRepository(BaseRepository): class StatusRepository(BaseRepository, RepDeleteMixin[Status]):
async def get_all(self, board_id: int) -> list[Status]: async def get_all(self, board_id: int) -> list[Status]:
stmt = ( stmt = (
select(Status) select(Status)
@ -44,13 +45,3 @@ class StatusRepository(BaseRepository):
await self.session.commit() await self.session.commit()
await self.session.refresh(status) await self.session.refresh(status)
return 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()