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