bijux-dag-artifacts 0.4.1

Artifact identity, persistence, integrity, and lifecycle helpers for Bijux DAG runs.
Documentation
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ArtifactLineageEdge {
    pub artifact_id: String,
    pub producer_node_id: String,
    pub upstream_artifact_ids: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ArtifactLineageSnapshot {
    pub schema_version: String,
    pub edges: Vec<ArtifactLineageEdge>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ArtifactLineageVisualization {
    pub schema_version: String,
    pub nodes: Vec<String>,
    pub links: Vec<(String, String)>,
}

pub fn write_lineage_snapshot(
    path: impl AsRef<Path>,
    snapshot: &ArtifactLineageSnapshot,
) -> Result<(), String> {
    let path = path.as_ref();
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).map_err(|err| err.to_string())?;
    }
    let payload = serialize_lineage_snapshot(snapshot)?;
    fs::write(path, payload).map_err(|err| err.to_string())
}

pub fn serialize_lineage_snapshot(snapshot: &ArtifactLineageSnapshot) -> Result<Vec<u8>, String> {
    serde_json::to_vec_pretty(snapshot).map_err(|err| err.to_string())
}

pub fn export_lineage_visualization(
    path: impl AsRef<Path>,
    snapshot: &ArtifactLineageSnapshot,
) -> Result<(), String> {
    let visualization = build_lineage_visualization(snapshot);
    let path = path.as_ref();
    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).map_err(|err| err.to_string())?;
    }
    let payload = serialize_lineage_visualization(&visualization)?;
    fs::write(path, payload).map_err(|err| err.to_string())
}

pub fn serialize_lineage_visualization(
    visualization: &ArtifactLineageVisualization,
) -> Result<Vec<u8>, String> {
    serde_json::to_vec_pretty(visualization).map_err(|err| err.to_string())
}

pub fn build_lineage_visualization(
    snapshot: &ArtifactLineageSnapshot,
) -> ArtifactLineageVisualization {
    let mut nodes: Vec<String> = snapshot
        .edges
        .iter()
        .flat_map(|edge| {
            let mut list = vec![edge.artifact_id.clone()];
            list.extend(edge.upstream_artifact_ids.clone());
            list
        })
        .collect();
    nodes.sort();
    nodes.dedup();
    let links: Vec<(String, String)> = snapshot
        .edges
        .iter()
        .flat_map(|edge| {
            edge.upstream_artifact_ids
                .iter()
                .map(|up| (up.clone(), edge.artifact_id.clone()))
                .collect::<Vec<_>>()
        })
        .collect();
    ArtifactLineageVisualization { schema_version: snapshot.schema_version.clone(), nodes, links }
}