1use std::fmt;
2
3use radicle::cob::{ObjectId, TypeName};
4use radicle::git::Oid;
5use radicle::prelude::RepoId;
6
7use crate::models::activity_feed::ActivityFeedOperation;
8use crate::models::entry::{OperationEntry, TimelineEntry};
9
10pub trait FeedStorage {
13 type Error: snafu::Error + 'static;
14
15 fn get_last_processed_operation(
17 &mut self,
18 rid: &RepoId,
19 cob_id: &ObjectId,
20 typename: &TypeName,
21 ) -> Result<Option<String>, Self::Error>;
22
23 fn get_operation_by_id(
24 &mut self,
25 id: &radicle::git::Oid,
26 ) -> Result<ActivityFeedOperation, Self::Error>;
27
28 fn resolve_rid(&mut self, rid: &RepoId) -> Result<Option<String>, Self::Error>;
29
30 fn insert_timeline_entry(&mut self, entry: &TimelineEntry) -> Result<(), Self::Error>;
31
32 fn operation_exists(&mut self, operation_id: &Oid) -> Result<bool, Self::Error>;
34
35 fn insert_batch(&mut self, entries: &[OperationEntry]) -> Result<(), Self::Error>;
37
38 fn get_stats(&mut self) -> Result<StorageStats, Self::Error>;
40}
41
42#[derive(Debug, Default)]
44pub struct StorageStats {
45 pub total_operations: u64,
46 pub operations_by_type: std::collections::HashMap<String, u64>,
47 pub tracked_objects: u64,
48}
49
50impl fmt::Display for StorageStats {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 writeln!(f, "=== Storage Statistics ===")?;
53 writeln!(f, "Total operations: {}", self.total_operations)?;
54
55 for (kind, count) in &self.operations_by_type {
56 writeln!(f, "{}: {}", kind, count)?;
57 }
58
59 writeln!(f, "Tracked objects: {}", self.tracked_objects)?;
60 Ok(())
61 }
62}
63
64pub mod postgres;