Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ members = [
"crates/codegraph-ai",
"crates/codegraph-api",
"crates/codegraph-cli",
"crates/codegraph-napi",
"crates/core-rag-mcp-server",
"scripts",
"tests/integration"
Expand Down
210 changes: 147 additions & 63 deletions crates/codegraph-api/src/graph_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl CodeGraph {
}
}

/// Temporary stub for TransactionalGraph from codegraph-graph crate
/// TransactionalGraph with real storage-backed managers
#[derive(Clone)]
pub struct TransactionalGraph {
pub transaction_manager: ConcurrentTransactionManager,
Expand All @@ -69,6 +69,7 @@ pub struct TransactionalGraph {
}

impl TransactionalGraph {
/// Create a new TransactionalGraph with stub managers (for backward compatibility)
pub fn new() -> Self {
Self {
transaction_manager: ConcurrentTransactionManager::new(),
Expand All @@ -77,6 +78,32 @@ impl TransactionalGraph {
}
}

/// Create a new TransactionalGraph with real storage-backed managers
pub async fn with_storage(storage_path: &str) -> Result<Self> {
use codegraph_graph::{RecoveryManager as RealRecoveryManager, VersionedRocksDbStorage};
use tokio::sync::RwLock as TokioRwLock;
use std::sync::Arc;

// Initialize storage
let storage = VersionedRocksDbStorage::new(storage_path).await?;
let storage_arc = Arc::new(TokioRwLock::new(storage));

// Create managers with real storage
let transaction_manager = ConcurrentTransactionManager::with_storage(storage_arc.clone());
let version_manager = GitLikeVersionManager::with_storage(storage_arc.clone());

let recovery_manager = RealRecoveryManager::new(
storage_path,
format!("{}_backups", storage_path),
);

Ok(Self {
transaction_manager,
version_manager,
recovery_manager,
})
}

pub async fn begin_transaction(&self) -> Result<Transaction> {
Ok(Transaction {
_marker: std::marker::PhantomData,
Expand Down Expand Up @@ -180,46 +207,35 @@ pub struct IntegrityReport {
pub corrupted_data_count: usize,
}

// Stub manager types
// Note: uuid and chrono are already imported at the top of this file

// Define missing types that were incorrectly imported from codegraph_core
pub type TransactionId = Uuid;
pub type SnapshotId = Uuid;
pub type VersionId = Uuid;

#[derive(Debug, Clone)]
pub struct IsolationLevel;

#[derive(Debug, Clone)]
pub struct Snapshot {
pub id: SnapshotId,
pub timestamp: DateTime<Utc>,
}

#[derive(Debug, Clone)]
pub struct Version {
pub id: VersionId,
pub timestamp: DateTime<Utc>,
}

#[derive(Debug, Clone)]
pub struct VersionDiff {
pub added_nodes: Vec<NodeId>,
pub modified_nodes: Vec<NodeId>,
pub deleted_nodes: Vec<NodeId>,
}
// Import the real types from codegraph_core instead of redefining them
pub use codegraph_core::{
IsolationLevel, Snapshot, SnapshotId, TransactionId, Version, VersionDiff, VersionId,
};

#[derive(Clone)]
pub struct ConcurrentTransactionManager;
pub struct ConcurrentTransactionManager {
storage: Option<Arc<tokio::sync::RwLock<codegraph_graph::VersionedRocksDbStorage>>>,
}

impl ConcurrentTransactionManager {
pub fn new() -> Self {
Self
Self { storage: None }
}

pub async fn begin_transaction(&self, _isolation_level: IsolationLevel) -> Result<TransactionId> {
Ok(Uuid::new_v4())
pub fn with_storage(storage: Arc<tokio::sync::RwLock<codegraph_graph::VersionedRocksDbStorage>>) -> Self {
Self {
storage: Some(storage),
}
}

pub async fn begin_transaction(&self, isolation_level: IsolationLevel) -> Result<TransactionId> {
if let Some(storage) = &self.storage {
let mut guard = storage.write().await;
guard.begin_transaction(isolation_level).await
} else {
// Stub fallback
Ok(Uuid::new_v4())
}
}

pub async fn commit_transaction(&self, _tx_id: TransactionId) -> Result<()> {
Expand All @@ -241,60 +257,128 @@ impl ConcurrentTransactionManager {
}

#[derive(Clone)]
pub struct GitLikeVersionManager;
pub struct GitLikeVersionManager {
storage: Option<Arc<RwLock<codegraph_graph::VersionedRocksDbStorage>>>,
}

impl GitLikeVersionManager {
pub fn new() -> Self {
Self
Self { storage: None }
}

pub async fn create_version(&self, _name: String, _description: String, _author: String, _parent_versions: Vec<VersionId>) -> Result<VersionId> {
Ok(Uuid::new_v4())
pub fn with_storage(storage: Arc<RwLock<codegraph_graph::VersionedRocksDbStorage>>) -> Self {
Self {
storage: Some(storage),
}
}

pub async fn create_version(&self, name: String, description: String, author: String, parent_versions: Vec<VersionId>) -> Result<VersionId> {
if let Some(storage) = &self.storage {
let snapshot_id = Uuid::new_v4(); // TODO: Create real snapshot
let mut guard = storage.write().await;
guard.create_version(name, description, author, snapshot_id, parent_versions).await
} else {
// Stub fallback
Ok(Uuid::new_v4())
}
}

pub async fn list_versions(&self) -> Result<Vec<Version>> {
Ok(Vec::new())
if let Some(storage) = &self.storage {
let guard = storage.read().await;
guard.list_versions(None).await
} else {
// Stub fallback
Ok(Vec::new())
}
}

pub async fn get_version(&self, _id: VersionId) -> Result<Option<Version>> {
Ok(None)
pub async fn get_version(&self, id: VersionId) -> Result<Option<Version>> {
if let Some(storage) = &self.storage {
let guard = storage.read().await;
guard.get_version(id).await
} else {
// Stub fallback
Ok(None)
}
}

pub async fn tag_version(&self, _version_id: VersionId, _tag_name: String) -> Result<()> {
Ok(())
pub async fn tag_version(&self, version_id: VersionId, tag_name: String) -> Result<()> {
if let Some(storage) = &self.storage {
let mut guard = storage.write().await;
guard.tag_version(version_id, tag_name).await
} else {
Ok(())
}
}

pub async fn compare_versions(&self, _from: VersionId, _to: VersionId) -> Result<VersionDiff> {
Ok(VersionDiff {
added_nodes: Vec::new(),
deleted_nodes: Vec::new(),
modified_nodes: Vec::new(),
})
pub async fn compare_versions(&self, from: VersionId, to: VersionId) -> Result<VersionDiff> {
if let Some(storage) = &self.storage {
let guard = storage.read().await;
guard.compare_versions(from, to).await
} else {
Ok(VersionDiff {
added_nodes: Vec::new(),
deleted_nodes: Vec::new(),
modified_nodes: Vec::new(),
node_changes: HashMap::new(),
})
}
}

pub async fn create_branch(&self, _name: String, _from_version: VersionId) -> Result<()> {
Ok(())
pub async fn create_branch(&self, name: String, from_version: VersionId) -> Result<()> {
if let Some(storage) = &self.storage {
let mut guard = storage.write().await;
use codegraph_graph::GitLikeVersioning;
guard.create_branch(name, from_version, "system".to_string()).await
} else {
Ok(())
}
}

pub async fn list_branches(&self) -> Result<Vec<Branch>> {
Ok(Vec::new())
if let Some(storage) = &self.storage {
let guard = storage.read().await;
use codegraph_graph::GitLikeVersioning;
guard.list_branches().await
} else {
Ok(Vec::new())
}
}

pub async fn get_branch(&self, _name: String) -> Result<Option<Branch>> {
Ok(None)
pub async fn get_branch(&self, name: String) -> Result<Option<Branch>> {
if let Some(storage) = &self.storage {
let guard = storage.read().await;
use codegraph_graph::GitLikeVersioning;
guard.get_branch(&name).await
} else {
Ok(None)
}
}

pub async fn delete_branch(&self, _name: String) -> Result<()> {
Ok(())
pub async fn delete_branch(&self, name: String) -> Result<()> {
if let Some(storage) = &self.storage {
let mut guard = storage.write().await;
use codegraph_graph::GitLikeVersioning;
guard.delete_branch(&name).await
} else {
Ok(())
}
}

pub async fn merge_branches(&self, _source: String, _target: String) -> Result<MergeResult> {
Ok(MergeResult {
success: true,
conflicts: Vec::new(),
merged_version_id: Some(Uuid::new_v4()),
merge_commit_message: "Merged".to_string(),
})
pub async fn merge_branches(&self, source: String, target: String) -> Result<MergeResult> {
if let Some(storage) = &self.storage {
let mut guard = storage.write().await;
use codegraph_graph::GitLikeVersioning;
guard.merge(&source, &target, "system".to_string(), format!("Merge {} into {}", source, target)).await
} else {
Ok(MergeResult {
success: true,
conflicts: Vec::new(),
merged_version_id: Some(Uuid::new_v4()),
merge_commit_message: "Merged".to_string(),
})
}
}

pub async fn resolve_conflicts(&self, _conflicts: Vec<MergeConflict>) -> Result<()> {
Expand Down
17 changes: 16 additions & 1 deletion crates/codegraph-api/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,22 @@ pub struct AppState {
impl AppState {
pub async fn new(config: Arc<ConfigManager>) -> codegraph_core::Result<Self> {
let graph = Arc::new(RwLock::new(InMemoryGraph::new()));
let transactional_graph = Arc::new(TransactionalGraph::new());

// Try to initialize with real storage, fallback to stub if it fails
let storage_path = std::env::var("CODEGRAPH_STORAGE_PATH")
.unwrap_or_else(|_| "./codegraph_data".to_string());

let transactional_graph = match TransactionalGraph::with_storage(&storage_path).await {
Ok(tg) => {
tracing::info!("Initialized TransactionalGraph with real storage at {}", storage_path);
Arc::new(tg)
}
Err(e) => {
tracing::warn!("Failed to initialize real storage ({}), using stub fallback", e);
Arc::new(TransactionalGraph::new())
}
};

let parser = Arc::new(TreeSitterParser::new());
let vector_store = Arc::new(FaissVectorStore::new(384)?);
// Use advanced embeddings when CODEGRAPH_EMBEDDING_PROVIDER=local, otherwise fallback
Expand Down
Loading