zakat_sqlite/
persistence.rs1use async_trait::async_trait;
6use std::path::PathBuf;
7use zakat_core::types::{ZakatError, InvalidInputDetails};
8use zakat_ledger::events::LedgerEvent;
9
10#[async_trait]
12pub trait LedgerStore: Send + Sync {
13 async fn save_event(&self, event: &LedgerEvent) -> Result<(), ZakatError>;
15
16 async fn load_events(&self) -> Result<Vec<LedgerEvent>, ZakatError>;
18}
19
20pub struct JsonFileStore {
22 path: PathBuf,
23}
24
25impl JsonFileStore {
26 pub fn new(path: impl Into<PathBuf>) -> Self {
27 Self { path: path.into() }
28 }
29}
30
31#[async_trait]
32impl LedgerStore for JsonFileStore {
33 async fn save_event(&self, event: &LedgerEvent) -> Result<(), ZakatError> {
34 let mut events = self.load_events().await.unwrap_or_default();
35 events.push(event.clone());
36
37 let json = serde_json::to_string_pretty(&events).map_err(|e| ZakatError::InvalidInput(Box::new(InvalidInputDetails {
38 code: zakat_core::types::ZakatErrorCode::InvalidInput,
39 field: "ledger".to_string(),
40 value: "json".to_string(),
41 reason_key: "error-parse-json".to_string(),
42 args: Some(std::collections::HashMap::from([("error".to_string(), e.to_string())])),
43 source_label: Some("JsonFileStore".to_string()),
44 ..Default::default()
45 })))?;
46
47 tokio::fs::write(&self.path, json).await.map_err(|e: std::io::Error| ZakatError::NetworkError(format!("IO Error: {}", e)))?;
48 Ok(())
49 }
50
51 async fn load_events(&self) -> Result<Vec<LedgerEvent>, ZakatError> {
52 if !self.path.exists() {
53 return Ok(Vec::new());
54 }
55
56 let content = tokio::fs::read_to_string(&self.path).await.map_err(|e: std::io::Error| ZakatError::NetworkError(format!("IO Error: {}", e)))?;
57
58 if content.trim().is_empty() {
59 return Ok(Vec::new());
60 }
61
62 serde_json::from_str(&content).map_err(|e| ZakatError::InvalidInput(Box::new(InvalidInputDetails {
63 code: zakat_core::types::ZakatErrorCode::InvalidInput,
64 field: "ledger".to_string(),
65 value: "json".to_string(),
66 reason_key: "error-parse-json".to_string(),
67 args: Some(std::collections::HashMap::from([("error".to_string(), e.to_string())])),
68 source_label: Some("JsonFileStore".to_string()),
69 ..Default::default()
70 })))
71 }
72}