Skip to main content

Save

Trait Save 

Source
pub trait Save<A>: Send
where A: AggregateRoot,
{ // Required method fn save( &self, aggregate: &mut A, ) -> impl Future<Output = Result<(), PortError>> + Send; }
Expand description

Persists an aggregate.

§Examples

use ddd_toolkit_core::domain::{AggregateRoot, DomainEvent, Entity, EntityId, ValueObject};
use ddd_toolkit_core::mock::repository::InMemoryStore;
use ddd_toolkit_core::port::repository::{Load, Save};
use std::fmt::Display;

let store = InMemoryStore::new();
let mut order = Order { id: OrderId(1), events: vec![OrderPlaced] };

block_on(store.save(&mut order))?;

// save() drains the aggregate's recorded events as a side effect
assert!(order.take_events().is_empty());

let loaded = block_on(store.load(&OrderId(1)))?.expect("just-saved order should be found");
assert_eq!(loaded.id, OrderId(1));

Implementations backed by optimistic concurrency control (e.g. a stored version/etag compared against the aggregate’s current state) should return Err with PortErrorKind::Conflict when the stored version has moved on since the aggregate was loaded, so the caller can reload and retry. The in-memory reference implementations in this crate (mock::repository::InMemoryStore and the doctest fixtures) intentionally do not: they have no notion of a stored version and always last-write-wins, so they never produce Conflict. A real backend copying them as a starting point should add its own version check rather than assume last-write-wins is the port’s default behavior.

Required Methods§

Source

fn save( &self, aggregate: &mut A, ) -> impl Future<Output = Result<(), PortError>> + Send

Persists the aggregate, draining and recording any events it has accumulated via AggregateRoot::take_events. See the trait-level docs for the Conflict contract.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl<A> Save<A> for InMemoryStore<A>
where A: AggregateRoot + Clone,