use std::{
any::TypeId,
collections::HashMap,
sync::{Arc, OnceLock, RwLock},
};
use crate::core::condition::SqlValue;
#[derive(Debug, Clone)]
pub struct OrmError(pub String);
impl OrmError {
pub fn new(msg: impl Into<String>) -> Self {
Self(msg.into())
}
}
impl std::fmt::Display for OrmError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}
impl std::error::Error for OrmError {}
pub type OrmResult<T = ()> = Result<T, OrmError>;
pub trait ModelHooks: Sized {
fn before_create(&mut self) -> OrmResult<()> {
Ok(())
}
fn after_create(&self) {}
fn before_update(&mut self, _dirty: &[&str]) -> OrmResult<()> {
Ok(())
}
fn after_update(&self) {}
fn before_save(&mut self) -> OrmResult<()> {
Ok(())
}
fn after_save(&self) {}
fn before_delete(&self) -> OrmResult<()> {
Ok(())
}
fn after_delete(&self) {}
}
pub trait Observer<T: Send + Sync + 'static>: Send + Sync + 'static {
fn creating(&self, _model: &mut T) -> OrmResult<()> {
Ok(())
}
fn created(&self, _model: &T) {}
fn updating(&self, _model: &mut T, _dirty: &[&str]) -> OrmResult<()> {
Ok(())
}
fn updated(&self, _model: &T) {}
fn saving(&self, _model: &mut T) -> OrmResult<()> {
Ok(())
}
fn saved(&self, _model: &T) {}
fn deleting(&self, _model: &T) -> OrmResult<()> {
Ok(())
}
fn deleted(&self, _model: &T) {}
}
#[allow(clippy::type_complexity)]
static OBSERVER_REGISTRY: OnceLock<
RwLock<HashMap<TypeId, Vec<Arc<dyn std::any::Any + Send + Sync>>>>,
> = OnceLock::new();
#[allow(clippy::type_complexity)]
fn observer_registry() -> &'static RwLock<HashMap<TypeId, Vec<Arc<dyn std::any::Any + Send + Sync>>>>
{
OBSERVER_REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
#[allow(dead_code)]
struct ObserverWrapper<T: Send + Sync + 'static>(Arc<dyn Observer<T>>);
unsafe impl<T: Send + Sync + 'static> Send for ObserverWrapper<T> {}
unsafe impl<T: Send + Sync + 'static> Sync for ObserverWrapper<T> {}
pub fn observe<T: Send + Sync + 'static, Obs: Observer<T>>(obs: Obs) {
let type_id = TypeId::of::<T>();
let wrapped: Arc<dyn std::any::Any + Send + Sync> =
Arc::new(ObserverWrapper::<T>(Arc::new(obs)));
observer_registry()
.write()
.unwrap()
.entry(type_id)
.or_default()
.push(wrapped);
}
pub fn dispatch_creating<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) -> OrmResult<()> {
if observers_muted() {
return Ok(());
}
Ok(())
}
pub fn dispatch_created<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) {
if observers_muted() {}
}
pub fn dispatch_updating<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) -> OrmResult<()> {
if observers_muted() {
return Ok(());
}
Ok(())
}
pub fn dispatch_updated<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) {
if observers_muted() {}
}
pub fn dispatch_deleting<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) -> OrmResult<()> {
if observers_muted() {
return Ok(());
}
Ok(())
}
pub fn dispatch_deleted<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) {
if observers_muted() {}
}
pub fn dispatch_saving<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) -> OrmResult<()> {
if observers_muted() {
return Ok(());
}
Ok(())
}
pub fn dispatch_saved<T: 'static>(_table: &str, _data: &[(&str, SqlValue)]) {
if observers_muted() {}
}
pub fn clear_observers<T: Send + Sync + 'static>() {
let type_id = TypeId::of::<T>();
observer_registry().write().unwrap().remove(&type_id);
}
thread_local! {
static MUTE_OBSERVERS: std::cell::RefCell<bool> = const { std::cell::RefCell::new(false) };
}
pub async fn without_events<F, Fut, T, E>(f: F) -> Result<T, E>
where
F: FnOnce() -> Fut,
Fut: std::future::Future<Output = Result<T, E>>,
{
MUTE_OBSERVERS.with(|m| *m.borrow_mut() = true);
let result = f().await;
MUTE_OBSERVERS.with(|m| *m.borrow_mut() = false);
result
}
pub fn observers_muted() -> bool {
MUTE_OBSERVERS.with(|m| *m.borrow())
}