use cognee_graph::GraphDBTrait;
use cognee_session::SessionStore;
use cognee_storage::StorageTrait;
use cognee_vector::VectorDB;
use tracing::info;
use super::error::ApiError;
#[derive(Debug, Clone)]
pub struct PruneTarget {
pub graph: bool,
pub vector: bool,
pub metadata: bool,
pub cache: bool,
}
impl PruneTarget {
pub fn default_system() -> Self {
Self {
graph: true,
vector: true,
metadata: false,
cache: true,
}
}
pub fn all() -> Self {
Self {
graph: true,
vector: true,
metadata: false,
cache: true,
}
}
}
impl Default for PruneTarget {
fn default() -> Self {
Self::default_system()
}
}
#[derive(Debug, Clone, Default)]
pub struct PruneResult {
pub data_pruned: bool,
pub graph_pruned: bool,
pub vector_pruned: bool,
pub metadata_pruned: bool,
pub cache_pruned: bool,
}
pub async fn prune_data(storage: &dyn StorageTrait) -> Result<(), ApiError> {
storage.remove_all().await?;
info!("prune_data: all storage files removed");
Ok(())
}
pub async fn prune_system(
target: &PruneTarget,
graph_db: Option<&dyn GraphDBTrait>,
vector_db: Option<&dyn VectorDB>,
session_store: Option<&dyn SessionStore>,
) -> Result<PruneResult, ApiError> {
let mut result = PruneResult::default();
if target.graph {
if let Some(gdb) = graph_db {
gdb.delete_graph().await?;
result.graph_pruned = true;
info!("prune_system: graph wiped");
} else {
tracing::warn!("prune_system: graph=true but no graph_db provided; skipping");
}
}
if target.vector {
if let Some(vdb) = vector_db {
vdb.prune().await?;
result.vector_pruned = true;
info!("prune_system: vector collections wiped");
} else {
tracing::warn!("prune_system: vector=true but no vector_db provided; skipping");
}
}
if target.metadata {
tracing::warn!(
"prune_system: metadata pruning is NOT implemented; the relational \
database was NOT dropped (result.metadata_pruned stays false)"
);
}
if target.cache {
if let Some(store) = session_store {
store.prune().await?;
result.cache_pruned = true;
info!("prune_system: session cache wiped");
} else {
tracing::warn!("prune_system: cache=true but no session_store provided; skipping");
}
}
Ok(result)
}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test code — panics are acceptable failures"
)]
mod tests {
use super::*;
#[test]
fn prune_target_defaults_match_python() {
let target = PruneTarget::default();
assert!(target.graph);
assert!(target.vector);
assert!(!target.metadata, "metadata defaults to false like Python");
assert!(target.cache);
}
#[test]
fn prune_target_all_does_not_advertise_metadata() {
let target = PruneTarget::all();
assert!(target.graph);
assert!(target.vector);
assert!(
!target.metadata,
"all() must not advertise metadata=true until Option A is implemented"
);
assert!(target.cache);
}
#[tokio::test]
async fn prune_system_metadata_pruned_stays_false_when_not_implemented() {
let target = PruneTarget {
graph: false,
vector: false,
metadata: true,
cache: false,
};
let result = prune_system(&target, None, None, None)
.await
.expect("prune_system must not error");
assert!(
!result.metadata_pruned,
"metadata_pruned must be false when metadata drop is not implemented"
);
}
}