freya_query/
lib.rs

1//! # Freya Query
2//!
3//! A powerful, async-focused data management library for Freya applications.
4//! Inspired by React Query and SWR, it provides intelligent caching, background
5//! updates, and automatic invalidation for async operations.
6//!
7//! ## Overview
8//!
9//! Freya Query manages two types of async operations:
10//!
11//! - **Queries**: Read operations that fetch and cache data
12//! - **Mutations**: Write operations that modify data and can invalidate queries
13//!
14//! ## Key Features
15//!
16//! - **Automatic Caching**: Query results are cached and reused across components
17//! - **Background Refetching**: Stale data is automatically refreshed in the background
18//! - **Invalidation**: Mutations can invalidate related queries to keep data fresh
19//! - **Deduplication**: Multiple identical queries are automatically deduplicated
20//! - **Error Handling**: Built-in error states
21//! - **Reactive**: Integrates seamlessly with Freya's reactive state system
22//!
23//! ## Basic Usage
24//!
25//! ### Queries
26//!
27//! ```rust,no_run
28//! use freya::{
29//!     prelude::*,
30//!     query::*,
31//! };
32//!
33//! # #[derive(Debug)]
34//! # struct User;
35//!
36//! # async fn fetch_user(_id: u32) -> Result<User, String> {
37//! #   Ok(User)
38//! # }
39//!
40//! // Define a query capability
41//! #[derive(Clone, PartialEq, Hash, Eq)]
42//! struct FetchUser;
43//!
44//! impl QueryCapability for FetchUser {
45//!     type Ok = User;
46//!     type Err = String;
47//!     type Keys = u32;
48//!
49//!     async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
50//!         // Fetch user from API
51//!         fetch_user(*keys).await
52//!     }
53//! }
54//!
55//! #[derive(PartialEq)]
56//! struct UserProfile(u32);
57//!
58//! impl Component for UserProfile {
59//!     fn render(&self) -> impl IntoElement {
60//!         let user_query = use_query(Query::new(self.0, FetchUser));
61//!
62//!         format!("{:?}", user_query.read().state())
63//!     }
64//! }
65//! ```
66//!
67//! ### Mutations
68//!
69//! ```rust,no_run
70//! use freya::{
71//!     prelude::*,
72//!     query::*,
73//! };
74//!
75//! # struct User;
76//!
77//! # async fn update_user(_id: u32, _name: &str) -> Result<User, String> {
78//! #   Ok(User)
79//! # }
80//!
81//! #[derive(Clone, PartialEq, Hash, Eq)]
82//! struct UpdateUser {
83//!     id: u32,
84//! }
85//!
86//! // Define a query capability
87//! # #[derive(Clone, PartialEq, Hash, Eq)]
88//! # struct FetchUser;
89//!
90//! # impl QueryCapability for FetchUser {
91//! #    type Ok = User;
92//! #    type Err = String;
93//! #    type Keys = u32;
94//! #
95//! #    async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
96//! #        Ok(User)
97//! #    }
98//! # }
99//!
100//! impl MutationCapability for UpdateUser {
101//!     type Ok = ();
102//!     type Err = String;
103//!     type Keys = String;
104//!
105//!     async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
106//!         update_user(self.id, &keys).await?;
107//!         Ok(())
108//!     }
109//!
110//!     async fn on_settled(&self, keys: &Self::Keys, result: &Result<Self::Ok, Self::Err>) {
111//!         if result.is_ok() {
112//!             QueriesStorage::<FetchUser>::invalidate_matching(self.id).await;
113//!         }
114//!     }
115//! }
116//!
117//! #[derive(PartialEq)]
118//! struct UserEditor {
119//!     user_id: u32,
120//! }
121//!
122//! impl Component for UserEditor {
123//!     fn render(&self) -> impl IntoElement {
124//!         let mutation = use_mutation(Mutation::new(UpdateUser { id: self.user_id }));
125//!
126//!         Button::new()
127//!             .child("Update User")
128//!             .on_press(move |_| mutation.mutate("New Name".to_string()))
129//!     }
130//! }
131//! ```
132//!
133//! ## Advanced Patterns
134//!
135//! ### Query Invalidation
136//!
137//! Mutations can invalidate queries to ensure data consistency:
138//!
139//! ```rust, ignore
140//! # use freya::query::*;
141//! // Invalidate all user queries
142//! QueriesStorage::<FetchUser>::invalidate_all().await;
143//!
144//! // Invalidate specific user query
145//! QueriesStorage::<FetchUser>::invalidate_matching(1).await;
146//! ```
147//!
148//! ### Custom Query Matching
149//!
150//! Control which queries get invalidated by implementing custom matching logic:
151//!
152//! ```rust, no_run
153//! # use freya::query::*;
154//! # #[derive(Hash, Clone, Eq, PartialEq)]
155//! # struct FetchUser { id: u32 };
156//! impl QueryCapability for FetchUser {
157//!     # type Ok = ();
158//!     # type Err = String;
159//!     # type Keys = u32;
160//!     // ... other methods
161//!
162//!     # async fn run(&self, keys: &Self::Keys) -> Result<Self::Ok, Self::Err> {
163//!     #     Ok(())
164//!     # }
165//!
166//!     fn matches(&self, keys: &Self::Keys) -> bool {
167//!         // Only match queries with the same user ID
168//!         &self.id == keys
169//!     }
170//! }
171//! ```
172//!
173//! ### Background Refetching
174//!
175//! Queries automatically refetch data in the background when components remount
176//! or when explicitly invalidated by mutations.
177//!
178//! ## Architecture
179//!
180//! Freya Query uses a hierarchical caching system:
181//!
182//! - **Query Store**: Global cache of query results by capability type and keys
183//! - **Mutation Store**: Tracks running mutations and their invalidation logic
184//! - **Reactive Integration**: Seamlessly integrates with Freya's state management
185//!
186//! ## Error Handling
187//!
188//! Both queries and mutations return `Result<T, E>` types. Freya Query provides
189//! utilities for handling loading states, errors, and retries.
190//!
191//! ## Performance
192//!
193//! - **Queries Deduplication**: Identical concurrent queries are automatically deduplicated
194//! - **Smart Caching**: Results are cached until invalidated or expired
195//! - **Minimal Re-renders**: Only components reading changed data re-render
196
197pub mod captured;
198pub mod mutation;
199pub mod query;
200
201pub mod prelude {
202    pub use crate::{
203        captured::*,
204        mutation::*,
205        query::*,
206    };
207}