pub struct QueryResultCache { /* private fields */ }Expand description
Thread-safe W-TinyLFU cache for query results.
Backed by moka::sync::Cache which provides lock-free reads via
Concurrent TinyLFU. Reverse DashMap indexes enable O(k) invalidation.
§Thread Safety
moka::sync::Cache is Send + Sync. All reverse indexes use DashMap
(fine-grained shard locking) and DashSet (also shard-locked). There is no
global mutex on the read path.
§Example
use fraiseql_core::cache::{QueryResultCache, CacheConfig};
use fraiseql_core::db::types::JsonbValue;
use serde_json::json;
let cache = QueryResultCache::new(CacheConfig::default());
// Cache a result
let result = vec![JsonbValue::new(json!({"id": 1, "name": "Alice"}))];
cache.put(
12345_u64,
result.clone(),
vec!["v_user".to_string()],
None, // use global TTL
None, // no entity type index
).unwrap();
// Retrieve from cache
if let Some(cached) = cache.get(12345).unwrap() {
println!("Cache hit! {} results", cached.len());
}Implementations§
Source§impl QueryResultCache
impl QueryResultCache
Sourcepub fn new(config: CacheConfig) -> Self
pub fn new(config: CacheConfig) -> Self
Sourcepub const fn is_enabled(&self) -> bool
pub const fn is_enabled(&self) -> bool
Returns whether caching is enabled.
Used by CachedDatabaseAdapter to short-circuit key generation
and result clone overhead when caching is disabled.
Sourcepub fn get(&self, cache_key: u64) -> Result<Option<Arc<Vec<JsonbValue>>>>
pub fn get(&self, cache_key: u64) -> Result<Option<Arc<Vec<JsonbValue>>>>
Look up a cached result by its cache key.
Returns None when caching is disabled or the key is not present or expired.
Moka handles TTL expiry internally — if get() returns Some, the entry is live.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
Sourcepub fn put_arc(
&self,
cache_key: u64,
result: Arc<Vec<JsonbValue>>,
accessed_views: Vec<String>,
ttl_override: Option<u64>,
entity_type: Option<&str>,
) -> Result<()>
pub fn put_arc( &self, cache_key: u64, result: Arc<Vec<JsonbValue>>, accessed_views: Vec<String>, ttl_override: Option<u64>, entity_type: Option<&str>, ) -> Result<()>
Store query result in cache, accepting an already-Arc-wrapped result.
Preferred over put on the hot miss path: callers that already
hold an Arc<Vec<JsonbValue>> (e.g. CachedDatabaseAdapter) can store it
without an extra Vec clone.
§Arguments
cache_key- Cache key (fromgenerate_cache_key())result- Arc-wrapped query result to cacheaccessed_views- List of views accessed by this queryttl_override- Per-entry TTL in seconds;NoneusesCacheConfig::ttl_secondsentity_type- Optional GraphQL type name for entity-ID indexing
§Errors
This method is infallible. The Result return type is kept for API compatibility.
Sourcepub fn put(
&self,
cache_key: u64,
result: Vec<JsonbValue>,
accessed_views: Vec<String>,
ttl_override: Option<u64>,
entity_type: Option<&str>,
) -> Result<()>
pub fn put( &self, cache_key: u64, result: Vec<JsonbValue>, accessed_views: Vec<String>, ttl_override: Option<u64>, entity_type: Option<&str>, ) -> Result<()>
Store query result in cache.
If caching is disabled, this is a no-op.
Wraps result in an Arc and delegates to put_arc.
Prefer put_arc when the caller already holds an Arc.
§Arguments
cache_key- Cache key (fromgenerate_cache_key())result- Query result to cacheaccessed_views- List of views accessed by this queryttl_override- Per-entry TTL in seconds;NoneusesCacheConfig::ttl_secondsentity_type- Optional GraphQL type name (e.g."User") for entity-ID indexing. When provided, each row’s"id"field is extracted and stored inentity_indexso thatinvalidate_by_entity()can perform selective eviction.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
§Example
use fraiseql_core::cache::{QueryResultCache, CacheConfig};
use fraiseql_core::db::types::JsonbValue;
use serde_json::json;
let cache = QueryResultCache::new(CacheConfig::default());
let result = vec![JsonbValue::new(json!({"id": "uuid-1"}))];
cache.put(0xabc123, result, vec!["v_user".to_string()], None, Some("User"))?;Sourcepub fn invalidate_views(&self, views: &[String]) -> Result<u64>
pub fn invalidate_views(&self, views: &[String]) -> Result<u64>
Invalidate entries accessing specified views.
Uses the view_index for O(k) lookup instead of O(n) full-cache scan.
Keys accessing multiple views in views are deduplicated before invalidation.
§Arguments
views- List of view/table names modified by mutation
§Returns
Number of cache entries invalidated.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
§Example
use fraiseql_core::cache::{QueryResultCache, CacheConfig};
let cache = QueryResultCache::new(CacheConfig::default());
// After createUser mutation
let invalidated = cache.invalidate_views(&["v_user".to_string()])?;
println!("Invalidated {} cache entries", invalidated);Sourcepub fn invalidate_list_queries(&self, views: &[String]) -> Result<u64>
pub fn invalidate_list_queries(&self, views: &[String]) -> Result<u64>
Evict only list (multi-row) cache entries for the given views.
Unlike invalidate_views(), this method leaves single-entity point-lookup
entries intact. Used for CREATE mutations: creating a new entity does not
affect queries that fetch a different existing entity by UUID, but it
does invalidate queries that return a variable-length list of entities.
Uses the list_index for O(k) lookup.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
Sourcepub fn invalidate_by_entity(
&self,
entity_type: &str,
entity_id: &str,
) -> Result<u64>
pub fn invalidate_by_entity( &self, entity_type: &str, entity_id: &str, ) -> Result<u64>
Evict cache entries that contain a specific entity UUID.
Uses the entity_index for O(k) lookup. Entries not referencing this
entity are left untouched.
§Arguments
entity_type- GraphQL type name (e.g."User")entity_id- UUID string of the mutated entity
§Returns
Number of cache entries evicted.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
Sourcepub fn metrics(&self) -> Result<CacheMetrics>
pub fn metrics(&self) -> Result<CacheMetrics>
Get cache metrics snapshot.
Returns a consistent snapshot of current counters. Individual fields may be updated independently (atomics), so the snapshot is not a single atomic transaction, but is accurate enough for monitoring.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
§Example
use fraiseql_core::cache::{QueryResultCache, CacheConfig};
let cache = QueryResultCache::new(CacheConfig::default());
let metrics = cache.metrics()?;
println!("Hit rate: {:.1}%", metrics.hit_rate() * 100.0);
println!("Size: {} / {} entries", metrics.size, 10_000);Sourcepub fn clear(&self) -> Result<()>
pub fn clear(&self) -> Result<()>
Clear all cache entries.
Resets the store, reverse indexes, and memory_bytes synchronously.
The eviction listener will still fire asynchronously for each evicted entry,
but its index-cleanup operations will be no-ops on the already-cleared maps.
§Errors
This method is infallible. The Result return type is kept for API compatibility.
§Example
use fraiseql_core::cache::{QueryResultCache, CacheConfig};
let cache = QueryResultCache::new(CacheConfig::default());
cache.clear()?;Auto Trait Implementations§
impl !Freeze for QueryResultCache
impl !RefUnwindSafe for QueryResultCache
impl Send for QueryResultCache
impl Sync for QueryResultCache
impl Unpin for QueryResultCache
impl UnsafeUnpin for QueryResultCache
impl !UnwindSafe for QueryResultCache
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more