1use cognee_graph::GraphDBTrait;
6use cognee_session::SessionStore;
7use cognee_storage::StorageTrait;
8use cognee_vector::VectorDB;
9use tracing::info;
10
11use super::error::ApiError;
12
13#[derive(Debug, Clone)]
15pub struct PruneTarget {
16 pub graph: bool,
18 pub vector: bool,
20 pub metadata: bool,
27 pub cache: bool,
29}
30
31impl PruneTarget {
32 pub fn default_system() -> Self {
34 Self {
35 graph: true,
36 vector: true,
37 metadata: false,
38 cache: true,
39 }
40 }
41
42 pub fn all() -> Self {
49 Self {
50 graph: true,
51 vector: true,
52 metadata: false,
53 cache: true,
54 }
55 }
56}
57
58impl Default for PruneTarget {
59 fn default() -> Self {
60 Self::default_system()
61 }
62}
63
64#[derive(Debug, Clone, Default)]
66pub struct PruneResult {
67 pub data_pruned: bool,
68 pub graph_pruned: bool,
69 pub vector_pruned: bool,
70 pub metadata_pruned: bool,
71 pub cache_pruned: bool,
72}
73
74pub async fn prune_data(storage: &dyn StorageTrait) -> Result<(), ApiError> {
78 storage.remove_all().await?;
79 info!("prune_data: all storage files removed");
80 Ok(())
81}
82
83pub async fn prune_system(
97 target: &PruneTarget,
98 graph_db: Option<&dyn GraphDBTrait>,
99 vector_db: Option<&dyn VectorDB>,
100 session_store: Option<&dyn SessionStore>,
101) -> Result<PruneResult, ApiError> {
102 let mut result = PruneResult::default();
103
104 if target.graph {
105 if let Some(gdb) = graph_db {
106 gdb.delete_graph().await?;
107 result.graph_pruned = true;
108 info!("prune_system: graph wiped");
109 } else {
110 tracing::warn!("prune_system: graph=true but no graph_db provided; skipping");
111 }
112 }
113
114 if target.vector {
115 if let Some(vdb) = vector_db {
116 vdb.prune().await?;
117 result.vector_pruned = true;
118 info!("prune_system: vector collections wiped");
119 } else {
120 tracing::warn!("prune_system: vector=true but no vector_db provided; skipping");
121 }
122 }
123
124 if target.metadata {
125 tracing::warn!(
130 "prune_system: metadata pruning is NOT implemented; the relational \
131 database was NOT dropped (result.metadata_pruned stays false)"
132 );
133 }
134
135 if target.cache {
136 if let Some(store) = session_store {
137 store.prune().await?;
138 result.cache_pruned = true;
139 info!("prune_system: session cache wiped");
140 } else {
141 tracing::warn!("prune_system: cache=true but no session_store provided; skipping");
142 }
143 }
144
145 Ok(result)
146}
147
148#[cfg(test)]
149#[allow(
150 clippy::unwrap_used,
151 clippy::expect_used,
152 reason = "test code — panics are acceptable failures"
153)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn prune_target_defaults_match_python() {
159 let target = PruneTarget::default();
160 assert!(target.graph);
161 assert!(target.vector);
162 assert!(!target.metadata, "metadata defaults to false like Python");
163 assert!(target.cache);
164 }
165
166 #[test]
167 fn prune_target_all_does_not_advertise_metadata() {
168 let target = PruneTarget::all();
171 assert!(target.graph);
172 assert!(target.vector);
173 assert!(
174 !target.metadata,
175 "all() must not advertise metadata=true until Option A is implemented"
176 );
177 assert!(target.cache);
178 }
179
180 #[tokio::test]
181 async fn prune_system_metadata_pruned_stays_false_when_not_implemented() {
182 let target = PruneTarget {
185 graph: false,
186 vector: false,
187 metadata: true,
188 cache: false,
189 };
190 let result = prune_system(&target, None, None, None)
191 .await
192 .expect("prune_system must not error");
193 assert!(
194 !result.metadata_pruned,
195 "metadata_pruned must be false when metadata drop is not implemented"
196 );
197 }
198}