1use crate::{Graph, Node, NodeId, Relation};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
6pub struct Lineage {
7 pub root: Option<Node>,
8 pub incoming: Vec<Relation>,
9 pub outgoing: Vec<Relation>,
10 pub related_nodes: Vec<Node>,
11}
12
13impl Lineage {
14 pub fn from_graph(graph: &Graph, id: &NodeId) -> Self {
15 let incoming = graph.incoming(id, None);
16 let outgoing = graph.outgoing(id, None);
17 let mut related = BTreeMap::new();
18
19 for rel in incoming.iter().chain(outgoing.iter()) {
20 for node_id in [&rel.from, &rel.to] {
21 if node_id != id {
24 if let Some(node) = graph.nodes.get(node_id) {
25 related.insert(node_id.clone(), node.clone());
26 }
27 }
28 }
29 }
30
31 Self {
32 root: graph.nodes.get(id).cloned(),
33 incoming,
34 outgoing,
35 related_nodes: related.into_values().collect(),
36 }
37 }
38
39 pub fn to_markdown(&self) -> String {
40 let Some(root) = &self.root else {
41 return "Node not found.\n".to_string();
42 };
43
44 let title = root
45 .props
46 .get("title")
47 .and_then(|value| value.as_str())
48 .unwrap_or(root.id.as_str());
49 let status = root
50 .props
51 .get("status")
52 .and_then(|value| value.as_str())
53 .unwrap_or("unknown");
54
55 let mut lines = vec![
56 format!("# {}", title),
57 String::new(),
58 format!("- id: {}", root.id),
59 format!("- kind: {}", root.kind),
60 format!("- status: {}", status),
61 ];
62
63 if !root.artifacts.is_empty() {
64 lines.push(String::new());
65 lines.push("## Artifacts".to_string());
66 for artifact in &root.artifacts {
67 lines.push(format!("- {}: {}", artifact.kind, artifact.uri));
68 }
69 }
70
71 if !self.outgoing.is_empty() {
72 lines.push(String::new());
73 lines.push("## Outgoing".to_string());
74 for rel in &self.outgoing {
75 lines.push(format!("- {} -> {}", rel.rel, rel.to));
76 }
77 }
78
79 if !self.incoming.is_empty() {
80 lines.push(String::new());
81 lines.push("## Incoming".to_string());
82 for rel in &self.incoming {
83 lines.push(format!("- {} <- {}", rel.rel, rel.from));
84 }
85 }
86
87 lines.push(String::new());
88 lines.join("\n")
89 }
90}