use rullst_orm::{Orm, sqlx::FromRow};
#[cfg(feature = "redis")]
use std::time::Duration;
#[derive(Debug, Clone, FromRow, rullst_orm::Orm)]
#[orm(table = "products")]
pub struct Product {
pub id: i32,
pub name: String,
pub price: f64,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let _ = std::fs::remove_file("products_demo.db");
std::fs::File::create("products_demo.db")?;
Orm::init("sqlite://products_demo.db").await?;
let pool = Orm::pool();
rullst_orm::sqlx::query(
"CREATE TABLE products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, price REAL NOT NULL)"
)
.execute(pool)
.await?;
let redis_url = "redis://127.0.0.1:6379";
println!("Connecting to Redis at {}...", redis_url);
#[cfg(feature = "redis")]
{
if let Err(e) = Orm::init_redis(redis_url).await {
println!("⚠️ Could not connect to Redis: {}. Skipping Redis caching and Pub/Sub event demo.", e);
let _ = std::fs::remove_file("products_demo.db");
return Ok(());
}
println!("✅ Connected to Redis successfully!");
tokio::spawn(async move {
let client = Orm::redis_client();
if let Ok(mut conn) = client.get_connection() {
let mut pubsub = conn.as_pubsub();
let _ = pubsub.psubscribe("orm:events:products:*");
println!("📡 Background Subscriber: Listening for products Pub/Sub events on Redis...");
loop {
if let Ok(msg) = pubsub.get_message() {
let channel: String = msg.get_channel_name().to_string();
let payload: String = msg.get_payload().unwrap_or_default();
println!("🔔 [Pub/Sub Event] Received event on channel '{}': {}", channel, payload);
}
tokio::time::sleep(Duration::from_millis(50)).await;
}
}
});
tokio::time::sleep(Duration::from_millis(200)).await;
println!("\n📥 Saving a new product to database...");
let mut p = Product { id: 0, name: "Super Quantum Laptop".to_string(), price: 2499.99 };
p.save().await?;
println!("✅ Product saved with ID: {}", p.id);
tokio::time::sleep(Duration::from_millis(200)).await;
Orm::enable_query_log();
println!("\n🔍 Fetching product for the FIRST time (should hit SQL database and cache in Redis):");
let p_db = Product::query().where_id(p.id).remember(10).first().await?;
println!("Fetched product: {:?}", p_db);
println!("\n⚡ Fetching product for the SECOND time (should hit cache instantly, no SQL log!):");
let p_cached = Product::query().where_id(p.id).remember(10).first().await?;
println!("Fetched from cache: {:?}", p_cached);
println!("\n🗑️ Deleting product...");
p.delete().await?;
println!("✅ Product deleted successfully!");
tokio::time::sleep(Duration::from_millis(200)).await;
}
#[cfg(not(feature = "redis"))]
{
println!("⚠️ Caching & Event features require '--features redis' flag to run!");
}
let _ = std::fs::remove_file("products_demo.db");
println!("\n🎉 Redis Caching and Pub/Sub event demo completed successfully!");
Ok(())
}