Skip to main content

hydracache_macros/
lib.rs

1use proc_macro::TokenStream;
2use syn::{parse_macro_input, DeriveInput};
3
4mod cacheable;
5mod config;
6mod entity;
7mod paths;
8mod policy;
9
10/// Derive `CacheEntity` metadata for database result-cache helpers.
11///
12/// # Example
13///
14/// ```rust,ignore
15/// use hydracache_db::{CacheEntity, HydraCacheEntity};
16///
17/// #[derive(HydraCacheEntity)]
18/// #[hydracache(entity = "user", collection = "users", id = i64)]
19/// struct User {
20///     id: i64,
21///     name: String,
22/// }
23///
24/// assert_eq!(User::cache_key_for(&42), "user:42");
25/// ```
26#[proc_macro_derive(HydraCacheEntity, attributes(hydracache))]
27pub fn derive_hydracache_entity(input: TokenStream) -> TokenStream {
28    entity::expand(parse_macro_input!(input as DeriveInput))
29        .unwrap_or_else(syn::Error::into_compile_error)
30        .into()
31}
32
33/// Build a `QueryCachePolicy` with less boilerplate.
34///
35/// # Example
36///
37/// ```rust,ignore
38/// use hydracache_db::{query_cache_policy, QueryCachePolicy};
39///
40/// let user_id = 42_i64;
41/// let policy = query_cache_policy!(
42///     name = "load-user",
43///     entity = User,
44///     id = user_id,
45///     ttl_secs = 60,
46/// );
47/// ```
48#[proc_macro]
49pub fn query_cache_policy(input: TokenStream) -> TokenStream {
50    policy::expand(input.into())
51        .unwrap_or_else(syn::Error::into_compile_error)
52        .into()
53}
54
55/// Cache an ordinary fallible async loader with explicit local-cache metadata.
56///
57/// The macro builds `CacheOptions` and calls `HydraCache::get_or_load`.
58/// `cache`, `key`, and `load` are required. `tag = ...` can be repeated,
59/// `tags = ...` accepts any iterable accepted by `CacheOptions::tags`, and
60/// either `ttl = Duration` or `ttl_secs = u64` can be supplied.
61///
62/// # Example
63///
64/// ```rust,ignore
65/// use hydracache::{cacheable, CacheKeyBuilder, HydraCache, TagSet};
66///
67/// let cache = HydraCache::local().build();
68/// let user_id = 42_u64;
69/// let key = CacheKeyBuilder::new().entity("user", user_id).build_string();
70///
71/// let value = cacheable!(
72///     cache = cache,
73///     key = key.as_str(),
74///     tags = TagSet::new().tag("users").entity("user", user_id),
75///     ttl_secs = 60,
76///     load = move || async move { Ok::<_, std::io::Error>(user_id) },
77/// )
78/// .await?;
79/// ```
80#[proc_macro]
81pub fn cacheable(input: TokenStream) -> TokenStream {
82    cacheable::expand(input.into())
83        .unwrap_or_else(syn::Error::into_compile_error)
84        .into()
85}
86
87/// Cache an ordinary async loader that cannot fail in application terms.
88///
89/// The macro builds `CacheOptions` and calls `HydraCache::get_or_insert_with`.
90/// Use it when the loader returns `T` instead of `Result<T, E>`.
91///
92/// # Example
93///
94/// ```rust,ignore
95/// use hydracache::{cacheable_infallible, HydraCache};
96///
97/// let cache = HydraCache::local().build();
98///
99/// let value = cacheable_infallible!(
100///     cache = cache,
101///     key = "expensive:42",
102///     tags = ["expensive"],
103///     ttl_secs = 60,
104///     load = || async { 42_u64 },
105/// )
106/// .await?;
107/// ```
108#[proc_macro]
109pub fn cacheable_infallible(input: TokenStream) -> TokenStream {
110    cacheable::expand_infallible(input.into())
111        .unwrap_or_else(syn::Error::into_compile_error)
112        .into()
113}