use futures::future::BoxFuture;
use mockall::automock;
use serde_json::Value;
use std::fmt;
use std::sync::Arc;
use bevy::prelude::Resource;
use crate::query::persistence_query_specification::PersistenceQuerySpecification;
pub const BEVY_PERSISTENCE_VERSION_FIELD: &str = "bevy_persistence_version";
#[derive(Debug, Clone, Copy, serde::Serialize)]
pub enum Collection {
Entities,
Resources,
}
impl std::fmt::Display for Collection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Collection::Entities => write!(f, "entities"),
Collection::Resources => write!(f, "resources"),
}
}
}
#[derive(Debug, Clone)]
pub enum PersistenceError {
General(String),
Conflict { key: String },
}
impl fmt::Display for PersistenceError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PersistenceError::General(msg) => write!(f, "Persistence Error: {}", msg),
PersistenceError::Conflict { key } => write!(f, "Version conflict for key: {}", key),
}
}
}
impl std::error::Error for PersistenceError {}
impl PersistenceError {
pub fn new(msg: impl Into<String>) -> Self {
PersistenceError::General(msg.into())
}
}
#[derive(serde::Serialize, Debug, Clone)]
pub enum TransactionOperation {
CreateDocument {
collection: Collection,
data: Value,
},
UpdateDocument {
collection: Collection,
key: String,
expected_current_version: u64,
patch: Value,
},
DeleteDocument {
collection: Collection,
key: String,
expected_current_version: u64,
},
}
#[automock]
pub trait DatabaseConnection: Send + Sync + std::fmt::Debug {
fn document_key_field(&self) -> &'static str;
fn execute_keys(
&self,
spec: &PersistenceQuerySpecification,
) -> BoxFuture<'static, Result<Vec<String>, PersistenceError>>;
fn execute_documents(
&self,
spec: &PersistenceQuerySpecification,
) -> BoxFuture<'static, Result<Vec<Value>, PersistenceError>>;
fn execute_documents_sync(
&self,
_spec: &PersistenceQuerySpecification,
) -> Result<Vec<Value>, PersistenceError> {
panic!("execute_documents_sync not implemented");
}
fn execute_transaction(
&self,
operations: Vec<TransactionOperation>,
) -> BoxFuture<'static, Result<Vec<String>, PersistenceError>>;
fn fetch_document(
&self,
entity_key: &str,
) -> BoxFuture<'static, Result<Option<(Value, u64)>, PersistenceError>>;
fn fetch_component(
&self,
entity_key: &str,
comp_name: &str,
) -> BoxFuture<'static, Result<Option<Value>, PersistenceError>>;
fn fetch_resource(
&self,
resource_name: &str,
) -> BoxFuture<'static, Result<Option<(Value, u64)>, PersistenceError>>;
fn clear_entities(&self) -> BoxFuture<'static, Result<(), PersistenceError>>;
fn clear_resources(&self) -> BoxFuture<'static, Result<(), PersistenceError>>;
fn count_documents(
&self,
spec: &PersistenceQuerySpecification,
) -> BoxFuture<'static, Result<usize, PersistenceError>>;
}
#[derive(Resource)]
pub struct DatabaseConnectionResource(pub Arc<dyn DatabaseConnection>);
impl std::ops::Deref for DatabaseConnectionResource {
type Target = Arc<dyn DatabaseConnection>;
fn deref(&self) -> &Self::Target {
&self.0
}
}