use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, JsonSchema, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct CacheLimitsConfig {
#[serde(default = "default_max_entries")]
pub max_entries: u64,
}
impl Default for CacheLimitsConfig {
fn default() -> Self {
Self {
max_entries: default_max_entries(),
}
}
}
impl CacheLimitsConfig {
pub fn with_max_entries(mut self, max_entries: u64) -> Self {
self.max_entries = max_entries;
self
}
}
fn default_max_entries() -> u64 {
1000
}
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct CacheConfig {
#[serde(default)]
pub router: RouterCacheConfig,
#[serde(default)]
pub supergraph: SupergraphCacheConfig,
}
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct RouterCacheConfig {
#[serde(default)]
pub parsing: CacheLimitsConfig,
}
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema, Clone, PartialEq)]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct SupergraphCacheConfig {
#[serde(default)]
pub validation: CacheLimitsConfig,
#[serde(default)]
pub normalization: CacheLimitsConfig,
#[serde(default)]
pub query_plans: CacheLimitsConfig,
}
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct SupergraphCacheOverrides {
pub validation: CacheOverride,
pub normalization: CacheOverride,
pub query_plans: CacheOverride,
}
#[derive(Debug, Default, Clone)]
pub struct CacheOverride {
inner: Option<CacheLimitsConfig>,
}
impl CacheOverride {
pub fn set_max_entries(&mut self, max_entries: u64) -> &mut Self {
self.inner = Some(CacheLimitsConfig {
max_entries,
..Default::default()
});
self
}
pub fn disable(&mut self) -> &mut Self {
self.set_max_entries(0)
}
pub fn inherit(&mut self) -> &mut Self {
self.inner = None;
self
}
pub(crate) fn resolve<'a>(&'a self, inherited: &'a CacheLimitsConfig) -> &'a CacheLimitsConfig {
self.inner.as_ref().unwrap_or(inherited)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_default_every_cache_when_config_is_empty() {
let from_empty: CacheConfig = serde_json::from_str("{}").unwrap();
assert_eq!(from_empty, CacheConfig::default());
assert_eq!(from_empty.router.parsing.max_entries, 1000);
assert_eq!(from_empty.supergraph.query_plans.max_entries, 1000);
}
#[test]
fn should_keep_defaults_for_unset_siblings() {
let config: CacheConfig =
serde_json::from_str(r#"{"supergraph": {"query_plans": {"max_entries": 5}}}"#).unwrap();
assert_eq!(config.supergraph.query_plans.max_entries, 5);
assert_eq!(config.supergraph.validation.max_entries, 1000);
assert_eq!(config.router.parsing.max_entries, 1000);
}
#[tokio::test]
async fn should_cache_nothing_when_max_entries_is_zero() {
let cache: moka::future::Cache<u64, u64> = moka::future::Cache::new(0);
cache.insert(1, 1).await;
cache.run_pending_tasks().await;
assert_eq!(cache.entry_count(), 0);
}
}