1use async_trait::async_trait;
9use serde_json::{Map, Value};
10
11use crate::error::Result;
12use crate::event::{now_ms, stamp, validate};
13use crate::position::Committed;
14use crate::store::{Decision, EventStore};
15use crate::upcast::{apply_chain, Current, UpcastChain};
16
17#[derive(Default)]
18pub struct MemEventStore {
19 stream_id: String,
20 events: Vec<Map<String, Value>>,
21 chain: UpcastChain,
22}
23
24impl MemEventStore {
25 pub fn new(stream_id: impl Into<String>) -> Self {
26 MemEventStore {
27 stream_id: stream_id.into(),
28 events: Vec::new(),
29 chain: UpcastChain::new(),
30 }
31 }
32
33 pub fn with_upcasters(mut self, chain: UpcastChain) -> Self {
35 self.chain = chain;
36 self
37 }
38
39 fn project(&self, kinds: Option<&[&str]>, from_seq: u64, limit: usize) -> Result<Vec<Current>> {
42 let selected: Vec<Value> = self
43 .events
44 .iter()
45 .filter(|event| stored_seq(event) >= from_seq)
46 .filter(|event| match kinds {
47 None => true,
48 Some(kinds) => stored_kind(event).is_some_and(|k| kinds.contains(&k)),
49 })
50 .take(limit)
51 .map(|event| Value::Object(event.clone()))
52 .collect();
53 apply_chain(&self.chain, selected)
54 .into_iter()
55 .map(Current::from_upcasted)
56 .collect()
57 }
58
59 fn next_seq(&self) -> u64 {
60 self.events.len() as u64 + 1
61 }
62}
63
64#[async_trait]
65impl EventStore for MemEventStore {
66 fn stream_id(&self) -> &str {
67 &self.stream_id
68 }
69
70 async fn append(&mut self, event: Map<String, Value>) -> Result<Committed> {
71 let seq = self.next_seq();
72 let epoch_ms = now_ms();
73 let stamped = stamp(event, seq, epoch_ms)?;
74 self.events.push(stamped);
75 Ok(Committed {
76 seq,
77 epoch_ms,
78 position: None,
79 })
80 }
81
82 async fn append_many(&mut self, events: Vec<Map<String, Value>>) -> Result<Vec<Committed>> {
85 for event in &events {
86 validate(event)?;
87 }
88 let mut committed = Vec::with_capacity(events.len());
89 for event in events {
90 committed.push(self.append(event).await?);
91 }
92 Ok(committed)
93 }
94
95 async fn append_if(
96 &mut self,
97 kinds: Option<&[&str]>,
98 decide: Decision,
99 ) -> Result<Option<Committed>> {
100 let seen = self.project(kinds, 0, usize::MAX)?;
101 match decide(&seen) {
102 None => Ok(None),
103 Some(event) => self.append(event).await.map(Some),
104 }
105 }
106
107 async fn read_kinds(
108 &self,
109 kinds: Option<&[&str]>,
110 from_seq: u64,
111 limit: usize,
112 ) -> Result<Vec<Current>> {
113 self.project(kinds, from_seq, limit)
114 }
115
116 async fn read_last(&self, n: usize) -> Result<Vec<Current>> {
117 let from = self.events.len().saturating_sub(n);
118 let selected: Vec<Value> = self.events[from..]
119 .iter()
120 .map(|event| Value::Object(event.clone()))
121 .collect();
122 apply_chain(&self.chain, selected)
123 .into_iter()
124 .map(Current::from_upcasted)
125 .collect()
126 }
127
128 async fn head(&self) -> Result<Option<u64>> {
129 Ok(self.events.last().map(stored_seq))
130 }
131
132 async fn len(&self) -> Result<usize> {
133 Ok(self.events.len())
134 }
135}
136
137fn stored_seq(event: &Map<String, Value>) -> u64 {
138 event
139 .get(crate::event::FIELD_SEQ)
140 .and_then(Value::as_u64)
141 .expect("every stored event was stamped")
142}
143
144fn stored_kind(event: &Map<String, Value>) -> Option<&str> {
145 event.get(crate::event::FIELD_KIND).and_then(Value::as_str)
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use serde_json::json;
152
153 fn object(value: Value) -> Map<String, Value> {
154 value
155 .as_object()
156 .expect("test literal is an object")
157 .clone()
158 }
159
160 fn event(kind: &str) -> Map<String, Value> {
161 object(json!({ "kind": kind }))
162 }
163
164 #[tokio::test]
165 async fn seq_starts_at_one_and_increases() {
166 let mut store = MemEventStore::new("s");
167 assert_eq!(store.append(event("a")).await.unwrap().seq, 1);
168 assert_eq!(store.append(event("b")).await.unwrap().seq, 2);
169 assert_eq!(store.head().await.unwrap(), Some(2));
170 assert_eq!(store.len().await.unwrap(), 2);
171 }
172
173 #[tokio::test]
174 async fn a_rejected_event_consumes_no_sequence_number() {
175 let mut store = MemEventStore::new("s");
176 store.append(event("a")).await.unwrap();
177 assert!(store.append(object(json!({ "nope": 1 }))).await.is_err());
178 assert_eq!(store.append(event("b")).await.unwrap().seq, 2);
179 }
180
181 #[tokio::test]
182 async fn a_batch_that_fails_validation_writes_none_of_itself() {
183 let mut store = MemEventStore::new("s");
184 let batch = vec![event("a"), object(json!({ "nope": 1 }))];
185 assert!(store.append_many(batch).await.is_err());
186 assert_eq!(store.len().await.unwrap(), 0);
187 }
188
189 #[tokio::test]
190 async fn reads_filter_by_kind_and_limit_counts_what_came_back() {
191 let mut store = MemEventStore::new("s");
192 for kind in ["a", "b", "a", "b", "a"] {
193 store.append(event(kind)).await.unwrap();
194 }
195 let read = store.read_kinds(Some(&["a"]), 0, 2).await.unwrap();
196 assert_eq!(read.len(), 2);
197 assert!(read.iter().all(|e| e.kind() == "a"));
198 assert_eq!(read[0].seq(), 1);
199 assert_eq!(read[1].seq(), 3);
200 }
201
202 #[tokio::test]
203 async fn an_empty_kind_slice_selects_nothing() {
204 let mut store = MemEventStore::new("s");
205 store.append(event("a")).await.unwrap();
206 assert!(store.read_kinds(Some(&[]), 0, 10).await.unwrap().is_empty());
207 }
208
209 #[tokio::test]
210 async fn a_decision_sees_the_filtered_stream_and_may_write_nothing() {
211 let mut store = MemEventStore::new("s");
212 store.append(event("a")).await.unwrap();
213 store.append(event("b")).await.unwrap();
214
215 let refused = store
216 .append_if(
217 Some(&["a"]),
218 Box::new(|seen| {
219 assert_eq!(seen.len(), 1);
220 assert_eq!(seen[0].kind(), "a");
221 None
222 }),
223 )
224 .await
225 .unwrap();
226 assert!(refused.is_none());
227 assert_eq!(store.len().await.unwrap(), 2);
228
229 let written = store
230 .append_if(
231 None,
232 Box::new(|seen| {
233 Some(object(
234 json!({ "kind": "c", "data": { "saw": seen.len() } }),
235 ))
236 }),
237 )
238 .await
239 .unwrap();
240 assert_eq!(written.unwrap().seq, 3);
241 }
242
243 #[tokio::test]
244 async fn read_last_returns_the_end_in_seq_order() {
245 let mut store = MemEventStore::new("s");
246 for kind in ["a", "b", "c"] {
247 store.append(event(kind)).await.unwrap();
248 }
249 let last = store.read_last(2).await.unwrap();
250 assert_eq!(last.len(), 2);
251 assert_eq!(last[0].kind(), "b");
252 assert_eq!(last[1].kind(), "c");
253 }
254
255 #[tokio::test]
256 async fn this_backend_assigns_no_global_position() {
257 let mut store = MemEventStore::new("s");
258 assert!(store.append(event("a")).await.unwrap().position.is_none());
259 }
260}