Skip to main content

meerkat_core/
session_store.rs

1//! SessionStore trait — canonical session persistence contract.
2//!
3//! This trait lives in `meerkat-core` so that custom storage implementations
4//! (Postgres, DynamoDB, etc.) can be written without depending on `meerkat-store`.
5
6use async_trait::async_trait;
7
8use crate::Session;
9use crate::session::SessionMeta;
10use crate::time_compat::SystemTime;
11use crate::types::SessionId;
12
13/// Filter for listing sessions.
14#[derive(Debug, Clone, Default)]
15pub struct SessionFilter {
16    /// Only sessions created after this time.
17    pub created_after: Option<SystemTime>,
18    /// Only sessions updated after this time.
19    pub updated_after: Option<SystemTime>,
20    /// Maximum number of results.
21    pub limit: Option<usize>,
22    /// Offset for pagination.
23    pub offset: Option<usize>,
24}
25
26/// Errors from session store operations.
27///
28/// Backend-specific details (rusqlite, filesystem, etc.) are erased to strings
29/// so that the trait contract carries no I/O dependencies.
30#[derive(Debug, thiserror::Error)]
31pub enum SessionStoreError {
32    #[error("IO error: {0}")]
33    Io(#[from] std::io::Error),
34
35    #[error("Serialization error: {0}")]
36    Serialization(String),
37
38    #[error("Session not found: {0}")]
39    NotFound(SessionId),
40
41    #[error("Session corrupted: {0}")]
42    Corrupted(SessionId),
43
44    #[error("Internal error: {0}")]
45    Internal(String),
46}
47
48impl From<serde_json::Error> for SessionStoreError {
49    fn from(e: serde_json::Error) -> Self {
50        Self::Serialization(e.to_string())
51    }
52}
53
54/// Abstraction over session storage backends.
55///
56/// All methods take `&self` — implementations must handle interior mutability.
57/// Object-safe: consumed as `Arc<dyn SessionStore>` throughout the system.
58#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
59#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
60pub trait SessionStore: Send + Sync {
61    /// Save a session (create or update).
62    async fn save(&self, session: &Session) -> Result<(), SessionStoreError>;
63
64    /// Load a session by ID.
65    async fn load(&self, id: &SessionId) -> Result<Option<Session>, SessionStoreError>;
66
67    /// List sessions matching filter.
68    async fn list(&self, filter: SessionFilter) -> Result<Vec<SessionMeta>, SessionStoreError>;
69
70    /// Delete a session.
71    async fn delete(&self, id: &SessionId) -> Result<(), SessionStoreError>;
72
73    /// Check if a session exists.
74    async fn exists(&self, id: &SessionId) -> Result<bool, SessionStoreError> {
75        Ok(self.load(id).await?.is_some())
76    }
77}