#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GraphMetadata {
pub created_at: u64,
pub version: u64,
pub description: String,
pub attributes: indexmap::IndexMap<String, String>,
}
impl GraphMetadata {
pub fn new(description: &str) -> Self {
Self {
created_at: Self::current_timestamp(),
version: 1,
description: String::from(description),
attributes: indexmap::IndexMap::new(),
}
}
pub fn with_version(description: &str, version: u64) -> Self {
Self {
created_at: Self::current_timestamp(),
version,
description: String::from(description),
attributes: indexmap::IndexMap::new(),
}
}
fn current_timestamp() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}
pub fn get_attribute(&self, key: &str) -> Option<&String> {
self.attributes.get(key)
}
pub fn add_warning(&mut self, message: String) {
let index = self
.attributes
.keys()
.filter(|k| k.starts_with("warning."))
.count();
self
.attributes
.insert(std::format!("warning.{index}"), message);
}
pub fn warnings(&self) -> std::vec::Vec<&String> {
let mut keyed: std::vec::Vec<(usize, &String)> = self
.attributes
.iter()
.filter_map(|(k, v)| {
k.strip_prefix("warning.")
.and_then(|n| n.parse::<usize>().ok())
.map(|n| (n, v))
})
.collect();
keyed.sort_by_key(|(n, _)| *n);
keyed.into_iter().map(|(_, v)| v).collect()
}
}
impl Default for GraphMetadata {
fn default() -> Self {
Self::new("Hexagonal Architecture Graph")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_graph_metadata_creation() {
let metadata = GraphMetadata::new("Test Graph");
assert_eq!(metadata.description, "Test Graph");
assert_eq!(metadata.version, 1);
assert!(metadata.created_at > 0);
}
#[test]
fn test_graph_metadata_with_version() {
let metadata = GraphMetadata::with_version("Test", 42);
assert_eq!(metadata.version, 42);
}
#[test]
fn test_graph_metadata_default() {
let metadata = GraphMetadata::default();
assert!(metadata.description.contains("Hexagonal"));
}
#[test]
fn test_add_and_read_warnings_in_order() {
let mut metadata = GraphMetadata::new("Test");
assert!(metadata.warnings().is_empty());
metadata.add_warning(String::from("first"));
metadata.add_warning(String::from("second"));
let warnings = metadata.warnings();
assert_eq!(warnings.len(), 2);
assert_eq!(warnings[0], "first");
assert_eq!(warnings[1], "second");
}
}