openzeppelin_monitor/repositories/
trigger.rs1#![allow(clippy::result_large_err)]
8
9use std::{collections::HashMap, path::Path};
10
11use async_trait::async_trait;
12
13use crate::{
14	models::{ConfigLoader, Trigger},
15	repositories::error::RepositoryError,
16};
17
18#[derive(Clone)]
20pub struct TriggerRepository {
21	pub triggers: HashMap<String, Trigger>,
23}
24
25impl TriggerRepository {
26	pub async fn new(path: Option<&Path>) -> Result<Self, RepositoryError> {
31		let triggers = Self::load_all(path).await?;
32		Ok(TriggerRepository { triggers })
33	}
34}
35
36#[async_trait]
41pub trait TriggerRepositoryTrait: Clone {
42	async fn new(path: Option<&Path>) -> Result<Self, RepositoryError>
44	where
45		Self: Sized;
46
47	async fn load_all(path: Option<&Path>) -> Result<HashMap<String, Trigger>, RepositoryError>;
52
53	fn get(&self, trigger_id: &str) -> Option<Trigger>;
57
58	fn get_all(&self) -> HashMap<String, Trigger>;
62}
63
64#[async_trait]
65impl TriggerRepositoryTrait for TriggerRepository {
66	async fn new(path: Option<&Path>) -> Result<Self, RepositoryError> {
67		TriggerRepository::new(path).await
68	}
69
70	async fn load_all(path: Option<&Path>) -> Result<HashMap<String, Trigger>, RepositoryError> {
71		Trigger::load_all(path).await.map_err(|e| {
72			RepositoryError::load_error(
73				"Failed to load triggers",
74				Some(Box::new(e)),
75				Some(HashMap::from([(
76					"path".to_string(),
77					path.map_or_else(|| "default".to_string(), |p| p.display().to_string()),
78				)])),
79			)
80		})
81	}
82
83	fn get(&self, trigger_id: &str) -> Option<Trigger> {
84		self.triggers.get(trigger_id).cloned()
85	}
86
87	fn get_all(&self) -> HashMap<String, Trigger> {
88		self.triggers.clone()
89	}
90}
91
92#[derive(Clone)]
97pub struct TriggerService<T: TriggerRepositoryTrait> {
98	repository: T,
99}
100
101impl<T: TriggerRepositoryTrait> TriggerService<T> {
102	pub async fn new(
104		path: Option<&Path>,
105	) -> Result<TriggerService<TriggerRepository>, RepositoryError> {
106		let repository = TriggerRepository::new(path).await?;
107		Ok(TriggerService { repository })
108	}
109
110	pub fn new_with_repository(repository: T) -> Result<Self, RepositoryError> {
112		Ok(TriggerService { repository })
113	}
114
115	pub async fn new_with_path(
117		path: Option<&Path>,
118	) -> Result<TriggerService<TriggerRepository>, RepositoryError> {
119		let repository = TriggerRepository::new(path).await?;
120		Ok(TriggerService { repository })
121	}
122
123	pub fn get(&self, trigger_id: &str) -> Option<Trigger> {
125		self.repository.get(trigger_id)
126	}
127
128	pub fn get_all(&self) -> HashMap<String, Trigger> {
130		self.repository.get_all()
131	}
132}
133
134#[cfg(test)]
135mod tests {
136	use super::*;
137	use crate::repositories::error::RepositoryError;
138	use std::path::PathBuf;
139
140	#[tokio::test]
141	async fn test_load_error_messages() {
142		let invalid_path = PathBuf::from("/non/existent/path");
144		let result = TriggerRepository::load_all(Some(&invalid_path)).await;
145		assert!(result.is_err());
146		let err = result.unwrap_err();
147		match err {
148			RepositoryError::LoadError(message) => {
149				assert!(message.to_string().contains("Failed to load triggers"));
150			}
151			_ => panic!("Expected RepositoryError::LoadError"),
152		}
153	}
154}