use std::collections::BTreeMap;
use batpak::event::EventKind;
use syncbat::effect_backend::{EffectBackend, EffectError};
use crate::schema::{SchemaRegistry, SchemaRole};
pub struct ValidatingEffectBackend {
inner: Box<dyn EffectBackend>,
bindings: BTreeMap<u16, String>,
registry: SchemaRegistry,
}
impl ValidatingEffectBackend {
#[must_use]
pub fn new(
inner: Box<dyn EffectBackend>,
bindings: BTreeMap<u16, String>,
registry: SchemaRegistry,
) -> Self {
Self {
inner,
bindings,
registry,
}
}
}
impl EffectBackend for ValidatingEffectBackend {
fn read_event(&mut self, event_category: &str) -> Result<(), EffectError> {
self.inner.read_event(event_category)
}
fn query_projection(&mut self, projection_id: &str) -> Result<(), EffectError> {
self.inner.query_projection(projection_id)
}
fn emit_receipt(&mut self, receipt_kind: &str) -> Result<(), EffectError> {
self.inner.emit_receipt(receipt_kind)
}
fn use_host_control(&mut self, control: &str) -> Result<(), EffectError> {
self.inner.use_host_control(control)
}
fn append_event(&mut self, kind: EventKind, payload: &[u8]) -> Result<(), EffectError> {
let kind_raw = kind.as_raw_u16();
let schema_ref = self.bindings.get(&kind_raw).ok_or_else(|| {
EffectError::new(format!(
"event kind 0x{kind_raw:04x} has no payload schema binding"
))
})?;
self.registry
.validate(schema_ref, SchemaRole::EventPayload, payload)
.map_err(|error| {
EffectError::new(format!(
"event kind 0x{kind_raw:04x} payload schema validation failed: {error}"
))
})?;
self.inner.append_event(kind, payload)
}
}