eventide-domain 0.1.0

Domain layer for the eventide DDD/CQRS toolkit: aggregates, entities, value objects, domain events, repositories, and an in-memory event engine.
Documentation

eventide-domain

Crates.io Documentation

中文版本: README.zh.md

Domain layer of the eventide DDD/CQRS toolkit. This crate ships the pure-Rust building blocks that your business logic actually depends on — and only those. It has no database driver, no message broker, and no HTTP framework.

What is in here

Module Highlights
aggregate Aggregate trait (TYPE, Command, Event, Error, execute, apply).
aggregate_root AggregateRoot<A, R> orchestrating load → execute → apply → save.
entity Entity trait with id / version for optimistic concurrency.
value_object ValueObject marker trait and Version newtype.
domain_event DomainEvent trait, EventEnvelope, EventContext, Metadata, FieldChanged.
event_upcaster EventUpcaster + EventUpcasterChain for evolving event schemas.
persist EventRepository, SnapshotRepository, AggregateRepository and reusable adapters.
eventing Optional async event subsystem (bus / engine / dispatcher / reclaimer) on tokio.
specification Specification<T> combinator pattern (and, or, not).
error DomainError, ErrorKind, ErrorCode for typed domain failures.

Add it

[dependencies]
eventide-domain = "0.1"
serde = { version = "1", features = ["derive"] }

Or pull everything in via the umbrella crate:

[dependencies]
eventide = "0.1"

Feature flags

Flag Default What it enables
eventing yes Asynchronous event subsystem (bus / engine / dispatcher / reclaimer). Pulls in tokio and futures-util.
infra-sqlx no sqlx conversions on SerializedEvent / SerializedSnapshot for Postgres-backed event stores.

Disable eventing when you only need pure aggregate modelling:

[dependencies]
eventide-domain = { version = "0.1", default-features = false }

Macros

The companion crate eventide-macros generates the boilerplate (Entity, DomainEvent, etc.). The generated code uses absolute paths ::eventide_domain::..., and this crate exposes a self-alias so the macros also resolve inside its own tests:

// src/lib.rs
extern crate self as eventide_domain;

Repository helpers

use std::sync::Arc;
use eventide_domain::event_upcaster::EventUpcasterChain;
use eventide_domain::persist::{
    EventSourcedRepo, SnapshotPolicy, SnapshotPolicyRepo, SnapshotRepositoryWithPolicy,
};

let upcasters = Arc::new(EventUpcasterChain::default());
let event_repo = Arc::new(MyEventRepo::new());
let snapshot_repo = Arc::new(SnapshotRepositoryWithPolicy::new(
    MySnapshotRepo::new(),
    SnapshotPolicy::Every(100),
));

// Pure event sourcing.
let es = EventSourcedRepo::new(event_repo.clone(), upcasters.clone());

// Event sourcing + snapshots.
let snap = SnapshotPolicyRepo::new(event_repo.clone(), snapshot_repo, upcasters);

Examples

cargo run -p eventide-domain --example event_upcasting       # upcaster chain + repos
cargo run -p eventide-domain --example event_repository      # custom EventRepository
cargo run -p eventide-domain --example snapshot_repository   # snapshot policies
cargo run -p eventide-domain --example eventing_inmemory     # async event engine
cargo run -p eventide-domain --example account_aggregate     # full aggregate flow

Layered architecture

eventide-domain is the centre of the dependency graph:

eventide-application  →  eventide-domain  ←  eventide-macros
                                 ↑
                                 └──── (optional) infra-sqlx

The domain crate intentionally never imports application or infrastructure types, which keeps your business logic pure and trivially testable.

License

Licensed under either of Apache-2.0 or MIT at your option.