rs_query/
state.rs

1//! Query state enum representing all possible states
2
3use crate::QueryError;
4
5/// Represents the state of a query.
6///
7/// This enum carries data in its variants for ergonomic pattern matching:
8///
9/// ```rust,ignore
10/// match state {
11///     QueryState::Success(data) => { /* use data directly */ }
12///     QueryState::Error { error, stale_data } => { /* handle error */ }
13///     QueryState::Loading => { /* show spinner */ }
14///     _ => {}
15/// }
16/// ```
17#[derive(Debug, Clone, Default)]
18pub enum QueryState<T: Clone> {
19    /// Initial state, no data yet
20    #[default]
21    Idle,
22    /// Currently fetching (first time)
23    Loading,
24    /// Data available, refetching in background
25    Refetching(T),
26    /// Fresh data available
27    Success(T),
28    /// Data is stale but still usable
29    Stale(T),
30    /// Error occurred (with optional stale data)
31    Error {
32        error: QueryError,
33        stale_data: Option<T>,
34    },
35}
36
37impl<T: Clone> QueryState<T> {
38    pub fn is_idle(&self) -> bool {
39        matches!(self, Self::Idle)
40    }
41
42    pub fn is_loading(&self) -> bool {
43        matches!(self, Self::Loading)
44    }
45
46    pub fn is_fetching(&self) -> bool {
47        matches!(self, Self::Loading | Self::Refetching(_))
48    }
49
50    pub fn is_success(&self) -> bool {
51        matches!(self, Self::Success(_))
52    }
53
54    pub fn is_stale(&self) -> bool {
55        matches!(self, Self::Stale(_))
56    }
57
58    pub fn is_error(&self) -> bool {
59        matches!(self, Self::Error { .. })
60    }
61
62    /// Get data if available (success, stale, refetching, or error with stale)
63    pub fn data(&self) -> Option<&T> {
64        match self {
65            Self::Success(d) | Self::Stale(d) | Self::Refetching(d) => Some(d),
66            Self::Error { stale_data, .. } => stale_data.as_ref(),
67            _ => None,
68        }
69    }
70
71    /// Get error if in error state
72    pub fn error(&self) -> Option<&QueryError> {
73        match self {
74            Self::Error { error, .. } => Some(error),
75            _ => None,
76        }
77    }
78
79    /// Unwrap data or return default
80    pub fn unwrap_or_default(&self) -> T
81    where
82        T: Default,
83    {
84        self.data().cloned().unwrap_or_default()
85    }
86}