use radicle::cob::{Op, TypeName};
use radicle::node::AliasStore;
use radicle::profile::Aliases;
use snafu::ResultExt;
use crate::feed::cobs;
use crate::models::entry::OperationEntry;
use crate::storage::FeedStorage;
pub struct OperationBuilder<'a> {
aliases: &'a Aliases,
rid: &'a radicle::prelude::RepoId,
typename: &'a TypeName,
repo_alias: Option<String>,
}
impl<'a> OperationBuilder<'a> {
pub fn new(
aliases: &'a Aliases,
rid: &'a radicle::prelude::RepoId,
typename: &'a TypeName,
repo_alias: Option<String>,
) -> Self {
Self {
aliases,
rid,
typename,
repo_alias,
}
}
pub fn build_operations<A, S: FeedStorage>(
&self,
stream_entries: Vec<Op<A>>,
mut last_processed_id: Option<radicle::git::Oid>,
storage: &mut S,
) -> Result<(Vec<OperationEntry>, Option<radicle::git::Oid>), snafu::Whatever>
where
A: serde::Serialize + for<'de> serde::Deserialize<'de> + Clone,
{
let mut operations = Vec::new();
let mut state_accumulator: cobs::CobStateAccumulator = match last_processed_id {
Some(ref last) => {
let last_operation = storage
.get_operation_by_id(last)
.whatever_context("context")?;
last_operation.into()
}
None => cobs::CobStateAccumulator::new(),
};
for stream_entry in stream_entries {
for action in &stream_entry.actions {
let action_json = serde_json::to_value(action.clone())
.whatever_context("Failed to serialize action")?;
state_accumulator.update_from_action(&action_json);
}
if storage
.operation_exists(&stream_entry.id())
.whatever_context("Unable to query for existing operation")?
{
tracing::debug!("Operation already exists in storage, skipping");
continue;
}
operations.push(OperationEntry {
operation_id: stream_entry.id().to_string(),
rid: self.rid.to_string(),
cob_title: state_accumulator.title(),
cob_status: state_accumulator.state(),
repo_alias: self.repo_alias.clone(),
created_at: stream_entry.timestamp.as_secs() as i32,
actions: stream_entry
.actions
.clone()
.into_iter()
.filter_map(|action| serde_json::to_value(action).ok())
.collect(),
author: stream_entry.author.to_string(),
author_alias: self.aliases.alias(&stream_entry.author).map(Into::into),
typename: self.typename.to_string(),
});
last_processed_id = Some(stream_entry.id());
}
Ok((operations, last_processed_id))
}
}