rs_query/
mutation.rs

1//! Mutation definition
2
3use crate::{QueryError, QueryKey};
4use std::future::Future;
5use std::pin::Pin;
6use std::sync::Arc;
7
8/// Type alias for boxed async mutation function
9pub type MutateFn<T, P> =
10    Arc<dyn Fn(P) -> Pin<Box<dyn Future<Output = Result<T, QueryError>> + Send>> + Send + Sync>;
11
12/// Mutation state
13#[derive(Debug, Clone, Default)]
14pub enum MutationState<T: Clone> {
15    #[default]
16    Idle,
17    Pending,
18    Success(T),
19    Error(QueryError),
20}
21
22impl<T: Clone> MutationState<T> {
23    pub fn is_idle(&self) -> bool {
24        matches!(self, Self::Idle)
25    }
26
27    pub fn is_pending(&self) -> bool {
28        matches!(self, Self::Pending)
29    }
30
31    pub fn is_success(&self) -> bool {
32        matches!(self, Self::Success(_))
33    }
34
35    pub fn is_error(&self) -> bool {
36        matches!(self, Self::Error(_))
37    }
38
39    pub fn data(&self) -> Option<&T> {
40        match self {
41            Self::Success(d) => Some(d),
42            _ => None,
43        }
44    }
45
46    pub fn error(&self) -> Option<&QueryError> {
47        match self {
48            Self::Error(e) => Some(e),
49            _ => None,
50        }
51    }
52}
53
54/// A mutation definition.
55///
56/// # Example
57///
58/// ```rust,ignore
59/// let mutation = Mutation::new(|params: CreateUserParams| async move {
60///     api::create_user(params).await
61/// })
62/// .invalidates_key(QueryKey::new("users"));
63/// ```
64pub struct Mutation<T, P>
65where
66    T: Clone + Send + Sync + 'static,
67    P: Clone + Send + 'static,
68{
69    pub mutate_fn: MutateFn<T, P>,
70    pub invalidate_keys: Vec<QueryKey>,
71}
72
73impl<T, P> Mutation<T, P>
74where
75    T: Clone + Send + Sync + 'static,
76    P: Clone + Send + 'static,
77{
78    /// Create a new mutation
79    pub fn new<F, Fut>(mutate_fn: F) -> Self
80    where
81        F: Fn(P) -> Fut + Send + Sync + 'static,
82        Fut: Future<Output = Result<T, QueryError>> + Send + 'static,
83    {
84        Self {
85            mutate_fn: Arc::new(move |p| Box::pin(mutate_fn(p))),
86            invalidate_keys: Vec::new(),
87        }
88    }
89
90    /// Add query keys to invalidate on success
91    pub fn invalidates(mut self, keys: impl IntoIterator<Item = QueryKey>) -> Self {
92        self.invalidate_keys.extend(keys);
93        self
94    }
95
96    /// Add a single key to invalidate
97    pub fn invalidates_key(mut self, key: QueryKey) -> Self {
98        self.invalidate_keys.push(key);
99        self
100    }
101}