#[derive(Debug, Clone, PartialEq)]
pub enum SyncMode {
Immediate,
Threshold(usize),
AsyncBatch { max_latency_ms: u64 },
}
#[derive(Debug, Clone)]
pub struct RealtimeSyncConfig {
pub mode: SyncMode,
pub batch_size: usize,
}
impl Default for RealtimeSyncConfig {
fn default() -> Self {
Self {
mode: SyncMode::Threshold(10_000),
batch_size: 1_000,
}
}
}
impl RealtimeSyncConfig {
pub fn immediate() -> Self {
Self {
mode: SyncMode::Immediate,
batch_size: 1,
}
}
pub fn threshold(n: usize) -> Self {
Self {
mode: SyncMode::Threshold(n),
batch_size: n.min(10_000),
}
}
pub fn async_batch(max_latency_ms: u64, batch_size: usize) -> Self {
Self {
mode: SyncMode::AsyncBatch { max_latency_ms },
batch_size,
}
}
pub fn is_immediate(&self) -> bool {
matches!(self.mode, SyncMode::Immediate)
}
pub fn should_flush(&self, row_count: usize) -> bool {
match &self.mode {
SyncMode::Immediate => true,
SyncMode::Threshold(n) => row_count >= *n,
SyncMode::AsyncBatch { .. } => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = RealtimeSyncConfig::default();
assert_eq!(config.mode, SyncMode::Threshold(10_000));
assert_eq!(config.batch_size, 1_000);
}
#[test]
fn test_immediate_mode() {
let config = RealtimeSyncConfig::immediate();
assert!(config.is_immediate());
assert!(config.should_flush(0));
assert!(config.should_flush(1_000_000));
}
#[test]
fn test_threshold_should_flush() {
let config = RealtimeSyncConfig::threshold(100);
assert!(!config.should_flush(99));
assert!(config.should_flush(100));
assert!(config.should_flush(500));
}
#[test]
fn test_async_batch_never_auto_flush() {
let config = RealtimeSyncConfig::async_batch(50, 1_000);
assert!(!config.should_flush(0));
assert!(!config.should_flush(1_000_000));
assert!(!config.is_immediate());
assert_eq!(config.mode, SyncMode::AsyncBatch { max_latency_ms: 50 });
}
#[test]
fn test_clone_and_debug() {
let config = RealtimeSyncConfig::immediate();
let cloned = config.clone();
assert!(cloned.is_immediate());
let _ = format!("{:?}", cloned);
}
}