use crate::common::{ReadExecutor, WriteExecutor};
use crate::errors::NitriteResult;
use crate::{atomic, get_current_time_or_zero, Atomic, Value};
use anyhow::Error;
use basu::error::BasuError;
use basu::event::Event;
use basu::Handle;
use std::fmt::Debug;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq)]
pub enum CollectionEvents {
Insert,
Update,
Remove,
IndexStart,
IndexEnd,
}
#[derive(Clone)]
pub struct CollectionEventInfo {
inner: Arc<CollectionEventInner>,
}
impl CollectionEventInfo {
pub fn new(item: Option<Value>, event_type: CollectionEvents, originator: String) -> Self {
CollectionEventInfo {
inner: Arc::new(CollectionEventInner::new(item, event_type, originator)),
}
}
pub fn event_type(&self) -> CollectionEvents {
self.inner.event_type.clone()
}
pub fn item(&self) -> Option<Value> {
self.inner.item.clone()
}
pub fn originator(&self) -> String {
self.inner.originator.read_with(|x| x.clone())
}
pub fn timestamp(&self) -> u128 {
self.inner.timestamp
}
pub(crate) fn set_originator(&self, originator: String) {
self.inner.set_originator(originator);
}
}
impl Debug for CollectionEventInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CollectionEventInfo")
.field("item", &self.item())
.field("event_type", &self.event_type())
.field("timestamp", &self.timestamp())
.field("originator", &self.originator())
.finish()
}
}
pub(crate) struct CollectionEventInner {
item: Option<Value>,
event_type: CollectionEvents,
timestamp: u128,
originator: Atomic<String>,
}
impl CollectionEventInner {
fn new(item: Option<Value>, event_type: CollectionEvents, originator: String) -> Self {
CollectionEventInner {
item,
event_type,
timestamp: get_current_time_or_zero(),
originator: atomic(originator),
}
}
fn set_originator(&self, originator: String) {
self.originator.write_with(|o| *o = originator);
}
}
pub trait CollectionEventCallback: Send + Sync + Fn(CollectionEventInfo) -> NitriteResult<()> {}
impl<F> CollectionEventCallback for F
where
F: Send + Sync + Fn(CollectionEventInfo) -> NitriteResult<()>,
{
}
#[derive(Clone)]
pub struct CollectionEventListener {
on_event: Arc<dyn CollectionEventCallback>,
}
impl CollectionEventListener {
pub fn new(on_event: impl CollectionEventCallback + 'static) -> Self {
CollectionEventListener {
on_event: Arc::new(on_event),
}
}
}
impl Handle<CollectionEventInfo> for CollectionEventListener {
fn handle(&self, event: &Event<CollectionEventInfo>) -> Result<(), BasuError> {
match (self.on_event)(event.data.clone()) {
Ok(_) => Ok(()),
Err(e) => Err(BasuError::HandlerError(Error::from(e))),
}
}
}
impl Debug for CollectionEventListener {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CollectionEventListener")
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use basu::event::Event;
use std::sync::Arc;
#[test]
fn test_collection_event_new() {
let item = Some(Value::String("test_item".to_string()));
let event_type = CollectionEvents::Insert;
let originator = "originator".to_string();
let event = CollectionEventInfo::new(item.clone(), event_type.clone(), originator.clone());
assert_eq!(event.item(), item);
assert_eq!(event.event_type(), event_type);
assert_eq!(event.originator(), originator);
}
#[test]
fn test_collection_event_set_originator() {
let item = Some(Value::String("test_item".to_string()));
let event_type = CollectionEvents::Insert;
let originator = "originator".to_string();
let event = CollectionEventInfo::new(item, event_type, originator);
let new_originator = "new_originator".to_string();
event.set_originator(new_originator.clone());
assert_eq!(event.originator(), new_originator);
}
#[test]
fn test_collection_event_listener_new() {
let callback = |_event| Ok(());
let listener = CollectionEventListener::new(callback);
assert!(Arc::strong_count(&listener.on_event) > 0);
}
#[test]
fn test_collection_event_listener_handle() {
let callback = |_event| Ok(());
let listener = CollectionEventListener::new(callback);
let item = Some(Value::String("test_item".to_string()));
let event_type = CollectionEvents::Insert;
let originator = "originator".to_string();
let collection_event = CollectionEventInfo::new(item, event_type, originator);
let event = Event::new(collection_event);
assert!(listener.handle(&event).is_ok());
}
#[test]
fn test_collection_event_debug() {
let item = Some(Value::String("test_item".to_string()));
let event_type = CollectionEvents::Insert;
let originator = "originator".to_string();
let event = CollectionEventInfo::new(item, event_type, originator);
let debug_str = format!("{:?}", event);
assert!(debug_str.contains("CollectionEvent"));
}
}