pub trait EventLog: Send + Sync {
// Required methods
fn stream<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn EventStore>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn read_all<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Recorded>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn head_position<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn subscribe(
&self,
from: Position,
filter: Filter,
) -> Result<BoxStream<'static, Result<Recorded>>>;
fn checkpoint_load<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn checkpoint_save<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
at: Position,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
// Provided methods
fn export<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ExportedEvent>>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn import<'life0, 'async_trait>(
&'life0 self,
events: Vec<ExportedEvent>,
) -> Pin<Box<dyn Future<Output = Result<ImportReport>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
}Required Methods§
Sourcefn stream<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn EventStore>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn stream<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Box<dyn EventStore>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
A handle on one stream. Everything below this is the per-stream SPI, unchanged.
Sourcefn read_all<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Recorded>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn read_all<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Recorded>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Events with position > from, across every stream, in position order,
at most limit.
Exclusive on from so a cursor can be fed straight back in:
Position::BEGINNING reads from the start, and the position of the
last event handled reads the next batch.
Sourcefn head_position<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn head_position<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
The newest position in the log, or Position::BEGINNING if it is
empty.
Sourcefn subscribe(
&self,
from: Position,
filter: Filter,
) -> Result<BoxStream<'static, Result<Recorded>>>
fn subscribe( &self, from: Position, filter: Filter, ) -> Result<BoxStream<'static, Result<Recorded>>>
Catch up from from, then stay live.
There is no seam a consumer has to handle: the live tail is the same
range read, resumed. Ordering is by position and nothing is skipped —
see Position for why that holds without gap detection.
How the live half learns of a write is the backend’s business. The SQLite backend wakes subscribers on the same log directly, and falls back to polling for anything else, because SQLite has no notification a writer elsewhere could send.
“Anything else” includes a second log opened on the same file in this
same process — the wake-up channel belongs to the log, not to the
database. Nothing is lost either way; the difference is latency, and it
is about three orders of magnitude [measured: 552µs woken directly
against 552ms on a 600ms poll, tests/two_logs.rs]. Open the file once
per process and share the log if that matters.
Sourcefn checkpoint_load<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn checkpoint_load<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Position>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
How far consumer has got, or Position::BEGINNING if it has never
reported.
Sourcefn checkpoint_save<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
at: Position,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn checkpoint_save<'life0, 'life1, 'async_trait>(
&'life0 self,
consumer: &'life1 str,
at: Position,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Record how far consumer has got.
Callers that need the checkpoint to move in the same transaction as the work it accounts for must not use this — it is its own write. That is what a projection runner is for.
Provided Methods§
Sourcefn export<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ExportedEvent>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn export<'life0, 'life1, 'async_trait>(
&'life0 self,
from: Position,
filter: &'life1 Filter,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<ExportedEvent>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Read events out in position order, as they are stored.
The one read that does not run the upcaster chain. Every other read wants the current shape; a transfer wants the bytes, so the receiving log can hold exactly what this one held and run its own chain over them. Upcasting on the way out would bake this build’s reading of an old event into the copy and lose the original.
Page with from and limit, feeding the last returned position back
in; a short batch is the end. See crate::transfer for what travels
and what the receiving log reassigns.
The default declines, because a log with no stored form has nothing to hand over that another log could hold.
Sourcefn import<'life0, 'async_trait>(
&'life0 self,
events: Vec<ExportedEvent>,
) -> Pin<Box<dyn Future<Output = Result<ImportReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn import<'life0, 'async_trait>(
&'life0 self,
events: Vec<ExportedEvent>,
) -> Pin<Box<dyn Future<Output = Result<ImportReport>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Write exported events into this log, in the order given.
seq and position are this log’s to assign; everything else travels
unchanged, epoch_ms and _schema_version included. Keeping the
version is what leaves an old event within reach of the upcaster
written for it, and
ImportReport::reproduced_coordinates reports whether the batch
landed where it came from, so a migration can check rather than assume.
The default declines rather than appending one at a time. A backend with no transaction could only offer a partial import, and a transfer that stopped half way is worse than one that refused: from the outside there is no way to tell how far it got.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".