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}