Skip to main content

Crate es_entity

Crate es_entity 

Source
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

Re-exports§

pub use errlanes;

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 ALL over 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 AtomicOperation for 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§

BisectOutcomes
The result of a completed search: one outcome per input item, plus what it cost.
BisectSearch
Drives a bisect over n items: which range to probe next, and what each verdict means for the ranges still outstanding.
CodeInfo
One code a rejection family can resolve to, with its operator-facing text.
ConstraintConflict
A known constraint and the typed write input, when it can be attributed. Values may contain PII. Inspect deliberately; default Display never prints them.
ConstraintDiagnostics
Structured diagnostics. Attempted values are deliberately absent from Display.
ContextData
Immutable context data that can be safely shared across thread boundaries.
Continuation
A continuation to the next page, carrying the cursor it resumes from.
CursorDestructureError
DbOp
Default return type of the derived EsRepo::begin_op().
DbOpWithTime
Equivileant of DbOp just that the time is guaranteed to be cached.
Denied
Authorization failure. Never retried, always audited.
EntityEvents
A Vec wrapper that manages event-stream of an entity with helpers for event-sourcing operations
EsQuery
Query builder for event-sourced entities.
EsQueryFlavorFlat
Query flavor for flat entities without nested relationships.
EsQueryFlavorNested
Query flavor for entities with nested relationships that need to be loaded recursively.
EventContext
Thread-local event context for tracking metadata throughout event sourcing operations.
EventContextFuture
A future wrapper that provides event context during polling.
EventWithContext
Fatal
A failure that will not succeed on retry: a bug, a misconfiguration, or corrupt state.
Forgettable
Wrapper for event fields containing data that can be forgotten (e.g., for GDPR).
ForgettableRef
A non-serializable reference to the value inside a Forgettable<T>.
GenericEvent
Represent the events in raw deserialized format when loaded from database
HookSlot
Where a released SavepointOp’s staged commit hooks fold into.
HydrationRow
Internal common shape loaders normalise into before decoding a container.
IdConflict
The primary-key conflict of a create: the id is always known, from the write’s own input (a single create) or by matching the database’s reported key against the batch’s own ids (create_all). Unlike ConstraintConflict, attempted is never optional here — a pkey violation with no attributable id is Fatal(Invariant) instead, never this variant with a guessed or missing id.
Nested
NotFound
A repo op that requires a row (find_by_*) found none. There is no NotFound rejection — callers that tolerate absence use maybe_find_by_*, which returns Option instead. Construct one and propagate it with ?: it converts into any errlanes::Fault or errlanes::Fail<D> as Fatal(Invariant).
NotFoundValue
Wrapper used by generated code to format not-found values. Prefers Display over Debug via inherent-vs-trait method resolution.
OneTimeExecutor
A struct that owns an sqlx::Executor.
OpWithTime
Wrapper that guarantees time is available, borrowing the underlying operation.
PaginatedQueryArgs
A cursor-based pagination structure for efficiently paginating through large datasets
PaginatedQueryRet
Return type for paginated queries containing entities and pagination metadata
PersistedEvent
Strongly-typed event wrapper with metadata for successfully stored events.
SavepointOp
An AtomicOperation scoped to a database SAVEPOINT inside a parent DbOp or another SavepointOp.
SnapshotGenericEvent
Row type of every loader on a snapshot repo (aliased as Repo__DbEvent there). GenericEvent<Id> itself is untouched — every existing repo’s query_as! and .sqlx entry stay as is; this confines the wider row shape to snapshot repos only.
SnapshotRecord
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
TracingContext
Transient
A failure that may succeed if the same operation is retried.
TransientLimitExceeded
The transient allowance ran out: the same range kept failing on contention.
TransientPolicy
Which probe failures are contention — not attributable to the range’s contents — and how many re-probes they may buy.
TreeQuerySource
The root user query plus the bits needed to fold it into the tree query.
TreeSpec
Static description of one node (repo) in a nested tree, used to build the query.

Enums§

BisectBudget
How many probes a bisect may spend before giving up on the ranges it has not yet resolved.
ConstraintKind
The kind of database constraint behind a classified ConstraintViolation.
EntityHydrationError
Error type for entity hydration failures (reconstructing entities from events).
Fail
The generic view over a domain rejection D, before retries have run.
FatalKind
Why a Fatal outcome is a bug, a misconfiguration, or corrupt state.
Fault
Fail minus the Rejected lane: what an operation that cannot reject (nothing about it is the caller’s to correct) returns. Reads return Fault<L>; writes return Fail<{Entity}ConstraintViolation, L> — the type itself says whether a call can ever hand back a domain outcome.
Idempotent
Signals if a mutation is applied or was skipped.
ItemOutcome
One input item’s resolution. Positionally aligned with the input slice.
Lane
Which of the four lanes an outcome travels in.
ListDirection
Controls the sorting order when listing the entities from the database
NoSnapshot
The default S of EntityEvents<E, S>: this entity has no snapshot.
Page
ProbeVerdict
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].
TransientKind
Why a Transient outcome may succeed on retry.

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§

AtomicOperation
Trait to signify we can make multiple consistent database roundtrips.
AtomicOperationWithTime
BatchIsolation
Batch isolation for every AtomicOperation.
Carrier
A crate-local enum that stands in for Fault<L> / Fail<R, L>. Implemented by #[derive(errlanes::Carrier)] on a lane enum; do not implement it by hand.
CascadeDeleteNested
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 for NoSnapshot.
FromAlreadyApplied
Internal trait used by the idempotency_guard macro.
GuardWithoutSnapshotClause
Reached by idempotency_guard! when a stream yields Replay::Snapshot but the guard has no snapshot: clause. Only NoSnapshot (and SnapshotRecord<NoSnapshot>) implement it, so on a real snapshot this is a compile error with the message below.
HeadSnapshot
Implemented by every entity whose repo enables snapshot.
HydrateNested
IntoEvents
Required trait for converting new entities into their initial events before persistence.
IntoOneTimeExecutor
Marker trait for IntoOneTimeExecutorAt<'a> + 'a. Do not implement directly.
IntoOneTimeExecutorAt
A trait to signify that we can use an argument for 1 round trip to the database
IntoReplay
Normalises idempotency_guard! input: a plain &E stream (today’s call sites) and a replay() stream both become Replay. Do not implement for other types.
Laned
Sealed. The thing retry/record need from any error they are handed: its lane, and how to narrow it. Implemented by Fail<D, L>, by Fault<L> — the two shapes a generated repo op can return — and by every Carrier whose built-in is Laned.
Lift
Consuming mapping. #[derive(Lift)] with #[lift(Source)] generates an exhaustive mapping with Unmapped = Infallible and a total From<Source> conversion. #[lift(Source, unhandled = fatal)] returns the original unmapped source; Fail::lift wraps it as a fatal invariant with its source intact. The derive does not require or implement Rejection. Derive Rejection separately to provide codes and levels; simple lift mappings forward that metadata by default unless the destination declares its own.
Parent
Trait that entities implement for every field marked #[es_entity(nested)]
Rejection
A pure, caller-correctable domain outcome. Implemented by hand or via #[derive(errlanes::Rejection)], which emits Display/Error itself (defaulting Display to the code) unless #[rejection(error = manual)] hands that to thiserror or a hand-written impl.
RejectionCode
The code type of a rejection family: a closed, enumerable catalogue.
ResultExt
The one trait a consumer imports to move a Result between error signatures: lift its rejection, narrow away a lane that is no longer live at this boundary, hand the rejection to the caller as a value, classify a foreign error into a local wrapper, or (under tracing) record it onto the current span.
RetryableInto
SavepointOperation
Savepoints for every AtomicOperation, derived rather than hand-written.
ToNotFoundValueFallback
TryFromEvents
Required trait for re-constructing entities from their events in chronological order.
WithEventContext
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: event and recorded_at may be NULL (the lone snapshot-only row when the tail is empty), and the five snapshot* 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.
fatal_is_not_found
is_classified_constraint_violation
true when the database error is a violation kind the generated repo classifiers surface as ConstraintViolation: unique (SQLSTATE 23505), foreign key (23503), or check (23514). NOT NULL (23502) and exclusion (23P01) violations are not classified and surface as Sqlx.
parse_constraint_detail_value
Extracts the conflicting value from a PostgreSQL constraint violation detail message.
partition_by_tag
snapshot_fingerprints
Walks the tree in the same DFS order build_tree_query assigns fingerprint bind-parameter indices in (root, then children depth-first), returning the fingerprint of every node that has a snapshot table.
tree_has_snapshot
true if this node or any descendant enables snapshot. Determines whether every branch in the tree’s UNION ALL needs the same (wider) column list — a tree with no snapshot node anywhere emits the same SQL as before this feature existed.

Type Aliases§

LastPersisted
An alias for iterator over the persisted events
RepoFault
Transient or fatal, never rejected: every read, and every write whose statement can hit no constraint (see RepositoryOptions::update_can_reject in the macro crate for exactly which generated updates qualify). Reads cannot reject or deny; optional reads represent absence with None.
RepoWriteError
Repository write failures, with C carrying the typed constraint violation. Writes may reject, fail transiently, or fail fatally, but cannot deny.
WithDenied
E with the denied lane enabled.
WithoutDenied
E with the denied lane disabled (what narrow_denied returns).
WithoutTransient
E with the transient lane disabled (what narrow_transient returns).

Attribute Macros§

es_event_context
Automatically captures function arguments into the event context.

Derive Macros§

Carrier
Derive a carrier: a crate-local lane enum that stands in for Fault<lanes!(..)> or Fail<R, lanes!(..)>.
EsEntity
EsEvent
EsRepo
EsSnapshot
Lift
Derive error conversion mappings. A single-field tuple struct can project a source struct field with #[lift(Source, field = name)], generating From<Source> independently of rejection metadata.
Rejection