use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::OnceLock;
use parking_lot::RwLock;
use sz_orm_adaptive::{AdaptiveConfig, AdaptiveExecutor, ExecutionPath};
static ADAPTIVE_EXECUTOR: OnceLock<RwLock<AdaptiveExecutor>> = OnceLock::new();
static DECISION_COUNT: AtomicU64 = AtomicU64::new(0);
fn executor() -> &'static RwLock<AdaptiveExecutor> {
ADAPTIVE_EXECUTOR.get_or_init(|| RwLock::new(AdaptiveExecutor::new(AdaptiveConfig::default())))
}
pub fn adaptive_decide(query_key: &str) -> ExecutionPath {
DECISION_COUNT.fetch_add(1, Ordering::Relaxed);
let executor = executor().read();
executor.decide(query_key)
}
pub fn adaptive_record(query_key: &str, rows: u64, elapsed_ms: u64) -> bool {
let executor = executor().read();
executor.record(query_key, rows, elapsed_ms)
}
pub fn adaptive_decision_count() -> u64 {
DECISION_COUNT.load(Ordering::Relaxed)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_adaptive_decide_returns_path() {
let path = adaptive_decide("test_query");
assert!(matches!(
path,
ExecutionPath::Normal | ExecutionPath::Paginated | ExecutionPath::Cached
));
}
#[test]
fn test_adaptive_record_updates_stats() {
let slow = adaptive_record("test_record", 500, 200);
assert!(slow);
}
#[test]
fn test_adaptive_count_increments() {
let before = adaptive_decision_count();
let _ = adaptive_decide("count_test");
let after = adaptive_decision_count();
assert!(after > before);
}
}