use crate::*;
use bevy::ecs::system::SystemState;
use bevy::prelude::*;
use bevy::tasks::futures_lite::future;
use bevy::tasks::{block_on, Task};
use sqlx::{Database, Error, Executor, IntoArguments};
use std::marker::PhantomData;
#[derive(Resource, Debug)]
pub struct SqlxTasks<DB: Database, C: SqlxComponent<DB::Row>> {
pub(crate) components: Vec<(SqlxEventId, bool, Task<Result<Vec<C>, Error>>)>,
_r: PhantomData<DB::Row>,
}
impl<DB: Database, C: SqlxComponent<DB::Row>> Default for SqlxTasks<DB, C> {
fn default() -> Self {
SqlxTasks { components: Vec::new(), _r: PhantomData::<DB::Row> }
}
}
impl<DB: Database + Sync, C: SqlxComponent<DB::Row>> SqlxTasks<DB, C>
where
for<'c> &'c mut <DB as Database>::Connection: Executor<'c, Database = DB>,
for<'q> <DB as Database>::Arguments<'q>: IntoArguments<'q, DB>,
{
pub fn handle_tasks(
world: &mut World,
params: &mut SystemState<(
Query<(Entity, Ref<C>)>,
Commands,
ResMut<Self>,
EventWriter<SqlxEventStatus<DB, C>>,
)>,
) {
let (mut query, mut commands, mut tasks, mut status) =
params.get_mut(world);
tasks.components.retain_mut(|(id, sync, task)| {
block_on(future::poll_once(task))
.map(|result| {
match result {
Ok(task_components) => {
if *sync {
for task_component in task_components {
let mut existing_entity = None;
for (entity, spawned_component) in
&mut query
{
if task_component.primary_key()
== spawned_component.primary_key()
{
existing_entity = Some(entity);
break;
}
}
if let Some(entity) = existing_entity {
status.send(SqlxEventStatus::Update(
*id,
task_component.primary_key(),
PhantomData,
));
commands
.entity(entity)
.insert(task_component);
} else {
status.send(SqlxEventStatus::Spawn(
*id,
task_component.primary_key(),
PhantomData,
));
commands.spawn(task_component);
}
}
} else {
status.send(SqlxEventStatus::Return(
*id,
task_components,
));
}
}
Err(err) => {
status.send(SqlxEventStatus::Error(*id, err));
}
}
})
.is_none()
});
params.apply(world);
}
}