Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
event-store-adapter-rs
This library provides an Event Store for CQRS/Event Sourcing with multiple storage backends: DynamoDB, Google Cloud Bigtable, SQLite, and in-memory.
Backends and Cargo features
No backend is enabled by default. Pick the backend(s) you use via Cargo features:
| Feature | Backend | What it enables |
|---|---|---|
dynamodb |
Amazon DynamoDB (EventStoreForDynamoDB) |
aws-config / aws-sdk-dynamodb |
bigtable |
Google Cloud Bigtable (EventStoreForBigtable) |
tonic / googleapis-tonic-google-bigtable-v2 |
sqlite |
SQLite with a bundled library (EventStoreForSqlite) |
rusqlite with its bundled feature — SQLite is compiled in, no system SQLite required |
sqlite-system |
SQLite linked against the system library (EventStoreForSqlite) |
rusqlite without bundled — links to the SQLite installed on the system |
| (none) | In-memory (EventStoreForMemory) |
Always available, no feature required |
[]
= { = "<latest>", = ["sqlite"] }
Notes:
- Because there is no default feature, existing users must add an explicit
features = [...]entry when upgrading (see Migration from 1.x). - If both
sqliteandsqlite-systemare enabled, the bundled SQLite wins. This is a consequence of Cargo feature additivity:sqliteturns onrusqlite/bundled, and features can only be added, never subtracted. Enable onlysqlite-systemif you want to link against the system SQLite.
Usage
You can easily implement an Event Sourcing-enabled repository using an event store. The following uses the SQLite backend (features = ["sqlite"]):
use EventEnvelope;
use ;
use EventStoreForSqlite;
// UserAccount / UserAccountEvent are plain `#[derive(Serialize, Deserialize)]` types —
// v3 requires no library traits on your domain types.
/// Read result restored from the latest snapshot plus the differential replay.
/// `seq_nr` numbers the next event as `seq_nr + 1`; `version` is the expected_version for the next write.
The following is an example of the repository usage with SQLite. The store persists to a database file (or to :memory:) and creates the required tables and indexes automatically on construction — no DDL on your side:
// A file-backed database. Use EventStoreForSqlite::new_in_memory() for `:memory:`.
let event_store = new?;
let mut repository = new;
// Create: the first event of a stream is seq_nr == 1 and is written with expected_version == 0.
let = new;
let envelope = new.with_manifest;
repository.store_event_and_snapshot.await?;
// Replay the aggregate from the event store: seq_nr / version come from the
// envelopes (the store columns), not from aggregate fields.
let mut replayed = repository.find_by_id.await?.unwrap;
// Execute a command, number the next event as replayed.seq_nr + 1, and pass the
// replayed version as expected_version for the optimistic lock.
let renamed = replayed.state.rename.unwrap;
let envelope = new;
repository.store_event.await?;
A complete runnable example is examples/user-account-sqlite (cargo run -p example-user-account-sqlite — no cloud connection, no Docker).
With features = ["dynamodb"], the same repository works against DynamoDB by replacing the store construction:
let event_store = new;
A complete runnable DynamoDB example is examples/user-account.
SQLite support boundary
- The supported sharing unit is one store instance and its clones (clones share the underlying connection). Opening the same database file from multiple store instances or from multiple processes is not supported. Guarding against concurrent multi-process access (for example, preventing multiple instances of a CLI tool from running at once) is the application's responsibility.
- An in-memory store (
new_in_memory) is shared by the instance and its clones only, and disappears when the last clone is dropped.
Migration to 3.x
The 3.x line replaces the Event / Aggregate traits with the EventEnvelope API: domain event and aggregate types are plain serde types, metadata (aggregate_id / seq_nr / occurred_at / manifest) travels in the envelope, and the optimistic-lock version lives in the store columns only. Data written by 2.x cannot be read by 3.x — migrating stored data is the user's responsibility. See docs/MIGRATION_GUIDE_v3.md (日本語) for the complete guide.
Migration from 1.x
The next major release contains breaking changes (see CHANGELOG.md).
1. Backends are now opt-in Cargo features
In 1.x every backend was always compiled. Now there is no default feature, so specify the backend(s) you use:
# Before (1.x)
[]
= "1"
# After — pick your backend(s); "<latest>" is the latest version on crates.io
[]
= { = "<latest>", = ["dynamodb"] }
The in-memory backend (EventStoreForMemory) needs no feature and is always available.
2. Error type changes
| Item | Before (1.x) | After |
|---|---|---|
EventStoreWriteError::OptimisticLockError |
Wrapped the AWS SDK type (TransactionCanceledException via TransactionCanceledExceptionWrapper) |
Carries a backend-neutral String message: optimistic lock failed, aid=<id>, expected_version=<n>[, actual_version=<m>] |
| In-memory backend failures | Some operations panicked (e.g. unsupported create) | Returns Err(EventStoreWriteError / EventStoreReadError) — no panic |
If you matched on OptimisticLockError(cause) to inspect the AWS SDK error, switch to the message string (or handle the variant without inspecting its payload). Retrying after an optimistic lock failure remains the caller's responsibility.
Table Specifications
See docs/DATABASE_SCHEMA.md. Note that for SQLite the tables are created automatically by the library; the document is informational.
CQRS/Event Sourcing Example
See j5ik2o/cqrs-es-example-rs.
License.
MIT License. See LICENSE for details.