use crate::{AggregateRoot, Entity};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct StreamRevision(u64);
impl StreamRevision {
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn value(self) -> u64 {
self.0
}
pub const fn next(self) -> Option<Self> {
match self.0.checked_add(1) {
Some(value) => Some(Self(value)),
None => None,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct NoStream;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExpectedRevision {
NoStream(NoStream),
Revision(StreamRevision),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CurrentRevision {
NoStream(NoStream),
Revision(StreamRevision),
}
#[derive(Debug, Eq, PartialEq)]
pub struct StreamHistory<E> {
events: Vec<E>,
revision: StreamRevision,
}
impl<E> StreamHistory<E> {
pub fn try_new(events: Vec<E>, revision: StreamRevision) -> Result<Self, StreamHistoryError> {
if events.is_empty() {
return Err(StreamHistoryError::Empty);
}
let event_count =
u64::try_from(events.len()).map_err(|_| StreamHistoryError::TooManyEvents)?;
let expected = StreamRevision::new(event_count - 1);
if revision != expected {
return Err(StreamHistoryError::RevisionMismatch {
expected,
actual: revision,
});
}
Ok(Self { events, revision })
}
pub fn events(&self) -> &[E] {
&self.events
}
pub fn revision(&self) -> StreamRevision {
self.revision
}
pub fn into_events(self) -> Vec<E> {
self.events
}
pub fn events_after(&self, revision: StreamRevision) -> Option<&[E]> {
if revision > self.revision {
return None;
}
let start = usize::try_from(revision.value()).ok()?.checked_add(1)?;
Some(&self.events[start..])
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum StreamHistoryError {
Empty,
TooManyEvents,
RevisionMismatch {
expected: StreamRevision,
actual: StreamRevision,
},
}
#[derive(Debug, Eq, PartialEq)]
pub enum LoadResult<E> {
NoStream(NoStream),
Found(StreamHistory<E>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AppendResult {
pub resulting_revision: StreamRevision,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RevisionConflict {
pub expected: ExpectedRevision,
pub current: CurrentRevision,
}
#[derive(Debug, Eq, PartialEq)]
pub enum AppendError<E> {
EmptyBatch,
Conflict(RevisionConflict),
Adapter(E),
RevisionExhausted {
current: StreamRevision,
},
}
pub trait EventStore {
type Aggregate: AggregateRoot;
type Error;
fn load(
&self,
id: &<Self::Aggregate as Entity>::Id,
) -> Result<LoadResult<<Self::Aggregate as AggregateRoot>::Event>, Self::Error>;
fn append(
&mut self,
id: &<Self::Aggregate as Entity>::Id,
expected: ExpectedRevision,
events: Vec<<Self::Aggregate as AggregateRoot>::Event>,
) -> Result<AppendResult, AppendError<Self::Error>>;
}