mod blocking;
#[cfg(feature = "async")]
mod non_blocking;
pub use blocking::*;
#[cfg(feature = "async")]
pub use non_blocking::*;
use std::time::Duration;
use redis::Value;
use serde::de::DeserializeOwned;
use crate::{BatchResult, RedissonError, RedissonResult};
pub fn convert_value_to_batch_result(value: Value) -> RedissonResult<BatchResult> {
BatchResult::from_redis_value(value)
}
#[derive(Debug)]
pub struct TransactionResult {
pub success: bool, pub retries: u32, pub execution_time: Duration, pub results: Vec<BatchResult>, pub watch_keys: Vec<String>, pub transaction_id: String, pub batches_executed: usize, }
impl TransactionResult {
pub fn get_result<T: DeserializeOwned>(&self, index: usize) -> RedissonResult<Option<T>> {
if index >= self.results.len() {
return Ok(None);
}
match &self.results[index] {
BatchResult::String(s) => {
let parsed: T = serde_json::from_str(s)?;
Ok(Some(parsed))
}
BatchResult::Integer(i) => {
let s = i.to_string();
let parsed: T = serde_json::from_str(&s)?;
Ok(Some(parsed))
}
BatchResult::Float(f) => {
let s = f.to_string();
let parsed: T = serde_json::from_str(&s)?;
Ok(Some(parsed))
}
BatchResult::Bool(b) => {
let s = if *b { "true" } else { "false" };
let parsed: T = serde_json::from_str(s)?;
Ok(Some(parsed))
}
BatchResult::Nil => Ok(None),
_ => Err(RedissonError::DeserializationError(
format!("The result type {:? } deserialize", self.results[index])
)),
}
}
pub fn get_string(&self, index: usize) -> RedissonResult<Option<String>> {
if index >= self.results.len() {
return Ok(None);
}
match &self.results[index] {
BatchResult::String(s) => Ok(Some(s.clone())),
BatchResult::Status(s) => Ok(Some(s.clone())),
BatchResult::Integer(i) => Ok(Some(i.to_string())),
BatchResult::Float(f) => Ok(Some(f.to_string())),
BatchResult::Bool(b) => Ok(Some(b.to_string())),
BatchResult::Nil => Ok(None),
BatchResult::Raw(value) => {
match value {
Value::SimpleString(s) => Ok(Some(s.clone())),
Value::BulkString(data) => {
String::from_utf8(data.clone())
.map(Some)
.map_err(|e| RedissonError::DeserializationError(e.to_string()))
}
Value::Int(i) => Ok(Some(i.to_string())),
Value::Okay => Ok(Some("OK".to_string())),
_ => Err(RedissonError::DeserializationError(
format!("Cannot convert from raw value to string:{:?}", value)
)),
}
}
_ => Err(RedissonError::DeserializationError(
format!("The result type {:? } Get string", self.results[index])
)),
}
}
pub fn get_i64(&self, index: usize) -> RedissonResult<Option<i64>> {
if index >= self.results.len() {
return Ok(None);
}
match &self.results[index] {
BatchResult::Integer(i) => Ok(Some(*i)),
BatchResult::String(s) => s.parse::<i64>()
.map(Some)
.map_err(|e| RedissonError::DeserializationError(e.to_string())),
BatchResult::Raw(value) => {
if let Value::Int(i) = value {
Ok(Some(*i))
} else {
Err(RedissonError::DeserializationError(
format!("You can't get an integer from a raw value: {:?}", value)
))
}
}
BatchResult::Nil => Ok(None),
_ => Err(RedissonError::DeserializationError(
format!("The result type {:? } Get an integer", self.results[index])
)),
}
}
pub fn get_bool(&self, index: usize) -> RedissonResult<Option<bool>> {
if index >= self.results.len() {
return Ok(None);
}
match &self.results[index] {
BatchResult::Bool(b) => Ok(Some(*b)),
BatchResult::Integer(1) => Ok(Some(true)),
BatchResult::Integer(0) => Ok(Some(false)),
BatchResult::String(s) => match s.as_str() {
"1" | "true" | "TRUE" | "yes" | "YES" => Ok(Some(true)),
"0" | "false" | "FALSE" | "no" | "NO" => Ok(Some(false)),
_ => Err(RedissonError::DeserializationError(
format!("Unable to convert a string to a Boolean: {}", s)
)),
},
BatchResult::Raw(value) => {
if let Value::Int(1) = value {
Ok(Some(true))
} else if let Value::Int(0) = value {
Ok(Some(false))
} else if let Value::SimpleString(s) = value {
match s.as_str() {
"OK" | "true" | "TRUE" | "yes" | "YES" => Ok(Some(true)),
_ => Ok(Some(false)),
}
} else {
Err(RedissonError::DeserializationError(
format!("A Boolean value cannot be retrieved from a primitive value: {:?}", value)
))
}
}
BatchResult::Nil => Ok(None),
_ => Err(RedissonError::DeserializationError(
format!("The result type {:? } get a Boolean value", self.results[index])
)),
}
}
pub fn all_success(&self) -> bool {
for result in &self.results {
match result {
BatchResult::Status(s) if s == "OK" => continue,
BatchResult::Integer(1) => continue, BatchResult::Bool(true) => continue,
BatchResult::Nil => continue, BatchResult::Raw(Value::Okay) => continue,
BatchResult::Raw(Value::SimpleString(s)) if s == "OK" => continue,
BatchResult::Raw(Value::Int(1)) => continue,
_ => {
if let BatchResult::Error(_) = result {
return false;
}
}
}
}
true
}
pub fn id(&self) -> &str {
&self.transaction_id
}
}
#[derive(Clone, Debug)]
pub struct TransactionStats {
pub total_batches: u64,
pub total_commands: u64,
pub total_executions: u64,
pub total_success: u64,
pub total_failures: u64,
pub avg_batch_size: f64,
pub avg_execution_time_ms: f64,
}
impl Default for TransactionStats {
fn default() -> Self {
Self {
total_batches: 0,
total_commands: 0,
total_executions: 0,
total_success: 0,
total_failures: 0,
avg_batch_size: 0.0,
avg_execution_time_ms: 0.0,
}
}
}