1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! An event sourced entity (also known as a persistent entity) receives a (non-persistent) command which is first validated
//! if it can be applied to the current state. Here validation can mean anything, from simple inspection of a command message’s
//! fields up to a conversation with several external services, for example. If validation succeeds, events are generated
//! from the command, representing the effect of the command. These events are then persisted and, after successful persistence,
//! used to change the entity's state. When the event sourced actor needs to be recovered, only the persisted events are replayed
//! of which we know that they can be successfully applied. In other words, events cannot fail when being replayed to a persistent
//! entity, in contrast to commands. Event sourced entities may also process commands that do not change application state such
//! as query commands for example.

use async_trait::async_trait;

use crate::effect::Effect;
use crate::EntityId;

/// A context provides information about the environment that hosts a specific entity.
pub struct Context<'a> {
    /// The entity's unique identifier.
    pub entity_id: &'a EntityId,
}

/// An entity's behavior is the basic unit of modelling aspects of an Akka-Persistence-based application and
/// encapsulates how commands can be applied to state, including the emission of events. Events can
/// also be applied to state in order to produce more state.
#[async_trait]
pub trait EventSourcedBehavior {
    /// The state managed by the entity.
    type State: Default;
    /// The command(s) that are able to be processed by the entity.
    type Command;
    /// The event produced having performed an effect.
    type Event;

    /// Given a state and command, optionally produce an effect that may cause an
    /// event transition. Events are responsible for mutating state.
    /// State can also be associated with the behavior so that other effects can be
    /// performed. For example, a behavior might be created with a channel sender
    /// so that data can be sent as an effect of performing a command.
    /// Effects can be chained and are guaranteed to be applied in their entirety
    /// before the next command for their entity id is processed.
    fn for_command(
        context: &Context,
        state: &Self::State,
        command: Self::Command,
    ) -> Box<dyn Effect<Self>>;

    /// Given a state and event, modify state, which could indicate transition to
    /// the next state. No side effects are to be performed. Can be used to replay
    /// events to attain a new state i.e. the major function of event sourcing.
    fn on_event(context: &Context, state: &mut Self::State, event: Self::Event);

    /// The entity will always receive a "recovery completed" signal, even if there
    /// are no events sourced, or if it’s a new entity with a previously unused EntityId.
    /// Any required side effects should be performed once recovery has completed by
    /// overriding this method.
    async fn on_recovery_completed(&self, _context: &Context, _state: &Self::State) {}

    /// Called when the entity manager has completed initially recoverying entities,
    /// even if there are no initial entities.
    async fn on_initial_recovery_completed(&self) {}
}