/// Redis client abstraction for dependency injection pub trait RedisClient: Send + Sync { // Hash operations fn hash_mset(&self, key: String, fields: Vec<(String, String)>) -> Result<(), String>; fn hash_get_all(&self, key: String) -> Result; fn hash_get(&self, key: String, field: String) -> Result; fn hash_del(&self, key: String, field: String) -> Result<(), String>; // List operations fn list_rpush(&self, key: String, value: String) -> Result<(), String>; fn list_range(&self, key: String, start: isize, end: isize) -> Result, String>; fn list_del(&self, key: String, count: isize, value: String) -> Result<(), String>; // Set operations fn set_add(&self, key: String, member: String) -> Result<(), String>; fn set_members(&self, key: String) -> Result, String>; fn set_del(&self, key: String, member: String) -> Result<(), String>; // Common operations fn get_key(&self, key: String) -> Result; fn set_key(&self, key: String, value: String) -> Result<(), String>; fn key_exists(&self, key: String) -> Result; fn delete_key(&self, key: String) -> Result<(), String>; } /// Converts a JSON value to a Redis-compatible string format. pub fn parse_json_value(value: &serde_json::Value) -> String { let wrapped = serde_json::Value::Array(vec![value.clone()]); wrapped.to_string() } /// Converts a Redis string value back to a JSON value with intelligent type detection. pub fn parse_redis_value(value: &str) -> serde_json::Value { // Handle empty values if value.is_empty() { return serde_json::Value::Null; } // Try to parse as JSON first if let Ok(json_val) = serde_json::from_str(value) { // Special handling for single-element arrays (unwrap them) if let serde_json::Value::Array(arr) = &json_val { if arr.len() == 1 { return arr[0].clone(); } } return json_val; } // Try to parse as integer if let Ok(int_val) = value.parse::() { return serde_json::Value::Number(serde_json::Number::from(int_val)); } // Try to parse as float if let Ok(float_val) = value.parse::() { if let Some(num) = serde_json::Number::from_f64(float_val) { return serde_json::Value::Number(num); } } // Try to parse as boolean (case-insensitive) match value.to_lowercase().as_str() { "true" => serde_json::Value::Bool(true), "false" => serde_json::Value::Bool(false), // Default to string if no other type matches _ => serde_json::Value::String(value.to_string()), } }