4 releases
0.2.2 | Feb 3, 2025 |
---|---|
0.2.1 | Feb 1, 2025 |
0.2.0 | Jan 25, 2025 |
0.1.0 | Jan 24, 2025 |
#273 in Game dev
451 downloads per month
42KB
889 lines
Bevy Cached Query
Simple query library for Bevy based on async tasks and Observer API very loosely inspired by TanStack Query.
Usage
Add the plugin to your Bevy app
App::build()
.add_plugins(DefaultPlugins)
.add_plugin(CachedQueryPlugin)
.run();
Trigger a request
commands.trigger(QueryBuilder::default()
.method(Method::Get)
.url("www.example.com")
.build()
.unwrap());
This will be added to the query cache, any subsequent calls to the same url will return the cached response. Only the url is used to determine if a query is a duplicate, any other fields will be ignored.
Systems can then extract the reponse from the cache
#[derive(Deserialize)]
pub struct MyResponse {
pub msg: String,
}
let response = query_extractor::<MyResponse>(
QueryConsumable {
url: url.to_string(),
..Default::default()
},
&mut store.cache,
);
if let Ok(r) = response {
assert_eq!(r.msg, "success");
}
query_key
field can be used to avoid caching queries with the same url.
force_next_refetch
set to true removes the query from the cache after it has been extracted.
ErrorTriggerEvent
is fired any time a query reponds with an error. Using the Observer API you can listen for the event and handle errors.
fn api_error_triggered(
t: Trigger<ErrorTriggerEvent>,
mut app_res: ResMut<ApplicationResource>,
mut commands: Commands,
) {
if t.event().error == 401 {
app_res.require_authentication = true;
commands.trigger(AuthenticateUser);
}
}
Ordered queries can be used with Sequence:
commands.trigger(QuerySequence {
key: "authenticate_user_flow".to_string(),
tasks: vec![
QueryBuilder::default()
.method(Method::Post)
.url(endpoint_from_base("api/user/auth".to_string()))
.body(serde_json::json!({
"username": ...,
"password": ...
}))
.query_key("user_auth".to_string())
.build()
.unwrap(),
QueryBuilder::default()
.method(Method::Post)
.url(endpoint_from_base("api/user/profile".to_string()))
.headers(vec![("Authorization".to_string(), token)])
.body(serde_json::json!({
"bio": ...,
}))
.query_key("update_profile".to_string())
.build()
.unwrap(),
]
.into(),
});
Then you can consume the requests from within a system:
let sequence = vec![
QueryConsumable {
url: endpoint_from_base("api/user/auth".to_string()),
query_key: Some("user_auth".to_string()),
..default()
},
QueryConsumable {
url: endpoint_from_base("api/user/profile".to_string()),
query_key: Some("update_profile".to_string()),
..default()
},
];
// bypassing here so we can run the system only when the store changes
if !check_completed_queries(sequence.clone(), &mut query_store.bypass_change_detection().cache) {
return;
}
let response_user = query_extractor::<ResponseUser>(
sequence[0].clone(),
&mut query_store.bypass_change_detection().cache,
);
let scores = query_extractor::<Vec<TimeseriesItem>>(
sequence[1].clone(),
&mut query_store.bypass_change_detection().cache,
);
Todo
- Add staletime functionality
- Implement and_then for sequence queries to retrieve previous value
- Strategy to return early for systems using query_extractor that have already consumed a result until signaled otherwise
Bevy version support
bevy | bevy_cached_query |
---|---|
0.15 | 0.2.1, main |
0.14 | 0.2 |
Dependencies
~62–100MB
~2M SLoC