Queries with persisted views

A ViewRepository provides a simple database backed repository for views that do not require multiple indexes. This is designed to back work with a GenericQuery to apply events to a view synchronously immediately after those events are committed.

A GenericQuery will load the view, apply any events, and store the updated version back in the database. The logic for the update is placed in a View implementation. For our bank account example this might look like:


#![allow(unused)]
fn main() {
impl View<BankAccount> for BankAccountView {
    fn update(&mut self, event: &EventEnvelope<BankAccount>) {
        match &event.payload {
            BankAccountEvent::CustomerDepositedMoney { amount, balance } => {
                self.ledger.push(LedgerEntry::new("deposit", *amount));
                self.balance = *balance;
            }
            ...
        }
    }
}
}

The view repositories use the same database connection as the event repositories, for postgres-es this is a database connection pool.


#![allow(unused)]
fn main() {
type MyViewRepository = PostgresViewRepository<MyView,MyAggregate>;

fn configure_view_repository(db_pool: Pool<Postgres>) -> MyViewRepository {
    PostgresViewRepository::new("my_view_name", db_pool)
}
}

The database must have a table prepared before use, where the table name should match the value passed while initiating the PostgresViewRepository.

CREATE TABLE my_view_name
(
    view_id text                        NOT NULL,
    version bigint CHECK (version >= 0) NOT NULL,
    payload json                        NOT NULL,
    PRIMARY KEY (view_id)
);

To use this view repository with a GenericQuery it must be configured with the CqrsFramework.


#![allow(unused)]
fn main() {
fn configure_cqrs(store: PostgresEventStore, my_view_repo: MyViewRepository) -> CqrsFramework {
    let my_query = GenericQuery::<MyViewRepository, MyView, MyAggregate>::new(my_view_repo);
    let my_query = Box::new(my_query);
    CqrsFramework::new(store, vec![my_query]);
}
}