use redis::{Client, Commands, FromRedisValue, RedisResult, ToRedisArgs};
use std::num::NonZeroUsize;
use r2d2::PooledConnection;
use crate::error::{Error, Result};
use crate::database::config::REDIS_POOL;
pub struct RedisUtil {
connection: PooledConnection<Client>
}
impl RedisUtil {
pub fn new() -> Result<RedisUtil> {
let client = REDIS_POOL.get().ok_or_else(|| {
tracing::error!("Failed to get Redis connection pool");
Error::NotFound()
})?;
let connection = client.get().map_err(|e| {
tracing::error!("Failed to obtain Redis connection: {:?}", e);
Error::NotFound()
})?;
Ok(RedisUtil {
connection
})
}
pub fn set<T: ToRedisArgs>(&mut self, key: &str, value: &T) -> RedisResult<bool> {
let result = self.connection.set(key, value)?;
Ok(result)
}
pub fn set_with_expiry<T: ToRedisArgs>(&mut self, key: &str, value: &T, expiry_seconds: u64) -> RedisResult<()> {
let result =self.connection.set_ex(key, value, expiry_seconds)?;
Ok(result)
}
pub fn expire(&mut self, key: &str, expiry_seconds: i64) -> RedisResult<bool> {
let result =self.connection.expire(key, expiry_seconds)?;
Ok(result)
}
pub fn get<T: FromRedisValue>(&mut self,key: &str) -> RedisResult<Option<T>> {
let value: Option<T> = self.connection.get(key)?;
Ok(value)
}
pub fn pipeline_operations<T: ToRedisArgs>(&mut self, keys: Vec<&str>, values: Vec<&T>) -> RedisResult<()> {
if keys.len() != values.len() {
return Err(redis::RedisError::from((
redis::ErrorKind::TypeError,
"Keys and values must have the same length",
)));
}
let mut pipe = redis::pipe();
for (key, value) in keys.iter().zip(values.iter()) {
pipe.set(*key, *value).ignore();
}
pipe.query::<()>(&mut self.connection)?;
Ok(())
}
pub fn exists(&mut self, key: &str) -> RedisResult<bool> {
let exists = self.connection.exists(key)?;
Ok(exists)
}
pub fn del_vec(&mut self, keys: Vec<&str>) -> RedisResult<usize> {
self.connection.del(keys)
}
pub fn del(&mut self, key: &str) -> RedisResult<usize> {
self.connection.del(key)
}
pub fn ttl(&mut self, key: &str) -> RedisResult<isize> {
self.connection.ttl(key)
}
pub fn incr(&mut self, key: &str) -> RedisResult<isize> {
self.connection.incr(key, 1)
}
pub fn decr(&mut self, key: &str) -> RedisResult<isize> {
self.connection.decr(key, 1)
}
pub fn hset(&mut self, key: &str, field: &str, value: &str) -> RedisResult<()> {
self.connection.hset(key, field, value)
}
pub fn hget(&mut self, key: &str, field: &str) -> RedisResult<Option<String>> {
self.connection.hget(key, field)
}
pub fn lpush<T: FromRedisValue>(&mut self, key: &str, value: &str) -> RedisResult<T> {
self.connection.lpush(key, value)
}
pub fn rpop<T: ToString>(&mut self, key: &str, count: Option<usize>) -> RedisResult<Option<Vec<String>>> {
let non_zero_count = count.and_then(NonZeroUsize::new);
self.connection.rpop(key, non_zero_count)
}
}