use chrono::Utc;
use netabase_store::{
NetabaseDateTime, NetabaseModel, netabase, netabase_definition_module, streams,
};
#[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");
println!("📊 Available subscription topics:");
println!(" - Users (for user-related data)");
println!(" - Posts (for post-related data)");
println!(" - Comments (for comment-related data)");
println!();
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!();
println!("🌳 Simulated Merkle Tree Operations:");
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!();
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(())
}
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,
};
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");
}
}