use super::history_step::{
AvatarUrlHistoryStep, EmailHistoryStep, IdentityHistoryStep, LoginNameHistoryStep,
MetadataHistoryStep, NameHistoryStep,
};
use crate::{
entities::identity::{Identity, identity_operation::IdentityOperationData},
replica::entity::{Entity, operation::Operation, snapshot::timeline::Timeline},
};
#[derive(Debug, Clone)]
pub struct IdentityTimeline {
history: Vec<IdentityHistoryStep>,
}
impl Timeline<Identity> for IdentityTimeline {
fn new() -> Self {
Self { history: vec![] }
}
fn from_root_operation(operation: &Operation<Identity>) -> Self {
let mut me = Self::new();
let IdentityOperationData::Create { name } = operation.operation_data() else {
unreachable!("This should only be called with the root operation.");
};
me.add_name_history(NameHistoryStep {
author: operation.author(),
name: name.to_owned(),
at: operation.creation_time(),
});
me
}
fn add(&mut self, op: &Operation<Identity>) {
match op.operation_data() {
IdentityOperationData::Create { .. } => unreachable!("Already processed."),
IdentityOperationData::SetName { name } => self.add_name_history(NameHistoryStep {
author: op.author(),
name: name.to_owned(),
at: op.creation_time(),
}),
IdentityOperationData::SetEmail { email } => self.add_email_history(EmailHistoryStep {
author: op.author(),
email: email.to_owned(),
at: op.creation_time(),
}),
IdentityOperationData::SetLoginName { login_name } => {
self.add_login_name_history(LoginNameHistoryStep {
author: op.author(),
login_name: login_name.to_owned(),
at: op.creation_time(),
});
}
IdentityOperationData::SetAvatarUrl { url } => {
self.add_avatar_url_history(AvatarUrlHistoryStep {
author: op.author(),
avatar_url: url.to_owned(),
at: op.creation_time(),
});
}
IdentityOperationData::SetMetadata { metadata } => {
self.add_metadata_history(MetadataHistoryStep {
author: op.author(),
metadata: metadata.to_owned(),
at: op.creation_time(),
});
}
}
}
fn history(&self) -> &[<Identity as Entity>::HistoryStep] {
&self.history
}
}
macro_rules! filter_history {
($history:expr, $type_name:ident) => {
filter_history!(@iter $history, $type_name)
};
(@$mode:ident $history:expr, $type_name:ident) => {
$history.$mode().filter_map(|h| {
if let IdentityHistoryStep::$type_name(a) = h {
Some(a)
} else {
None
}
})
};
}
impl IdentityTimeline {
pub fn name_history(&self) -> impl Iterator<Item = &NameHistoryStep> {
filter_history!(self.history, Name)
}
pub fn email_history(&self) -> impl Iterator<Item = &EmailHistoryStep> {
filter_history!(self.history, Email)
}
pub fn login_name_history(&self) -> impl Iterator<Item = &LoginNameHistoryStep> {
filter_history!(self.history, LoginName)
}
pub fn avatar_url_history(&self) -> impl Iterator<Item = &AvatarUrlHistoryStep> {
filter_history!(self.history, AvatarUrl)
}
pub fn metadata_history(&self) -> impl Iterator<Item = &MetadataHistoryStep> {
filter_history!(self.history, Metadata)
}
pub fn add_name_history(&mut self, item: NameHistoryStep) {
self.history.push(IdentityHistoryStep::Name(item));
}
pub fn add_email_history(&mut self, item: EmailHistoryStep) {
self.history.push(IdentityHistoryStep::Email(item));
}
pub fn add_login_name_history(&mut self, item: LoginNameHistoryStep) {
self.history.push(IdentityHistoryStep::LoginName(item));
}
pub fn add_avatar_url_history(&mut self, item: AvatarUrlHistoryStep) {
self.history.push(IdentityHistoryStep::AvatarUrl(item));
}
pub fn add_metadata_history(&mut self, item: MetadataHistoryStep) {
self.history.push(IdentityHistoryStep::Metadata(item));
}
}