use core::marker::PhantomData;
use crate::repository::EventStore;
use crate::store::{RawEventStore, Store};
pub struct NeedsCodec(PhantomData<*const ()>);
impl NeedsCodec {
pub(crate) const fn new() -> Self {
Self(PhantomData)
}
}
pub struct NoSnapshot;
#[cfg(feature = "snapshot")]
pub struct WithSnapshot<SS, T> {
store: SS,
trigger: T,
schema_version: core::num::NonZeroU32,
snapshot_on_read: bool,
}
pub struct RepositoryBuilder<S, C, A, Snap = NoSnapshot, M = ()> {
store: Store<S>,
codec: C,
snapshot: Snap,
meta: M,
aggregate: PhantomData<fn() -> A>,
}
impl<S, C, A, Snap, M> RepositoryBuilder<S, C, A, Snap, M> {
#[must_use]
pub fn codec<NewC>(self, codec: NewC) -> RepositoryBuilder<S, NewC, A, Snap, M> {
RepositoryBuilder {
store: self.store,
codec,
snapshot: self.snapshot,
meta: self.meta,
aggregate: PhantomData,
}
}
#[must_use]
pub fn metadata<NewM>(self, provider: NewM) -> RepositoryBuilder<S, C, A, Snap, NewM> {
RepositoryBuilder {
store: self.store,
codec: self.codec,
snapshot: self.snapshot,
meta: provider,
aggregate: PhantomData,
}
}
}
#[cfg(feature = "json")]
impl<S, C, A, Snap, M> RepositoryBuilder<S, C, A, Snap, M> {
#[must_use]
pub fn json(self) -> RepositoryBuilder<S, crate::JsonCodec, A, Snap, M> {
self.codec(crate::JsonCodec::default())
}
}
impl<S, C, A, M> RepositoryBuilder<S, C, A, NoSnapshot, M>
where
S: RawEventStore,
C: Send + Sync + 'static,
M: Send + Sync + 'static,
{
#[must_use]
pub fn build(self) -> EventStore<S, C, A, M> {
EventStore::new(self.store, self.codec, self.meta)
}
}
#[cfg(feature = "snapshot")]
use super::snapshot::Snapshotting;
#[cfg(feature = "snapshot")]
use crate::state;
#[cfg(feature = "snapshot")]
use core::num::NonZeroU64;
#[cfg(feature = "snapshot")]
const DEFAULT_SNAPSHOT_INTERVAL: u64 = 100;
#[cfg(feature = "snapshot")]
const DEFAULT_SCHEMA_VERSION: core::num::NonZeroU32 = core::num::NonZeroU32::MIN;
#[cfg(feature = "snapshot-json")]
impl<S, C, A, M> RepositoryBuilder<S, C, A, NoSnapshot, M> {
#[must_use]
#[allow(
clippy::expect_used,
reason = "DEFAULT_SNAPSHOT_INTERVAL is non-zero by inspection"
)]
pub fn snapshot_store_json<SS>(
self,
snapshot_store: SS,
) -> RepositoryBuilder<
S,
C,
A,
WithSnapshot<state::CodecSnapshotStore<SS, crate::JsonCodec>, state::EveryNEvents>,
M,
> {
let typed_store =
state::CodecSnapshotStore::new(snapshot_store, crate::JsonCodec::default());
RepositoryBuilder {
store: self.store,
codec: self.codec,
snapshot: WithSnapshot {
store: typed_store,
trigger: state::EveryNEvents(
NonZeroU64::new(DEFAULT_SNAPSHOT_INTERVAL)
.expect("DEFAULT_SNAPSHOT_INTERVAL is non-zero"),
),
schema_version: DEFAULT_SCHEMA_VERSION,
snapshot_on_read: false,
},
meta: self.meta,
aggregate: PhantomData,
}
}
}
#[cfg(feature = "snapshot")]
impl<S, C, A, M> RepositoryBuilder<S, C, A, NoSnapshot, M> {
#[must_use]
#[allow(
clippy::expect_used,
reason = "DEFAULT_SNAPSHOT_INTERVAL is non-zero by inspection"
)]
pub fn snapshot_store<SS>(
self,
snapshot_store: SS,
) -> RepositoryBuilder<S, C, A, WithSnapshot<SS, state::EveryNEvents>, M> {
RepositoryBuilder {
store: self.store,
codec: self.codec,
snapshot: WithSnapshot {
store: snapshot_store,
trigger: state::EveryNEvents(
NonZeroU64::new(DEFAULT_SNAPSHOT_INTERVAL)
.expect("DEFAULT_SNAPSHOT_INTERVAL is non-zero"),
),
schema_version: DEFAULT_SCHEMA_VERSION,
snapshot_on_read: false,
},
meta: self.meta,
aggregate: PhantomData,
}
}
}
#[cfg(feature = "snapshot")]
impl<S, C, A, SS, T, M> RepositoryBuilder<S, C, A, WithSnapshot<SS, T>, M> {
#[must_use]
pub fn snapshot_trigger<NewT: state::PersistTrigger>(
self,
trigger: NewT,
) -> RepositoryBuilder<S, C, A, WithSnapshot<SS, NewT>, M> {
RepositoryBuilder {
store: self.store,
codec: self.codec,
snapshot: WithSnapshot {
store: self.snapshot.store,
trigger,
schema_version: self.snapshot.schema_version,
snapshot_on_read: self.snapshot.snapshot_on_read,
},
meta: self.meta,
aggregate: PhantomData,
}
}
#[must_use]
pub const fn snapshot_schema_version(mut self, version: core::num::NonZeroU32) -> Self {
self.snapshot.schema_version = version;
self
}
#[must_use]
pub const fn snapshot_on_read(mut self, enabled: bool) -> Self {
self.snapshot.snapshot_on_read = enabled;
self
}
}
#[cfg(feature = "snapshot")]
impl<S, C, A, SS, T, M> RepositoryBuilder<S, C, A, WithSnapshot<SS, T>, M>
where
S: RawEventStore,
C: Send + Sync + 'static,
M: Send + Sync + 'static,
{
#[must_use]
pub fn build(self) -> Snapshotting<EventStore<S, C, A, M>, SS, T> {
let inner = EventStore::new(self.store, self.codec, self.meta);
let snap = self.snapshot;
Snapshotting::new(
inner,
snap.store,
snap.trigger,
snap.schema_version,
snap.snapshot_on_read,
)
}
}
impl<S: RawEventStore> Store<S> {
#[must_use]
pub fn repository<A>(&self) -> RepositoryBuilder<S, NeedsCodec, A> {
RepositoryBuilder {
store: self.clone(),
codec: NeedsCodec::new(),
snapshot: NoSnapshot,
meta: (),
aggregate: PhantomData,
}
}
}