weavatrix_memory/projection/memory/
apply.rs1use super::{MemoryProjection, state::NodeRevision};
2use crate::{MemoryError, MemoryEvent, Projection, Result, StoredEvent};
3
4impl Projection<MemoryEvent> for MemoryProjection {
5 fn prepare_replay(&mut self, events: &[StoredEvent<MemoryEvent>]) {
6 let mut nodes = 0;
7 let mut facts = 0;
8 for event in events {
9 match event.payload {
10 MemoryEvent::NodeUpserted { .. } => nodes += 1,
11 MemoryEvent::FactRecorded { .. } => facts += 1,
12 MemoryEvent::FactRetracted { .. } => {}
13 }
14 }
15 self.nodes.reserve(nodes);
16 self.facts.reserve(facts);
17 self.node_lookup.reserve(nodes);
18 self.fact_lookup.reserve(facts);
19 self.incident_offsets.reserve(nodes);
20 }
21
22 fn apply(&mut self, event: &StoredEvent<MemoryEvent>) -> Result<()> {
23 if event.metadata.event_type != event.payload.event_type() {
24 return Err(MemoryError::InvalidValue {
25 field: "event_type",
26 reason: "must match the memory event payload",
27 });
28 }
29 match &event.payload {
30 MemoryEvent::NodeUpserted { node } => self.insert_node(NodeRevision {
31 node: node.clone(),
32 recorded_at: event.metadata.recorded_at,
33 position: event.metadata.global_position,
34 })?,
35 MemoryEvent::FactRecorded { fact } => {
36 if fact.recorded_at != event.metadata.recorded_at
37 || fact.agent_id != event.metadata.agent_id
38 || fact.session_id != event.metadata.session_id
39 {
40 return Err(MemoryError::InvalidValue {
41 field: "fact.envelope",
42 reason: "fact provenance must match its event envelope",
43 });
44 }
45 self.insert_fact(fact.clone())?;
46 }
47 MemoryEvent::FactRetracted {
48 fact_id,
49 valid_until,
50 evidence,
51 } => {
52 self.apply_retraction(event.metadata.recorded_at, fact_id, *valid_until, evidence)?;
53 }
54 }
55 self.last_global_position = Some(event.metadata.global_position);
56 Ok(())
57 }
58
59 fn apply_owned(&mut self, event: StoredEvent<MemoryEvent>) -> Result<()> {
60 let StoredEvent { metadata, payload } = event;
61 if metadata.event_type != payload.event_type() {
62 return Err(MemoryError::InvalidValue {
63 field: "event_type",
64 reason: "must match the memory event payload",
65 });
66 }
67 match payload {
68 MemoryEvent::NodeUpserted { node } => self.insert_node(NodeRevision {
69 node,
70 recorded_at: metadata.recorded_at,
71 position: metadata.global_position,
72 })?,
73 MemoryEvent::FactRecorded { fact } => {
74 if fact.recorded_at != metadata.recorded_at
75 || fact.agent_id != metadata.agent_id
76 || fact.session_id != metadata.session_id
77 {
78 return Err(MemoryError::InvalidValue {
79 field: "fact.envelope",
80 reason: "fact provenance must match its event envelope",
81 });
82 }
83 self.insert_fact(fact)?;
84 }
85 MemoryEvent::FactRetracted {
86 fact_id,
87 valid_until,
88 evidence,
89 } => {
90 self.apply_retraction(metadata.recorded_at, &fact_id, valid_until, &evidence)?;
91 }
92 }
93 self.last_global_position = Some(metadata.global_position);
94 Ok(())
95 }
96}