use super::GraphNode;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct NodeDiff {
pub package_name: String,
pub ecosystem: String,
pub old_version: Option<String>,
pub new_version: Option<String>,
pub old_hash: Option<String>,
pub new_hash: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GraphDiffResult {
pub added: Vec<GraphNode>,
pub removed: Vec<GraphNode>,
pub changed: Vec<NodeDiff>,
pub unchanged_count: usize,
pub rebuild_required: bool,
}
pub fn diff_graphs(old_nodes: &[GraphNode], new_nodes: &[GraphNode]) -> GraphDiffResult {
let mut old_map: HashMap<(String, String), &GraphNode> = HashMap::new();
for node in old_nodes {
old_map.insert((node.ecosystem.clone(), node.package_name.clone()), node);
}
let mut new_map: HashMap<(String, String), &GraphNode> = HashMap::new();
for node in new_nodes {
new_map.insert((node.ecosystem.clone(), node.package_name.clone()), node);
}
let mut added = Vec::new();
let mut removed = Vec::new();
let mut changed = Vec::new();
let mut unchanged_count = 0;
for (key, new_node) in &new_map {
match old_map.get(key) {
Some(old_node) => {
if old_node.resolved_version != new_node.resolved_version
|| old_node.content_hash != new_node.content_hash
{
changed.push(NodeDiff {
package_name: new_node.package_name.clone(),
ecosystem: new_node.ecosystem.clone(),
old_version: Some(old_node.resolved_version.clone()),
new_version: Some(new_node.resolved_version.clone()),
old_hash: Some(old_node.content_hash.clone()),
new_hash: Some(new_node.content_hash.clone()),
});
} else {
unchanged_count += 1;
}
}
None => {
added.push((*new_node).clone());
}
}
}
for (key, old_node) in &old_map {
if !new_map.contains_key(key) {
removed.push((*old_node).clone());
}
}
let rebuild_required = !added.is_empty() || !removed.is_empty() || !changed.is_empty();
GraphDiffResult {
added,
removed,
changed,
unchanged_count,
rebuild_required,
}
}