domain events: DomainEvent enum w/ ID-only variants

This commit is contained in:
2026-07-12 01:29:40 +02:00
parent 6d12ac4c5e
commit 87e7d85239
3 changed files with 126 additions and 24 deletions

View File

@@ -0,0 +1,123 @@
//! Domain events emitted when important state transitions occur.
//!
//! Events carry only IDs — consumers fetch the data they need from
//! repositories. This keeps `Clone` cheap and avoids coupling events
//! to model internals.
use crate::value_objects::{ChannelId, ScheduleId, SlotId};
/// Events emitted by domain aggregates on state transitions.
///
/// Must be `Clone + Send + 'static` so publishers can fan out cheaply.
/// Marked `#[non_exhaustive]` — downstream consumers must handle unknown
/// variants gracefully (wildcard arm).
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum DomainEvent {
/// The active broadcast switched to a new slot.
BroadcastTransition {
channel_id: ChannelId,
slot_id: SlotId,
},
/// No content is currently airing on the channel.
NoSignal { channel_id: ChannelId },
/// A new schedule was generated for a channel.
ScheduleGenerated {
channel_id: ChannelId,
schedule_id: ScheduleId,
},
/// A channel was created.
ChannelCreated { channel_id: ChannelId },
/// A channel configuration was updated.
ChannelUpdated { channel_id: ChannelId },
/// A channel was deleted.
ChannelDeleted { channel_id: ChannelId },
}
#[cfg(test)]
mod tests {
use super::*;
use uuid::Uuid;
#[test]
fn broadcast_transition_carries_ids() {
let ch = ChannelId::from(Uuid::new_v4());
let sl = SlotId::from(Uuid::new_v4());
let event = DomainEvent::BroadcastTransition {
channel_id: ch,
slot_id: sl,
};
match event {
DomainEvent::BroadcastTransition {
channel_id,
slot_id,
} => {
assert_eq!(channel_id, ch);
assert_eq!(slot_id, sl);
}
_ => panic!("wrong variant"),
}
}
#[test]
fn no_signal_carries_channel_id() {
let ch = ChannelId::from(Uuid::new_v4());
let event = DomainEvent::NoSignal { channel_id: ch };
match event {
DomainEvent::NoSignal { channel_id } => assert_eq!(channel_id, ch),
_ => panic!("wrong variant"),
}
}
#[test]
fn schedule_generated_carries_ids() {
let ch = ChannelId::from(Uuid::new_v4());
let sc = ScheduleId::from(Uuid::new_v4());
let event = DomainEvent::ScheduleGenerated {
channel_id: ch,
schedule_id: sc,
};
match event {
DomainEvent::ScheduleGenerated {
channel_id,
schedule_id,
} => {
assert_eq!(channel_id, ch);
assert_eq!(schedule_id, sc);
}
_ => panic!("wrong variant"),
}
}
#[test]
fn channel_lifecycle_events() {
let ch = ChannelId::from(Uuid::new_v4());
let created = DomainEvent::ChannelCreated { channel_id: ch };
let updated = DomainEvent::ChannelUpdated { channel_id: ch };
let deleted = DomainEvent::ChannelDeleted { channel_id: ch };
// All three carry the same channel_id.
for event in [created, updated, deleted] {
match event {
DomainEvent::ChannelCreated { channel_id }
| DomainEvent::ChannelUpdated { channel_id }
| DomainEvent::ChannelDeleted { channel_id } => {
assert_eq!(channel_id, ch);
}
_ => panic!("wrong variant"),
}
}
}
#[test]
fn event_is_clone() {
let ch = ChannelId::from(Uuid::new_v4());
let event = DomainEvent::NoSignal { channel_id: ch };
let cloned = event.clone();
match cloned {
DomainEvent::NoSignal { channel_id } => assert_eq!(channel_id, ch),
_ => panic!("wrong variant"),
}
}
}