An event sourcing and CQRS astraction that aims to be practical more than "go by the book". It's built on top of Riker a lightweight actor framework.
WARNING It's pretty much alpha quality at the moment, features are still missing and the API is still changing.
This library adds a few extra event-sourcing related concepts to Riker, entities represent a domain and are the entry point where external commands and bussiness logic is handled. Created with the Entity
actor using the usual Riker machinery(see creating actors).
rust
let entity = actor_system.actor_of_args::<Entity<MyEntity>, _>("my-entity", SomeArgs)`;
MyEntity
is a user supplied struct that implements the ES
trait.
```rust
struct MyEntity;
impl ES for MyEntity { type Args = SomeArgs; // the arguments passed to the constructor type Agg = MyData; // The "aggregate" is the data that is to be persisted along with its updates. type Cmd = MyEntityCommands; // The external command or commands(often in the form of an enum) this entity can handle. // type Event = (); // TODO: Similar to commands but for handling events emitted by other entities. type Error = MyEntityError; // Error produced by the handler functions.
// Used to construct an entity, receives the Entity
actor's context
// to be able to create other actors and hold their references
fn new(_cx: &Context
async fn handle_command( &mut self, cmd: Self::Cmd, ) -> Result
// when entities are created for the first time
Ok(Some(Event::Create(MyData).into()))
// or to update an existing entity
// Ok(Some(Event::Update("some id".into(), MyDataUpdate).into()))
} } ```
Define your aggregate(the data model), the updates it can handle and how to apply them.
```rust
struct MyData {
someid: String,
somefield: String,
other_field: Option
enum MyDataUpdate { TheChange(String, String), LittleChange(String), }
impl Aggregate for MyData { type Update = MyDataUpdate;
fn id(&self) -> EntityId { self.some_id.into() }
fn applyupdate(&mut self, update: Self::Update) {
match update {
MyDataUpdate::TheChange(field, other) => {
self.somefield = field;
self.otherfield = Some(other);
},
MyDataUpdate::LittleChange(field) => {
self.somefield = field;
},
}
}
}
Later the state of an entity can be queried with the entity actor.
rust
let mydata: MyData = ask(&actorsystem, &entity, Query::One("123".into())).await;
```