Skip to main content

Store

Struct Store 

Source
pub struct Store { /* private fields */ }
Expand description

Reads from and writes to EventSourcingDB, through the client SDK.

Create one with Store::builder, from a client and the source to use for all events it writes:

use architecturekit::{Store, eventsourcingdb::Client};

let client = Client::new("http://localhost:3000".parse().unwrap(), "secret");
let store = Store::builder(client, "https://library.eventsourcingdb.io").build();

The store checks the hash of every event it reads, before any upcaster or state sees it, and an event whose hash does not match its content makes reading fail with Permanent::Unverified. To turn this off, use StoreBuilder::without_hash_verification.

Implementations§

Source§

impl Store

Source

pub async fn catch_up_projection<P: Projection>( &self, subjects: &Subjects, projection: &P, ) -> Result<(), ProjectionError>

Applies the events of the subjects that are stored so far to a projection, from the first one on, and returns. Use it to build a read model once, for a batch job or in a test, instead of following the events as they are written. Dropping the future stops it, so a read model that is built only in part never looks complete.

§Errors

Fails with the first failure, of reading, of verifying an event, or of the projection, including a panic of the projection, which is ProjectionError::Panicked.

Source

pub async fn catch_up_resumable_projection<P: ResumableProjection>( &self, subjects: &Subjects, projection: &P, ) -> Result<(), ProjectionError>

Applies the events of the subjects that are stored so far to a resumable projection, from its checkpoint on, saving the checkpoint after every batch, and returns. See catch_up_projection.

§Errors

Fails as catch_up_projection does, and if the checkpoint can not be read or saved.

Source

pub async fn catch_up_transactional_projection<P: TransactionalProjection>( &self, subjects: &Subjects, projection: &P, ) -> Result<(), ProjectionError>

Applies the events of the subjects that are stored so far to a transactional projection, from its checkpoint on, one transaction per batch, and returns. See catch_up_projection.

§Errors

Fails as catch_up_projection does, and if the checkpoint can not be read, or a transaction can not be begun or committed. A transaction that fails is rolled back, and a failure of the rollback is reported alongside the failure that caused it.

Source

pub fn start_projection<P: Projection>( &self, subjects: Subjects, projection: Arc<P>, token: CancellationToken, options: ProjectionOptions, ) -> ProjectionRun

Starts a projection on a task of its own, which applies the events of the subjects stored so far, from the first one on, and then follows them as they are written, until the token is cancelled, or until a failure that trying again will not fix. It returns the run, which tells how far the projection has got (see ProjectionRun).

Reading that fails in a way that may pass, which includes a stream of events that ends, and a failure of the projection of the category Category::Transient, is tried again from the last event applied on, after a delay (see StoreBuilder::reconnect_delays). Any other failure ends the run, and so does a panic of the projection, as ProjectionError::Panicked, rather than the task. Cancelling the token stops waiting for the next event at once, while an event that is being applied is applied to the end, and the run then stops without a failure.

It needs a Tokio runtime with the time driver, as the client SDK does.

§Panics

A name of the options that is empty is a programming error, so this panics.

Source

pub fn start_resumable_projection<P: ResumableProjection>( &self, subjects: Subjects, projection: Arc<P>, token: CancellationToken, options: ProjectionOptions, ) -> ProjectionRun

Starts a resumable projection as start_projection does, from its checkpoint on. While it catches up, it saves the checkpoint after every batch, and once it follows the events, after every event.

§Panics

As start_projection does.

Source

pub fn start_transactional_projection<P: TransactionalProjection>( &self, subjects: Subjects, projection: Arc<P>, token: CancellationToken, options: ProjectionOptions, ) -> ProjectionRun

Starts a transactional projection as start_projection does, from its checkpoint on, one transaction per batch while it catches up, and one per event once it follows the events.

§Panics

As start_projection does.

Source§

impl Store

Source

pub fn builder(client: Client, source: impl Into<String>) -> StoreBuilder

Creates a builder for a store that reads and writes with the given client, and writes its events with the given source.

Source

pub async fn load<S: State>(&self, subject: &Subject) -> Result<S, LoadError>

Reads the state of a subject, from the events of the subject alone, starting from Default, or from the latest event of the type the state names with State::from_latest. Use it for a query that needs the state of a single subject, rather than a view across many.

Every event is verified before the upcasters of the state, and then the state, see it. Dropping the future before the state is read completely returns nothing, so part of a state never reaches a caller.

§Errors

Fails transiently if the database can not be reached, and permanently if an event fails its verification, if the state has no rule for an event, if the data of an event does not match its type, if the ID of an event is not a revision or its subject not a subject, neither of which the database ever writes, or if the database refuses the request.

§Panics

A state that starts from an event type it has no rule for is a programming error, so this panics (see State::from_latest).

Source

pub async fn read<'a>( &'a self, subjects: &'a Subjects, options: &'a ReadOptions, ) -> Result<impl Stream<Item = Result<Event, ReadError>> + 'a, ReadError>

Hands out the events of the given subjects as they are stored, for a read that neither load nor a projection fits: one page of a long stream, the events up to a certain one, or a single event. Every event is verified like everything else the store reads, before the caller sees it. Neither upcasters nor states apply, since there is no state.

Without options, it hands out every event of the subjects, oldest first. The bounds and the order of ReadOptions narrow that down. The stream ends with the first failure, and dropping it stops reading.

§Errors

Fails before the database is asked, as check_read_options does, with ReadError::EmptyRange for bounds that leave no room for an event. Otherwise it fails, or the stream ends, with ReadError::Transient if the database can not be reached, and with ReadError::Permanent if an event fails its verification or the database refuses the read.

§Panics

Panics for options that contradict each other (see LowerBound::FromLatestEvent).

Source

pub async fn execute<C, S, D>( &self, decider: &Decider<C, S, D>, command: C, ) -> Result<Vec<Event>, ExecuteError<D>>
where C: Command + Clone, S: State,

Executes a command: reads the state of its subject, lets the decider decide on it, and writes the events it decided on to the subject, under the preconditions the command declares. It returns the events as the database recorded them, or none if the decider decided on none.

Precondition::on_state_read is filled in with the last event read, so that the events are only written if the state they were decided on still holds. A conflict is reported, and the caller decides what to do about it, unless the store was built with StoreBuilder::conflict_retries and the conflict may come from the state that was read, in which case it decides again first.

The decider decides on variants of the events of the state, so the state has a rule for every event that is written, and can read the subject for the next command. If the data of one of the events can not be encoded as JSON, none of them is written, and executing fails permanently, naming the event type, the subject and the reason, since trying again would fail the same way.

Dropping the future before the write has begun writes nothing, also while the decider decides. Once the write has begun, it runs on a task of its own, as with Store::write, so that it is finished even if the caller stops waiting for it.

§Errors

Fails with ExecuteError::Decider if the decider refuses the command, with ExecuteError::Transient, including a Transient::Conflict for a precondition that did not hold, or with ExecuteError::Permanent if nothing was written, and with ExecuteError::OutcomeUnknown if the events may have been stored nonetheless. The preconditions are checked before anything is read, as check_preconditions checks them.

§Panics

A state that starts from an event type it has no rule for is a programming error, so this panics (see State::from_latest).

Source

pub async fn write( &self, events: Vec<EventOn>, preconditions: Vec<Precondition>, ) -> Result<Vec<Event>, WriteError>

Writes events to one or several subjects at once, so that either all of them are written or none, under the given preconditions. Use it for what is not a decision on the state of a single subject, such as a result derived from many of them.

Like a command, a write declares at least one precondition, such as Precondition::on_pristine_subject, or Precondition::unconditionally to write without any. Precondition::on_state_read has nothing to guard, since a write reads no state. Writing no events writes nothing, but the preconditions are checked first.

Once the write has begun, it runs on a task of its own, so that it is finished even if the caller stops waiting for it: a write cut off in the middle would leave open whether the events were stored. If it fails after its caller has stopped waiting, the failure is logged.

A write knows no state, so every state that reads one of the subjects needs a variant for each event type written to it, or reading fails afterwards.

§Errors

Fails with WriteError::Transient, including a Transient::Conflict for a precondition that did not hold, or with WriteError::Permanent if the write certainly stored nothing, and with WriteError::OutcomeUnknown if it may have been stored nonetheless.

Source

pub async fn register_schemas( &self, schemas: impl IntoIterator<Item = EventSchema>, ) -> Result<(), RegisterSchemasError>

Registers the schemas of the given events with the database, such as those of BookEvent::schemas(). It is meant to be called on every start: for an event type the database knows already, it checks that the registered schema is the given one.

A registered schema can not change. If it differs from the given one, or if the database refuses the given one, for example because stored events of the type do not match it, this fails permanently. To change the shape of an event, introduce a new event type and an upcaster instead. A registration that has begun runs on a task of its own, as a write does.

§Errors

Fails transiently if the database can not be reached, and permanently if a schema differs from the registered one, if the same event type comes with two different schemas, or if the database refuses a schema.

Trait Implementations§

Source§

impl Debug for Store

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Store

§

impl !RefUnwindSafe for Store

§

impl !UnwindSafe for Store

§

impl Send for Store

§

impl Sync for Store

§

impl Unpin for Store

§

impl UnsafeUnpin for Store

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> IntoResult<T> for T

Source§

type Err = !

Source§

fn into_result(self) -> Result<T, <T as IntoResult<T>>::Err>

Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more