From 1d8e863ce9752ffbb14df0f7a70d82f5a9b8900f Mon Sep 17 00:00:00 2001 From: harsh Date: Wed, 28 Jan 2026 00:29:58 +0530 Subject: [PATCH 1/3] fix: optimize toggle_favourite endpoint performance Related to #977 --- backend/app/database/images.py | 29 ++++++++++++++++++++++++++++- backend/app/routes/images.py | 14 ++++++++++---- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/backend/app/database/images.py b/backend/app/database/images.py index ec9541a56..da10b76b6 100644 --- a/backend/app/database/images.py +++ b/backend/app/database/images.py @@ -1,6 +1,8 @@ # Standard library imports import sqlite3 -from typing import Any, List, Mapping, Tuple, TypedDict, Union +from typing import Any, List, Mapping, Tuple, TypedDict, Union, Optional +import json + # App-specific imports from app.config.settings import ( @@ -419,3 +421,28 @@ def db_toggle_image_favourite_status(image_id: str) -> bool: return False finally: conn.close() + +def db_get_image_by_id(image_id: str) -> Optional[dict]: + """Get a single image by ID with its favorite status.""" + conn = _connect() + cursor = conn.cursor() + try: + cursor.execute(""" + SELECT id, path, folder_id, thumbnailPath, metadata, isTagged, isFavourite + FROM images + WHERE id = ? + """, (image_id,)) + row = cursor.fetchone() + if not row: + return None + return { + "id": row[0], + "path": row[1], + "folder_id": row[2], + "thumbnailPath": row[3], + "metadata": json.loads(row[4]) if row[4] else {}, + "isTagged": bool(row[5]), + "isFavourite": bool(row[6]), + } + finally: + conn.close() diff --git a/backend/app/routes/images.py b/backend/app/routes/images.py index 2e40cd825..7f9d8a353 100644 --- a/backend/app/routes/images.py +++ b/backend/app/routes/images.py @@ -4,9 +4,10 @@ from app.schemas.images import ErrorResponse from app.utils.images import image_util_parse_metadata from pydantic import BaseModel -from app.database.images import db_toggle_image_favourite_status +from app.database.images import db_toggle_image_favourite_status, db_get_image_by_id from app.logging.setup_logging import get_logger + # Initialize logger logger = get_logger(__name__) router = APIRouter() @@ -105,9 +106,14 @@ def toggle_favourite(req: ToggleFavouriteRequest): status_code=404, detail="Image not found or failed to toggle" ) # Fetch updated status to return - image = next( - (img for img in db_get_all_images() if img["id"] == image_id), None - ) + #image = next( + # (img for img in db_get_all_images() if img["id"] == image_id), None + #) + image = db_get_image_by_id(image_id) + if not image: + raise HTTPException( + status_code=404, detail="Image not found after toggle" + ) return { "success": True, "image_id": image_id, From 5eb18116d8c207d22eafa905936ccfdda5689863 Mon Sep 17 00:00:00 2001 From: harsh Date: Wed, 28 Jan 2026 01:03:14 +0530 Subject: [PATCH 2/3] fix: guard against invalid metadata JSON --- backend/app/database/images.py | 6 +++++- backend/app/routes/images.py | 7 ++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backend/app/database/images.py b/backend/app/database/images.py index da10b76b6..704b31ee9 100644 --- a/backend/app/database/images.py +++ b/backend/app/database/images.py @@ -435,12 +435,16 @@ def db_get_image_by_id(image_id: str) -> Optional[dict]: row = cursor.fetchone() if not row: return None + try: + metadata = json.loads(row[4]) if row[4] else {} + except json.JSONDecodeError: + metadata = {} return { "id": row[0], "path": row[1], "folder_id": row[2], "thumbnailPath": row[3], - "metadata": json.loads(row[4]) if row[4] else {}, + "metadata": metadata, "isTagged": bool(row[5]), "isFavourite": bool(row[6]), } diff --git a/backend/app/routes/images.py b/backend/app/routes/images.py index 7f9d8a353..193801a37 100644 --- a/backend/app/routes/images.py +++ b/backend/app/routes/images.py @@ -106,9 +106,6 @@ def toggle_favourite(req: ToggleFavouriteRequest): status_code=404, detail="Image not found or failed to toggle" ) # Fetch updated status to return - #image = next( - # (img for img in db_get_all_images() if img["id"] == image_id), None - #) image = db_get_image_by_id(image_id) if not image: raise HTTPException( @@ -119,12 +116,12 @@ def toggle_favourite(req: ToggleFavouriteRequest): "image_id": image_id, "isFavourite": image.get("isFavourite", False), } - + except HTTPException: + raise except Exception as e: logger.error(f"error in /toggle-favourite route: {e}") raise HTTPException(status_code=500, detail=f"Internal server error: {e}") - class ImageInfoResponse(BaseModel): id: str path: str From 668bd12a7338047cf94c9b8b9dea214d7526a0eb Mon Sep 17 00:00:00 2001 From: harsh Date: Wed, 28 Jan 2026 01:15:28 +0530 Subject: [PATCH 3/3] fix: add docstrings and improve error handling --- backend/app/database/images.py | 6 ++++-- backend/app/routes/images.py | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/backend/app/database/images.py b/backend/app/database/images.py index 704b31ee9..ff408cd2d 100644 --- a/backend/app/database/images.py +++ b/backend/app/database/images.py @@ -423,7 +423,9 @@ def db_toggle_image_favourite_status(image_id: str) -> bool: conn.close() def db_get_image_by_id(image_id: str) -> Optional[dict]: - """Get a single image by ID with its favorite status.""" + """ + Get a single image by ID with its favorite status. + """ conn = _connect() cursor = conn.cursor() try: @@ -449,4 +451,4 @@ def db_get_image_by_id(image_id: str) -> Optional[dict]: "isFavourite": bool(row[6]), } finally: - conn.close() + conn.close() \ No newline at end of file diff --git a/backend/app/routes/images.py b/backend/app/routes/images.py index 193801a37..f00b0a941 100644 --- a/backend/app/routes/images.py +++ b/backend/app/routes/images.py @@ -98,18 +98,23 @@ class ToggleFavouriteRequest(BaseModel): @router.post("/toggle-favourite") def toggle_favourite(req: ToggleFavouriteRequest): + """ + Toggle the favorite status of an image. + """ image_id = req.image_id try: success = db_toggle_image_favourite_status(image_id) if not success: raise HTTPException( - status_code=404, detail="Image not found or failed to toggle" + status_code=status.HTTP_404_NOT_FOUND, + detail="Image not found or failed to toggle" ) # Fetch updated status to return image = db_get_image_by_id(image_id) if not image: raise HTTPException( - status_code=404, detail="Image not found after toggle" + status_code=status.HTTP_404_NOT_FOUND, + detail="Image not found after toggle" ) return { "success": True, @@ -117,10 +122,13 @@ def toggle_favourite(req: ToggleFavouriteRequest): "isFavourite": image.get("isFavourite", False), } except HTTPException: - raise + raise # Re-raise HTTPExceptions to preserve status codes except Exception as e: logger.error(f"error in /toggle-favourite route: {e}") - raise HTTPException(status_code=500, detail=f"Internal server error: {e}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Internal server error: {e}" + ) class ImageInfoResponse(BaseModel): id: str