use async_trait::async_trait;
use crate::cache_observer::{CacheEvent, CacheObserver};
#[async_trait(?Send)]
pub trait QueryPersister {
async fn persist(&self, key: &str, query: PersistQueryData);
async fn remove(&self, key: &str);
async fn retrieve(&self, key: &str) -> Option<PersistQueryData>;
async fn clear(&self);
}
impl<Persist> CacheObserver for Persist
where
Persist: QueryPersister + Clone + 'static,
{
fn process_cache_event(&self, event: CacheEvent) {
match event {
#[cfg(any(feature = "hydrate", feature = "csr"))]
CacheEvent::Created(query) => {
if let Ok(value) = TryInto::<PersistQueryData>::try_into(query.state) {
let key = query.key.0;
let persister = self.clone();
leptos::spawn_local(async move {
persister.persist(&key, value).await;
})
}
}
#[cfg(any(feature = "hydrate", feature = "csr"))]
CacheEvent::Updated(query) => {
if let Ok(value) = TryInto::<PersistQueryData>::try_into(query.state) {
let key = query.key.0;
let persister = self.clone();
leptos::spawn_local(async move {
persister.persist(&key, value).await;
})
}
}
#[cfg(any(feature = "hydrate", feature = "csr"))]
CacheEvent::Removed(key) => {
let persister = self.clone();
leptos::spawn_local(async move {
let _ = persister.remove(&key.0).await;
})
}
_ => (),
}
}
}
#[derive(Clone)]
#[cfg_attr(
any(feature = "local_storage", feature = "indexed_db"),
derive(miniserde::Serialize, miniserde::Deserialize)
)]
pub struct PersistQueryData {
pub value: String,
pub updated_at: u64,
}
impl<V> TryFrom<PersistQueryData> for crate::QueryData<V>
where
V: crate::QueryValue,
{
type Error = leptos::SerializationError;
fn try_from(value: PersistQueryData) -> Result<Self, Self::Error> {
let data = leptos::Serializable::de(value.value.as_str())?;
let updated_at = crate::Instant(std::time::Duration::from_millis(value.updated_at));
Ok(crate::QueryData { data, updated_at })
}
}
impl TryFrom<crate::QueryState<String>> for PersistQueryData {
type Error = ();
fn try_from(state: crate::QueryState<String>) -> Result<Self, Self::Error> {
match state {
crate::QueryState::Loaded(data) => Ok(data.into()),
crate::QueryState::Loading
| crate::QueryState::Created
| crate::QueryState::Invalid(_)
| crate::QueryState::Fetching(_) => Err(()),
}
}
}
impl From<crate::QueryData<String>> for PersistQueryData {
fn from(data: crate::QueryData<String>) -> Self {
let value = data.data;
let updated_at = data.updated_at.0.as_millis() as u64;
PersistQueryData { value, updated_at }
}
}
#[cfg(feature = "indexed_db")]
mod indexed_db;
#[cfg(feature = "indexed_db")]
pub use indexed_db::IndexedDbPersister;
#[cfg(feature = "local_storage")]
mod local_storage;
#[cfg(feature = "local_storage")]
pub use local_storage::LocalStoragePersister;