use super::StateRuntime; use crate::model::datetime_to_epoch_millis; use chrono::Utc; use serde::Deserialize; use serde::Serialize; use sqlx::Row; use std::path::PathBuf; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExternalAgentConfigImportSuccessRecord { pub item_type: String, pub cwd: Option, pub source: Option, pub target: Option, #[serde(default)] pub title: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExternalAgentConfigImportFailureRecord { pub item_type: String, pub error_type: Option, #[serde(default)] pub sub_error_type: Option, pub failure_stage: String, pub message: String, pub cwd: Option, pub source: Option, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExternalAgentConfigImportDetailsRecord { pub successes: Vec, pub failures: Vec, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ExternalAgentConfigImportHistoryRecord { pub import_id: String, pub provider_id: Option, pub completed_at_ms: i64, pub successes: Vec, pub failures: Vec, } impl StateRuntime { pub async fn record_external_agent_config_import_completed( &self, import_id: &str, provider_id: Option<&str>, successes: &[ExternalAgentConfigImportSuccessRecord], failures: &[ExternalAgentConfigImportFailureRecord], ) -> anyhow::Result<()> { sqlx::query( r#" INSERT INTO external_agent_config_imports ( import_id, provider_id, completed_at_ms, successes, failures ) VALUES (?, ?, ?, ?, ?) ON CONFLICT(import_id) DO UPDATE SET provider_id = excluded.provider_id, completed_at_ms = excluded.completed_at_ms, successes = excluded.successes, failures = excluded.failures "#, ) .bind(import_id) .bind(provider_id) .bind(datetime_to_epoch_millis(Utc::now())) .bind(serde_json::to_string(successes)?) .bind(serde_json::to_string(failures)?) .execute(self.pool.as_ref()) .await?; Ok(()) } pub async fn external_agent_config_import_details_record( &self, import_id: &str, ) -> anyhow::Result> { let row = sqlx::query( r#" SELECT successes, failures FROM external_agent_config_imports WHERE import_id = ? "#, ) .bind(import_id) .fetch_optional(self.pool.as_ref()) .await?; row.map(|row| { let successes: String = row.try_get("successes")?; let failures: String = row.try_get("failures")?; Ok(ExternalAgentConfigImportDetailsRecord { successes: serde_json::from_str(&successes)?, failures: serde_json::from_str(&failures)?, }) }) .transpose() } pub async fn external_agent_config_import_history_records( &self, ) -> anyhow::Result> { let rows = sqlx::query( r#" SELECT import_id, provider_id, completed_at_ms, successes, failures FROM external_agent_config_imports ORDER BY completed_at_ms DESC, import_id ASC "#, ) .fetch_all(self.pool.as_ref()) .await?; rows.into_iter() .map(|row| { let import_id: String = row.try_get("import_id")?; let provider_id: Option = row.try_get("provider_id")?; let completed_at_ms: i64 = row.try_get("completed_at_ms")?; let successes: String = row.try_get("successes")?; let failures: String = row.try_get("failures")?; Ok(ExternalAgentConfigImportHistoryRecord { import_id, provider_id, completed_at_ms, successes: serde_json::from_str(&successes)?, failures: serde_json::from_str(&failures)?, }) }) .collect() } } #[cfg(test)] #[path = "external_agent_config_imports_tests.rs"] mod tests;