1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
use crate::Cache;
use async_trait::async_trait;
use std::fmt::Display;
use std::hash::Hash;
/// A trait for fetching values from some datastore in bulk. A `Fetcher`
/// will be given an array of keys and should insert fetched values into
/// a given cache. Implementing `Fetcher` will allow queries to be batch
/// using a [`Batcher`](crate::Batcher). See the [`Batcher`](crate::Batcher)
/// docs for details about batching, caching, and error semantics.
///
/// Implementors should use [`async-trait`](https://crates.io/crates/async-trait)
/// to implement this trait.
///
/// # Examples
///
/// ```
/// # use async_trait::async_trait;
/// # use ultra_batch::{Fetcher, Cache};
/// # #[derive(Clone, Copy, Hash, PartialEq, Eq)] struct UserId(usize);
/// # #[derive(Clone)] struct User { id: UserId }
/// # struct DbConnection(std::sync::Arc<Vec<User>>);
/// # impl DbConnection {
/// # async fn get_users_by_ids(&self, user_ids: &[UserId]) -> anyhow::Result<Vec<User>> {
/// # let users = user_ids.iter().flat_map(|id| self.0.iter().nth(id.0).cloned());
/// # Ok(users.collect())
/// # }
/// # }
/// struct UserFetcher {
/// db_conn: DbConnection,
/// }
///
/// #[async_trait]
/// impl Fetcher for UserFetcher {
/// type Key = UserId;
/// type Value = User;
/// type Error = anyhow::Error;
///
/// async fn fetch(&self, keys: &[UserId], values: &mut Cache<'_, UserId, User>) -> anyhow::Result<()> {
/// let users = self.db_conn.get_users_by_ids(keys).await?;
/// for user in users {
/// values.insert(user.id, user);
/// }
/// Ok(())
/// }
/// }
/// ```
#[async_trait]
pub trait Fetcher {
/// The type used to look up a single value in a batch.
type Key: Clone + Hash + Eq + Send + Sync;
/// The type returned in a batch. `Value` is usually a single database
/// record, but could also be a more sophisticated type, such as a
/// `Vec` of values for a `Fetcher` that deals with one-to-many
/// relationships.
type Value: Clone + Send + Sync;
/// The error indicating that fetching a batch failed.
type Error: Display + Send + Sync + 'static;
/// Retrieve the values associated with the given keys, and insert them into
/// `values` if found. If `Ok(_)` is returned, then any keys not inserted
/// into `values` will be marked as "not found" (meaning any future attempts
/// to retrieve them will fail). If `Err(_)` is returned, then the caller(s)
/// waiting on the batch will receive a [`LoadError::FetchError`](crate::LoadError::FetchError)
/// with the message from returned error (note that any values inserted into
/// `values` before the `Err(_)` is returned will still be cached). See the
/// [`Batcher`](crate::Batcher) docs for more details.
async fn fetch(
&self,
keys: &[Self::Key],
values: &mut Cache<'_, Self::Key, Self::Value>,
) -> Result<(), Self::Error>;
}