use crate::engine::error::{DataflowError, Result};
use crate::engine::task::Task;
use serde::Deserialize;
use serde_json::Value;
use std::fs;
use std::path::Path;
#[derive(Deserialize, Clone, Debug)]
pub struct Workflow {
pub id: String,
pub name: String,
pub description: Option<String>,
pub condition: Option<Value>,
pub tasks: Vec<Task>,
}
impl Default for Workflow {
fn default() -> Self {
Self::new()
}
}
impl Workflow {
pub fn new() -> Self {
Workflow {
id: String::new(),
name: String::new(),
description: None,
condition: None,
tasks: Vec::new(),
}
}
pub fn from_json(json_str: &str) -> Result<Self> {
serde_json::from_str(json_str).map_err(DataflowError::from_serde)
}
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let json_str = fs::read_to_string(path).map_err(DataflowError::from_io)?;
Self::from_json(&json_str)
}
pub fn validate(&self) -> Result<()> {
if self.id.is_empty() {
return Err(DataflowError::Workflow(
"Workflow id cannot be empty".to_string(),
));
}
if self.name.is_empty() {
return Err(DataflowError::Workflow(
"Workflow name cannot be empty".to_string(),
));
}
if self.tasks.is_empty() {
return Err(DataflowError::Workflow(
"Workflow must have at least one task".to_string(),
));
}
let mut task_ids = std::collections::HashSet::new();
for task in &self.tasks {
if !task_ids.insert(&task.id) {
return Err(DataflowError::Workflow(format!(
"Duplicate task ID '{}' in workflow",
task.id
)));
}
}
Ok(())
}
}