use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
use super::RunType;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RunTree {
pub id: Uuid,
pub name: String,
pub run_type: RunType,
pub inputs: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub outputs: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_run_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace_id: Option<Uuid>,
pub start_time: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<DateTime<Utc>>,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
#[serde(default)]
pub tags: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub project_name: Option<String>,
#[serde(default)]
pub serialized: serde_json::Value,
}
impl RunTree {
pub fn new(name: impl Into<String>, run_type: RunType, inputs: serde_json::Value) -> Self {
Self {
id: Uuid::now_v7(),
name: name.into(),
run_type,
inputs,
outputs: None,
error: None,
parent_run_id: None,
trace_id: None,
start_time: Utc::now(),
end_time: None,
metadata: HashMap::new(),
tags: Vec::new(),
project_name: None,
serialized: serde_json::Value::Null,
}
}
pub fn create_child(
&self,
name: impl Into<String>,
run_type: RunType,
inputs: serde_json::Value,
) -> Self {
let mut child = Self::new(name, run_type, inputs);
child.parent_run_id = Some(self.id);
child.trace_id = self.trace_id.or(Some(self.id));
child.project_name = self.project_name.clone();
child
}
pub fn end(&mut self, outputs: serde_json::Value) {
self.outputs = Some(outputs);
self.end_time = Some(Utc::now());
}
pub fn end_with_error(&mut self, error: impl Into<String>) {
self.error = Some(error.into());
self.end_time = Some(Utc::now());
}
pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn with_metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
self.metadata.insert(key.into(), value);
self
}
pub fn with_project(mut self, project: impl Into<String>) -> Self {
self.project_name = Some(project.into());
self
}
pub fn duration_ms(&self) -> Option<i64> {
self.end_time
.map(|end| (end - self.start_time).num_milliseconds())
}
}
#[derive(Debug, Serialize)]
pub struct RunCreate {
pub id: String,
pub name: String,
pub run_type: String,
pub inputs: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub outputs: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_run_id: Option<String>,
pub start_time: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_name: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
pub metadata: HashMap<String, serde_json::Value>,
}
impl From<&RunTree> for RunCreate {
fn from(run: &RunTree) -> Self {
Self {
id: run.id.to_string(),
name: run.name.clone(),
run_type: run.run_type.as_str().to_string(),
inputs: run.inputs.clone(),
outputs: run.outputs.clone(),
error: run.error.clone(),
parent_run_id: run.parent_run_id.map(|id| id.to_string()),
start_time: run.start_time.to_rfc3339(),
end_time: run.end_time.map(|t| t.to_rfc3339()),
session_name: run.project_name.clone(),
tags: run.tags.clone(),
metadata: run.metadata.clone(),
}
}
}
#[derive(Debug, Serialize)]
pub struct RunUpdate {
#[serde(skip_serializing_if = "Option::is_none")]
pub outputs: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<String>,
}
impl From<&RunTree> for RunUpdate {
fn from(run: &RunTree) -> Self {
Self {
outputs: run.outputs.clone(),
error: run.error.clone(),
end_time: run.end_time.map(|t| t.to_rfc3339()),
}
}
}