use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Strategy {
ReadWrite,
ReadOnly,
}
#[derive(Debug, Clone)]
pub struct Region {
pub(crate) strategy: Strategy,
pub(crate) ttl: Option<Duration>,
pub(crate) entities: bool,
pub(crate) queries: bool,
pub(crate) max_rows: usize,
}
impl Region {
pub fn new() -> Region {
Region::default()
}
pub fn read_only() -> Region {
Region { strategy: Strategy::ReadOnly, ttl: Some(Duration::from_secs(3600)), ..Region::default() }
}
pub fn ttl(mut self, ttl: Duration) -> Region {
self.ttl = Some(ttl);
self
}
pub fn forever(mut self) -> Region {
self.ttl = None;
self
}
pub fn entities_only(mut self) -> Region {
self.queries = false;
self
}
pub fn queries_only(mut self) -> Region {
self.entities = false;
self
}
pub fn max_rows(mut self, rows: usize) -> Region {
self.max_rows = rows;
self
}
pub fn strategy(&self) -> Strategy {
self.strategy
}
pub(crate) fn check(&self, model: &str) -> rustlavel_core::Result<()> {
if self.strategy == Strategy::ReadOnly && self.ttl.is_none() {
return Err(rustlavel_core::Error::msg(format!(
"the `{model}` region is read-only with no expiry, so nothing would ever \
remove an entry from it — not a write, not a sweep. Give it a `ttl(...)`, \
or use the default read-write strategy."
)));
}
if !self.entities && !self.queries {
return Err(rustlavel_core::Error::msg(format!(
"the `{model}` region caches neither entities nor queries, so registering \
it does nothing. Drop the region, or turn one of them back on."
)));
}
Ok(())
}
}
impl Default for Region {
fn default() -> Region {
Region {
strategy: Strategy::ReadWrite,
ttl: Some(Duration::from_secs(300)),
entities: true,
queries: true,
max_rows: 500,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_read_only_region_with_no_expiry_is_refused() {
let region = Region::read_only().forever();
let error = region.check("Country").unwrap_err().to_string();
assert!(error.contains("nothing would ever remove an entry"), "{error}");
assert!(error.contains("Country"), "the message does not say which region: {error}");
assert!(Region::read_only().check("Country").is_ok());
assert!(Region::new().forever().check("User").is_ok());
}
#[test]
fn a_region_that_caches_nothing_is_refused() {
let region = Region::new().entities_only().queries_only();
let error = region.check("User").unwrap_err().to_string();
assert!(error.contains("neither entities nor queries"), "{error}");
}
#[test]
fn the_defaults_are_the_conservative_ones() {
let region = Region::default();
assert_eq!(region.strategy, Strategy::ReadWrite);
assert_eq!(region.ttl, Some(Duration::from_secs(300)));
assert!(region.entities && region.queries);
}
}