From 3326e406f886b66d09cec6a36565e4551d77952e Mon Sep 17 00:00:00 2001 From: JSC Date: Sun, 17 Aug 2025 01:27:41 +0200 Subject: [PATCH] feat: Add filtering, searching, and sorting to user extractions retrieval --- app/api/v1/extractions.py | 14 +++++++++++-- app/repositories/extraction.py | 38 +++++++++++++++++++++++++++++++++- app/services/extraction.py | 19 ++++++++++++++--- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/app/api/v1/extractions.py b/app/api/v1/extractions.py index feba222..ee19415 100644 --- a/app/api/v1/extractions.py +++ b/app/api/v1/extractions.py @@ -2,7 +2,7 @@ from typing import Annotated -from fastapi import APIRouter, Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlmodel.ext.asyncio.session import AsyncSession from app.core.database import get_db @@ -91,6 +91,10 @@ async def get_extraction( async def get_user_extractions( current_user: Annotated[User, Depends(get_current_active_user_flexible)], extraction_service: Annotated[ExtractionService, Depends(get_extraction_service)], + search: Annotated[str | None, Query(description="Search in title, URL, or service")] = None, + sort_by: Annotated[str, Query(description="Sort by field")] = "created_at", + sort_order: Annotated[str, Query(description="Sort order (asc/desc)")] = "desc", + status_filter: Annotated[str | None, Query(description="Filter by status")] = None, ) -> dict[str, list[ExtractionInfo]]: """Get all extractions for the current user.""" try: @@ -100,7 +104,13 @@ async def get_user_extractions( detail="User ID not available", ) - extractions = await extraction_service.get_user_extractions(current_user.id) + extractions = await extraction_service.get_user_extractions( + user_id=current_user.id, + search=search, + sort_by=sort_by, + sort_order=sort_order, + status_filter=status_filter, + ) except Exception as e: raise HTTPException( diff --git a/app/repositories/extraction.py b/app/repositories/extraction.py index ff30a9d..ff4167e 100644 --- a/app/repositories/extraction.py +++ b/app/repositories/extraction.py @@ -1,6 +1,6 @@ """Extraction repository for database operations.""" -from sqlalchemy import desc +from sqlalchemy import asc, desc, or_ from sqlmodel import select from sqlmodel.ext.asyncio.session import AsyncSession @@ -55,3 +55,39 @@ class ExtractionRepository(BaseRepository[Extraction]): .order_by(desc(Extraction.created_at)), ) return list(result.all()) + + async def get_user_extractions_filtered( + self, + user_id: int, + search: str | None = None, + sort_by: str = "created_at", + sort_order: str = "desc", + status_filter: str | None = None, + ) -> list[Extraction]: + """Get extractions for a user with filtering, search, and sorting.""" + query = select(Extraction).where(Extraction.user_id == user_id) + + # Apply search filter + if search: + search_pattern = f"%{search}%" + query = query.where( + or_( + Extraction.title.ilike(search_pattern), + Extraction.url.ilike(search_pattern), + Extraction.service.ilike(search_pattern), + ) + ) + + # Apply status filter + if status_filter: + query = query.where(Extraction.status == status_filter) + + # Apply sorting + sort_column = getattr(Extraction, sort_by, Extraction.created_at) + if sort_order.lower() == "asc": + query = query.order_by(asc(sort_column)) + else: + query = query.order_by(desc(sort_column)) + + result = await self.session.exec(query) + return list(result.all()) diff --git a/app/services/extraction.py b/app/services/extraction.py index 53488ce..98003ba 100644 --- a/app/services/extraction.py +++ b/app/services/extraction.py @@ -545,9 +545,22 @@ class ExtractionService: "updated_at": extraction.updated_at.isoformat(), } - async def get_user_extractions(self, user_id: int) -> list[ExtractionInfo]: - """Get all extractions for a user.""" - extractions = await self.extraction_repo.get_by_user(user_id) + async def get_user_extractions( + self, + user_id: int, + search: str | None = None, + sort_by: str = "created_at", + sort_order: str = "desc", + status_filter: str | None = None, + ) -> list[ExtractionInfo]: + """Get all extractions for a user with filtering, search, and sorting.""" + extractions = await self.extraction_repo.get_user_extractions_filtered( + user_id=user_id, + search=search, + sort_by=sort_by, + sort_order=sort_order, + status_filter=status_filter, + ) return [ {