use crate::error::{GlideError, Result};
use glide_core::client::Client as CoreClient;
use redis::cluster_routing::RoutingInfo;
use redis::{Pipeline, PipelineRetryStrategy, Value};
use std::time::Duration;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PipelineOptions {
pub timeout: Option<Duration>,
pub retry_server_error: bool,
pub retry_connection_error: bool,
}
impl PipelineOptions {
pub fn new() -> Self {
PipelineOptions::default()
}
#[must_use]
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn with_retry_server_error(mut self, retry: bool) -> Self {
self.retry_server_error = retry;
self
}
#[must_use]
pub fn with_retry_connection_error(mut self, retry: bool) -> Self {
self.retry_connection_error = retry;
self
}
fn timeout_millis(&self) -> Option<u32> {
self.timeout
.map(|d| u32::try_from(d.as_millis()).unwrap_or(u32::MAX))
}
}
pub(crate) async fn run_pipeline(
core: &CoreClient,
pipeline: &Pipeline,
routing: Option<RoutingInfo>,
raise_on_error: bool,
options: &PipelineOptions,
) -> Result<Vec<Value>> {
if pipeline.is_empty() {
return Ok(Vec::new());
}
let timeout = options.timeout_millis();
let mut client = core.clone();
let value = if pipeline.is_atomic() {
client
.send_transaction(pipeline, routing, timeout, raise_on_error)
.await
.map_err(GlideError::from)?
} else {
client
.send_pipeline(
pipeline,
routing,
raise_on_error,
timeout,
PipelineRetryStrategy {
retry_server_error: options.retry_server_error,
retry_connection_error: options.retry_connection_error,
},
)
.await
.map_err(GlideError::from)?
};
match value {
Value::Array(items) => Ok(items),
Value::Nil => Ok(Vec::new()),
other => Ok(vec![other]),
}
}