1use crate::topology_impl::PetTopologyGraph;
6use phago_core::topology::TopologyGraph;
7
8#[cfg(feature = "sqlite")]
9use std::path::PathBuf;
10
11#[derive(Debug, Clone)]
13pub enum BackendConfig {
14 InMemory,
16
17 #[cfg(feature = "sqlite")]
19 Sqlite {
20 path: Option<PathBuf>,
23 cache_size: usize,
25 },
26}
27
28impl Default for BackendConfig {
29 fn default() -> Self {
30 BackendConfig::InMemory
31 }
32}
33
34impl BackendConfig {
35 pub fn in_memory() -> Self {
37 BackendConfig::InMemory
38 }
39
40 #[cfg(feature = "sqlite")]
42 pub fn sqlite(path: impl Into<PathBuf>) -> Self {
43 BackendConfig::Sqlite {
44 path: Some(path.into()),
45 cache_size: 1000,
46 }
47 }
48
49 #[cfg(feature = "sqlite")]
51 pub fn sqlite_in_memory() -> Self {
52 BackendConfig::Sqlite {
53 path: None,
54 cache_size: 1000,
55 }
56 }
57
58 #[cfg(feature = "sqlite")]
60 pub fn with_cache_size(mut self, size: usize) -> Self {
61 if let BackendConfig::Sqlite { cache_size, .. } = &mut self {
62 *cache_size = size;
63 }
64 self
65 }
66}
67
68pub type DynTopologyGraph = Box<dyn TopologyGraph + Send + Sync>;
72
73pub fn create_backend(config: &BackendConfig) -> Result<DynTopologyGraph, BackendError> {
78 match config {
79 BackendConfig::InMemory => Ok(Box::new(PetTopologyGraph::new())),
80
81 #[cfg(feature = "sqlite")]
82 BackendConfig::Sqlite { path, cache_size } => {
83 use crate::sqlite_topology::SqliteTopologyGraph;
84
85 let graph = if let Some(p) = path {
86 SqliteTopologyGraph::open(p)
87 .map_err(|e| BackendError::SqliteError(e.to_string()))?
88 } else {
89 SqliteTopologyGraph::new_in_memory()
90 .map_err(|e| BackendError::SqliteError(e.to_string()))?
91 };
92
93 Ok(Box::new(graph.with_cache_size(*cache_size)))
94 }
95 }
96}
97
98#[derive(Debug, Clone)]
100pub enum BackendError {
101 #[cfg(feature = "sqlite")]
103 SqliteError(String),
104
105 Other(String),
107}
108
109impl std::fmt::Display for BackendError {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 #[cfg(feature = "sqlite")]
113 BackendError::SqliteError(msg) => write!(f, "SQLite error: {}", msg),
114 BackendError::Other(msg) => write!(f, "Backend error: {}", msg),
115 }
116 }
117}
118
119impl std::error::Error for BackendError {}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn create_in_memory_backend() {
127 let config = BackendConfig::in_memory();
128 let backend = create_backend(&config).unwrap();
129 assert_eq!(backend.node_count(), 0);
130 }
131
132 #[cfg(feature = "sqlite")]
133 #[test]
134 fn create_sqlite_in_memory_backend() {
135 let config = BackendConfig::sqlite_in_memory();
136 let backend = create_backend(&config).unwrap();
137 assert_eq!(backend.node_count(), 0);
138 }
139
140 #[cfg(feature = "sqlite")]
141 #[test]
142 fn create_sqlite_file_backend() {
143 let tmp = std::env::temp_dir().join("phago_backend_test.db");
144 let config = BackendConfig::sqlite(&tmp);
145 let backend = create_backend(&config).unwrap();
146 assert_eq!(backend.node_count(), 0);
147 std::fs::remove_file(&tmp).ok();
148 }
149}