Skip to main content

slipstream/
stores.rs

1use async_trait::async_trait;
2use std::sync::Arc;
3use std::time::Duration;
4
5use crate::kv::{KvError, KvReader, KvWatcher, KvWriter};
6
7/// Storage type for a store.
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
9pub enum StorageType {
10    /// In-memory storage (fast, lost on restart).
11    Memory,
12    /// Persistent storage (survives restarts).
13    #[default]
14    Persistent,
15}
16
17/// Configuration for creating a store.
18#[derive(Debug, Clone, Default)]
19pub struct StoreConfig {
20    /// Store name/bucket identifier.
21    pub name: String,
22    /// Storage type (memory or persistent).
23    pub storage: StorageType,
24    /// Maximum history/versions to keep (NATS-specific, ignored by other stores).
25    pub max_history: Option<u32>,
26    /// Maximum age for entries in the bucket (bucket-level TTL).
27    /// Entries older than this are automatically removed.
28    /// NATS: maps to `max_age` on bucket config.
29    pub max_age: Option<Duration>,
30    /// Maximum bytes for the bucket (required by Synadia Cloud).
31    /// NATS: maps to `max_bytes` on bucket config.
32    pub max_bytes: Option<i64>,
33    /// Number of stream replicas for the bucket (NATS cluster mode).
34    /// Defaults to 1 (single replica). Set to 3 for production HA clusters.
35    pub num_replicas: Option<usize>,
36}
37
38/// A named KV store (bucket/namespace/database).
39pub trait KvStore: Send + Sync {
40    /// The store's name/bucket identifier.
41    fn name(&self) -> &str;
42
43    /// Get the reader interface.
44    fn reader(&self) -> Arc<dyn KvReader>;
45
46    /// Get the watcher interface (if supported).
47    fn watcher(&self) -> Option<Arc<dyn KvWatcher>> {
48        None
49    }
50
51    /// Get the writer interface (if supported).
52    fn writer(&self) -> Option<Arc<dyn KvWriter>> {
53        None
54    }
55}
56
57/// Capabilities a store connection may support.
58#[derive(Debug, Clone, Default)]
59pub struct ConnectionCapabilities {
60    /// Supports streaming watch (continuous updates). NATS: true, FDB: false.
61    pub streaming_watch: bool,
62    /// Supports native prefix watch. NATS: true, FDB: false (uses sentinel pattern).
63    pub prefix_watch: bool,
64    /// Supports TTL on keys.
65    pub ttl: bool,
66    /// Supports atomic compare-and-swap.
67    pub cas: bool,
68    /// Supports multi-key transactions.
69    pub transactions: bool,
70    /// Maximum value size in bytes (0 = unlimited).
71    pub max_value_size: usize,
72    /// Global ordering via versionstamps. FDB: true, NATS: false.
73    pub global_ordering: bool,
74}
75
76/// Store connection lifecycle and store factory.
77#[async_trait]
78pub trait Connection: Send + Sync {
79    /// Connect to the store.
80    async fn connect(&self) -> Result<(), KvError>;
81
82    /// Graceful shutdown.
83    async fn shutdown(&self) -> Result<(), KvError>;
84
85    /// Health check - fast, non-blocking.
86    fn is_healthy(&self) -> bool;
87
88    /// Get or create a named store with default configuration.
89    async fn store(&self, name: &str) -> Result<Arc<dyn KvStore>, KvError>;
90
91    /// Get or create a named store with custom configuration.
92    ///
93    /// Use this when you need to specify bucket-level settings like TTL or history.
94    ///
95    /// Config applies only at **creation**. If the bucket already exists, the
96    /// existing one is returned as-is and `config` (max_bytes, num_replicas,
97    /// max_history, max_age, …) is ignored — there is no reconciliation. To change
98    /// settings on a live bucket (e.g. raising `num_replicas` for HA), alter the
99    /// underlying stream out-of-band; calling this with new values is a no-op.
100    async fn store_with_config(&self, config: StoreConfig) -> Result<Arc<dyn KvStore>, KvError>;
101
102    /// Store capabilities for runtime feature detection.
103    fn capabilities(&self) -> ConnectionCapabilities;
104}