1use std::{hash::Hash, sync::Arc};
16use ulid::Ulid;
17
18use crate::{
19 cursor::{Args, ReadResult, Value},
20 Event, RoutingKey, WriteError,
21};
22
23#[derive(Clone, PartialEq, Eq)]
40pub struct ReadAggregator {
41 pub aggregator_type: String,
43 pub aggregator_id: Option<String>,
45 pub name: Option<String>,
47}
48
49impl ReadAggregator {
50 pub fn new(
54 aggregator_type: impl Into<String>,
55 id: impl Into<String>,
56 name: impl Into<String>,
57 ) -> Self {
58 Self {
59 aggregator_type: aggregator_type.into(),
60 aggregator_id: Some(id.into()),
61 name: Some(name.into()),
62 }
63 }
64
65 pub fn aggregator(value: impl Into<String>) -> Self {
69 Self {
70 aggregator_type: value.into(),
71 aggregator_id: None,
72 name: None,
73 }
74 }
75
76 pub fn id(aggregator_type: impl Into<String>, id: impl Into<String>) -> Self {
80 Self {
81 aggregator_type: aggregator_type.into(),
82 aggregator_id: Some(id.into()),
83 name: None,
84 }
85 }
86
87 pub fn event(aggregator_type: impl Into<String>, name: impl Into<String>) -> Self {
91 Self {
92 aggregator_type: aggregator_type.into(),
93 aggregator_id: None,
94 name: Some(name.into()),
95 }
96 }
97}
98
99impl Hash for ReadAggregator {
100 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
101 self.aggregator_type.hash(state);
102 self.aggregator_id.hash(state);
103 self.name.hash(state);
104 }
105}
106
107#[async_trait::async_trait]
122pub trait Executor: Send + Sync + 'static {
123 async fn write(&self, events: Vec<Event>) -> Result<(), WriteError>;
127
128 async fn get_subscriber_cursor(&self, key: String) -> anyhow::Result<Option<Value>>;
130
131 async fn is_subscriber_running(&self, key: String, worker_id: Ulid) -> anyhow::Result<bool>;
133
134 async fn upsert_subscriber(&self, key: String, worker_id: Ulid) -> anyhow::Result<()>;
136
137 async fn acknowledge(&self, key: String, cursor: Value, lag: u64) -> anyhow::Result<()>;
139
140 async fn read(
142 &self,
143 aggregators: Option<Vec<ReadAggregator>>,
144 routing_key: Option<RoutingKey>,
145 args: Args,
146 ) -> anyhow::Result<ReadResult<Event>>;
147
148 async fn latest_timestamp(
153 &self,
154 aggregators: Option<Vec<ReadAggregator>>,
155 routing_key: Option<RoutingKey>,
156 ) -> anyhow::Result<u64>;
157
158 async fn get_snapshot(
163 &self,
164 aggregator_type: String,
165 aggregator_revision: String,
166 id: String,
167 ) -> anyhow::Result<Option<(Vec<u8>, Value)>>;
168
169 async fn save_snapshot(
174 &self,
175 aggregator_type: String,
176 aggregator_revision: String,
177 id: String,
178 data: Vec<u8>,
179 cursor: Value,
180 ) -> anyhow::Result<()>;
181}
182
183pub struct Evento(Arc<Box<dyn Executor>>);
198
199impl Clone for Evento {
200 fn clone(&self) -> Self {
201 Self(self.0.clone())
202 }
203}
204
205#[async_trait::async_trait]
206impl Executor for Evento {
207 async fn write(&self, events: Vec<Event>) -> Result<(), WriteError> {
208 self.0.write(events).await
209 }
210
211 async fn read(
212 &self,
213 aggregators: Option<Vec<ReadAggregator>>,
214 routing_key: Option<RoutingKey>,
215 args: Args,
216 ) -> anyhow::Result<ReadResult<Event>> {
217 self.0.read(aggregators, routing_key, args).await
218 }
219
220 async fn latest_timestamp(
221 &self,
222 aggregators: Option<Vec<ReadAggregator>>,
223 routing_key: Option<RoutingKey>,
224 ) -> anyhow::Result<u64> {
225 self.0.latest_timestamp(aggregators, routing_key).await
226 }
227
228 async fn get_subscriber_cursor(&self, key: String) -> anyhow::Result<Option<Value>> {
229 self.0.get_subscriber_cursor(key).await
230 }
231
232 async fn is_subscriber_running(&self, key: String, worker_id: Ulid) -> anyhow::Result<bool> {
233 self.0.is_subscriber_running(key, worker_id).await
234 }
235
236 async fn upsert_subscriber(&self, key: String, worker_id: Ulid) -> anyhow::Result<()> {
237 self.0.upsert_subscriber(key, worker_id).await
238 }
239
240 async fn acknowledge(&self, key: String, cursor: Value, lag: u64) -> anyhow::Result<()> {
241 self.0.acknowledge(key, cursor, lag).await
242 }
243
244 async fn get_snapshot(
245 &self,
246 aggregator_type: String,
247 aggregator_revision: String,
248 id: String,
249 ) -> anyhow::Result<Option<(Vec<u8>, Value)>> {
250 self.0
251 .get_snapshot(aggregator_type, aggregator_revision, id)
252 .await
253 }
254
255 async fn save_snapshot(
256 &self,
257 aggregator_type: String,
258 aggregator_revision: String,
259 id: String,
260 data: Vec<u8>,
261 cursor: Value,
262 ) -> anyhow::Result<()> {
263 self.0
264 .save_snapshot(aggregator_type, aggregator_revision, id, data, cursor)
265 .await
266 }
267}
268
269impl Evento {
270 pub fn new<E: Executor>(executor: E) -> Self {
272 Self(Arc::new(Box::new(executor)))
273 }
274}
275
276#[cfg(feature = "group")]
283#[derive(Clone, Default)]
284pub struct EventoGroup {
285 executors: Vec<Evento>,
286}
287
288#[cfg(feature = "group")]
289impl EventoGroup {
290 pub fn executor(mut self, executor: impl Into<Evento>) -> Self {
294 self.executors.push(executor.into());
295
296 self
297 }
298
299 pub fn first(&self) -> &Evento {
305 self.executors
306 .first()
307 .expect("EventoGroup must have at least one executor")
308 }
309}
310
311#[cfg(feature = "group")]
312#[async_trait::async_trait]
313impl Executor for EventoGroup {
314 async fn write(&self, events: Vec<Event>) -> Result<(), WriteError> {
315 self.first().write(events).await
316 }
317
318 async fn read(
319 &self,
320 aggregators: Option<Vec<ReadAggregator>>,
321 routing_key: Option<RoutingKey>,
322 args: Args,
323 ) -> anyhow::Result<ReadResult<Event>> {
324 use crate::cursor;
325 let futures = self
326 .executors
327 .iter()
328 .map(|e| e.read(aggregators.to_owned(), routing_key.to_owned(), args.clone()));
329
330 let results = futures_util::future::join_all(futures).await;
331 let mut events = vec![];
332 for res in results {
333 for edge in res?.edges {
334 events.push(edge.node);
335 }
336 }
337
338 Ok(cursor::Reader::new(events).args(args).execute()?)
339 }
340
341 async fn latest_timestamp(
342 &self,
343 aggregators: Option<Vec<ReadAggregator>>,
344 routing_key: Option<RoutingKey>,
345 ) -> anyhow::Result<u64> {
346 let futures = self
347 .executors
348 .iter()
349 .map(|e| e.latest_timestamp(aggregators.to_owned(), routing_key.to_owned()));
350
351 let results = futures_util::future::join_all(futures).await;
352 let mut max = 0u64;
353 for res in results {
354 let ts = res?;
355 if ts > max {
356 max = ts;
357 }
358 }
359
360 Ok(max)
361 }
362
363 async fn get_subscriber_cursor(&self, key: String) -> anyhow::Result<Option<Value>> {
364 self.first().get_subscriber_cursor(key).await
365 }
366
367 async fn is_subscriber_running(&self, key: String, worker_id: Ulid) -> anyhow::Result<bool> {
368 self.first().is_subscriber_running(key, worker_id).await
369 }
370
371 async fn upsert_subscriber(&self, key: String, worker_id: Ulid) -> anyhow::Result<()> {
372 self.first().upsert_subscriber(key, worker_id).await
373 }
374
375 async fn acknowledge(&self, key: String, cursor: Value, lag: u64) -> anyhow::Result<()> {
376 self.first().acknowledge(key, cursor, lag).await
377 }
378
379 async fn get_snapshot(
380 &self,
381 aggregator_type: String,
382 aggregator_revision: String,
383 id: String,
384 ) -> anyhow::Result<Option<(Vec<u8>, Value)>> {
385 self.first()
386 .get_snapshot(aggregator_type, aggregator_revision, id)
387 .await
388 }
389
390 async fn save_snapshot(
391 &self,
392 aggregator_type: String,
393 aggregator_revision: String,
394 id: String,
395 data: Vec<u8>,
396 cursor: Value,
397 ) -> anyhow::Result<()> {
398 self.first()
399 .save_snapshot(aggregator_type, aggregator_revision, id, data, cursor)
400 .await
401 }
402}
403
404#[cfg(feature = "rw")]
415pub struct Rw<R: Executor, W: Executor> {
416 r: R,
417 w: W,
418}
419
420#[cfg(feature = "rw")]
421impl<R: Executor + Clone, W: Executor + Clone> Clone for Rw<R, W> {
422 fn clone(&self) -> Self {
423 Self {
424 r: self.r.clone(),
425 w: self.w.clone(),
426 }
427 }
428}
429
430#[cfg(feature = "rw")]
431#[async_trait::async_trait]
432impl<R: Executor, W: Executor> Executor for Rw<R, W> {
433 async fn write(&self, events: Vec<Event>) -> Result<(), WriteError> {
434 self.w.write(events).await
435 }
436
437 async fn read(
438 &self,
439 aggregators: Option<Vec<ReadAggregator>>,
440 routing_key: Option<RoutingKey>,
441 args: Args,
442 ) -> anyhow::Result<ReadResult<Event>> {
443 self.r.read(aggregators, routing_key, args).await
444 }
445
446 async fn latest_timestamp(
447 &self,
448 aggregators: Option<Vec<ReadAggregator>>,
449 routing_key: Option<RoutingKey>,
450 ) -> anyhow::Result<u64> {
451 self.r.latest_timestamp(aggregators, routing_key).await
452 }
453
454 async fn get_subscriber_cursor(&self, key: String) -> anyhow::Result<Option<Value>> {
455 self.r.get_subscriber_cursor(key).await
456 }
457
458 async fn is_subscriber_running(&self, key: String, worker_id: Ulid) -> anyhow::Result<bool> {
459 self.r.is_subscriber_running(key, worker_id).await
460 }
461
462 async fn upsert_subscriber(&self, key: String, worker_id: Ulid) -> anyhow::Result<()> {
463 self.w.upsert_subscriber(key, worker_id).await
464 }
465
466 async fn acknowledge(&self, key: String, cursor: Value, lag: u64) -> anyhow::Result<()> {
467 self.w.acknowledge(key, cursor, lag).await
468 }
469
470 async fn get_snapshot(
471 &self,
472 aggregator_type: String,
473 aggregator_revision: String,
474 id: String,
475 ) -> anyhow::Result<Option<(Vec<u8>, Value)>> {
476 self.r
477 .get_snapshot(aggregator_type, aggregator_revision, id)
478 .await
479 }
480
481 async fn save_snapshot(
482 &self,
483 aggregator_type: String,
484 aggregator_revision: String,
485 id: String,
486 data: Vec<u8>,
487 cursor: Value,
488 ) -> anyhow::Result<()> {
489 self.w
490 .save_snapshot(aggregator_type, aggregator_revision, id, data, cursor)
491 .await
492 }
493}
494
495#[cfg(feature = "rw")]
496impl<R: Executor, W: Executor> From<(R, W)> for Rw<R, W> {
497 fn from((r, w): (R, W)) -> Self {
498 Self { r, w }
499 }
500}