<p align="center">
<img src="https://dreamstack-us.github.io/rs-query/logo.png" alt="rs-query" width="400">
</p>
<p align="center">
<strong>TanStack Query-inspired async state management for <a href="https://gpui.rs">GPUI</a></strong>
</p>
<p align="center">
<a href="https://crates.io/crates/rs-query"><img src="https://img.shields.io/crates/v/rs-query.svg" alt="crates.io"></a>
<a href="https://docs.rs/rs-query"><img src="https://docs.rs/rs-query/badge.svg" alt="docs.rs"></a>
<a href="https://github.com/DreamStack-us/rs-query/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
</p>
---
> **A note on this project's origins:**
>
> This library was built by a developer with minimal Rust experience, with significant assistance from Claude (Opus 4.5). It's an honest attempt to bring TanStack Query patterns to the GPUI ecosystem.
>
> **This is not production-ready.** It's an early alpha (v0.0.1) that needs:
> - More comprehensive unit tests (aspiring to follow standards set by `tokio`, `serde`, etc.)
> - Real-world battle testing
> - API refinement based on community feedback
>
> **Contributions, criticism, and feedback are warmly welcomed.** If you're an experienced Rustacean, your guidance would be invaluable. Open an issue, submit a PR, or just tell us what we got wrong.
---
```rust
spawn_query(cx, &client, &query, |this, state, cx| {
match state {
QueryState::Success(users) => this.users = users,
QueryState::Error { error, .. } => this.error = Some(error),
_ => {}
}
cx.notify();
});
```
## Features
- **`spawn_query` / `spawn_mutation`** — One-liner async execution with automatic state management
- **Stale-while-revalidate** — Show cached data instantly while fetching fresh data
- **Automatic retries** — Exponential backoff for transient failures
- **Cache invalidation** — Hierarchical key patterns for precise cache control
- **GPUI-native** — Built for GPUI's context and reactive model
## Installation
```toml
[dependencies]
rs-query = "0.0.1"
```
## Quick Start
```rust
use rs_query::{QueryClient, QueryKey, QueryState, Query, spawn_query};
use gpui::*;
struct MyView {
client: QueryClient,
users: Vec<User>,
loading: bool,
}
impl MyView {
fn fetch_users(&mut self, cx: &mut Context<Self>) {
let query = Query::new(
QueryKey::new("users"),
|| async { fetch_users_from_api().await }
);
spawn_query(cx, &self.client, &query, |this, state, cx| {
match state {
QueryState::Loading => {
this.loading = true;
}
QueryState::Success(users) => {
this.users = users;
this.loading = false;
}
QueryState::Error { error, retry_count } => {
eprintln!("Failed after {} retries: {}", retry_count, error);
this.loading = false;
}
QueryState::Stale(users) => {
// Show stale data while refetching
this.users = users;
}
}
cx.notify();
});
}
}
```
## Mutations
```rust
use rs_query::{Mutation, MutationState, spawn_mutation};
});
MutationState::Success(user) => {
this.users.push(user);
// Invalidate related queries
this.client.invalidate(&QueryKey::new("users"));
}
MutationState::Error(e) => this.error = Some(e),
_ => {}
}
cx.notify();
});
```
## Query Keys
Hierarchical keys for cache management:
```rust
// Simple key
let key = QueryKey::new("users");
// Nested key
let key = QueryKey::new("users").push("123").push("posts");
// Invalidate all user queries
client.invalidate(&QueryKey::new("users"));
```
## Configuration
```rust
use rs_query::{Query, QueryOptions, RetryConfig, RefetchOnMount};
let query = Query::new(QueryKey::new("users"), fetch_users)
.with_options(
QueryOptions::new()
.stale_time(Duration::from_secs(60))
.cache_time(Duration::from_secs(300))
.retry(RetryConfig::new(3).with_base_delay(Duration::from_millis(500)))
.refetch_on_mount(RefetchOnMount::Stale)
);
```
## Why rs-query?
If you're building GPUI apps with async data fetching, you've probably written this pattern dozens of times:
```rust
this.update(&mut cx, |this, cx| {
this.data = result;
cx.notify();
});
});
```
rs-query handles loading states, caching, retries, and cache invalidation — so you can focus on your app.
## Roadmap
- [ ] Comprehensive test suite
- [ ] Benchmarks
- [ ] Query devtools
- [ ] Infinite queries
- [ ] Optimistic updates
- [ ] Persistence adapters
## Contributing
This project needs your help! Whether you're:
- An experienced Rustacean who can improve the internals
- A GPUI user who can provide real-world feedback
- Someone who can write tests and documentation
...we'd love to hear from you. See [CONTRIBUTING.md](CONTRIBUTING.md) or open an issue.
## License
MIT — Built by [DreamStack](https://dreamstack.us)