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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! # Freya Query
//!
//! A powerful, async-focused data management library for Freya applications.
//! Inspired by React Query and SWR, it provides intelligent caching, background
//! updates, and automatic invalidation for async operations.
//!
//! ## Overview
//!
//! Freya Query manages two types of async operations:
//!
//! - **Queries**: Read operations that fetch and cache data
//! - **Mutations**: Write operations that modify data and can invalidate queries
//!
//! ## Key Features
//!
//! - **Automatic Caching**: Query results are cached and reused across components
//! - **Background Refetching**: Stale data is automatically refreshed in the background
//! - **Invalidation**: Mutations can invalidate related queries to keep data fresh
//! - **Deduplication**: Multiple identical queries are automatically deduplicated
//! - **Error Handling**: Built-in error states
//! - **Reactive**: Integrates seamlessly with Freya's reactive state system
//!
//! ## Basic Usage
//!
//! ### Queries
//!
//! ```rust,no_run
//! use freya::{
//! prelude::*,
//! query::*,
//! };
//!
//! # #[derive(Debug)]
//! # struct User;
//!
//! # async fn fetch_user(_id: u32) -> Result<User, String> {
//! # Ok(User)
//! # }
//!
//! // Define a query capability
//! #[derive(Clone, PartialEq, Hash, Eq)]
//! struct FetchUser;
//!
//! impl QueryCapability for FetchUser {
//! type Ok = User;
//! type Err = String;
//! type Keys = u32;
//!
//! async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
//! // Fetch user from API
//! fetch_user(*keys).await
//! }
//! }
//!
//! #[derive(PartialEq)]
//! struct UserProfile(u32);
//!
//! impl Component for UserProfile {
//! fn render(&self) -> impl IntoElement {
//! let user_query = use_query(Query::new(self.0, FetchUser));
//!
//! format!("{:?}", user_query.read().state())
//! }
//! }
//! ```
//!
//! ### Mutations
//!
//! ```rust,no_run
//! use freya::{
//! prelude::*,
//! query::*,
//! };
//!
//! # struct User;
//!
//! # async fn update_user(_id: u32, _name: &str) -> Result<User, String> {
//! # Ok(User)
//! # }
//!
//! #[derive(Clone, PartialEq, Hash, Eq)]
//! struct UpdateUser {
//! id: u32,
//! }
//!
//! // Define a query capability
//! # #[derive(Clone, PartialEq, Hash, Eq)]
//! # struct FetchUser;
//!
//! # impl QueryCapability for FetchUser {
//! # type Ok = User;
//! # type Err = String;
//! # type Keys = u32;
//! #
//! # async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
//! # Ok(User)
//! # }
//! # }
//!
//! impl MutationCapability for UpdateUser {
//! type Ok = ();
//! type Err = String;
//! type Keys = String;
//!
//! async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
//! update_user(self.id, &keys).await?;
//! Ok(())
//! }
//!
//! async fn on_settled(&self, keys: &Self::Keys, result: &Result<Self::Ok, Self::Err>) {
//! if result.is_ok() {
//! QueriesStorage::<FetchUser>::invalidate_matching(self.id).await;
//! }
//! }
//! }
//!
//! #[derive(PartialEq)]
//! struct UserEditor {
//! user_id: u32,
//! }
//!
//! impl Component for UserEditor {
//! fn render(&self) -> impl IntoElement {
//! let mutation = use_mutation(Mutation::new(UpdateUser { id: self.user_id }));
//!
//! Button::new()
//! .child("Update User")
//! .on_press(move |_| mutation.mutate("New Name".to_string()))
//! }
//! }
//! ```
//!
//! ## Advanced Patterns
//!
//! ### Query Invalidation
//!
//! Mutations can invalidate queries to ensure data consistency:
//!
//! ```rust, ignore
//! # use freya::query::*;
//! // Invalidate all user queries
//! QueriesStorage::<FetchUser>::invalidate_all().await;
//!
//! // Invalidate specific user query
//! QueriesStorage::<FetchUser>::invalidate_matching(1).await;
//! ```
//!
//! ### Custom Query Matching
//!
//! Control which queries get invalidated by implementing custom matching logic:
//!
//! ```rust, no_run
//! # use freya::query::*;
//! # #[derive(Hash, Clone, Eq, PartialEq)]
//! # struct FetchUser { id: u32 };
//! impl QueryCapability for FetchUser {
//! # type Ok = ();
//! # type Err = String;
//! # type Keys = u32;
//! // ... other methods
//!
//! # async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
//! # Ok(())
//! # }
//!
//! fn matches(&self, keys: &Self::Keys) -> bool {
//! // Only match queries with the same user ID
//! &self.id == keys
//! }
//! }
//! ```
//!
//! ### Background Refetching
//!
//! Queries automatically refetch data in the background when components remount
//! or when explicitly invalidated by mutations.
//!
//! ## Architecture
//!
//! Freya Query uses a hierarchical caching system:
//!
//! - **Query Store**: Global cache of query results by capability type and keys
//! - **Mutation Store**: Tracks running mutations and their invalidation logic
//! - **Reactive Integration**: Seamlessly integrates with Freya's state management
//!
//! ## Error Handling
//!
//! Both queries and mutations return `Result<T, E>` types. Freya Query provides
//! utilities for handling loading states, errors, and retries.
//!
//! ## Performance
//!
//! - **Queries Deduplication**: Identical concurrent queries are automatically deduplicated
//! - **Smart Caching**: Results are cached until invalidated or expired
//! - **Minimal Re-renders**: Only components reading changed data re-render