first commit
This commit is contained in:
0
backend/app/repositories/__init__.py
Normal file
0
backend/app/repositories/__init__.py
Normal file
34
backend/app/repositories/assessment_repo.py
Normal file
34
backend/app/repositories/assessment_repo.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.models.assessment import FraudAssessment, ConfidenceLevel
|
||||
from app.repositories.base import BaseRepository
|
||||
|
||||
|
||||
class AssessmentRepository(BaseRepository[FraudAssessment]):
|
||||
def __init__(self, session: AsyncSession):
|
||||
super().__init__(FraudAssessment, session)
|
||||
|
||||
async def list_by_case(
|
||||
self,
|
||||
case_id: UUID,
|
||||
confidence_level: ConfidenceLevel | None = None,
|
||||
) -> tuple[list[FraudAssessment], int]:
|
||||
query = (
|
||||
select(FraudAssessment)
|
||||
.options(selectinload(FraudAssessment.transaction))
|
||||
.where(FraudAssessment.case_id == case_id)
|
||||
)
|
||||
count_q = select(func.count()).select_from(FraudAssessment).where(FraudAssessment.case_id == case_id)
|
||||
|
||||
if confidence_level:
|
||||
query = query.where(FraudAssessment.confidence_level == confidence_level)
|
||||
count_q = count_q.where(FraudAssessment.confidence_level == confidence_level)
|
||||
|
||||
total = (await self.session.execute(count_q)).scalar() or 0
|
||||
query = query.order_by(FraudAssessment.created_at.asc())
|
||||
result = await self.session.execute(query)
|
||||
return list(result.scalars().all()), total
|
||||
50
backend/app/repositories/base.py
Normal file
50
backend/app/repositories/base.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from typing import TypeVar, Generic, Type
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import Base
|
||||
|
||||
ModelT = TypeVar("ModelT", bound=Base)
|
||||
|
||||
|
||||
class BaseRepository(Generic[ModelT]):
|
||||
def __init__(self, model: Type[ModelT], session: AsyncSession):
|
||||
self.model = model
|
||||
self.session = session
|
||||
|
||||
async def get(self, id: UUID) -> ModelT | None:
|
||||
return await self.session.get(self.model, id)
|
||||
|
||||
async def list(self, offset: int = 0, limit: int = 50, **filters) -> tuple[list[ModelT], int]:
|
||||
query = select(self.model)
|
||||
count_query = select(func.count()).select_from(self.model)
|
||||
|
||||
for attr, value in filters.items():
|
||||
if value is not None and hasattr(self.model, attr):
|
||||
query = query.where(getattr(self.model, attr) == value)
|
||||
count_query = count_query.where(getattr(self.model, attr) == value)
|
||||
|
||||
total = (await self.session.execute(count_query)).scalar() or 0
|
||||
query = query.offset(offset).limit(limit)
|
||||
result = await self.session.execute(query)
|
||||
return list(result.scalars().all()), total
|
||||
|
||||
async def create(self, obj: ModelT) -> ModelT:
|
||||
self.session.add(obj)
|
||||
await self.session.flush()
|
||||
await self.session.refresh(obj)
|
||||
return obj
|
||||
|
||||
async def update(self, obj: ModelT, data: dict) -> ModelT:
|
||||
for key, value in data.items():
|
||||
if value is not None:
|
||||
setattr(obj, key, value)
|
||||
await self.session.flush()
|
||||
await self.session.refresh(obj)
|
||||
return obj
|
||||
|
||||
async def delete(self, obj: ModelT) -> None:
|
||||
await self.session.delete(obj)
|
||||
await self.session.flush()
|
||||
35
backend/app/repositories/case_repo.py
Normal file
35
backend/app/repositories/case_repo.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from sqlalchemy import select, func, or_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.case import Case, CaseStatus
|
||||
from app.repositories.base import BaseRepository
|
||||
|
||||
|
||||
class CaseRepository(BaseRepository[Case]):
|
||||
def __init__(self, session: AsyncSession):
|
||||
super().__init__(Case, session)
|
||||
|
||||
async def list_cases(
|
||||
self,
|
||||
offset: int = 0,
|
||||
limit: int = 50,
|
||||
status: CaseStatus | None = None,
|
||||
search: str | None = None,
|
||||
) -> tuple[list[Case], int]:
|
||||
query = select(Case).where(Case.deleted_at.is_(None))
|
||||
count_query = select(func.count()).select_from(Case).where(Case.deleted_at.is_(None))
|
||||
|
||||
if status:
|
||||
query = query.where(Case.status == status)
|
||||
count_query = count_query.where(Case.status == status)
|
||||
|
||||
if search:
|
||||
pattern = f"%{search}%"
|
||||
search_filter = or_(Case.case_no.ilike(pattern), Case.title.ilike(pattern))
|
||||
query = query.where(search_filter)
|
||||
count_query = count_query.where(search_filter)
|
||||
|
||||
total = (await self.session.execute(count_query)).scalar() or 0
|
||||
query = query.order_by(Case.created_at.desc()).offset(offset).limit(limit)
|
||||
result = await self.session.execute(query)
|
||||
return list(result.scalars().all()), total
|
||||
39
backend/app/repositories/image_repo.py
Normal file
39
backend/app/repositories/image_repo.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.evidence_image import EvidenceImage, SourceApp, PageType
|
||||
from app.repositories.base import BaseRepository
|
||||
|
||||
|
||||
class ImageRepository(BaseRepository[EvidenceImage]):
|
||||
def __init__(self, session: AsyncSession):
|
||||
super().__init__(EvidenceImage, session)
|
||||
|
||||
async def find_by_hash(self, file_hash: str) -> EvidenceImage | None:
|
||||
result = await self.session.execute(
|
||||
select(EvidenceImage).where(EvidenceImage.file_hash == file_hash)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def list_by_case(
|
||||
self,
|
||||
case_id: UUID,
|
||||
source_app: SourceApp | None = None,
|
||||
page_type: PageType | None = None,
|
||||
) -> list[EvidenceImage]:
|
||||
query = select(EvidenceImage).where(EvidenceImage.case_id == case_id)
|
||||
if source_app:
|
||||
query = query.where(EvidenceImage.source_app == source_app)
|
||||
if page_type:
|
||||
query = query.where(EvidenceImage.page_type == page_type)
|
||||
query = query.order_by(EvidenceImage.uploaded_at.desc())
|
||||
result = await self.session.execute(query)
|
||||
return list(result.scalars().all())
|
||||
|
||||
async def count_by_case(self, case_id: UUID) -> int:
|
||||
result = await self.session.execute(
|
||||
select(func.count()).select_from(EvidenceImage).where(EvidenceImage.case_id == case_id)
|
||||
)
|
||||
return result.scalar() or 0
|
||||
40
backend/app/repositories/transaction_repo.py
Normal file
40
backend/app/repositories/transaction_repo.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.transaction import TransactionRecord
|
||||
from app.repositories.base import BaseRepository
|
||||
|
||||
|
||||
class TransactionRepository(BaseRepository[TransactionRecord]):
|
||||
def __init__(self, session: AsyncSession):
|
||||
super().__init__(TransactionRecord, session)
|
||||
|
||||
async def list_by_case(
|
||||
self,
|
||||
case_id: UUID,
|
||||
filter_type: str | None = None,
|
||||
) -> tuple[list[TransactionRecord], int]:
|
||||
query = select(TransactionRecord).where(TransactionRecord.case_id == case_id)
|
||||
count_q = select(func.count()).select_from(TransactionRecord).where(TransactionRecord.case_id == case_id)
|
||||
|
||||
if filter_type == "unique":
|
||||
query = query.where(TransactionRecord.is_duplicate.is_(False))
|
||||
count_q = count_q.where(TransactionRecord.is_duplicate.is_(False))
|
||||
elif filter_type == "duplicate":
|
||||
query = query.where(TransactionRecord.is_duplicate.is_(True))
|
||||
count_q = count_q.where(TransactionRecord.is_duplicate.is_(True))
|
||||
|
||||
total = (await self.session.execute(count_q)).scalar() or 0
|
||||
query = query.order_by(TransactionRecord.trade_time.asc())
|
||||
result = await self.session.execute(query)
|
||||
return list(result.scalars().all()), total
|
||||
|
||||
async def get_all_by_case(self, case_id: UUID) -> list[TransactionRecord]:
|
||||
result = await self.session.execute(
|
||||
select(TransactionRecord)
|
||||
.where(TransactionRecord.case_id == case_id)
|
||||
.order_by(TransactionRecord.trade_time.asc())
|
||||
)
|
||||
return list(result.scalars().all())
|
||||
Reference in New Issue
Block a user