Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,14 @@ are written once and are transport-agnostic.
use std::sync::Arc;
use distributed::microsvc::{self, Routes, Service, Session};
use distributed::bus::{InMemoryBus, RunOptions};
use distributed::{AggregateBuilder, HashMapRepository, Queueable};
use distributed::{AggregateBuilder, InMemoryRepository, Queueable};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let routes = distributed::routes!(
Routes::new().with_repo(
HashMapRepository::new().queued().aggregate::<Todo>()
InMemoryRepository::new().queued().aggregate::<Todo>()
),
command handlers::todo_create,
command handlers::todo_complete,
Expand Down Expand Up @@ -251,7 +251,7 @@ a handler change — every infrastructure concern is an async trait with an in-m
default you replace with a durable adapter.

```rust,ignore
// Persistence: HashMapRepository → durable SQL (features "postgres" / "sqlite")
// Persistence: InMemoryRepository → durable SQL (features "postgres" / "sqlite")
let repo = distributed::PostgresRepository::connect_and_migrate(database_url).await?;
let routes = distributed::routes!(
Routes::new().with_repo(repo.queued().aggregate::<Todo>()),
Expand Down Expand Up @@ -290,7 +290,7 @@ names through `subscription_plan()` and passes them to the transport.

| Concern | In-memory default | Swap in for production |
|---|---|---|
| Storage | `HashMapRepository` | `PostgresRepository`, `SqliteRepository` |
| Storage | `InMemoryRepository` | `PostgresRepository`, `SqliteRepository` |
| Messaging | `InMemoryBus` | `NatsBus`, `PostgresBus`, `SqliteBus`, `RabbitBus`, `KafkaBus`, `KnativeBus` |
| Locking | `InMemoryLockManager` | `PostgresLockManager`, `SqliteLockManager` (durable leases), any `LockManager` (Redis, …) |

Expand Down Expand Up @@ -342,7 +342,7 @@ network servers.
- **EventRecord**: An immutable aggregate event record with name, payload, sequence, timestamp, and optional metadata. It is replayable model history, not automatically a published domain event.
- **Aggregate**: A struct that embeds an `Entity` and replays `EventRecord`s. `aggregate_type()` provides the durable stream-identity component for persistence.
- **Repository / AggregateRepository**: Persists and loads aggregates by event history. The event store is optimized for append and replay; `get`/`commit` are async.
- **HashMapRepository**: In-memory repository for tests and examples. Implements every async trait (repository, read-model, snapshot, outbox).
- **InMemoryRepository**: In-memory repository for tests and examples. Implements every async trait (repository, read-model, snapshot, outbox).
- **SqliteRepository / PostgresRepository**: Durable async SQL adapters (optional features).
- **QueuedRepository**: Wraps any repository and adds async per-entity queue locking.
- **EventUpcaster**: A pure, stateless transformation that converts event payloads from one version to another at read time.
Expand All @@ -369,11 +369,11 @@ Every infrastructure concern in `distributed` follows the same pattern: a **trai

| Concern | Trait(s) | In-memory default | Swap in for production |
|---|---|---|---|
| Storage | `GetStream` + `TransactionalCommit` | `HashMapRepository` | `PostgresRepository`, `SqliteRepository`, … |
| Storage | `GetStream` + `TransactionalCommit` | `InMemoryRepository` | `PostgresRepository`, `SqliteRepository`, … |
| Messaging | `Bus` + `BusConsumer` | `InMemoryBus` | `NatsBus`, `PostgresBus`, `SqliteBus`, `RabbitBus`, `KafkaBus`, `KnativeBus` |
| Read model rows | `ReadModelWritePlanStore` + `RelationalReadModelQueryStore` | `InMemoryReadModelStore` | Postgres, SQLite |
| Snapshot store | `SnapshotStore` | `InMemorySnapshotStore` | Postgres, SQLite, … |
| Outbox publishing | `OutboxStore` + async `MessagePublisher` | `HashMapRepository` outbox store (dev/test) | Any `MessagePublisher` (e.g. `BusPublisher` over a real `Bus`) |
| Outbox publishing | `OutboxStore` + async `MessagePublisher` | `InMemoryRepository` outbox store (dev/test) | Any `MessagePublisher` (e.g. `BusPublisher` over a real `Bus`) |
| Locking | `Lock` + `LockManager` | `InMemoryLockManager` | `PostgresLockManager`, `SqliteLockManager` (durable leases), Redis, … |

All in-memory defaults are `Clone` and `Send + Sync`, so they work in single-task tests and multi-task servers alike. When you're ready for production, implement the trait for your infrastructure and plug it in — handler code does not change.
Expand Down Expand Up @@ -750,9 +750,9 @@ This pattern is useful for reactive workflows within the same process. For cross
Per-entity async locking for serialized workflows. `get` acquires the lock, `commit` releases it:

```rust,ignore
use distributed::{AggregateBuilder, HashMapRepository, Queueable, RepositoryError};
use distributed::{AggregateBuilder, InMemoryRepository, Queueable, RepositoryError};

let repo = HashMapRepository::new().queued().aggregate::<Todo>();
let repo = InMemoryRepository::new().queued().aggregate::<Todo>();

let Some(mut todo) = repo.get("todo-1").await? else {
return Err(RepositoryError::NotFound { id: "todo-1".into() });
Expand Down Expand Up @@ -792,7 +792,7 @@ set the lease TTL above your longest critical section. Tune with `with_lease_ttl
## Persistent Repositories

The optional `sqlite` and `postgres` features add async, SQL-backed repositories
that implement the same async traits as `HashMapRepository`. They persist aggregate
that implement the same async traits as `InMemoryRepository`. They persist aggregate
event streams, relational read-model write plans, processed-message marks,
snapshots, and outbox rows — staging everything through one SQL transaction when
committed via `CommitBatch`. They also enable SQL-backed bus transports over the
Expand Down Expand Up @@ -999,11 +999,11 @@ Handlers are registered with a fluent builder. `.command(name)` / `.event(name)`
```rust,ignore
use std::sync::Arc;
use distributed::microsvc::{Context, HandlerError, Routes, Service, Session};
use distributed::{AggregateBuilder, HashMapRepository, Queueable};
use distributed::{AggregateBuilder, InMemoryRepository, Queueable};
use serde_json::json;

let routes = Routes::new()
.with_repo(HashMapRepository::new().queued().aggregate::<Counter>())
.with_repo(InMemoryRepository::new().queued().aggregate::<Counter>())
.command("counter.initialize")
.handle(|ctx: &Context<Repo>| {
let input = ctx.input::<CreateCounter>();
Expand Down Expand Up @@ -1092,7 +1092,7 @@ Register them with the `routes!` macro:

```rust,ignore
let routes = distributed::routes!(
Routes::new().with_repo(HashMapRepository::new().queued().aggregate::<Counter>()),
Routes::new().with_repo(InMemoryRepository::new().queued().aggregate::<Counter>()),
command handlers::counter_create,
command handlers::counter_increment,
);
Expand Down Expand Up @@ -1335,9 +1335,9 @@ struct Widget {
Chain `.with_snapshots(frequency)` onto any aggregate repository. The frequency is how many events between automatic snapshots:

```rust,ignore
use distributed::{AggregateBuilder, HashMapRepository, Queueable, RepositoryError};
use distributed::{AggregateBuilder, InMemoryRepository, Queueable, RepositoryError};

let repo = HashMapRepository::new()
let repo = InMemoryRepository::new()
.queued()
.aggregate::<Todo>()
.with_snapshots(10); // snapshot every 10 events
Expand Down Expand Up @@ -1512,7 +1512,7 @@ src/
commit_builder/ # Transactional batches for aggregates, outbox, and read models
emitter/ # In-process event emitter helpers (feature = "emitter")
entity/ # Entity, event records, metadata, upcasting codecs
hashmap_repo/ # In-memory repository (implements every async trait)
in_memory_repo/ # In-memory repository (implements every async trait)
lock/ # Lock + lock manager traits, in-memory locks
microsvc/ # Command/event handler framework: service, context, session
outbox/ # Durable outbox message + commit extension
Expand Down
6 changes: 3 additions & 3 deletions distributed_cli/src/generate/service_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,15 @@ pub fn service_manifest() -> ServiceManifest {{

use distributed::{{
microsvc::{{Routes, Service}},
HashMapRepository, ServiceManifest,
InMemoryRepository, ServiceManifest,
}};

use crate::handlers;

pub type ServiceRepo = HashMapRepository;
pub type ServiceRepo = InMemoryRepository;

pub fn in_memory() -> Arc<Service> {{
build(HashMapRepository::new())
build(InMemoryRepository::new())
}}

pub fn build(repo: ServiceRepo) -> Arc<Service> {{
Expand Down
2 changes: 1 addition & 1 deletion docs/postgres-event-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ Intentionally changed:
The in-memory repository already pins the behaviors the Postgres repository must
match:

- `src/hashmap_repo/repository.rs::duplicate_stream_ids_rejected_before_write`
- `src/in_memory_repo/repository.rs::duplicate_stream_ids_rejected_before_write`
verifies duplicate stream IDs are rejected before any write.
- `tests/event_store/main.rs::concurrent_writes_detected` verifies optimistic
conflicts return `ConcurrentWrite`.
Expand Down
2 changes: 1 addition & 1 deletion docs/repositories.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ aggregate_type = "...")`, `aggregate!(..., aggregate_type = "..." { ... })`, or

## In-Memory Reference

`HashMapRepository`, `InMemoryReadModelStore`, and `InMemorySnapshotStore`
`InMemoryRepository`, `InMemoryReadModelStore`, and `InMemorySnapshotStore`
implement the repository traits as a behavioral reference for conformance tests.
The in-memory implementation is not a production I/O adapter; it exists so
Postgres, SQLite, and other persistent backends can be tested against the same
Expand Down
4 changes: 2 additions & 2 deletions src/bus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ mod nats_bus;
mod postgres_bus;
mod publisher;
#[cfg(feature = "rabbitmq")]
mod rabbit_bus;
mod rabbitmq_bus;
#[cfg(feature = "rabbitmq")]
mod rabbitmq;
mod router;
Expand All @@ -132,7 +132,7 @@ pub use nats::{NatsJetStreamSource, NatsPublisher, NatsReceived};
#[cfg(feature = "nats")]
pub use nats_bus::{NatsBus, NatsBusConnect};
#[cfg(feature = "rabbitmq")]
pub use rabbit_bus::{RabbitBus, RabbitBusConnect};
pub use rabbitmq_bus::{RabbitBus, RabbitBusConnect};
#[cfg(feature = "rabbitmq")]
pub use rabbitmq::{RabbitPublisher, RabbitReceived, RabbitSource};

Expand Down
File renamed without changes.
16 changes: 8 additions & 8 deletions src/commit_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ impl<R: TransactionalCommit> ReadModelWritePlanCommitExt for R {}
mod tests {
use super::*;
use crate::{
sourced, Entity, HashMapRepository, ReadModelWorkspaceExt, RowKey, RowValue,
sourced, Entity, InMemoryRepository, ReadModelWorkspaceExt, RowKey, RowValue,
TransactionalCommit,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -381,7 +381,7 @@ mod tests {
.lock_key()
}

async fn loaded_view(repo: &HashMapRepository, id: &str) -> Option<RelationalView> {
async fn loaded_view(repo: &InMemoryRepository, id: &str) -> Option<RelationalView> {
repo.model_store()
.workspace()
.load::<RelationalView>(view_key(id))
Expand All @@ -393,7 +393,7 @@ mod tests {

#[tokio::test]
async fn commit_builder_ext_commits_read_models_and_aggregate() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view = RelationalView {
id: "1".into(),
Expand All @@ -415,7 +415,7 @@ mod tests {

#[tokio::test]
async fn commit_multiple_read_models() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view1 = RelationalView {
id: "1".into(),
Expand Down Expand Up @@ -443,7 +443,7 @@ mod tests {

#[tokio::test]
async fn commit_read_models_with_outbox() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view = RelationalView {
id: "1".into(),
Expand All @@ -466,7 +466,7 @@ mod tests {

#[tokio::test]
async fn commit_outbox_then_read_models() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view = RelationalView {
id: "1".into(),
Expand All @@ -489,7 +489,7 @@ mod tests {

#[tokio::test]
async fn commit_all_without_aggregate() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view1 = RelationalView {
id: "standalone-1".into(),
Expand Down Expand Up @@ -520,7 +520,7 @@ mod tests {

#[tokio::test]
async fn commit_many_multiple_aggregates() {
let repo = HashMapRepository::new();
let repo = InMemoryRepository::new();

let view = RelationalView {
id: "multi".into(),
Expand Down
3 changes: 2 additions & 1 deletion src/emitter/entity_ext.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use event_emitter_rs::EventEmitter;

use crate::entity::{Entity, EventRecordError, LocalEvent};
use super::LocalEvent;
use crate::entity::{Entity, EventRecordError};
use crate::SourcedResult;

/// Extension wrapper that adds event emitter capabilities to an Entity.
Expand Down
7 changes: 7 additions & 0 deletions src/emitter/local_event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// An in-process event queued on an [`EntityEmitter`](super::EntityEmitter)
/// and emitted after a successful commit.
#[derive(Clone, Debug, PartialEq)]
pub struct LocalEvent {
pub event_type: String,
pub data: String,
}
2 changes: 2 additions & 0 deletions src/emitter/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod entity_ext;
mod local_event;

pub use entity_ext::{EmittableEntity, EntityEmitter};
pub use local_event::LocalEvent;
69 changes: 0 additions & 69 deletions src/entity/committable.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/entity/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Entity {
self.replaying
}

pub fn set_replaying(&mut self, replaying: bool) {
pub(crate) fn set_replaying(&mut self, replaying: bool) {
self.replaying = replaying;
}
}
Expand Down
31 changes: 0 additions & 31 deletions src/entity/event.rs

This file was deleted.

Loading
Loading