use crate::database::universal_types::{UniversalTimestamp, UniversalUuid};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TriggerExecution {
pub id: UniversalUuid,
pub trigger_name: String,
pub context_hash: String,
pub pipeline_execution_id: Option<UniversalUuid>,
pub started_at: UniversalTimestamp,
pub completed_at: Option<UniversalTimestamp>,
pub created_at: UniversalTimestamp,
pub updated_at: UniversalTimestamp,
}
impl TriggerExecution {
pub fn is_in_progress(&self) -> bool {
self.completed_at.is_none()
}
pub fn duration(&self) -> Option<chrono::Duration> {
self.completed_at
.map(|completed| completed.0 - self.started_at.0)
}
pub fn started_at(&self) -> DateTime<Utc> {
self.started_at.0
}
pub fn completed_at(&self) -> Option<DateTime<Utc>> {
self.completed_at.map(|ts| ts.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewTriggerExecution {
pub id: Option<UniversalUuid>,
pub trigger_name: String,
pub context_hash: String,
pub pipeline_execution_id: Option<UniversalUuid>,
pub started_at: Option<UniversalTimestamp>,
pub completed_at: Option<UniversalTimestamp>,
}
impl NewTriggerExecution {
pub fn new(trigger_name: &str, context_hash: &str) -> Self {
Self {
id: Some(UniversalUuid::new_v4()),
trigger_name: trigger_name.to_string(),
context_hash: context_hash.to_string(),
pipeline_execution_id: None,
started_at: None,
completed_at: None,
}
}
pub fn with_pipeline_execution(
trigger_name: &str,
context_hash: &str,
pipeline_execution_id: UniversalUuid,
) -> Self {
Self {
id: Some(UniversalUuid::new_v4()),
trigger_name: trigger_name.to_string(),
context_hash: context_hash.to_string(),
pipeline_execution_id: Some(pipeline_execution_id),
started_at: None,
completed_at: None,
}
}
pub fn with_started_at(
trigger_name: &str,
context_hash: &str,
pipeline_execution_id: Option<UniversalUuid>,
started_at: DateTime<Utc>,
) -> Self {
Self {
id: Some(UniversalUuid::new_v4()),
trigger_name: trigger_name.to_string(),
context_hash: context_hash.to_string(),
pipeline_execution_id,
started_at: Some(UniversalTimestamp(started_at)),
completed_at: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::database::universal_types::current_timestamp;
use chrono::Duration;
#[test]
fn test_new_trigger_execution() {
let new_execution = NewTriggerExecution::new("test_trigger", "abc123");
assert_eq!(new_execution.trigger_name, "test_trigger");
assert_eq!(new_execution.context_hash, "abc123");
assert!(new_execution.pipeline_execution_id.is_none());
assert!(new_execution.started_at.is_none());
assert!(new_execution.completed_at.is_none());
}
#[test]
fn test_trigger_execution_in_progress() {
let now = current_timestamp();
let execution = TriggerExecution {
id: UniversalUuid::new_v4(),
trigger_name: "test_trigger".to_string(),
context_hash: "abc123".to_string(),
pipeline_execution_id: Some(UniversalUuid::new_v4()),
started_at: now,
completed_at: None,
created_at: now,
updated_at: now,
};
assert!(execution.is_in_progress());
assert!(execution.duration().is_none());
}
#[test]
fn test_trigger_execution_completed() {
let start = Utc::now() - Duration::minutes(5);
let end = Utc::now();
let execution = TriggerExecution {
id: UniversalUuid::new_v4(),
trigger_name: "test_trigger".to_string(),
context_hash: "abc123".to_string(),
pipeline_execution_id: Some(UniversalUuid::new_v4()),
started_at: UniversalTimestamp(start),
completed_at: Some(UniversalTimestamp(end)),
created_at: UniversalTimestamp(start),
updated_at: UniversalTimestamp(end),
};
assert!(!execution.is_in_progress());
let duration = execution.duration().unwrap();
assert!(duration >= Duration::minutes(4) && duration <= Duration::minutes(6));
}
}