Examples
This page contains comprehensive examples showing how to use ProllyTree in different scenarios.
Basic Tree Operations
Simple Key-Value Store
from prollytree import ProllyTree
def example_basic_kv_store():
"""Basic key-value store example"""
tree = ProllyTree()
# Store user data
users = {
"alice": {"name": "Alice Smith", "age": 30},
"bob": {"name": "Bob Jones", "age": 25},
"charlie": {"name": "Charlie Brown", "age": 35}
}
# Insert users
import json
for user_id, user_data in users.items():
key = f"user:{user_id}".encode('utf-8')
value = json.dumps(user_data).encode('utf-8')
tree.insert(key, value)
# Retrieve a user
alice_data = tree.find(b"user:alice")
if alice_data:
alice = json.loads(alice_data.decode('utf-8'))
print(f"Alice: {alice['name']}, age {alice['age']}")
return tree
Working with Different Data Types
import json
import pickle
from datetime import datetime
def example_data_types():
"""Examples of storing different data types"""
tree = ProllyTree()
# String data
tree.insert(b"string_key", "Hello, World!".encode('utf-8'))
# JSON data
data = {"name": "Alice", "scores": [95, 87, 92]}
tree.insert(b"json_key", json.dumps(data).encode('utf-8'))
# Binary data (using pickle)
complex_data = {
"timestamp": datetime.now(),
"nested": {"list": [1, 2, 3], "dict": {"a": 1}}
}
tree.insert(b"pickle_key", pickle.dumps(complex_data))
# Retrieve and decode
string_val = tree.find(b"string_key").decode('utf-8')
json_val = json.loads(tree.find(b"json_key").decode('utf-8'))
pickle_val = pickle.loads(tree.find(b"pickle_key"))
print(f"String: {string_val}")
print(f"JSON: {json_val}")
print(f"Pickle: {pickle_val}")
Versioned Storage Examples
Document Version Control
from prollytree import VersionedKvStore
import json
from datetime import datetime
def example_document_versioning():
"""Example of version controlling documents"""
store = VersionedKvStore("./document_store")
# Create initial document
doc = {
"title": "My Document",
"content": "Initial content",
"author": "Alice",
"created": datetime.now().isoformat()
}
store.insert(b"doc:readme", json.dumps(doc).encode('utf-8'))
commit1 = store.commit("Initial document creation")
print(f"Initial commit: {commit1[:8]}")
# Update document
doc["content"] = "Updated content with more details"
doc["modified"] = datetime.now().isoformat()
store.update(b"doc:readme", json.dumps(doc).encode('utf-8'))
commit2 = store.commit("Add more content details")
print(f"Update commit: {commit2[:8]}")
# View commit history
print("\\nCommit History:")
commits = store.log()
for commit in commits:
timestamp = datetime.fromtimestamp(commit['timestamp'])
print(f" {commit['id'][:8]} - {commit['message']} ({timestamp})")
return store
Configuration Management
def example_config_management():
"""Example of managing application configuration with versions"""
store = VersionedKvStore("./config_store")
# Production config
prod_config = {
"database": {
"host": "prod-db.example.com",
"port": 5432,
"ssl": True
},
"api": {
"rate_limit": 1000,
"timeout": 30
}
}
store.insert(b"config:production", json.dumps(prod_config).encode('utf-8'))
store.commit("Initial production configuration")
# Development config
dev_config = prod_config.copy()
dev_config["database"]["host"] = "localhost"
dev_config["database"]["ssl"] = False
dev_config["api"]["rate_limit"] = 10000 # Higher for dev
store.insert(b"config:development", json.dumps(dev_config).encode('utf-8'))
store.commit("Add development configuration")
# Update production config
prod_config["api"]["rate_limit"] = 2000 # Increase rate limit
store.update(b"config:production", json.dumps(prod_config).encode('utf-8'))
store.commit("Increase production rate limit")
# Retrieve current configs
current_prod = json.loads(store.get(b"config:production").decode('utf-8'))
print(f"Production rate limit: {current_prod['api']['rate_limit']}")
return store
SQL Query Examples
from prollytree import ProllySQLStore
def example_sql_analytics():
"""Example using SQL for data analytics"""
sql_store = ProllySQLStore("./analytics_store")
# Create tables
sql_store.execute("""
CREATE TABLE users (
id INTEGER,
name TEXT,
email TEXT,
signup_date TEXT,
plan TEXT
)
""")
sql_store.execute("""
CREATE TABLE events (
id INTEGER,
user_id INTEGER,
event_type TEXT,
timestamp TEXT,
metadata TEXT
)
""")
# Insert sample data
users_data = [
(1, 'Alice Smith', 'alice@example.com', '2023-01-15', 'premium'),
(2, 'Bob Jones', 'bob@example.com', '2023-02-01', 'basic'),
(3, 'Charlie Brown', 'charlie@example.com', '2023-02-15', 'premium'),
]
for user in users_data:
sql_store.execute(
"INSERT INTO users (id, name, email, signup_date, plan) VALUES (?, ?, ?, ?, ?)",
user
)
# Analytics queries
print("=== User Analytics ===")
# Premium users
premium_users = sql_store.execute(
"SELECT name, email FROM users WHERE plan = 'premium'"
)
print(f"Premium users: {len(premium_users)}")
for user in premium_users:
print(f" - {user[0]} ({user[1]})")
return sql_store
Performance Examples
def example_batch_operations():
"""Example showing efficient batch operations"""
tree = ProllyTree()
# Generate test data
import time
# Single inserts (slower)
start_time = time.time()
for i in range(1000):
key = f"single:{i:04d}".encode('utf-8')
value = f"value_{i}".encode('utf-8')
tree.insert(key, value)
single_time = time.time() - start_time
# Batch insert (faster)
start_time = time.time()
batch_data = []
for i in range(1000):
key = f"batch:{i:04d}".encode('utf-8')
value = f"value_{i}".encode('utf-8')
batch_data.append((key, value))
tree.insert_batch(batch_data)
batch_time = time.time() - start_time
print(f"Single inserts: {single_time:.3f}s")
print(f"Batch insert: {batch_time:.3f}s")
print(f"Speedup: {single_time/batch_time:.1f}x")
return tree
Branch Merging and Conflict Resolution
from prollytree import VersionedKvStore, ConflictResolution, MergeConflict
import tempfile
import os
import subprocess
def example_merge_operations():
"""Comprehensive example of branch merging with conflict resolution"""
# Create temporary directory for the example
with tempfile.TemporaryDirectory() as tmpdir:
# Initialize git repository
subprocess.run(['git', 'init'], cwd=tmpdir, check=True, capture_output=True)
subprocess.run(['git', 'config', 'user.name', 'Example'], cwd=tmpdir, check=True, capture_output=True)
subprocess.run(['git', 'config', 'user.email', 'example@test.com'], cwd=tmpdir, check=True, capture_output=True)
# Create data subdirectory
data_dir = os.path.join(tmpdir, 'data')
os.makedirs(data_dir)
store = VersionedKvStore(data_dir)
print("=== Basic Merge Without Conflicts ===")
# Initial data
store.insert(b"users:alice", b"Alice Smith")
store.insert(b"users:bob", b"Bob Jones")
store.insert(b"config:theme", b"light")
store.commit("Initial data")
# Create feature branch
store.create_branch("add-user-feature")
# Changes on feature branch
store.insert(b"users:charlie", b"Charlie Brown")
store.update(b"config:theme", b"dark")
store.commit("Add Charlie and dark theme")
# Switch back to main and make different changes
store.checkout("main")
store.insert(b"users:diana", b"Diana Prince")
store.commit("Add Diana")
# Merge feature branch
merge_commit = store.merge("add-user-feature", ConflictResolution.TakeSource)
print(f"Merge successful: {merge_commit[:8]}")
# Show final state
print("Final users:")
for key in [b"users:alice", b"users:bob", b"users:charlie", b"users:diana"]:
value = store.get(key)
if value:
print(f" {key.decode()}: {value.decode()}")
print(f"Theme: {store.get(b'config:theme').decode()}")
print("\\n=== Conflict Detection ===")
# Create another scenario with conflicts
store.create_branch("conflicting-feature")
store.update(b"config:theme", b"blue")
store.commit("Change theme to blue")
store.checkout("main")
store.update(b"config:theme", b"red")
store.commit("Change theme to red")
# Check for conflicts without applying
success, conflicts = store.try_merge("conflicting-feature")
if not success:
print(f"Detected {len(conflicts)} conflicts:")
for conflict in conflicts:
print(f" Key: {conflict.key.decode()}")
print(f" Source: {conflict.source_value.decode()}")
print(f" Destination: {conflict.destination_value.decode()}")
print("\\n=== Conflict Resolution Strategies ===")
# Demonstrate different resolution strategies
strategies = [
("IgnoreAll", ConflictResolution.IgnoreAll),
("TakeSource", ConflictResolution.TakeSource),
("TakeDestination", ConflictResolution.TakeDestination)
]
for name, strategy in strategies:
# Create test branch for each strategy
branch_name = f"test-{name.lower()}"
store.checkout("main")
store.create_branch(branch_name)
store.update(b"config:theme", b"feature-theme")
store.commit(f"Feature theme on {branch_name}")
store.checkout("main")
# Apply merge with strategy
merge_commit = store.merge(branch_name, strategy)
final_theme = store.get(b"config:theme").decode()
print(f"{name:15} -> Theme: {final_theme}")
# Reset main for next test
store.checkout("main")
Running Examples
if __name__ == "__main__":
# Run examples
print("=== Basic Key-Value Store ===")
example_basic_kv_store()
print("\\n=== Data Types ===")
example_data_types()
print("\\n=== Document Versioning ===")
example_document_versioning()
print("\\n=== SQL Analytics ===")
example_sql_analytics()
print("\\n=== Branch Merging ===")
example_merge_operations()
print("\\n=== Performance ===")
example_batch_operations()