use crate::types::ServerFetchPolicy;
use leptos::prelude::{RwSignal, Update, WithUntracked};
use orbital_paging::PageRequest;
#[derive(Clone, Default)]
pub struct ServerFetchCoordinator {
generation: u32,
last_dedupe_key: Option<String>,
}
impl ServerFetchCoordinator {
pub fn begin(&mut self, request: &PageRequest, policy: &ServerFetchPolicy) -> Option<u32> {
if let Some(key_fn) = &policy.dedupe_key {
let key = key_fn(request);
if self.last_dedupe_key.as_deref() == Some(key.as_str()) {
return None;
}
self.last_dedupe_key = Some(key);
}
self.generation = self.generation.wrapping_add(1);
Some(self.generation)
}
pub fn is_current(&self, gen: u32) -> bool {
self.generation == gen
}
pub fn clear_dedupe(&mut self) {
self.last_dedupe_key = None;
}
}
pub fn coordinator_begin(
coordinator: RwSignal<ServerFetchCoordinator>,
request: &PageRequest,
policy: &ServerFetchPolicy,
) -> Option<u32> {
let mut generation = None;
coordinator.update(|c| {
generation = c.begin(request, policy);
});
generation
}
pub fn coordinator_is_current(
coordinator: RwSignal<ServerFetchCoordinator>,
generation: u32,
) -> bool {
coordinator.with_untracked(|c| c.is_current(generation))
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::*;
use orbital_paging::PageRequest;
#[test]
fn begin_increments_generation() {
let mut coord = ServerFetchCoordinator::default();
let policy = ServerFetchPolicy::default();
let req = PageRequest::new(0, 10);
let g1 = coord.begin(&req, &policy).expect("first fetch");
let g2 = coord.begin(&req, &policy).expect("second fetch");
assert_ne!(g1, g2);
assert!(coord.is_current(g2));
assert!(!coord.is_current(g1));
}
#[test]
fn dedupe_skips_identical_consecutive_requests() {
let mut coord = ServerFetchCoordinator::default();
let policy = ServerFetchPolicy {
dedupe_key: Some(Arc::new(|req| format!("{}:{}", req.offset, req.limit))),
};
let req = PageRequest::new(0, 10);
assert!(coord.begin(&req, &policy).is_some());
assert!(coord.begin(&req, &policy).is_none());
}
#[test]
fn clear_dedupe_allows_identical_request_again() {
let mut coord = ServerFetchCoordinator::default();
let policy = ServerFetchPolicy {
dedupe_key: Some(Arc::new(|req| format!("{}:{}", req.offset, req.limit))),
};
let req = PageRequest::new(0, 10);
assert!(coord.begin(&req, &policy).is_some());
assert!(coord.begin(&req, &policy).is_none());
coord.clear_dedupe();
assert!(coord.begin(&req, &policy).is_some());
}
}