netabase_store 0.0.8

A type-safe, multi-backend key-value storage library for Rust with support for native (Sled, Redb) and WASM (IndexedDB) environments.
Documentation
//! Simple streams demonstration without DateTime fields
//!
//! This example demonstrates the streams functionality with basic types
//! to avoid DateTime serialization complexity while testing streams generation.

use chrono::Utc;
use netabase_store::{
    NetabaseDateTime, NetabaseModel, netabase, netabase_definition_module, streams,
};

// Define a simple schema with subscription topics
#[netabase_definition_module(BlogDefinition, BlogKeys)]
#[streams(Users, Posts, Comments)]
mod blog {
    use super::*;

    #[derive(
        NetabaseModel,
        Clone,
        Debug,
        PartialEq,
        bincode::Encode,
        bincode::Decode,
        serde::Serialize,
        serde::Deserialize,
    )]
    #[netabase(BlogDefinition)]
    pub struct User {
        #[primary_key]
        pub id: u64,
        pub name: String,
        #[secondary_key]
        pub email: String,
        #[bincode(with_serde)]
        pub created_at: NetabaseDateTime,
    }

    #[derive(
        NetabaseModel,
        Clone,
        Debug,
        PartialEq,
        bincode::Encode,
        bincode::Decode,
        serde::Serialize,
        serde::Deserialize,
    )]
    #[netabase(BlogDefinition)]
    pub struct Post {
        #[primary_key]
        pub id: String,
        pub title: String,
        pub content: String,
        #[secondary_key]
        pub author_id: u64,
        #[bincode(with_serde)]
        pub created_at: NetabaseDateTime,
    }

    #[derive(
        NetabaseModel,
        Clone,
        Debug,
        PartialEq,
        bincode::Encode,
        bincode::Decode,
        serde::Serialize,
        serde::Deserialize,
    )]
    #[netabase(BlogDefinition)]
    pub struct Comment {
        #[primary_key]
        pub id: u64,
        pub post_id: String,
        pub author_id: u64,
        pub content: String,
        #[bincode(with_serde)]
        pub created_at: NetabaseDateTime,
    }
}

use blog::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("🚀 Netabase Subscription System Demo");
    println!("=====================================\n");

    // This would be generated by the macro:
    // - BlogDefinitionSubscriptions enum with Users, Posts, Comments variants
    // - BlogDefinitionSubscriptionManager struct
    // - Individual subscription trees for each topic

    println!("📊 Available subscription topics:");
    println!("   - Users (for user-related data)");
    println!("   - Posts (for post-related data)");
    println!("   - Comments (for comment-related data)");
    println!();

    // Create some test data
    let now = Utc::now();

    let alice = User {
        id: 1,
        name: "Alice Johnson".to_string(),
        email: "alice@example.com".to_string(),
        created_at: now,
    };

    let bob = User {
        id: 2,
        name: "Bob Smith".to_string(),
        email: "bob@example.com".to_string(),
        created_at: now,
    };

    let post1 = Post {
        id: "post-101".to_string(),
        title: "Introduction to Rust".to_string(),
        content: "Rust is a systems programming language...".to_string(),
        author_id: 1,
        created_at: now,
    };

    let comment1 = Comment {
        id: 201,
        post_id: "post-101".to_string(),
        author_id: 2,
        content: "Great post! Very informative.".to_string(),
        created_at: now,
    };

    println!("📝 Sample Data Created:");
    println!("   Users: Alice ({}), Bob ({})", alice.id, bob.id);
    println!("   Posts: {} (by user {})", post1.title, post1.author_id);
    println!(
        "   Comments: {} (on post {})",
        comment1.content, comment1.post_id
    );
    println!();

    println!("🔍 Subscription System Concepts:");
    println!("   1. Each topic (Users, Posts, Comments) would have its own merkle tree");
    println!("   2. When data is added/modified, it gets hashed and added to relevant topic trees");
    println!("   3. Merkle roots can be compared between nodes to detect differences");
    println!("   4. Exact differing keys can be identified for efficient synchronization");
    println!();

    // Simulate what the generated subscription manager would do
    println!("🌳 Simulated Merkle Tree Operations:");

    // Create hashes for our sample data (this would be automatic)
    let alice_hash = create_sample_hash(&alice);
    let bob_hash = create_sample_hash(&bob);
    let post_hash = create_sample_hash(&post1);
    let comment_hash = create_sample_hash(&comment1);

    println!("   User hashes:");
    println!("     Alice: {}", alice_hash);
    println!("     Bob:   {}", bob_hash);
    println!("   Post hashes:");
    println!("     Post 101: {}", post_hash);
    println!("   Comment hashes:");
    println!("     Comment 201: {}", comment_hash);
    println!();

    // Simulate comparison between two nodes
    println!("🔄 Simulated Node Synchronization:");
    println!("   Node A has: Alice, Bob, Post 101, Comment 201");
    println!("   Node B has: Alice, Post 101 (missing Bob and Comment 201)");
    println!();
    println!("   Merkle root comparison would show:");
    println!("   - Users topic: DIFFERENT (Node B missing Bob)");
    println!("   - Posts topic: SAME (both have Post 101)");
    println!("   - Comments topic: DIFFERENT (Node B missing Comment 201)");
    println!();
    println!("   Sync plan would identify:");
    println!(
        "   - Node B needs: User {} (Bob), Comment {} (Comment 201)",
        bob.id, comment1.id
    );
    println!();

    println!("✅ Subscription System Features Demonstrated:");
    println!("   ✓ Topic-based data organization");
    println!("   ✓ Efficient hash-based change detection");
    println!("   ✓ Merkle tree comparison for synchronization");
    println!("   ✓ Precise identification of missing data");
    println!("   ✓ Automated subscription management");
    println!();

    println!("🎯 Next Steps for Full Implementation:");
    println!("   • Complete macro generation of subscription infrastructure");
    println!("   • Integrate with database backends (memory, sled, redb)");
    println!("   • Add network synchronization protocols");
    println!("   • Implement conflict resolution strategies");
    println!("   • Add subscription filtering and custom topic assignment");

    Ok(())
}

// Helper function to simulate hash creation
fn create_sample_hash<T: std::fmt::Debug>(data: &T) -> String {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::{Hash, Hasher};

    let mut hasher = DefaultHasher::new();
    format!("{:?}", data).hash(&mut hasher);
    let hash = hasher.finish();
    format!("{:016x}", hash)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_subscription_concepts() {
        let now = Utc::now();

        let user = User {
            id: 1,
            name: "Test User".to_string(),
            email: "test@example.com".to_string(),
            created_at: now,
        };

        let post = Post {
            id: "test-post".to_string(),
            title: "Test Post".to_string(),
            content: "Test content".to_string(),
            author_id: 1,
            created_at: now,
        };

        // Verify that data can be created and hashed consistently
        let hash1 = create_sample_hash(&user);
        let hash2 = create_sample_hash(&user);
        assert_eq!(hash1, hash2, "Hash should be consistent");

        let post_hash = create_sample_hash(&post);
        assert_ne!(
            hash1, post_hash,
            "Different data should have different hashes"
        );
    }

    #[test]
    fn test_model_creation() {
        let now = Utc::now();

        let user = User {
            id: 42,
            name: "Alice".to_string(),
            email: "alice@test.com".to_string(),
            created_at: now,
        };

        assert_eq!(user.id, 42);
        assert_eq!(user.name, "Alice");
        assert_eq!(user.email, "alice@test.com");
    }
}