Skip to main content

sqlitegraph_cli/
client.rs

1use sqlitegraph::backend::GraphBackend;
2use sqlitegraph::backend::SqliteGraphBackend;
3
4/// CLI backend client supporting SQLite and V3 backends
5///
6/// Both variants box their payload so the enum stays pointer-sized
7/// (8 bytes) instead of being bloated to ~1.2 KB by the V3 variant,
8/// avoiding `clippy::large_enum_variant`. The CLI only ever holds
9/// one `CliClient` at a time, so the extra heap indirection has no
10/// measurable cost vs. paying for the largest variant on every value.
11pub enum CliClient {
12    Sqlite(Box<SqliteGraphBackend>),
13    #[cfg(feature = "native-v3")]
14    V3(Box<sqlitegraph::backend::native::v3::V3Backend>),
15}
16
17impl CliClient {
18    /// Open database with specified backend
19    pub fn open(backend: super::cli::BackendType, path: &std::path::Path) -> anyhow::Result<Self> {
20        match backend {
21            super::cli::BackendType::Sqlite => {
22                let graph = sqlitegraph::SqliteGraph::open(path)?;
23                Ok(Self::Sqlite(Box::new(SqliteGraphBackend::from_graph(
24                    graph,
25                ))))
26            }
27            #[cfg(feature = "native-v3")]
28            super::cli::BackendType::V3 => {
29                use sqlitegraph::backend::native::v3::V3Backend;
30                let backend = if path.exists() {
31                    V3Backend::open(path)?
32                } else {
33                    V3Backend::create(path)?
34                };
35                Ok(Self::V3(Box::new(backend)))
36            }
37        }
38    }
39
40    /// Open in-memory database
41    pub fn open_in_memory(backend: super::cli::BackendType) -> anyhow::Result<Self> {
42        match backend {
43            super::cli::BackendType::Sqlite => {
44                let graph = sqlitegraph::SqliteGraph::open_in_memory()?;
45                Ok(Self::Sqlite(Box::new(SqliteGraphBackend::from_graph(
46                    graph,
47                ))))
48            }
49            #[cfg(feature = "native-v3")]
50            super::cli::BackendType::V3 => {
51                anyhow::bail!("V3 backend does not support in-memory mode")
52            }
53        }
54    }
55
56    /// Get backend trait object
57    pub fn backend(&self) -> &dyn GraphBackend {
58        match self {
59            Self::Sqlite(b) => b.as_ref(),
60            #[cfg(feature = "native-v3")]
61            Self::V3(b) => b.as_ref(),
62        }
63    }
64
65    /// Get SQLite graph reference (if SQLite backend)
66    pub fn sqlite_graph(&self) -> Option<&sqlitegraph::SqliteGraph> {
67        match self {
68            Self::Sqlite(b) => Some(b.graph()),
69            #[cfg(feature = "native-v3")]
70            Self::V3(_) => None,
71        }
72    }
73
74    /// Get SQLite backend reference (for Cypher queries)
75    pub fn sqlite_backend(&self) -> Option<&SqliteGraphBackend> {
76        match self {
77            Self::Sqlite(b) => Some(b.as_ref()),
78            #[cfg(feature = "native-v3")]
79            Self::V3(_) => None,
80        }
81    }
82
83    /// Get backend name
84    pub fn backend_name(&self) -> &'static str {
85        match self {
86            Self::Sqlite(_) => "sqlite",
87            #[cfg(feature = "native-v3")]
88            Self::V3(_) => "v3",
89        }
90    }
91
92    /// Get node count
93    pub fn node_count(&self) -> anyhow::Result<usize> {
94        let ids = self.backend().entity_ids()?;
95        Ok(ids.len())
96    }
97}