Skip to main content

made_core/entities/ceremony_instance/
transitions.rs

1use super::{
2    CeremonyDefinition, CeremonyInstance, CeremonyTransitionRecord, DomainError, OffsetDateTime,
3    RoleAction, RoleId, StateId, TransitionTrigger,
4};
5
6impl CeremonyInstance {
7    pub fn apply_transition_as(
8        &mut self,
9        definition: &CeremonyDefinition,
10        role_id: &RoleId,
11        trigger: &TransitionTrigger,
12        now: OffsetDateTime,
13    ) -> Result<StateId, DomainError> {
14        self.require_role(
15            definition,
16            role_id,
17            &RoleAction::transition(trigger.clone()),
18        )?;
19        self.move_on(definition, trigger, Some(role_id.clone()), now)
20    }
21
22    pub fn apply_transition(
23        &mut self,
24        definition: &CeremonyDefinition,
25        trigger: &TransitionTrigger,
26        now: OffsetDateTime,
27    ) -> Result<StateId, DomainError> {
28        self.move_on(definition, trigger, None, now)
29    }
30
31    /// The one place a session moves.
32    ///
33    /// `applied_by` is absent when the engine took the move itself,
34    /// and naming somebody would be inventing them.
35    fn move_on(
36        &mut self,
37        definition: &CeremonyDefinition,
38        trigger: &TransitionTrigger,
39        applied_by: Option<RoleId>,
40        now: OffsetDateTime,
41    ) -> Result<StateId, DomainError> {
42        self.require_definition(definition)?;
43        if self.is_terminal(definition) {
44            return Err(DomainError::InvariantViolated {
45                reason: "terminal ceremony instances cannot transition",
46            });
47        }
48
49        let transition = definition
50            .transition_for_trigger(&self.current_state, trigger)
51            .ok_or(DomainError::InvalidTransition {
52                from: "ceremony_instance.current_state",
53                to: "transition_trigger",
54            })?;
55        if !definition.repeat_requirements_are_satisfied(&self.current_state, &self.step_records) {
56            return Err(DomainError::InvariantViolated {
57                reason: "ceremony step repeat condition is not satisfied",
58            });
59        }
60        if !definition.guards_are_satisfied(transition, &self.step_records, &self.context) {
61            return Err(DomainError::InvariantViolated {
62                reason: "ceremony transition guards are not satisfied",
63            });
64        }
65
66        let from_state = self.current_state.clone();
67        self.current_state = transition.to().clone();
68        self.transitions.push(CeremonyTransitionRecord::record(
69            trigger.clone(),
70            from_state,
71            self.current_state.clone(),
72            applied_by,
73            now,
74        ));
75        self.updated_at = now;
76        if definition.is_terminal_state(&self.current_state) {
77            self.completed_at = Some(now);
78        }
79        Ok(self.current_state.clone())
80    }
81}