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}