Skip to main content

entelix_persistence/redis/
persistence.rs

1//! `RedisPersistence` — handle owning a `redis::aio::ConnectionManager`
2//! plus builder for the four backend handles.
3
4use std::sync::Arc;
5
6use redis::Client;
7use redis::aio::ConnectionManager;
8
9use crate::error::{PersistenceError, PersistenceResult};
10
11/// Redis-backed persistence bundle. Cheap to clone — the connection
12/// manager is reference-counted internally.
13#[derive(Clone)]
14pub struct RedisPersistence {
15    manager: Arc<ConnectionManager>,
16}
17
18impl RedisPersistence {
19    fn from_manager(manager: ConnectionManager) -> Self {
20        Self {
21            manager: Arc::new(manager),
22        }
23    }
24
25    /// Borrow the underlying connection manager.
26    pub fn manager(&self) -> &ConnectionManager {
27        &self.manager
28    }
29
30    /// Build the lock handle.
31    pub fn lock(&self) -> super::RedisLock {
32        super::RedisLock::new(Arc::clone(&self.manager))
33    }
34
35    /// Build a typed [`super::RedisCheckpointer`].
36    pub fn checkpointer<S>(&self) -> super::RedisCheckpointer<S>
37    where
38        S: Clone + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
39    {
40        super::RedisCheckpointer::new(Arc::clone(&self.manager))
41    }
42
43    /// Build a typed [`super::RedisStore`].
44    pub fn store<V>(&self) -> super::RedisStore<V>
45    where
46        V: Clone + Send + Sync + serde::Serialize + serde::de::DeserializeOwned + 'static,
47    {
48        super::RedisStore::new(Arc::clone(&self.manager))
49    }
50
51    /// Build the session-log handle.
52    pub fn session_log(&self) -> super::RedisSessionLog {
53        super::RedisSessionLog::new(Arc::clone(&self.manager))
54    }
55
56    /// Start a builder.
57    pub fn builder() -> RedisPersistenceBuilder {
58        RedisPersistenceBuilder { url: None }
59    }
60}
61
62/// Fluent builder for [`RedisPersistence`].
63#[derive(Debug)]
64#[must_use]
65pub struct RedisPersistenceBuilder {
66    url: Option<String>,
67}
68
69impl RedisPersistenceBuilder {
70    /// Redis connection URL (`redis://host:6379/0`).
71    pub fn with_connection_string(mut self, url: impl Into<String>) -> Self {
72        self.url = Some(url.into());
73        self
74    }
75
76    /// Open the connection manager and return the bundle.
77    pub async fn connect(self) -> PersistenceResult<RedisPersistence> {
78        let url = self
79            .url
80            .ok_or_else(|| PersistenceError::Config("connection_string is required".into()))?;
81        let client = Client::open(url.as_str())
82            .map_err(|e| PersistenceError::Backend(format!("client open: {e}")))?;
83        let manager = ConnectionManager::new(client)
84            .await
85            .map_err(|e| PersistenceError::Backend(format!("connection manager: {e}")))?;
86        Ok(RedisPersistence::from_manager(manager))
87    }
88}