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, KvPurge, 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    /// Get the purge interface (if supported).
57    ///
58    /// Purge reclaims a key's bytes, unlike `writer().delete()` which only
59    /// writes a marker. See [`KvPurge`]. Returns `None` for backends without
60    /// byte-reclaiming purge.
61    fn purge_writer(&self) -> Option<Arc<dyn KvPurge>> {
62        None
63    }
64}
65
66/// Capabilities a store connection may support.
67#[derive(Debug, Clone, Default)]
68pub struct ConnectionCapabilities {
69    /// Supports streaming watch (continuous updates). NATS: true, FDB: false.
70    pub streaming_watch: bool,
71    /// Supports native prefix watch. NATS: true, FDB: false (uses sentinel pattern).
72    pub prefix_watch: bool,
73    /// Supports TTL on keys.
74    pub ttl: bool,
75    /// Supports byte-reclaiming purge (rollup delete). NATS: true.
76    pub purge: bool,
77    /// Supports atomic compare-and-swap.
78    pub cas: bool,
79    /// Supports multi-key transactions.
80    pub transactions: bool,
81    /// Maximum value size in bytes (0 = unlimited).
82    pub max_value_size: usize,
83    /// Global ordering via versionstamps. FDB: true, NATS: false.
84    pub global_ordering: bool,
85}
86
87/// Store connection lifecycle and store factory.
88#[async_trait]
89pub trait Connection: Send + Sync {
90    /// Connect to the store.
91    async fn connect(&self) -> Result<(), KvError>;
92
93    /// Graceful shutdown.
94    async fn shutdown(&self) -> Result<(), KvError>;
95
96    /// Health check - fast, non-blocking.
97    fn is_healthy(&self) -> bool;
98
99    /// Get or create a named store with default configuration.
100    async fn store(&self, name: &str) -> Result<Arc<dyn KvStore>, KvError>;
101
102    /// Get or create a named store with custom configuration.
103    ///
104    /// Use this when you need to specify bucket-level settings like TTL or history.
105    ///
106    /// Config applies only at **creation**. If the bucket already exists, the
107    /// existing one is returned as-is and `config` (max_bytes, num_replicas,
108    /// max_history, max_age, …) is ignored — there is no reconciliation. To change
109    /// settings on a live bucket (e.g. raising `num_replicas` for HA), alter the
110    /// underlying stream out-of-band; calling this with new values is a no-op.
111    async fn store_with_config(&self, config: StoreConfig) -> Result<Arc<dyn KvStore>, KvError>;
112
113    /// Store capabilities for runtime feature detection.
114    fn capabilities(&self) -> ConnectionCapabilities;
115}