mod accessors;
mod builder;
mod constructors;
mod events;
mod introspection;
#[cfg(test)]
mod tests;
use std::sync::Arc;
#[cfg(feature = "postgres")]
use stateset_core::CommerceError;
use stateset_db::Database;
use stateset_observability::Metrics;
#[cfg(feature = "events")]
use crate::events::EventSystem;
#[cfg(all(feature = "sqlite", feature = "vector"))]
use stateset_db::SqliteDatabase;
pub use builder::CommerceBuilder;
pub use introspection::CommerceHealth;
#[cfg(feature = "postgres")]
fn block_on_postgres<T, Fut, MakeFut>(make_fut: MakeFut) -> Result<T, CommerceError>
where
T: Send + 'static,
Fut: std::future::Future<Output = Result<T, CommerceError>> + Send + 'static,
MakeFut: FnOnce() -> Fut + Send + 'static,
{
let new_runtime = || {
tokio::runtime::Runtime::new()
.map_err(|e| CommerceError::Internal(format!("Failed to create runtime: {e}")))
};
match tokio::runtime::Handle::try_current() {
Ok(handle)
if matches!(handle.runtime_flavor(), tokio::runtime::RuntimeFlavor::MultiThread) =>
{
tokio::task::block_in_place(|| handle.block_on(make_fut()))
}
Ok(_) => std::thread::spawn(move || {
let rt = new_runtime()?;
rt.block_on(make_fut())
})
.join()
.map_err(|_| {
CommerceError::Internal("PostgreSQL initialization thread panicked".to_string())
})?,
Err(_) => {
let rt = new_runtime()?;
rt.block_on(make_fut())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommerceBackend {
Sqlite,
Postgres,
External,
}
pub struct Commerce {
db: Arc<dyn Database>,
backend: CommerceBackend,
metrics: Metrics,
#[cfg(feature = "events")]
event_system: Arc<EventSystem>,
#[cfg(all(feature = "sqlite", feature = "vector"))]
sqlite_db: Option<Arc<SqliteDatabase>>,
}
impl std::fmt::Debug for Commerce {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Commerce").field("backend", &self.backend).finish_non_exhaustive()
}
}