use std::sync::Arc;
use std::time::Duration;
use moka::future::Cache;
use tokio::sync::OnceCell;
use crate::config::CacheConfig;
use crate::models::futures::FuturesContract;
use crate::models::stock::{IndexInstrument, Instrument};
#[derive(Clone)]
pub struct ResolverCache {
pub(crate) enabled: bool,
pub(crate) enrichment_batch_size: usize,
pub(crate) instruments_by_symbol: Cache<String, Arc<Instrument>>,
pub(crate) instruments_by_id: Cache<String, String>,
pub(crate) index_instruments: Cache<String, Arc<IndexInstrument>>,
pub(crate) futures_contracts: Cache<String, Arc<FuturesContract>>,
pub(crate) futures_account_id: Arc<OnceCell<String>>,
}
impl ResolverCache {
pub fn from_config(config: &CacheConfig) -> Self {
let instruments_by_symbol = Cache::builder()
.max_capacity(config.instrument_max_entries)
.time_to_live(Duration::from_secs(config.instrument_ttl_secs))
.build();
let instruments_by_id = Cache::builder()
.max_capacity(config.instrument_id_max_entries)
.time_to_live(Duration::from_secs(config.instrument_id_ttl_secs))
.build();
let index_instruments = Cache::builder()
.max_capacity(config.index_max_entries)
.time_to_live(Duration::from_secs(config.index_ttl_secs))
.build();
let futures_contracts = Cache::builder()
.max_capacity(config.futures_max_entries)
.time_to_live(Duration::from_secs(config.futures_ttl_secs))
.build();
Self {
enabled: config.enabled,
enrichment_batch_size: config.enrichment_batch_size,
instruments_by_symbol,
instruments_by_id,
index_instruments,
futures_contracts,
futures_account_id: Arc::new(OnceCell::new()),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn from_config_builds_empty_caches() {
let cache = ResolverCache::from_config(&CacheConfig::default());
assert!(cache.enabled);
assert_eq!(cache.instruments_by_symbol.entry_count(), 0);
assert_eq!(cache.instruments_by_id.entry_count(), 0);
assert_eq!(cache.index_instruments.entry_count(), 0);
assert_eq!(cache.futures_contracts.entry_count(), 0);
assert!(cache.futures_account_id.get().is_none());
}
#[tokio::test]
async fn disabled_flag_propagates() {
let cfg = CacheConfig {
enabled: false,
..CacheConfig::default()
};
let cache = ResolverCache::from_config(&cfg);
assert!(!cache.enabled);
}
}