use salamander::{Event, Projection, Salamander};
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
enum Ledger {
Deposit(i64),
Withdraw(i64),
}
#[derive(Default)]
struct Balance {
cents: i64,
cursor: u64,
}
impl Projection for Balance {
type Body = Ledger; type State = i64;
fn apply(&mut self, e: &Event<Ledger>) {
match &e.body {
Ledger::Deposit(c) => self.cents += c,
Ledger::Withdraw(c) => self.cents -= c,
}
self.cursor = e.offset + 1;
}
fn cursor(&self) -> u64 {
self.cursor
}
fn state(&self) -> &i64 {
&self.cents
}
}
fn main() -> salamander::Result<()> {
let dir = fresh_dir("custom_payload");
let mut db: Salamander<Ledger> = Salamander::open(&dir)?;
db.append("acct", Ledger::Deposit(10_000))?; db.append("acct", Ledger::Withdraw(2_500))?; db.append("acct", Ledger::Deposit(1_000))?; db.commit()?;
let balance: Balance = db.projection()?;
println!("balance after replay: {} cents", balance.state());
let earlier: Balance = db.view_at(2)?;
println!("balance as of offset 2: {} cents", earlier.state());
Ok(())
}
fn fresh_dir(name: &str) -> std::path::PathBuf {
let dir = std::env::temp_dir().join(format!("salamander-example-{name}"));
let _ = std::fs::remove_dir_all(&dir);
dir
}