use crate::error::{MeiliBridgeError, Result};
use crate::models::{stream_event::Event, CdcEvent, EventType};
use serde_json::Value;
use tracing::{debug, warn};
pub struct BatchProcessor {
pub documents_to_upsert: Vec<Value>,
pub documents_to_delete: Vec<String>,
primary_key: Option<String>,
}
impl BatchProcessor {
pub fn new(primary_key: Option<String>) -> Self {
Self {
documents_to_upsert: Vec::new(),
documents_to_delete: Vec::new(),
primary_key,
}
}
pub fn process_event(&mut self, event: Event) -> Result<()> {
match event {
Event::Cdc(cdc_event) => self.process_cdc_event(cdc_event),
Event::FullSync { data, .. } => {
self.documents_to_upsert.push(data);
Ok(())
}
_ => {
debug!("Skipping non-data event");
Ok(())
}
}
}
fn process_cdc_event(&mut self, event: CdcEvent) -> Result<()> {
match event.event_type {
EventType::Create | EventType::Update => {
let document = serde_json::to_value(event.data).unwrap_or(Value::Null);
self.documents_to_upsert.push(document);
}
EventType::Delete => {
if let Some(pk_field) = &self.primary_key {
if let Some(pk_value) = event.data.get(pk_field) {
if let Some(id) = pk_value.as_str() {
self.documents_to_delete.push(id.to_string());
} else if let Some(id) = pk_value.as_i64() {
self.documents_to_delete.push(id.to_string());
} else {
warn!(
"Primary key value is not a string or number: {:?}",
pk_value
);
}
} else {
return Err(MeiliBridgeError::Meilisearch(format!(
"Missing primary key field '{}' in delete event",
pk_field
)));
}
} else {
return Err(MeiliBridgeError::Meilisearch(
"No primary key configured for delete operations".to_string(),
));
}
}
_ => {
debug!("Skipping event type: {:?}", event.event_type);
}
}
Ok(())
}
pub fn clear(&mut self) {
self.documents_to_upsert.clear();
self.documents_to_delete.clear();
}
pub fn is_empty(&self) -> bool {
self.documents_to_upsert.is_empty() && self.documents_to_delete.is_empty()
}
pub fn len(&self) -> usize {
self.documents_to_upsert.len() + self.documents_to_delete.len()
}
}