hydracache_db/lib.rs
1//! Database-neutral query result caching helpers for HydraCache.
2//!
3//! This crate is intentionally a thin runtime adapter. It does not replace a
4//! database client, ORM, or query builder. Callers keep their database library
5//! as the query authority and provide an explicit cache key, tags, and TTL
6//! around the operation they want to cache.
7//!
8//! # Example
9//!
10//! ```rust
11//! use hydracache::HydraCache;
12//! use hydracache_db::{
13//! DbCache, HydraCacheEntity, PreparedQueryPolicy, QueryCachePolicy, RefreshPolicy,
14//! };
15//! use serde::{Deserialize, Serialize};
16//!
17//! #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, HydraCacheEntity)]
18//! #[hydracache(entity = "user", collection = "users", id = i64)]
19//! struct User {
20//! id: i64,
21//! name: String,
22//! }
23//!
24//! # #[tokio::main]
25//! # async fn main() -> hydracache_db::Result<()> {
26//! let local = HydraCache::local().build();
27//!
28//! // The adapter wraps the local HydraCache instance. The namespace becomes
29//! // part of the physical cache key, so key("user:42") is stored as
30//! // "db:user:42".
31//! let queries = DbCache::new(local, "db");
32//!
33//! let policy = QueryCachePolicy::read_mostly()
34//! // Metadata helper: key "user:42", tag "user:42", and tag "users".
35//! .for_cache_entity::<User>(42)
36//! .with_name("load-user")
37//! .refresh_policy(
38//! RefreshPolicy::new()
39//! .refresh_ahead(std::time::Duration::from_secs(10))
40//! .stale_while_revalidate(std::time::Duration::from_secs(300)),
41//! );
42//!
43//! let user = queries
44//! .cached_with::<User>(policy)
45//! .load(|| async {
46//! // This loader runs only on a cache miss. On a cache hit, HydraCache
47//! // returns the cached User and this database code is not executed.
48//! Ok::<_, std::io::Error>(User {
49//! id: 42,
50//! name: "Ada".to_owned(),
51//! })
52//! })
53//! .await?;
54//!
55//! assert_eq!(user.id, 42);
56//! # Ok(())
57//! # }
58//! ```
59//!
60//! For hot repository methods, prepare stable metadata once and bind only the
61//! dynamic id on each call:
62//!
63//! ```rust
64//! use hydracache::HydraCache;
65//! use hydracache_db::{DbCache, HydraCacheEntity, PreparedQueryPolicy};
66//! use serde::{Deserialize, Serialize};
67//!
68//! #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, HydraCacheEntity)]
69//! #[hydracache(entity = "user", collection = "users", id = i64)]
70//! struct User {
71//! id: i64,
72//! name: String,
73//! }
74//!
75//! # #[tokio::main]
76//! # async fn main() -> hydracache_db::Result<()> {
77//! let queries = DbCache::new(HydraCache::local().build(), "db");
78//! let load_user = queries.prepare::<User>(
79//! PreparedQueryPolicy::per_entity()
80//! .cache_entity::<User>()
81//! .with_name("load-user"),
82//! );
83//!
84//! let user = load_user
85//! .load_id(42, || async {
86//! Ok::<_, std::io::Error>(User {
87//! id: 42,
88//! name: "Ada".to_owned(),
89//! })
90//! })
91//! .await?;
92//!
93//! assert_eq!(user.id, 42);
94//! # Ok(())
95//! # }
96//! ```
97//!
98//! For compact policy construction, use [`query_cache_policy!`]:
99//!
100//! ```rust
101//! use hydracache_db::{query_cache_policy, CacheEntity};
102//!
103//! struct User;
104//!
105//! impl CacheEntity for User {
106//! type Id = i64;
107//!
108//! const ENTITY: &'static str = "user";
109//! const COLLECTION: Option<&'static str> = Some("users");
110//! }
111//!
112//! let user_id = 42_i64;
113//! let policy = query_cache_policy!(
114//! name = "load-user",
115//! entity = User,
116//! id = user_id,
117//! ttl_secs = 60,
118//! );
119//!
120//! assert_eq!(policy.name(), Some("load-user"));
121//! assert_eq!(policy.key_value(), Some("user:42"));
122//! ```
123
124extern crate self as hydracache_db;
125
126mod entity;
127mod error;
128mod policy;
129mod prepared;
130mod query;
131
132pub use entity::CacheEntity;
133pub use error::{DbCacheError, Result};
134pub use hydracache_macros::{query_cache_policy, HydraCacheEntity};
135pub use policy::QueryCachePolicy;
136pub use prepared::PreparedQueryPolicy;
137pub use query::{DbCache, DbQuery, PreparedDbQuery};
138
139/// Database-facing alias for local cache refresh/stale behavior.
140pub type RefreshPolicy = hydracache::RefreshOptions;
141
142#[cfg(test)]
143mod tests;