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}