Skip to content

perf: avoid full table scan in toggle-favourite endpoint. Fixes #1223#1228

Closed
ajithhraj wants to merge 2 commits intoAOSSIE-Org:mainfrom
ajithhraj:perf-toggle-favourite-single-image
Closed

perf: avoid full table scan in toggle-favourite endpoint. Fixes #1223#1228
ajithhraj wants to merge 2 commits intoAOSSIE-Org:mainfrom
ajithhraj:perf-toggle-favourite-single-image

Conversation

@ajithhraj
Copy link

@ajithhraj ajithhraj commented Mar 17, 2026

Addressed Issues:

Fixes #1223

Screenshots/Recordings:

Not applicable.

Additional Notes:

This PR avoids a full table scan in the /toggle-favourite endpoint by replacing the db_get_all_images() scan with a targeted db_get_image_by_id(image_id) lookup.

Changes made:

  • added db_get_image_by_id(image_id) in backend/app/database/images.py
  • updated /toggle-favourite in backend/app/routes/images.py to fetch only the toggled image
  • added a focused test to verify the endpoint uses the single-image lookup

Verified locally with:

  • $env:GITHUB_ACTIONS='true'; python -m pytest backend\tests\test_images.py
  • python -m py_compile backend\app\database\images.py backend\app\routes\images.py

AI Usage Disclosure:

  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I have tested the code locally and I am responsible for it.

I have used the following AI models and tools: OpenAI Codex (GPT-5)

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions.
  • I have tested my changes locally.
  • I have reviewed my code before submitting.

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced image data retrieval with complete metadata and associated tag information.
    • Improved favorite toggle functionality with optimized database operations.
  • Tests

    • Added test coverage for the Images API, validating favorite toggle behavior and database operation handling.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 17, 2026

Warning

Rate limit exceeded

@ajithhraj has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dffaaa5c-d5f1-4c02-88a3-99696762f4aa

📥 Commits

Reviewing files that changed from the base of the PR and between 597a23c and 9356952.

📒 Files selected for processing (3)
  • backend/app/database/images.py
  • backend/app/routes/images.py
  • backend/tests/test_images.py

Walkthrough

The changes add a new db_get_image_by_id() function to query a single image by ID with metadata and tags, replacing a full table scan in the toggle_favourite endpoint. The route is updated to use this new function, and tests are added to verify the endpoint behavior.

Changes

Cohort / File(s) Summary
Database Layer
backend/app/database/images.py
Added db_get_image_by_id() function that retrieves a single image by ID via database join, including metadata parsing and tag collection. Returns image dictionary with all required fields or None on error.
Route Handler
backend/app/routes/images.py
Updated toggle_favourite endpoint to call db_get_image_by_id() instead of fetching all images, eliminating full table scan on each toggle action.
Test Coverage
backend/tests/test_images.py
Added test suite for Images API verifying toggle_favourite endpoint uses single image lookup and mocking both database functions.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Suggested labels

Python

Poem

🐰 No more hopping through every frame,
Query by ID—the speedy game!
One image fetched, not all the store,
The favourite toggle swifts once more! ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main performance improvement: avoiding full table scans in the toggle-favourite endpoint, with a reference to the issue being fixed.
Linked Issues check ✅ Passed The pull request successfully implements all coding requirements from issue #1223: adds db_get_image_by_id function and updates toggle-favourite to use single-image lookup instead of scanning all images.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing issue #1223: new db_get_image_by_id function, updated toggle-favourite endpoint logic, and corresponding test coverage for the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/app/routes/images.py (1)

109-114: ⚠️ Potential issue | 🟠 Major

Guard db_get_image_by_id() before dereferencing and preserve HTTP exceptions

db_get_image_by_id() can return None; Line 113 can crash on .get(...). Also, any HTTPException raised in this block is currently converted to 500 by the broad except.

Suggested fix
 `@router.post`("/toggle-favourite")
 def toggle_favourite(req: ToggleFavouriteRequest):
     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"
             )
         # Fetch updated status to return
         image = db_get_image_by_id(image_id)
+        if image is None:
+            raise HTTPException(
+                status_code=500,
+                detail="Unable to fetch updated favourite status",
+            )
         return {
             "success": True,
             "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}")

Also applies to: 116-118

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/app/routes/images.py` around lines 109 - 114, Guard the result of
db_get_image_by_id(image_id) before calling .get by checking for None and
returning an appropriate HTTP error (e.g., raise HTTPException(status_code=404,
detail="Image not found")) instead of letting a None dereference crash; also
when catching exceptions in the surrounding try/except, re-raise any caught
fastapi.HTTPException (or avoid catching it) so HTTP errors aren't converted to
500s. Update both the block that builds the response using
image.get("isFavourite", False) and the other similar block that uses
db_get_image_by_id to apply the same None check and HTTPException preservation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/app/database/images.py`:
- Around line 299-300: The code serializes folder_id using str(first_row[2])
which converts NULL to the literal "None"; update the image record construction
(the dict containing "folder_id" and "thumbnailPath") to set "folder_id" to None
when first_row[2] is None (e.g., use a conditional: folder_id =
str(first_row[2]) if first_row[2] is not None else None) so the JSON contains a
null value instead of the string "None".

In `@backend/tests/test_images.py`:
- Around line 16-36: Add a failing-path unit test alongside
test_toggle_favourite_uses_single_image_lookup that simulates
mock_toggle_favourite returning True while mock_get_image_by_id returns None:
call client.post("/images/toggle-favourite", json={"image_id": image_id}) using
the same image_id, assert response.status_code == 200, assert
response.json()["success"] is True and response.json()["image_id"] == image_id,
assert that the route handles the missing image lookup by exposing an
isFavourite field (or explicit null) — e.g., assert "isFavourite" in
response.json() and response.json()["isFavourite"] is None — and finally verify
mock_toggle_favourite.assert_called_once_with(image_id) and
mock_get_image_by_id.assert_called_once_with(image_id).

---

Outside diff comments:
In `@backend/app/routes/images.py`:
- Around line 109-114: Guard the result of db_get_image_by_id(image_id) before
calling .get by checking for None and returning an appropriate HTTP error (e.g.,
raise HTTPException(status_code=404, detail="Image not found")) instead of
letting a None dereference crash; also when catching exceptions in the
surrounding try/except, re-raise any caught fastapi.HTTPException (or avoid
catching it) so HTTP errors aren't converted to 500s. Update both the block that
builds the response using image.get("isFavourite", False) and the other similar
block that uses db_get_image_by_id to apply the same None check and
HTTPException preservation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b47f25ca-0a13-4d50-b795-b153ab31d3ee

📥 Commits

Reviewing files that changed from the base of the PR and between 8274ebd and 597a23c.

📒 Files selected for processing (3)
  • backend/app/database/images.py
  • backend/app/routes/images.py
  • backend/tests/test_images.py

@SIDDHANTCOOKIE
Copy link

Closing this as unreviewed issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: avoid full table scan in toggle-favourite endpoint

2 participants