Skip to main content

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:

  1. Chronological Sorting: Results are always sorted by created_at in descending order (newest first) before any pagination slicing occurs.
  2. 1-Based Indexing: The page parameter starts at 1.
  3. Slicing: The repository calculates the start index as (page - 1) * per_page and returns a slice of the list.
  4. Total Count: The method returns a tuple containing the list of items for the current page and the total count 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.