Expand description
A Rust library for persisting Event Sourced entities to PostgreSQL
This crate simplifies Event Sourcing persistence by automatically generating type-safe queries and operations for PostgreSQL. It decouples domain logic from persistence concerns while ensuring compile-time query verification via sqlx.
§Documentation
§Features
- Store and construct from event sequences
- Type-safe and compile-time verification
- Simple and configurable query generation
- Easy idempotency checks
- Cursor-based pagination
- Flexible ID types
- Atomic operations
Modules§
- clock
- Time abstraction for es-entity with support for real and manual time.
- context
- Thread-local system for adding context data to persisted events.
- db
- Centralized database type aliases.
- error
- Types for working with errors produced by es-entity.
- events
- Manage events and related operations for event-sourcing.
- forgettable
- Support for forgettable event data (e.g., for GDPR compliance).
- hooks
- Commit hooks for executing custom logic before and after transaction commits.
- idempotent
- Handle idempotency in event-sourced systems.
- nested
- Handle operations for nested entities.
- one_
time_ executor - Type-safe wrapper to ensure one database operation per executor.
- operation
- Handle execution of database operations and transactions.
- pagination
- Control and customize the query execution and its response.
- prelude
- Convenience re-export of crates that the derive macros reference in generated code.
- query
- Query execution infrastructure for event-sourced entities.
- snapshot
- Core types for entity snapshotting.
- sql_
commenter - Correlate SQL statements with OpenTelemetry traces.
- traits
- Traits to orchestrate and maintain the event-sourcing pattern.
- tree_
query - Dynamically assembles the single-statement tree query a nested repo’s
generated read fns execute at runtime: a tagged
UNION ALLover one CTE per tree node, so a parent and all of its nested children (recursively) come back in one statement instead of one per level.
Macros§
- delegate_
atomic_ operation - Implements
AtomicOperationfor a type by delegating every method to an operation it holds. - entity_
id - Create UUID-wrappers for database operations.
- es_
query - Execute an event-sourced query with automatic entity hydration.
- idempotency_
guard - Prevent duplicate event processing by checking for idempotent operations.
Structs§
- Bisect
Outcomes - The result of a completed search: one outcome per input item, plus what it cost.
- Bisect
Search - Drives a bisect over
nitems: which range to probe next, and what each verdict means for the ranges still outstanding. - Context
Data - Immutable context data that can be safely shared across thread boundaries.
- Continuation
- A continuation to the next page, carrying the cursor it resumes from.
- Cursor
Destructure Error - DbOp
- Default return type of the derived EsRepo::begin_op().
- DbOp
With Time - Equivileant of
DbOpjust that the time is guaranteed to be cached. - Entity
Events - A
Vecwrapper that manages event-stream of an entity with helpers for event-sourcing operations - EsQuery
- Query builder for event-sourced entities.
- EsQuery
Flavor Flat - Query flavor for flat entities without nested relationships.
- EsQuery
Flavor Nested - Query flavor for entities with nested relationships that need to be loaded recursively.
- Event
Context - Thread-local event context for tracking metadata throughout event sourcing operations.
- Event
Context Future - A future wrapper that provides event context during polling.
- Event
With Context - Forgettable
- Wrapper for event fields containing data that can be forgotten (e.g., for GDPR).
- Forgettable
Ref - A non-serializable reference to the value inside a
Forgettable<T>. - Forgettable
Remnants - Storage-level remnants of forgettable data found by a repository’s
generated
verify_forgottencheck. - Generic
Event - Represent the events in raw deserialized format when loaded from database
- Hook
Slot - Where a released
SavepointOp’s staged commit hooks fold into. - Hydration
Row - Internal common shape loaders normalise into before decoding a container.
- Nested
- NotFound
Value - Wrapper used by generated code to format not-found values.
Prefers
DisplayoverDebugvia inherent-vs-trait method resolution. - OneTime
Executor - A struct that owns an
sqlx::Executor. - OpWith
Time - Wrapper that guarantees time is available, borrowing the underlying operation.
- Paginated
Query Args - A cursor-based pagination structure for efficiently paginating through large datasets
- Paginated
Query Ret - Return type for paginated queries containing entities and pagination metadata
- Persisted
Event - Strongly-typed event wrapper with metadata for successfully stored events.
- Savepoint
Op - An
AtomicOperationscoped to a databaseSAVEPOINTinside a parentDbOpor anotherSavepointOp. - Snapshot
Generic Event - Row type of every loader on a
snapshotrepo (aliased asRepo__DbEventthere).GenericEvent<Id>itself is untouched — every existing repo’squery_as!and.sqlxentry stay as is; this confines the wider row shape to snapshot repos only. - Snapshot
Record - A persisted snapshot as loaded: the state plus the metadata of the events it summarises.
- Sort
- Structure to sort entities on a specific field when listing from database
- Tracing
Context - Transient
Limit Exceeded - The transient allowance ran out: the same range kept failing on contention.
- Transient
Policy - Which probe failures are transient, and how many re-probes they may buy.
- Tree
Query Source - The root user query plus the bits needed to fold it into the tree query.
- Tree
Spec - Static description of one node (repo) in a nested tree, used to build the query.
Enums§
- Bisect
Budget - How many probes a bisect may spend before giving up on the ranges it has not yet resolved.
- Constraint
Kind - The kind of database constraint behind a classified
ConstraintViolation. - Entity
Hydration Error - Error type for entity hydration failures (reconstructing entities from events).
- Idempotent
- Signals if a mutation is applied or was skipped.
- Item
Outcome - One input item’s resolution. Positionally aligned with the input slice.
- List
Direction - Controls the sorting order when listing the entities from the database
- NoSnapshot
- The default
SofEntityEvents<E, S>: this entity has no snapshot. - Page
- Probe
Verdict - What a probe over one range turned out to be.
- Replay
- One item of an entity’s replay. The snapshot, when present, is the FIRST
item in forward order and the LAST item in reverse order. Deliberately
exhaustive — do not add
#[non_exhaustive].
Constants§
- DEFAULT_
MAX_ TRANSIENT_ RETRIES - How many times a transiently-failed range may be re-probed before the search is abandoned.
- NO_
SNAPSHOT_ FINGERPRINT - Matches no stored snapshot; binds on full-history loads and is
NoSnapshot’s fingerprint.
Traits§
- Atomic
Operation - Trait to signify we can make multiple consistent database roundtrips.
- Atomic
Operation With Time - Batch
Isolation - Batch isolation for every
AtomicOperation. - Cascade
Delete Nested - Trait for cascade soft-deleting child entities when a parent is deleted.
- EsEntity
- Required trait for all entities to be compatible and recognised by es-entity.
- EsEvent
- Required trait for all event enums to be compatible and recognised by es-entity.
- EsRepo
- Required trait for all repositories to be compatible with es-entity and generate functions.
- EsSnapshot
- Implemented by
#[derive(EsSnapshot)]for user state types and by hand forNoSnapshot. - From
Already Applied - Internal trait used by the
idempotency_guardmacro. - Guard
Without Snapshot Clause - Reached by
idempotency_guard!when a stream yieldsReplay::Snapshotbut the guard has nosnapshot:clause. OnlyNoSnapshot(andSnapshotRecord<NoSnapshot>) implement it, so on a real snapshot this is a compile error with the message below. - Head
Snapshot - Implemented by every entity whose repo enables
snapshot. - Hydrate
Nested - Into
Events - Required trait for converting new entities into their initial events before persistence.
- Into
OneTime Executor - Marker trait for
IntoOneTimeExecutorAt<'a> + 'a. Do not implement directly. - Into
OneTime Executor At - A trait to signify that we can use an argument for 1 round trip to the database
- Into
Replay - Normalises
idempotency_guard!input: a plain&Estream (today’s call sites) and areplay()stream both becomeReplay. Do not implement for other types. - Parent
- Trait that entities implement for every field marked
#[es_entity(nested)] - Retryable
Into - Savepoint
Operation - Savepoints for every
AtomicOperation, derived rather than hand-written. - ToNot
Found Value Fallback - TryFrom
Events - Required trait for re-constructing entities from their events in chronological order.
- With
Event Context - Extension trait for propagating event context across async boundaries.
Functions§
- build_
tree_ query - decode_
tag - decode_
tagged_ row - Decodes a row from a tree branch with no snapshot columns (the branch’s own node has no snapshot table, and no sibling forced padding). Identical to what every tree branch decoded before snapshotting existed.
- decode_
tagged_ snapshot_ row - Decodes a row from a snapshot-enabled node’s own branch:
eventandrecorded_atmay beNULL(the lone snapshot-only row when the tail is empty), and the fivesnapshot*columns are present. - extract_
constraint_ value - Extracts the conflicting value from a database error’s constraint violation.
- extract_
events_ pkey_ id_ value - Extracts the conflicting id from an events-table primary-key violation.
- is_
classified_ constraint_ violation truewhen the database error is a violation kind the generated repo classifiers surface asConstraintViolation: unique (SQLSTATE 23505), foreign key (23503), or check (23514).NOT NULL(23502) and exclusion (23P01) violations are not classified and surface asSqlx.- is_
retryable_ conflict retryable_conflict_codeas a predicate.- parse_
constraint_ detail_ value - Extracts the conflicting value from a PostgreSQL constraint violation detail message.
- partition_
by_ tag - retryable_
conflict_ code - The Postgres sqlstate of a failure that says nothing about the statement
that hit it, or
None. - snapshot_
fingerprints - Walks the tree in the same DFS order
build_tree_queryassigns fingerprint bind-parameter indices in (root, then children depth-first), returning the fingerprint of every node that has a snapshot table. - tree_
has_ snapshot trueif this node or any descendant enablessnapshot. Determines whether every branch in the tree’sUNION ALLneeds the same (wider) column list — a tree with no snapshot node anywhere emits the same SQL as before this feature existed.
Type Aliases§
- Last
Persisted - An alias for iterator over the persisted events
Attribute Macros§
- es_
event_ context - Automatically captures function arguments into the event context.
- retry_
on_ concurrent_ modification - Retries the annotated async function when it fails with a concurrent
modification error (or with any error when
any_error = true).