use crate::event::DomainEvent;
use std::fmt::Debug;
mod root;
pub use root::*;
pub trait Aggregate: Sized + Clone {
const SNAPSHOT_VERSION: u64;
type AggregateId: Clone + Debug + Eq + PartialEq;
type DomainEvent: Clone + Debug + Eq + PartialEq + DomainEvent;
type ApplyError;
type SideEffect: SideEffect;
fn aggregate_id(&self) -> &Self::AggregateId;
fn apply_new(event: &Self::DomainEvent) -> Result<Self, Self::ApplyError>;
fn apply(&mut self, event: &Self::DomainEvent) -> Result<(), Self::ApplyError>;
fn side_effects(&self, event: &Self::DomainEvent) -> Option<Vec<Self::SideEffect>>;
}
pub trait SideEffect {
type SideEffectId;
fn id(&self) -> &Self::SideEffectId;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_fixtures::*;
#[test]
fn test_aggregate_creation() {
let reset_event = create_reset_event("reset-1", "calc-1");
let calc = TestCounter::apply_new(&reset_event).unwrap();
assert_eq!(calc.id, "calc-1");
assert_eq!(calc.result, 0);
assert_eq!(calc.operations_count, 0);
}
#[test]
fn test_aggregate_creation_with_invalid_event() {
let add_event = create_add_event("add-1", 10);
let result = TestCounter::apply_new(&add_event);
assert!(matches!(result, Err(TestError::InvalidOperation)));
}
#[test]
fn test_aggregate_apply_events() {
let reset_event = create_reset_event("reset-1", "calc-1");
let mut calc = TestCounter::apply_new(&reset_event).unwrap();
let add_event = create_add_event("add-1", 15);
calc.apply(&add_event).unwrap();
assert_eq!(calc.result, 15);
assert_eq!(calc.operations_count, 1);
let subtract_event = create_subtract_event("sub-1", 5);
calc.apply(&subtract_event).unwrap();
assert_eq!(calc.result, 10);
assert_eq!(calc.operations_count, 2);
let multiply_event = create_multiply_event("mul-1", 3);
calc.apply(&multiply_event).unwrap();
assert_eq!(calc.result, 30);
assert_eq!(calc.operations_count, 3);
}
#[test]
fn test_aggregate_apply_error() {
let reset_event = create_reset_event("reset-1", "calc-1");
let mut calc = TestCounter::apply_new(&reset_event).unwrap();
let another_reset = create_reset_event("reset-2", "calc-2");
let result = calc.apply(&another_reset);
assert!(matches!(result, Err(TestError::InvalidOperation)));
let multiply_zero = create_multiply_event("mul-zero", 0);
let result = calc.apply(&multiply_zero);
assert!(matches!(result, Err(TestError::DivisionByZero)));
}
#[test]
fn test_side_effects_generation() {
let reset_event = create_reset_event("reset-1", "calc-1");
let calc = TestCounter::apply_new(&reset_event).unwrap();
let side_effects = calc.side_effects(&reset_event);
assert!(side_effects.is_some());
let effects = side_effects.unwrap();
assert_eq!(effects.len(), 2);
let add_event = create_add_event("add-1", 10);
let side_effects = calc.side_effects(&add_event);
assert!(side_effects.is_some());
let effects = side_effects.unwrap();
assert_eq!(effects.len(), 1);
let multiply_event = create_multiply_event("mul-1", 2);
let side_effects = calc.side_effects(&multiply_event);
assert!(side_effects.is_none());
}
#[test]
fn test_aggregate_id() {
let reset_event = create_reset_event("reset-1", "my-counter");
let calc = TestCounter::apply_new(&reset_event).unwrap();
assert_eq!(calc.aggregate_id(), "my-counter");
}
#[test]
fn test_snapshot_version() {
assert_eq!(TestCounter::SNAPSHOT_VERSION, 1);
}
}