xz_memory_engine/
config.rs1use std::sync::Arc;
2
3use serde::{Deserialize, Serialize};
4
5use xz_memory_core::StoreError;
6use xz_memory_core::traits::store::EntryStore;
7
8use crate::backends::InMemoryEntryStore;
9
10#[cfg(feature = "sqlite-backend")]
11use crate::backends::SqliteEntryStore;
12
13#[cfg(feature = "markdown-backend")]
14use crate::backends::MarkdownEntryStore;
15
16#[derive(Debug, Clone, Serialize, Deserialize, Default)]
18pub struct MemoryConfig {
19 pub storage: StorageConfig,
20}
21
22impl MemoryConfig {
23 pub async fn build(&self) -> Result<Arc<dyn EntryStore>, StoreError> {
30 match self.storage.backend.as_str() {
31 "memory" => Ok(Arc::new(InMemoryEntryStore::new())),
32 #[cfg(feature = "sqlite-backend")]
33 "sqlite" => Ok(Arc::new(SqliteEntryStore::new(&self.storage.path).await?)),
34 #[cfg(feature = "markdown-backend")]
35 "markdown" => {
36 Ok(Arc::new(MarkdownEntryStore::new(std::path::PathBuf::from(&self.storage.path))))
37 }
38 unknown => Err(StoreError::Config(format!("Unknown backend: {}", unknown))),
39 }
40 }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct StorageConfig {
46 pub backend: String,
48 pub path: String,
50 pub pool_size: u32,
52}
53
54impl Default for StorageConfig {
55 fn default() -> Self {
56 Self { backend: "sqlite".into(), path: "./data/memory.db".into(), pool_size: 5 }
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[tokio::test]
65 async fn build_memory_backend() {
66 let config = MemoryConfig {
67 storage: StorageConfig { backend: "memory".into(), path: String::new(), pool_size: 1 },
68 };
69 let store = config.build().await.unwrap();
70 let entry = xz_memory_core::types::entry::Entry {
71 id: "test-1".into(),
72 partition: "p".into(),
73 body: "hello".into(),
74 recorded_at: 100,
75 };
76 store.append(entry).await.unwrap();
77 let results = store
78 .query(
79 "p",
80 &xz_memory_core::types::entry::TimeRange { start: None, end: None },
81 &xz_memory_core::types::entry::QueryOptions {
82 limit: 10,
83 sort: xz_memory_core::types::entry::SortOrder::Ascending,
84 },
85 )
86 .await
87 .unwrap();
88 assert_eq!(results.len(), 1);
89 assert_eq!(results[0].body, "hello");
90 }
91
92 #[cfg(feature = "sqlite-backend")]
93 #[tokio::test]
94 async fn build_sqlite_backend() {
95 let config = MemoryConfig {
96 storage: StorageConfig {
97 backend: "sqlite".into(),
98 path: "sqlite::memory:".into(),
99 pool_size: 1,
100 },
101 };
102 let store = config.build().await.unwrap();
103 let entry = xz_memory_core::types::entry::Entry {
104 id: "sqlite-test-1".into(),
105 partition: "p".into(),
106 body: "from sqlite".into(),
107 recorded_at: 200,
108 };
109 store.append(entry).await.unwrap();
110 let results = store
111 .query(
112 "p",
113 &xz_memory_core::types::entry::TimeRange { start: None, end: None },
114 &xz_memory_core::types::entry::QueryOptions {
115 limit: 10,
116 sort: xz_memory_core::types::entry::SortOrder::Ascending,
117 },
118 )
119 .await
120 .unwrap();
121 assert_eq!(results.len(), 1);
122 assert_eq!(results[0].body, "from sqlite");
123 }
124
125 #[tokio::test]
126 async fn build_unknown_backend_returns_config_error() {
127 let config = MemoryConfig {
128 storage: StorageConfig {
129 backend: "postgres".into(),
130 path: String::new(),
131 pool_size: 1,
132 },
133 };
134 match config.build().await {
135 Err(e) => {
136 assert!(matches!(e, StoreError::Config(_)));
137 assert!(e.to_string().contains("postgres"));
138 }
139 Ok(_) => panic!("expected Err, got Ok"),
140 }
141 }
142}