wb_cache/
entry_selector.rs

1use crate::prelude::*;
2use fieldx_plus::fx_plus;
3use fieldx_plus::Child;
4use std::fmt::Debug;
5use std::future::Future;
6use std::sync::Arc;
7use tracing::instrument;
8
9#[fx_plus(child(Cache<DC>, rc_strong), default(off), sync, builder(vis(pub(crate))))]
10pub struct EntryKeySelector<DC>
11where
12    DC: DataController,
13{
14    /// Contains the primary key for existing entries.
15    #[fieldx(optional, get)]
16    primary_key: DC::Key,
17
18    /// The key for which this selector is created.
19    #[fieldx(get)]
20    key: DC::Key,
21
22    /// True if this is a primary key selector, false if it is a secondary key selector.
23    #[fieldx(get(copy))]
24    primary: bool,
25}
26
27impl<DC> EntryKeySelector<DC>
28where
29    DC: DataController,
30{
31    /// Performs a compute operation on the entry identified by the key. If the entry is not cached yet the controller
32    /// will try to pull it from the backend via its data controller. If the entry is not found, the callback will be
33    /// called with `None`.
34    ///
35    /// The callback should return a `Result<Op<DC::Value>, DC::Error>`, where [`Op`] will instruct the controller how
36    /// to use the returned value.
37    ///
38    /// Returns a [result](`CompResult`) of the operation if it succeeds or an error.
39    #[instrument(level = "trace", skip(callback))]
40    pub async fn and_try_compute_with<F, Fut>(self, callback: F) -> Result<CompResult<DC>, Arc<DC::Error>>
41    where
42        F: FnOnce(Option<Entry<DC>>) -> Fut,
43        Fut: Future<Output = Result<Op<DC::Value>, DC::Error>>,
44    {
45        let parent = self.parent();
46        Ok(if self.primary {
47            parent.get_and_try_compute_with_primary(self.key(), callback).await?
48        }
49        else {
50            parent.get_and_try_compute_with_secondary(self.key(), callback).await?
51        })
52    }
53
54    /// Returns an [`Entry`] for the requested key if it's either cached or can be fetched from the backend. Otherwise
55    /// uses the give `init` future to create a new entry.
56    #[instrument(level = "trace", skip(init))]
57    pub async fn or_try_insert_with<F>(self, init: F) -> Result<Entry<DC>, Arc<DC::Error>>
58    where
59        F: Future<Output = Result<DC::Value, DC::Error>>,
60    {
61        let parent = self.parent();
62        if self.primary {
63            parent.get_or_try_insert_with_primary(self.key(), init).await
64        }
65        else {
66            parent.get_or_try_insert_with_secondary(self.key(), init).await
67        }
68    }
69}
70
71impl<DC> Debug for EntryKeySelector<DC>
72where
73    DC: DataController,
74{
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        f.debug_struct("EntryKeySelector")
77            .field("primary_key", &self.primary_key)
78            .field("key", &self.key)
79            .field("is_primary", &self.primary)
80            .finish()
81    }
82}