use std::sync::Arc;
use serde::{Deserialize, Serialize};
use xz_memory_core::StoreError;
use xz_memory_core::traits::store::EntryStore;
use crate::backends::InMemoryEntryStore;
#[cfg(feature = "sqlite-backend")]
use crate::backends::SqliteEntryStore;
#[cfg(feature = "markdown-backend")]
use crate::backends::MarkdownEntryStore;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MemoryConfig {
pub storage: StorageConfig,
}
impl MemoryConfig {
pub async fn build(&self) -> Result<Arc<dyn EntryStore>, StoreError> {
match self.storage.backend.as_str() {
"memory" => Ok(Arc::new(InMemoryEntryStore::new())),
#[cfg(feature = "sqlite-backend")]
"sqlite" => Ok(Arc::new(SqliteEntryStore::new(&self.storage.path).await?)),
#[cfg(feature = "markdown-backend")]
"markdown" => {
Ok(Arc::new(MarkdownEntryStore::new(std::path::PathBuf::from(&self.storage.path))))
}
unknown => Err(StoreError::Config(format!("Unknown backend: {}", unknown))),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageConfig {
pub backend: String,
pub path: String,
pub pool_size: u32,
}
impl Default for StorageConfig {
fn default() -> Self {
Self { backend: "sqlite".into(), path: "./data/memory.db".into(), pool_size: 5 }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn build_memory_backend() {
let config = MemoryConfig {
storage: StorageConfig { backend: "memory".into(), path: String::new(), pool_size: 1 },
};
let store = config.build().await.unwrap();
let entry = xz_memory_core::types::entry::Entry {
id: "test-1".into(),
partition: "p".into(),
body: "hello".into(),
recorded_at: 100,
};
store.append(entry).await.unwrap();
let results = store
.query(
"p",
&xz_memory_core::types::entry::TimeRange { start: None, end: None },
&xz_memory_core::types::entry::QueryOptions {
limit: 10,
sort: xz_memory_core::types::entry::SortOrder::Ascending,
},
)
.await
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].body, "hello");
}
#[cfg(feature = "sqlite-backend")]
#[tokio::test]
async fn build_sqlite_backend() {
let config = MemoryConfig {
storage: StorageConfig {
backend: "sqlite".into(),
path: "sqlite::memory:".into(),
pool_size: 1,
},
};
let store = config.build().await.unwrap();
let entry = xz_memory_core::types::entry::Entry {
id: "sqlite-test-1".into(),
partition: "p".into(),
body: "from sqlite".into(),
recorded_at: 200,
};
store.append(entry).await.unwrap();
let results = store
.query(
"p",
&xz_memory_core::types::entry::TimeRange { start: None, end: None },
&xz_memory_core::types::entry::QueryOptions {
limit: 10,
sort: xz_memory_core::types::entry::SortOrder::Ascending,
},
)
.await
.unwrap();
assert_eq!(results.len(), 1);
assert_eq!(results[0].body, "from sqlite");
}
#[tokio::test]
async fn build_unknown_backend_returns_config_error() {
let config = MemoryConfig {
storage: StorageConfig {
backend: "postgres".into(),
path: String::new(),
pool_size: 1,
},
};
match config.build().await {
Err(e) => {
assert!(matches!(e, StoreError::Config(_)));
assert!(e.to_string().contains("postgres"));
}
Ok(_) => panic!("expected Err, got Ok"),
}
}
}