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()