use std::sync::Arc;
use tracing::{debug, info};
use crate::error::Result;
use crate::storage::{PersistedDocument, Workspace};
use super::types::DocumentInfo;
use crate::events::{EventEmitter, WorkspaceEvent};
#[derive(Clone)]
pub(crate) struct WorkspaceClient {
workspace: Arc<Workspace>,
events: EventEmitter,
}
impl WorkspaceClient {
pub async fn new(workspace: Workspace) -> Self {
Self {
workspace: Arc::new(workspace),
events: EventEmitter::new(),
}
}
pub fn with_events(mut self, events: EventEmitter) -> Self {
self.events = events;
self
}
pub async fn save(&self, doc: &PersistedDocument) -> Result<()> {
let doc_id = doc.meta.id.clone();
self.workspace.add(doc).await?;
info!("Saved document: {}", doc_id);
self.events.emit_workspace(WorkspaceEvent::Saved { doc_id });
Ok(())
}
pub async fn load(&self, doc_id: &str) -> Result<Option<PersistedDocument>> {
if !self.workspace.contains(doc_id).await {
return Ok(None);
}
let doc = self.workspace.load_and_cache(doc_id).await?;
let cache_hit = doc.is_some();
if let Some(ref _doc) = doc {
debug!("Loaded document: {} (cache={})", doc_id, cache_hit);
}
self.events.emit_workspace(WorkspaceEvent::Loaded {
doc_id: doc_id.to_string(),
cache_hit,
});
Ok(doc)
}
pub async fn remove(&self, doc_id: &str) -> Result<bool> {
let removed = self.workspace.remove(doc_id).await?;
if removed {
info!("Removed document: {}", doc_id);
self.events.emit_workspace(WorkspaceEvent::Removed {
doc_id: doc_id.to_string(),
});
}
Ok(removed)
}
pub async fn exists(&self, doc_id: &str) -> Result<bool> {
Ok(self.workspace.contains(doc_id).await)
}
pub async fn list(&self) -> Result<Vec<DocumentInfo>> {
let doc_ids = self.workspace.list_documents().await;
let mut result = Vec::with_capacity(doc_ids.len());
for id in &doc_ids {
if let Some(meta) = self.workspace.get_meta(id).await {
result.push(DocumentInfo {
id: meta.id,
name: meta.doc_name,
format: meta.doc_type,
description: meta.doc_description,
source_path: meta.path,
page_count: meta.page_count,
line_count: meta.line_count,
});
}
}
Ok(result)
}
pub async fn get_document_info(&self, doc_id: &str) -> Result<Option<DocumentInfo>> {
Ok(self
.workspace
.get_meta(doc_id)
.await
.map(|meta| DocumentInfo {
id: meta.id,
name: meta.doc_name,
format: meta.doc_type,
description: meta.doc_description,
source_path: meta.path,
page_count: meta.page_count,
line_count: meta.line_count,
}))
}
pub async fn clear(&self) -> Result<usize> {
let doc_ids = self.workspace.list_documents().await;
let count = doc_ids.len();
for doc_id in &doc_ids {
let _ = self.workspace.remove(doc_id).await;
}
if count > 0 {
info!("Cleared workspace: {} documents removed", count);
self.events
.emit_workspace(WorkspaceEvent::Cleared { count });
}
Ok(count)
}
pub(crate) fn inner(&self) -> Arc<Workspace> {
Arc::clone(&self.workspace)
}
pub async fn find_by_source_path(&self, path: &std::path::Path) -> Option<String> {
self.workspace.find_by_source_path(path).await
}
pub async fn get_graph(&self) -> Result<Option<crate::graph::DocumentGraph>> {
self.workspace.get_graph().await
}
pub async fn set_graph(&self, graph: &crate::graph::DocumentGraph) -> Result<()> {
self.workspace.set_graph(graph).await
}
}