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 field: "ledger".to_string(),
39 value: "json".to_string(),
40 reason_key: "error-parse-json".to_string(),
41 args: Some(std::collections::HashMap::from([("error".to_string(), e.to_string())])),
42 source_label: Some("JsonFileStore".to_string()),
43 asset_id: None
44 })))?;
45
46 tokio::fs::write(&self.path, json).await.map_err(|e: std::io::Error| ZakatError::NetworkError(format!("IO Error: {}", e)))?;
47 Ok(())
48 }
49
50 async fn load_events(&self) -> Result<Vec<LedgerEvent>, ZakatError> {
51 if !self.path.exists() {
52 return Ok(Vec::new());
53 }
54
55 let content = tokio::fs::read_to_string(&self.path).await.map_err(|e: std::io::Error| ZakatError::NetworkError(format!("IO Error: {}", e)))?;
56
57 if content.trim().is_empty() {
58 return Ok(Vec::new());
59 }
60
61 serde_json::from_str(&content).map_err(|e| ZakatError::InvalidInput(Box::new(InvalidInputDetails {
62 field: "ledger".to_string(),
63 value: "json".to_string(),
64 reason_key: "error-parse-json".to_string(),
65 args: Some(std::collections::HashMap::from([("error".to_string(), e.to_string())])),
66 source_label: Some("JsonFileStore".to_string()),
67 asset_id: None
68 })))
69 }
70}