Querying and Pagination
The vik-advani-etchblok-test-api-7ee56a2 codebase implements querying and pagination primarily through the BookmarkRepository class. This implementation provides a way to filter bookmarks by their lifecycle status and retrieve them in manageable chunks (pages) sorted by creation date.
The Querying Engine
The core logic for retrieving bookmarks resides in BookmarkRepository.list_bookmarks (found in app/db/repository.py). This method serves as the single point of entry for listing bookmarks with support for filtering and pagination.
def list_bookmarks(
self,
page: int = 1,
per_page: int = 25,
status: Optional[str] = None,
) -> Tuple[List[Bookmark], int]:
"""Return a paginated slice of bookmarks."""
items = list(self._bookmarks.values())
# 1. Filtering
if status:
try:
target = BookmarkStatus(status)
items = [b for b in items if b.status == target]
except ValueError:
# Invalid status strings are silently ignored
pass
# 2. Sorting
items.sort(key=lambda b: b.created_at, reverse=True)
# 3. Pagination
total = len(items)
start = (page - 1) * per_page
return items[start : start + per_page], total
Filtering by Status
The repository supports filtering by the BookmarkStatus enum defined in app/models/bookmark.py. The valid status strings are:
active: Standard visible bookmarks.archived: Bookmarks moved to the archive.trashed: Bookmarks in the soft-delete state.
If an invalid status string is provided, the repository catches the ValueError and returns the full list of bookmarks (effectively ignoring the filter).
Sorting and Pagination Logic
The implementation follows these rules:
- Chronological Sorting: Results are always sorted by
created_atin descending order (newest first) before any pagination slicing occurs. - 1-Based Indexing: The
pageparameter starts at1. - Slicing: The repository calculates the start index as
(page - 1) * per_pageand returns a slice of the list. - Total Count: The method returns a tuple containing the list of items for the current page and the
totalcount of items matching the filter. This total count is essential for front-end components to calculate the number of available pages.
Integration with the API Layer
The BookmarkService (in app/services/bookmark_service.py) acts as a pass-through for these queries, allowing the API layer to interact with the repository without knowing the underlying storage details.
In app/routes/bookmarks.py, the Flask route handler extracts query parameters from the request and passes them to the service:
@bookmarks_bp.route("/", methods=["GET"])
def list_bookmarks():
"""Return a paginated list of bookmarks."""
page = request.args.get("page", 1, type=int)
per_page = request.args.get("per_page", 25, type=int)
status = request.args.get("status", None)
bookmarks, total = _service.list_bookmarks(
page=page,
per_page=per_page,
status=status
)
return jsonify({
"bookmarks": [b.to_dict() for b in bookmarks],
"total": total
})
Key Considerations
In-Memory Storage
Because the BookmarkRepository uses an in-memory dictionary (self._bookmarks), the pagination logic operates on a full list of objects in memory. While efficient for the current test implementation, a production database implementation would typically use LIMIT and OFFSET clauses in SQL to perform this slicing at the database level.
Tag-Based Querying
In addition to the general list_bookmarks method, the repository provides a specialized query method get_bookmarks_with_tag(tag_id). Unlike the main list method, this does not currently support pagination or status filtering; it returns all bookmarks associated with a specific tag ID.
Default Values
The system defaults to page=1 and per_page=25 if parameters are omitted. The per_page value is typically capped at 100 in the API layer documentation, though the repository itself does not enforce a maximum limit.