#![allow(dead_code, clippy::type_complexity)]
use std::{
any::TypeId,
collections::HashMap,
sync::{Arc, RwLock},
};
use crate::core::model::Model;
use crate::core::query::QueryBuilder;
pub trait GlobalScope<T: Model>: Send + Sync + 'static {
fn apply(&self, builder: QueryBuilder<T>) -> QueryBuilder<T>;
}
static TYPED_REGISTRY: std::sync::OnceLock<
RwLock<HashMap<TypeId, Vec<Box<dyn std::any::Any + Send + Sync>>>>,
> = std::sync::OnceLock::new();
fn typed_registry() -> &'static RwLock<HashMap<TypeId, Vec<Box<dyn std::any::Any + Send + Sync>>>> {
TYPED_REGISTRY.get_or_init(|| RwLock::new(HashMap::new()))
}
struct ScopeWrapper<T: Model>(Arc<dyn GlobalScope<T>>);
unsafe impl<T: Model + Send> Send for ScopeWrapper<T> {}
unsafe impl<T: Model + Sync> Sync for ScopeWrapper<T> {}
pub fn register<T: Model + Send + Sync + 'static>(scope: impl GlobalScope<T>) {
let type_id = TypeId::of::<T>();
let wrapper: Box<dyn std::any::Any + Send + Sync> =
Box::new(ScopeWrapper::<T>(Arc::new(scope)));
typed_registry()
.write()
.unwrap()
.entry(type_id)
.or_default()
.push(wrapper);
}
pub fn apply_scopes<T: Model + Send + Sync + 'static>(
mut builder: QueryBuilder<T>,
) -> QueryBuilder<T> {
let type_id = TypeId::of::<T>();
let reg = typed_registry().read().unwrap();
if let Some(entries) = reg.get(&type_id) {
for entry in entries {
if let Some(wrapper) = entry.downcast_ref::<ScopeWrapper<T>>() {
builder = wrapper.0.apply(builder);
}
}
}
builder
}
pub fn has_scopes<T: Model + 'static>() -> bool {
let type_id = TypeId::of::<T>();
typed_registry()
.read()
.unwrap()
.get(&type_id)
.map(|v| !v.is_empty())
.unwrap_or(false)
}
pub fn clear_scopes<T: Model + 'static>() {
let type_id = TypeId::of::<T>();
typed_registry().write().unwrap().remove(&type_id);
}