use cm_domain::{shard_of, AgentId, Session, SessionId, WorkspaceId}; use sqlx::PgPool; use crate::DbError; fn row_to_session( id: uuid::Uuid, agent_id: uuid::Uuid, workspace_id: uuid::Uuid, title: String, shard: i16, created_at: time::OffsetDateTime, last_active_at: time::OffsetDateTime, ) -> Session { Session { id: SessionId::from(id), agent_id: AgentId::from(agent_id), workspace_id: WorkspaceId::from(workspace_id), title, shard: shard as u16, created_at, last_active_at, } } pub async fn create( pool: &PgPool, agent_id: AgentId, workspace_id: WorkspaceId, title: &str, ) -> Result { let id = SessionId::new(); let shard = shard_of(agent_id); let row = sqlx::query!( "INSERT INTO sessions (id, agent_id, workspace_id, title, shard) VALUES ($1, $2, $3, $4, $5) RETURNING created_at, last_active_at", id.as_uuid(), agent_id.as_uuid(), workspace_id.as_uuid(), title, shard as i16, ) .fetch_one(pool) .await?; Ok(Session { id, agent_id, workspace_id, title: title.to_owned(), shard, created_at: row.created_at, last_active_at: row.last_active_at, }) } pub async fn get(pool: &PgPool, id: SessionId) -> Result { let row = sqlx::query!( "SELECT id, agent_id, workspace_id, title, shard, created_at, last_active_at FROM sessions WHERE id = $1", id.as_uuid(), ) .fetch_one(pool) .await?; Ok(row_to_session( row.id, row.agent_id, row.workspace_id, row.title, row.shard, row.created_at, row.last_active_at, )) } /// Sessions column ordering (ยง6): most recently active first. pub async fn list_by_agent(pool: &PgPool, agent_id: AgentId) -> Result, DbError> { let rows = sqlx::query!( "SELECT id, agent_id, workspace_id, title, shard, created_at, last_active_at FROM sessions WHERE agent_id = $1 ORDER BY last_active_at DESC, id DESC", agent_id.as_uuid(), ) .fetch_all(pool) .await?; Ok(rows .into_iter() .map(|row| { row_to_session( row.id, row.agent_id, row.workspace_id, row.title, row.shard, row.created_at, row.last_active_at, ) }) .collect()) } /// Marks a session as just-used so it sorts to the top of the column. pub async fn touch(pool: &PgPool, id: SessionId) -> Result<(), DbError> { let result = sqlx::query!( "UPDATE sessions SET last_active_at = clock_timestamp() WHERE id = $1", id.as_uuid(), ) .execute(pool) .await?; if result.rows_affected() == 0 { return Err(DbError::NotFound); } Ok(()) }