use async_trait::async_trait;
use chrono::{DateTime, Utc};
use paladin_core::platform::container::workflow::Workflow;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum WorkflowPersistenceStatus {
Pending,
Running,
Completed,
Failed,
}
impl WorkflowPersistenceStatus {
pub fn as_str(&self) -> &'static str {
match self {
WorkflowPersistenceStatus::Pending => "pending",
WorkflowPersistenceStatus::Running => "running",
WorkflowPersistenceStatus::Completed => "completed",
WorkflowPersistenceStatus::Failed => "failed",
}
}
pub fn from_str_value(value: &str) -> Result<Self, WorkflowRepositoryError> {
match value {
"pending" => Ok(WorkflowPersistenceStatus::Pending),
"running" => Ok(WorkflowPersistenceStatus::Running),
"completed" => Ok(WorkflowPersistenceStatus::Completed),
"failed" => Ok(WorkflowPersistenceStatus::Failed),
other => Err(WorkflowRepositoryError::DeserializationError(format!(
"unknown workflow status: {other}"
))),
}
}
pub fn is_terminal(&self) -> bool {
matches!(
self,
WorkflowPersistenceStatus::Completed | WorkflowPersistenceStatus::Failed
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistedWorkflow {
pub workflow_id: Uuid,
pub status: WorkflowPersistenceStatus,
pub completed_job_ids: Vec<Uuid>,
pub definition: Workflow,
pub updated_at: DateTime<Utc>,
}
impl PersistedWorkflow {
pub fn pending(definition: Workflow) -> Self {
Self {
workflow_id: definition.id,
status: WorkflowPersistenceStatus::Pending,
completed_job_ids: Vec::new(),
definition,
updated_at: Utc::now(),
}
}
}
#[derive(Debug, Error)]
pub enum WorkflowRepositoryError {
#[error("Workflow repository error: {0}")]
RepositoryError(String),
#[error("Workflow deserialization error: {0}")]
DeserializationError(String),
#[error("Workflow serialization error: {0}")]
SerializationError(String),
}
#[async_trait]
pub trait WorkflowRepositoryPort: Send + Sync {
async fn save(&self, record: &PersistedWorkflow) -> Result<(), WorkflowRepositoryError>;
async fn load(
&self,
workflow_id: Uuid,
) -> Result<Option<PersistedWorkflow>, WorkflowRepositoryError>;
async fn list_incomplete(&self) -> Result<Vec<PersistedWorkflow>, WorkflowRepositoryError>;
}