use itertools::Itertools as _; use super::{ Conversation, Id, event::{Created, Deleted, Event}, }; use crate::{ event::{Instant, Sequence}, name::Name, }; #[derive(Clone, Debug, Eq, PartialEq)] pub struct History { pub conversation: Conversation, } // Lifecycle interface impl History { pub fn begin(name: &Name, created: Instant) -> Self { Self { conversation: Conversation { id: Id::generate(), name: name.clone(), created, deleted: None, }, } } pub fn delete(self, deleted: Instant) -> Result { if self.conversation.deleted.is_none() { Ok(Self { conversation: Conversation { deleted: Some(deleted), ..self.conversation }, }) } else { Err(DeleteError::Deleted(self)) } } } #[derive(Debug, thiserror::Error)] pub enum DeleteError { #[error("conversation {} already deleted", .0.conversation.id)] Deleted(History), } // State interface impl History { pub fn id(&self) -> &Id { &self.conversation.id } // Snapshot of this conversation as it was when created. (Note to the future: // it's okay if this returns a redacted or modified version of the conversation. // If we implement renames by redacting the original name, then this should // return the renamed conversation, not the original, even if that's not how // it was "as created.") pub fn as_created(&self) -> Conversation { self.conversation.clone() } pub fn as_of(&self, sequence: S) -> Option where S: Into, { self.events().filter(Sequence::up_to(sequence)).collect() } // Snapshot of this conversation as of all events recorded in this history. pub fn as_snapshot(&self) -> Option { self.events().collect() } } // Event factories impl History { pub fn events(&self) -> impl Iterator + Clone + use<> { [self.created()] .into_iter() .merge_by(self.deleted(), Sequence::merge) } fn created(&self) -> Event { Created { conversation: self.conversation.clone(), } .into() } fn deleted(&self) -> Option { self.conversation.deleted.map(|instant| { Deleted { instant, id: self.conversation.id.clone(), } .into() }) } }