use crate::error::Result;
use crate::workspace::CurrentTaskResponse;
use neo4rs::{query, Graph};
use super::task_manager::neo4j_err;
pub struct Neo4jWorkspaceManager {
graph: Graph,
project_id: String,
}
impl Neo4jWorkspaceManager {
pub fn new(graph: Graph, project_id: String) -> Self {
Self { graph, project_id }
}
pub async fn get_current_task(
&self,
session_id: Option<String>,
) -> Result<CurrentTaskResponse> {
let session_id = crate::workspace::resolve_session_id(session_id.as_deref());
let mut result = self
.graph
.execute(
query(
"OPTIONAL MATCH (s:Session {project_id: $pid, session_id: $sid}) \
OPTIONAL MATCH (t:Task {project_id: $pid, id: s.current_task_id}) \
RETURN s.current_task_id AS current_task_id, t",
)
.param("pid", self.project_id.clone())
.param("sid", session_id.clone()),
)
.await
.map_err(|e| neo4j_err("get_current_task query", e))?;
match result
.next()
.await
.map_err(|e| neo4j_err("get_current_task fetch", e))?
{
Some(row) => {
let current_task_id: Option<i64> = row.get("current_task_id").ok();
let task = row
.get::<neo4rs::Node>("t")
.ok()
.and_then(|node| super::task_manager::node_to_task(&node).ok());
Ok(CurrentTaskResponse {
current_task_id,
task,
session_id: Some(session_id),
})
},
None => Ok(CurrentTaskResponse {
current_task_id: None,
task: None,
session_id: Some(session_id),
}),
}
}
pub async fn set_current_task(
&self,
task_id: i64,
session_id: Option<String>,
) -> Result<CurrentTaskResponse> {
let session_id = crate::workspace::resolve_session_id(session_id.as_deref());
self.graph
.run(
query(
"MERGE (s:Session {project_id: $pid, session_id: $sid}) \
ON CREATE SET s.created_at = datetime(), s.last_active_at = datetime() \
ON MATCH SET s.last_active_at = datetime() \
SET s.current_task_id = $tid",
)
.param("pid", self.project_id.clone())
.param("sid", session_id.clone())
.param("tid", task_id),
)
.await
.map_err(|e| neo4j_err("set_current_task", e))?;
self.get_current_task(Some(session_id)).await
}
pub async fn clear_current_task(&self, session_id: Option<String>) -> Result<()> {
let session_id = crate::workspace::resolve_session_id(session_id.as_deref());
self.graph
.run(
query(
"MATCH (s:Session {project_id: $pid, session_id: $sid}) \
SET s.current_task_id = null, s.last_active_at = datetime()",
)
.param("pid", self.project_id.clone())
.param("sid", session_id),
)
.await
.map_err(|e| neo4j_err("clear_current_task", e))?;
Ok(())
}
}
impl crate::backend::WorkspaceBackend for Neo4jWorkspaceManager {
fn get_current_task(
&self,
session_id: Option<String>,
) -> impl std::future::Future<Output = crate::error::Result<CurrentTaskResponse>> + Send {
self.get_current_task(session_id)
}
fn set_current_task(
&self,
task_id: i64,
session_id: Option<String>,
) -> impl std::future::Future<Output = crate::error::Result<CurrentTaskResponse>> + Send {
self.set_current_task(task_id, session_id)
}
fn clear_current_task(
&self,
session_id: Option<String>,
) -> impl std::future::Future<Output = crate::error::Result<()>> + Send {
self.clear_current_task(session_id)
}
}