use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(tag = "type", rename_all = "camelCase", rename_all_fields = "camelCase")]
pub enum SourceIdentity {
CurrentDoc {
workspace_id: String,
doc_id: String,
},
History {
workspace_id: String,
doc_id: String,
timestamp_ms: i64,
},
}
#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
pub(crate) enum SourceIdentityError {
#[error("workspace and document ids must not be empty")]
EmptyId,
#[error("history timestamp is invalid")]
InvalidTimestamp,
}
impl SourceIdentity {
pub(crate) fn validate(&self) -> Result<(), SourceIdentityError> {
if self.workspace_id().is_empty() || self.doc_id().is_empty() {
return Err(SourceIdentityError::EmptyId);
}
if let Self::History { timestamp_ms, .. } = self
&& DateTime::<Utc>::from_timestamp_millis(*timestamp_ms).is_none()
{
return Err(SourceIdentityError::InvalidTimestamp);
}
Ok(())
}
pub fn workspace_id(&self) -> &str {
match self {
Self::CurrentDoc { workspace_id, .. } | Self::History { workspace_id, .. } => workspace_id,
}
}
pub fn doc_id(&self) -> &str {
match self {
Self::CurrentDoc { doc_id, .. } | Self::History { doc_id, .. } => doc_id,
}
}
pub fn is_workspace_root(&self) -> bool {
matches!(
self,
Self::CurrentDoc {
workspace_id,
doc_id
} if workspace_id == doc_id
)
}
}
#[cfg(test)]
#[path = "tests/blob_access/tests.rs"]
mod tests;