Skip to main content

Organizing Data with Tags and Collections

Organizing data in etchblok-test-api involves using Tags for flexible labeling and Collections for structured grouping. The BookmarkService manages the lifecycle of these entities, ensuring that relationships between bookmarks and their labels remain consistent.

Managing Tags

Tags in etchblok-test-api are labels with a name and a color. You create and manage them through the BookmarkService, which validates inputs and persists them to the BookmarkRepository.

Creating and Updating Tags

To create a tag, provide a dictionary containing at least a name. The service validates that the name is non-empty and under 50 characters.

from app.services.bookmark_service import BookmarkService

service = BookmarkService()

# Create a new tag
tag_data = {
"name": "Research",
"color": "blue",
"description": "Academic papers and articles"
}
tag, error = service.create_tag(tag_data)

if tag:
print(f"Created tag: {tag.name} with ID: {tag.id}")

# Update an existing tag
update_data = {"color": "green"}
updated_tag, error = service.update_tag(tag.id, update_data)

Deleting Tags and Referential Integrity

When you delete a tag using BookmarkService.delete_tag, the service automatically strips that tag from all associated bookmarks before removing the tag itself. This prevents orphaned tag IDs from remaining in bookmark metadata.

# This method iterates through all bookmarks containing the tag,
# removes the tag ID from their metadata, and then deletes the tag.
success = service.delete_tag("tag_id_123")

Querying Bookmarks by Tag

To retrieve all bookmarks associated with a specific tag, use the get_bookmarks_with_tag method in the BookmarkRepository.

from app.db.repository import BookmarkRepository

repo = BookmarkRepository()

# Retrieve all bookmarks that have the 'Research' tag attached
bookmarks = repo.get_bookmarks_with_tag("research_tag_id")

for b in bookmarks:
print(f"Found bookmark: {b.title}")

Managing Collections

Collections in etchblok-test-api allow you to group bookmarks. They come in two types: Manual (where you explicitly add bookmarks) and Smart (which are intended to filter bookmarks based on rules).

Creating a Collection

Collections are created via the BookmarkService. By default, they are created as MANUAL collections.

collection_data = {
"name": "Project Alpha",
"collection_type": "manual",
"is_pinned": True
}
collection, error = service.create_collection(collection_data)

Adding and Removing Bookmarks

For manual collections, you can add or remove bookmarks by their IDs. The Collection model in app/models/collection.py prevents manual additions to smart collections.

# Add a bookmark to a collection
success = service.add_to_collection(collection.id, "bookmark_id_456")

# Remove a bookmark from a collection
success = service.remove_from_collection(collection.id, "bookmark_id_456")

Smart Collections

Smart collections use a filter_rule to determine membership. While the Collection model includes an internal _apply_filter method, the current BookmarkService implementation for listing and retrieving collections returns the stored bookmark_ids.

smart_collection_data = {
"name": "Recent PDFS",
"collection_type": "smart",
"filter_rule": "extension:pdf"
}
smart_collection, error = service.create_collection(smart_collection_data)

Troubleshooting and Performance

In-Memory Persistence

The BookmarkRepository in etchblok-test-api is strictly in-memory. All tags, collections, and bookmark associations are lost when the application process restarts.

Tag Deletion Performance

The delete_tag operation in BookmarkService performs a linear scan of all bookmarks to maintain referential integrity:

# From app/services/bookmark_service.py
for bookmark in self._repo.get_bookmarks_with_tag(tag_id):
bookmark.remove_tag(tag_id)
self._repo.save_bookmark(bookmark)
self._cache.invalidate(bookmark.id)

In etchblok-test-api, get_bookmarks_with_tag iterates over the entire _bookmarks dictionary. As the number of bookmarks grows, deleting a tag that is widely used may become a blocking operation.

Tag Sorting

When listing tags via the API (e.g., in app/routes/tags.py), tags are sorted alphabetically by name using the Tag model's __lt__ implementation.

# Example of how tags are sorted in the routes
tags = service.list_tags()
sorted_tags = sorted(tags)