use processor::state::{PostgresConfig, PostgresStateBackend, StateBackend};
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();
println!("=== PostgreSQL State Backend Example ===\n");
println!("1. Configuring PostgreSQL backend...");
let config = PostgresConfig::new("postgresql://postgres:postgres@localhost/optimizer")
.with_pool_size(5, 20)
.with_ssl_mode("prefer")
.with_timeout(Duration::from_secs(30))
.with_retries(3, Duration::from_millis(100))
.with_statement_logging(true);
println!(" Database URL: postgresql://***@localhost/optimizer");
println!(" Pool size: 5-20 connections");
println!(" Timeout: 30s");
println!();
println!("2. Initializing backend (running migrations)...");
let backend = PostgresStateBackend::new(config).await?;
println!(" ✓ Backend initialized successfully");
println!();
println!("3. Testing basic operations...");
backend.put(b"user:1:session", b"session_token_abc123").await?;
backend.put(b"user:2:session", b"session_token_xyz789").await?;
backend.put(b"window:123:state", b"aggregated_metrics_data").await?;
println!(" ✓ Inserted 3 entries");
if let Some(value) = backend.get(b"user:1:session").await? {
println!(" ✓ Retrieved: {} bytes", value.len());
}
let count = backend.count().await?;
println!(" ✓ Total entries: {}", count);
println!();
println!("4. Testing JSONB metadata...");
backend
.put_with_metadata(
b"event:12345",
b"event_payload_data",
serde_json::json!({
"source": "kafka",
"topic": "metrics",
"partition": 5,
"offset": 12345,
"timestamp": "2024-01-15T10:30:00Z"
}),
)
.await?;
println!(" ✓ Stored entry with metadata");
println!();
println!("5. Testing TTL (time-to-live)...");
backend
.put_with_ttl(b"temp:cache:key", b"temporary_value", Duration::from_secs(5))
.await?;
println!(" ✓ Stored entry with 5-second TTL");
assert!(backend.contains(b"temp:cache:key").await?);
println!(" ✓ Entry exists immediately after creation");
println!(" Waiting 6 seconds for expiration...");
tokio::time::sleep(Duration::from_secs(6)).await;
let exists = backend.contains(b"temp:cache:key").await?;
println!(" Entry exists after TTL: {}", exists);
println!();
println!("6. Cleaning up expired entries...");
let deleted = backend.cleanup_expired().await?;
println!(" ✓ Deleted {} expired entries", deleted);
println!();
println!("7. Testing batch operations...");
let batch_entries: Vec<(&[u8], &[u8])> = vec![
(b"batch:1", b"value1"),
(b"batch:2", b"value2"),
(b"batch:3", b"value3"),
(b"batch:4", b"value4"),
(b"batch:5", b"value5"),
];
backend.batch_put(&batch_entries).await?;
println!(" ✓ Batch inserted {} entries", batch_entries.len());
println!();
println!("8. Testing prefix queries...");
let batch_keys = backend.list_keys(b"batch:").await?;
println!(" ✓ Found {} entries with 'batch:' prefix", batch_keys.len());
let user_keys = backend.list_keys(b"user:").await?;
println!(" ✓ Found {} entries with 'user:' prefix", user_keys.len());
println!();
println!("9. Testing checkpointing...");
let checkpoint_id = backend.create_checkpoint().await?;
println!(" ✓ Created checkpoint: {}", checkpoint_id);
let checkpoints = backend.list_checkpoints().await?;
println!(" ✓ Total checkpoints: {}", checkpoints.len());
if let Some(checkpoint) = checkpoints.first() {
println!(" Latest checkpoint:");
println!(" - ID: {}", checkpoint.checkpoint_id);
println!(" - Created: {}", checkpoint.created_at);
println!(" - Rows: {}", checkpoint.row_count);
println!(" - Size: {} bytes", checkpoint.data_size);
}
println!();
println!("10. Testing checkpoint restore...");
let original_count = backend.count().await?;
println!(" Original entry count: {}", original_count);
backend.put(b"new:entry", b"new_value").await?;
backend.delete(b"batch:1").await?;
let modified_count = backend.count().await?;
println!(" Modified entry count: {}", modified_count);
backend.restore_checkpoint(checkpoint_id).await?;
let restored_count = backend.count().await?;
println!(" Restored entry count: {}", restored_count);
println!(" ✓ State restored successfully");
println!();
println!("11. Backend statistics...");
let stats = backend.stats().await;
println!(" Operations:");
println!(" - GET: {}", stats.get_count);
println!(" - PUT: {}", stats.put_count);
println!(" - DELETE: {}", stats.delete_count);
println!(" - Queries: {}", stats.query_count);
println!(" - Transactions: {}", stats.transaction_count);
println!(" - Retries: {}", stats.retry_count);
println!(" Data:");
println!(" - Bytes written: {}", stats.bytes_written);
println!(" - Bytes read: {}", stats.bytes_read);
println!();
println!("12. Table statistics...");
let (total_size, table_size) = backend.table_stats().await?;
println!(" Total size (with indexes): {} bytes ({:.2} MB)", total_size, total_size as f64 / 1_048_576.0);
println!(" Table size: {} bytes ({:.2} MB)", table_size, table_size as f64 / 1_048_576.0);
println!();
println!("13. Health check...");
let healthy = backend.health_check().await?;
println!(" Database status: {}", if healthy { "✓ HEALTHY" } else { "✗ UNHEALTHY" });
println!();
println!("14. Running VACUUM for optimization...");
backend.vacuum().await?;
println!(" ✓ VACUUM completed");
println!();
println!("15. Cleaning up test data...");
backend.clear().await?;
println!(" ✓ All entries cleared");
println!();
backend.close().await;
println!("=== Example completed successfully ===");
Ok(())
}