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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::Instant;
/// The lifecycle of a query.
///
/// Each variant in the enum corresponds to a particular state of a query in its lifecycle,
/// starting from creation and covering all possible transitions up to invalidation.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum QueryState<V> {
/// The initial state of a Query upon its creation.
///
/// In this state, a query is instantiated but no fetching operation has been initiated yet.
/// This means that no data has been requested or received, and the query is in a "pending" state,
/// waiting to begin its first fetch operation.
#[default]
Created,
/// Query is fetching for the first time.
///
/// In this state, the query has started its first data fetching process. It is actively communicating
/// with the data source and waiting for the data to be returned.
Loading,
/// A Query is in the process of fetching, not being its first fetch.
///
/// In this state, a query is undergoing another fetch operation following a previous one.
/// The associated `QueryData<V>` object holds the previous data was fetched.
Fetching(QueryData<V>),
/// The state indicating that a query has successfully completed a fetch operation.
///
/// In this state, the query has finished fetching data.
/// The associated `QueryData<V>` object holds the successfully loaded data.
Loaded(QueryData<V>),
/// The state indicating that a query has completed a fetch, but the fetched data is marked as invalid.
///
/// The associated `QueryData<V>` object holds the invalidated data.
Invalid(QueryData<V>),
}
impl<V> QueryState<V> {
/// Returns the QueryData for the current QueryState, if present.
pub fn query_data(&self) -> Option<&QueryData<V>> {
match self {
QueryState::Loading | QueryState::Created => None,
QueryState::Fetching(data) | QueryState::Loaded(data) | QueryState::Invalid(data) => {
Some(data)
}
}
}
/// Returns the data contained within the QueryState, if present.
pub fn data(&self) -> Option<&V> {
self.query_data().map(|s| &s.data)
}
/// Returns the last updated timestamp for the QueryState, if present.
pub fn updated_at(&self) -> Option<Instant> {
self.query_data().map(|s| s.updated_at)
}
/// Returns the mutable data contained within the QueryState, if present.
pub fn data_mut(&mut self) -> Option<&mut V> {
match self {
QueryState::Loading | QueryState::Created => None,
QueryState::Fetching(data) | QueryState::Loaded(data) | QueryState::Invalid(data) => {
Some(&mut data.data)
}
}
}
/// Maps the data contained within the QueryState, if present.
pub fn map_data<R>(&self, mapper: impl FnOnce(&V) -> R) -> QueryState<R> {
match self {
QueryState::Loading => QueryState::Loading,
QueryState::Created => QueryState::Created,
QueryState::Fetching(data) => QueryState::Fetching(QueryData {
data: mapper(&data.data),
updated_at: data.updated_at,
}),
QueryState::Loaded(data) => QueryState::Loaded(QueryData {
data: mapper(&data.data),
updated_at: data.updated_at,
}),
QueryState::Invalid(data) => QueryState::Invalid(QueryData {
data: mapper(&data.data),
updated_at: data.updated_at,
}),
}
}
}
/// The latest data for a Query.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryData<V> {
/// The Data.
pub data: V,
/// The instant this data was retrieved.
pub updated_at: Instant,
}
impl<V> QueryData<V> {
/// Creates a new QueryData with the given data and the current time as the updated_at timestamp.
pub fn now(data: V) -> Self {
Self {
data,
updated_at: Instant::now(),
}
}
}