Learn ThemisDB by doing! This guide provides hands-on code examples, try-it-yourself exercises, and real-world scenarios you can run immediately.
- ✅ Quick code snippets with explanations
- ✅ Try-it-yourself exercises
- ✅ Common patterns and recipes
- ✅ Real-world scenarios
- ✅ Links to runnable example projects
Prerequisites: Getting Started Tutorial
Time Required: Varies by example
Difficulty: Beginner to Advanced
Goal: Create, read, update, and delete your first entity
# 1. Create a user
curl -X PUT http://localhost:8080/entities/users:john \
-H "Content-Type: application/json" \
-d '{
"blob": "{\"name\":\"John Doe\",\"email\":\"john@example.com\",\"age\":28}"
}'
# 2. Read the user
curl http://localhost:8080/entities/users:john
# 3. Update the user
curl -X PUT http://localhost:8080/entities/users:john \
-H "Content-Type: application/json" \
-d '{
"blob": "{\"name\":\"John Doe\",\"email\":\"john@example.com\",\"age\":29}"
}'
# 4. Delete the user
curl -X DELETE http://localhost:8080/entities/users:johnExpected Output:
// Step 1: {"status":"success","entity":"users:john","version":1}
// Step 2: {"entity_id":"users:john","version":1,"blob":"{...}"}
// Step 3: {"status":"success","entity":"users:john","version":2}
// Step 4: {"status":"success","entity":"users:john","deleted":true}Try It Yourself:
- Change the entity to create a product instead
- Add more attributes (category, price, stock)
- Create 3 products and query them
Goal: Insert 100 products efficiently
Python:
import requests
import json
def create_products(count=100):
base_url = "http://localhost:8080"
# Prepare batch
entities = []
for i in range(count):
entity = {
"entity_id": f"products:item-{i:04d}",
"blob": json.dumps({
"name": f"Product {i}",
"price": 10.0 + (i % 50),
"stock": 100 + (i % 100),
"category": f"category-{i % 5}"
})
}
entities.append(entity)
# Batch create
response = requests.post(
f"{base_url}/batch/create",
json={"entities": entities}
)
result = response.json()
print(f"Created {result['created']} products")
return result
# Run it!
if __name__ == "__main__":
result = create_products(100)Expected Output:
Created 100 products
Try It Yourself:
- Increase to 1000 products
- Add more attributes (description, tags, ratings)
- Measure the time taken
Goal: Create an index and perform fast queries
# 1. Create index on category
curl -X POST http://localhost:8080/index/create \
-H "Content-Type: application/json" \
-d '{
"table": "products",
"column": "category",
"type": "btree"
}'
# 2. Query products by category
curl -X POST http://localhost:8080/query \
-H "Content-Type: application/json" \
-d '{
"table": "products",
"predicates": [
{
"column": "category",
"value": "category-0"
}
],
"use_index": true,
"return": "entities"
}'
# 3. Check index usage
curl http://localhost:4318/metrics | grep index_usageTry It Yourself:
- Create a composite index on (category, price)
- Query products in category-0 with price < 30
- Use EXPLAIN to see query plan
Problem: Need to create an entity if it doesn't exist, or update if it does.
Solution:
import requests
import json
def upsert_entity(entity_id: str, data: dict):
"""Create or update an entity"""
url = f"http://localhost:8080/entities/{entity_id}/upsert"
response = requests.post(url, json={"blob": json.dumps(data)})
return response.json()
# Usage
user_data = {"name": "Alice", "email": "alice@example.com", "age": 30}
result = upsert_entity("users:alice", user_data)
print(result) # Creates or updates AliceTry It Yourself:
- Run it once (creates)
- Change age to 31 and run again (updates)
- Verify version incremented
Problem: Need to increment/decrement a value atomically (thread-safe).
Solution:
def decrement_stock(product_id: str, quantity: int = 1):
"""Atomically decrement product stock"""
url = f"http://localhost:8080/entities/{product_id}/increment"
response = requests.post(url, json={
"attribute": "stock",
"delta": -quantity
})
return response.json()
# Usage: Sell 3 units
result = decrement_stock("products:item-0001", 3)
print(f"New stock: {result['attributes']['stock']}")Try It Yourself:
- Create a product with stock=100
- Run decrement_stock 10 times in parallel
- Verify final stock is exactly 90 (no race condition!)
Problem: Query returns too many results, need to paginate.
Solution:
def get_all_products_paginated(page_size=50):
"""Get all products with pagination"""
base_url = "http://localhost:8080"
all_products = []
offset = 0
while True:
response = requests.post(
f"{base_url}/query",
json={
"table": "products",
"predicates": [],
"limit": page_size,
"offset": offset,
"return": "entities"
}
)
result = response.json()
products = result['entities']
if not products:
break # No more results
all_products.extend(products)
offset += page_size
print(f"Fetched {len(products)} products (total: {len(all_products)})")
return all_products
# Usage
all_products = get_all_products_paginated()
print(f"Total products: {len(all_products)}")Try It Yourself:
- Adjust page_size to 10 and observe more iterations
- Add a filter (e.g., category="electronics")
- Sort by price descending
Problem: Need to "delete" entities but keep them recoverable.
Solution:
def soft_delete(entity_id: str):
"""Mark entity as deleted without removing it"""
url = f"http://localhost:8080/entities/{entity_id}"
response = requests.patch(url, json={
"attributes": {
"deleted": True,
"deleted_at": datetime.now().isoformat()
}
})
return response.json()
def query_active_only(table: str):
"""Query only non-deleted entities"""
response = requests.post(
"http://localhost:8080/query",
json={
"table": table,
"predicates": [
{"column": "deleted", "operator": "!=", "value": True}
],
"return": "entities"
}
)
return response.json()['entities']
# Usage
soft_delete("users:john") # Marks as deleted
active_users = query_active_only("users") # Doesn't include JohnTry It Yourself:
- Soft delete a few entities
- Create a "restore" function that sets deleted=False
- Add a cleanup job that hard-deletes after 30 days
Problem: Need multiple operations to succeed or fail together.
Solution:
def transfer_inventory(from_product: str, to_product: str, quantity: int):
"""Transfer inventory between products atomically"""
base_url = "http://localhost:8080"
# Start transaction
tx_response = requests.post(f"{base_url}/tx/begin")
tx_id = tx_response.json()['tx_id']
try:
# Decrement source
requests.post(
f"{base_url}/tx/{tx_id}/entities/{from_product}/increment",
json={"attribute": "stock", "delta": -quantity}
)
# Increment destination
requests.post(
f"{base_url}/tx/{tx_id}/entities/{to_product}/increment",
json={"attribute": "stock", "delta": quantity}
)
# Commit transaction
requests.post(f"{base_url}/tx/{tx_id}/commit")
return True
except Exception as e:
# Rollback on error
requests.post(f"{base_url}/tx/{tx_id}/rollback")
raise
# Usage
transfer_inventory("products:item-0001", "products:item-0002", 10)Try It Yourself:
- Verify stock changes in both products
- Simulate a failure (e.g., insufficient stock) and verify rollback
- Run multiple transfers in parallel
Requirements:
- Create order
- Decrement product stock
- Update user's order history
- All or nothing (transaction)
Solution:
import requests
import json
from datetime import datetime
def checkout(user_id: str, cart_items: list):
"""Complete checkout with transaction"""
base_url = "http://localhost:8080"
# Calculate total
total = sum(item['price'] * item['quantity'] for item in cart_items)
# Start transaction
tx_response = requests.post(f"{base_url}/tx/begin")
tx_id = tx_response.json()['tx_id']
try:
# Create order
order_id = f"orders:order-{datetime.now().strftime('%Y%m%d%H%M%S')}"
order_data = {
"user_id": user_id,
"items": cart_items,
"total": total,
"status": "pending",
"created_at": datetime.now().isoformat()
}
requests.put(
f"{base_url}/tx/{tx_id}/entities/{order_id}",
json={"blob": json.dumps(order_data)}
)
# Decrement stock for each item
for item in cart_items:
requests.post(
f"{base_url}/tx/{tx_id}/entities/{item['product_id']}/increment",
json={"attribute": "stock", "delta": -item['quantity']}
)
# Update user's order list
requests.patch(
f"{base_url}/tx/{tx_id}/entities/{user_id}",
json={"attributes": {"last_order": order_id}}
)
# Commit
requests.post(f"{base_url}/tx/{tx_id}/commit")
return {"status": "success", "order_id": order_id}
except Exception as e:
requests.post(f"{base_url}/tx/{tx_id}/rollback")
return {"status": "error", "message": str(e)}
# Usage
cart = [
{"product_id": "products:laptop-001", "quantity": 1, "price": 1299.99},
{"product_id": "products:mouse-001", "quantity": 2, "price": 29.99}
]
result = checkout("users:alice", cart)
print(result)Try It Yourself:
- Add stock validation before checkout
- Implement order cancellation (reverse the operations)
- Add email notification (outside transaction)
Requirements:
- Get posts from followed users
- Sort by time
- Paginate results
- Include user details
Solution:
def get_user_feed(user_id: str, page_size=20, offset=0):
"""Get personalized feed for user"""
base_url = "http://localhost:8080"
# 1. Get list of followed users
follows_response = requests.post(
f"{base_url}/query",
json={
"table": "follows",
"predicates": [{"column": "from_user", "value": user_id}],
"return": "entities"
}
)
followed_user_ids = [
json.loads(f['blob'])['to_user']
for f in follows_response.json()['entities']
]
# 2. Get posts from followed users
posts_response = requests.post(
f"{base_url}/query",
json={
"table": "posts",
"predicates": [
{"column": "author_id", "operator": "IN", "value": followed_user_ids}
],
"order_by": "created_at",
"order": "DESC",
"limit": page_size,
"offset": offset,
"return": "entities"
}
)
posts = [json.loads(p['blob']) for p in posts_response.json()['entities']]
return {
"posts": posts,
"count": len(posts),
"has_more": len(posts) == page_size
}
# Usage
feed = get_user_feed("users:alice", page_size=10)
for post in feed['posts']:
print(f"{post['author_name']}: {post['content']}")Try It Yourself:
- Add filtering (e.g., only posts with images)
- Cache the followed users list
- Implement "load more" functionality
Requirements:
- Search products by multiple criteria
- Support price range
- Filter by category
- Sort by relevance
Solution:
def search_products(
query: str = "",
category: str = None,
min_price: float = None,
max_price: float = None,
sort_by: str = "relevance",
limit: int = 50
):
"""Advanced product search"""
base_url = "http://localhost:8080"
predicates = []
# Category filter
if category:
predicates.append({"column": "category", "value": category})
# Price range
if min_price is not None:
predicates.append({"column": "price", "operator": ">=", "value": min_price})
if max_price is not None:
predicates.append({"column": "price", "operator": "<=", "value": max_price})
# Text search (if supported)
if query:
predicates.append({"column": "name", "operator": "CONTAINS", "value": query})
# Build query
query_data = {
"table": "products",
"predicates": predicates,
"limit": limit,
"return": "entities"
}
# Add sorting
if sort_by == "price_asc":
query_data["order_by"] = "price"
query_data["order"] = "ASC"
elif sort_by == "price_desc":
query_data["order_by"] = "price"
query_data["order"] = "DESC"
elif sort_by == "popularity":
query_data["order_by"] = "sales_count"
query_data["order"] = "DESC"
response = requests.post(f"{base_url}/query", json=query_data)
products = [json.loads(p['blob']) for p in response.json()['entities']]
return products
# Usage
products = search_products(
query="laptop",
category="electronics",
min_price=500,
max_price=2000,
sort_by="price_asc"
)
for product in products:
print(f"{product['name']}: ${product['price']}")Try It Yourself:
- Add more filters (brand, rating, in_stock)
- Implement faceted search (count per category)
- Add vector search for semantic matching
Goal: Implement CRUD operations for a todo application
Requirements:
- Create todo items
- Mark as complete
- Filter by status
- Sort by priority
Starter Code:
class TodoAPI:
def __init__(self, base_url):
self.base_url = base_url
def create_todo(self, title, description, priority="medium"):
# TODO: Implement
pass
def get_todo(self, todo_id):
# TODO: Implement
pass
def update_todo(self, todo_id, **kwargs):
# TODO: Implement
pass
def complete_todo(self, todo_id):
# TODO: Implement
pass
def list_todos(self, status=None, sort_by="created_at"):
# TODO: Implement
pass
def delete_todo(self, todo_id):
# TODO: Implement
pass
# Test your implementation
api = TodoAPI("http://localhost:8080")
todo = api.create_todo("Learn ThemisDB", "Complete all tutorials", priority="high")
print(f"Created: {todo}")Solution: See examples/02_todo_app/
Goal: Build an inventory system with stock tracking
Requirements:
- Add products
- Track stock levels
- Atomic stock operations
- Low stock alerts
Hints:
- Use atomic increment/decrement for stock
- Index on stock level for low-stock queries
- Use transactions for multi-product operations
Starter Code:
class InventoryManager:
def add_product(self, product_id, name, initial_stock):
# TODO: Implement
pass
def receive_stock(self, product_id, quantity):
# TODO: Implement atomic increment
pass
def sell_product(self, product_id, quantity):
# TODO: Implement atomic decrement with validation
pass
def check_low_stock(self, threshold=10):
# TODO: Query products with stock < threshold
pass
def transfer_stock(self, from_product, to_product, quantity):
# TODO: Use transaction
passSolution: See examples/04_inventory_system/
Goal: Model relationships and traversals
Requirements:
- Follow/unfollow users
- Get followers and following
- Find mutual friends
- Suggest friends (friends of friends)
Hints:
- Use graph edges for relationships
- Create indexes on both from and to fields
- Use graph traversal API
Starter Code:
class SocialGraph:
def follow(self, user_id, target_user_id):
# TODO: Create edge
pass
def unfollow(self, user_id, target_user_id):
# TODO: Delete edge
pass
def get_followers(self, user_id):
# TODO: Query incoming edges
pass
def get_following(self, user_id):
# TODO: Query outgoing edges
pass
def find_mutual_friends(self, user1, user2):
# TODO: Find intersection of following lists
pass
def suggest_friends(self, user_id, limit=10):
# TODO: Friends of friends, excluding already following
passSolution: See examples/06_graph_social_network/
ThemisDB includes 20+ complete example applications. Here's a curated selection:
| Example | Description | Key Concepts |
|---|---|---|
| 01_hello_world | Basic CRUD with GUI | Entity management, GUI |
| 02_todo_app | Todo list application | CRUD, filtering, sorting |
| 03_contact_manager | Contact management | Search, categories |
| 11_blog_wiki | Simple blog/wiki | Documents, tags |
| Example | Description | Key Concepts |
|---|---|---|
| 04_inventory_system | Inventory tracking | Atomic ops, transactions |
| 05_time_series_monitor | Time-series data | Batch insert, aggregation |
| 14_ecommerce_catalog | E-commerce catalog | Search, filters, pagination |
| 17_crm | Customer relationship mgmt | Complex queries, reports |
| Example | Description | Key Concepts |
|---|---|---|
| 06_graph_social_network | Social network | Graph traversal, edges |
| 07_vector_search_documents | Document similarity | Vector search, embeddings |
| 09_iot_sensor_network | IoT data processing | Time-series, batch ops |
| 19_recommendation_engine | Product recommendations | Vector search, graph |
| Example | Description | Lines of Code |
|---|---|---|
| 08_dms_erp_system | DMS/ERP system | ~2000 LOC |
| 18_realtime_chat | Real-time chat | ~1500 LOC |
| 21_coding_platform | Coding platform | ~2500 LOC |
Run an Example:
cd examples/02_todo_app
pip install -r requirements.txt
python main.pyShare your examples! Submit a PR to add your projects:
Template:
### Your Project Name
- **Author:** Your Name
- **Description:** Brief description
- **GitHub:** Link to repo
- **Concepts:** Key concepts demonstrated- Build Something: Pick an example and customize it
- Contribute: Share your examples with the community
- Learn More: Best Practices Guide
Questions? Ask in GitHub Discussions